Repository navigation
fix(composer): render skills as atomic inline book tags - #6663
Conversation
Use the existing RichEditor for inline skill atoms in drafts and sent messages, preserving canonical source text and whole-node editing. Keep completion, clipboard, IME and application shortcuts integrated. Fix reproduced NSH focus, composition and shortcut routing faults. Generated-by: Codex
Astro-Han
left a comment
There was a problem hiding this comment.
I reviewed all 30 changed files at b5e02cb, including the composer/message adapters, source-address projection, native key routing and plugin-authoring example. I found two P2 issues:
-
A skill atom survives after ordinary editing invalidates its invocation boundary (
composer_input/model.rs:281–315). Starting with a confirmed/skill:reviewatom, move before it and typex. The source becomesx/skill:review, for which both the editor grammar and the host invocation scanner find no skill.tokenizeonly adds/replaces matching tokens and leaves the old atom intact. It still renders as a skill and Backspace after it deletes the entire invocation. I reproduced this using the unchanged production model against the actual NSH editor-state/core crates. A freshly constructed document with the identical final text correctly has only plain text. Retokenization needs to turn existing atoms whose current surrounding source no longer matches into text, while preserving selection and undo. -
Existing terminal component fixtures cannot bundle the new composer (
SkillInput.tsx:20). The new unconditionalmaka/hostimport is registered in production and the new workbench fixture, but existing registries interminal-shell/tests/real_host/components.rs:45–60andterminal-shell/src/terminal/ui.rs:608–623only exposehost. The current CI logs fail with`maka/host` has no export `ComposerInput`across all six CLI partitions and both rest-1 partitions. These are actual bundle errors at the new import, not inferred timeout causes. Register the real component and state class through a shared accessible fixture registry, and rerun those existing tests. The production registration alone does not repair the test registries.
Local verification: both committed JavaScript skill-message tests and all six committed Rust model tests passed. The Rust model ran from a byte-identical source copy in an isolated package using this head's NSH core/base/macros; I limited the probe workspace and removed unrelated development dependencies/codec patch, without changing model or dependency Rust source. The additional edit/deletion sequence and fresh-document control produced the first finding. This was not a native desktop run. I have not independently run the full workbench/GPUI suites or macOS AppKit acceptance; the PR's broader local results remain the author's results.
merge-tree against rust-preview@41767ca7 succeeds. CI 42176376971 checks out synthetic merge d061368 into 7216229 and is red. Native7 repeats the separately established #6655 instruction-ack fixture failure. Additional CLI/Desktop waits are present; I have not assigned them to either finding without a separate causal check. No protocol or database migration changes. No approval or merge performed.
Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.
| let caret = projection.source_at(state.selection().head()) as usize; | ||
| let anchor = projection.source_at(state.selection().anchor()) as usize; | ||
| let mut replacements = Vec::new(); | ||
| for range in token_ranges(&projection.source) { |
There was a problem hiding this comment.
[P2] Remove skill atoms when edits invalidate their source boundary
This loop only considers current matches, so existing atoms outside those matches are never converted back to text. With the real model/EditorState: construct the confirmed /skill:review atom, place the caret at its start, insert x, then run tokenize. The resulting source is x/skill:review; token_ranges is empty, tokenize returns None, yet the second inline node remains skill. Moving after it and Backspace deletes the complete invocation. A fresh document from the same source has one plain text node. The host scanner also requires a whitespace/start boundary, so submitting the displayed skill does not invoke it. Reconcile existing atoms against the full source grammar, not only newly found token ranges, preserving selection and undo.
| * under the License. | ||
| */ | ||
|
|
||
| import { ComposerInput } from 'maka/host'; |
There was a problem hiding this comment.
[P2] Update the existing fixture registries for this new native export
The production and new skill-input fixture registries are updated, but terminal-shell/tests/real_host/components.rs and the fixture in terminal-shell/src/terminal/ui.rs still create maka/host registries containing only host. Importing their existing component fixture now reaches this import and fails before rendering. Current CI42176376971 records the exact maka/host has no export ComposerInput BundleError in CLI jobs127763590415/456/439/405/476/384 and rest-1 jobs127763590423/532. Expose/register the real component plus state class for those existing fixtures and rerun them; a stub declaration alone would only defer the failure to runtime.
Keep source and selection current across composition, paste and application shortcuts. Cover atomic skill editing through behavioral tests and update native editor consumers. Generated-by: Codex
Astro-Han
left a comment
There was a problem hiding this comment.
I rechecked the final 40-file change at ac283a3 against the previously reviewed b5e02cb version. I read the complete intervening delta, including the extra fixtures/tests, native editor behavior, key binding fallback, composition and paste handling, and the public UI registry; this supplements the earlier 30-file review.
Both previously reported P2 issues are fixed in the checked paths. model::tokenize now replaces a skill atom whose surrounding source no longer forms a valid token with identical plain source. Using the actual final model and NSH editor-state code, prefixing the atom with x produced plain x/skill:review; a normal backspace then removed one character. The old model control retained the invalid atom. The two current committed model tests pass, alongside six separately identified old-model control tests. All 428 extracted Rust dependency source files and both model versions were checked against their Git blobs; only the isolated workspace manifests were adapted to build the probe. This is an editor-model test, not a complete workbench build. Nine unmodified history tests also pass locally.
The missing native fixture export is addressed by bindings::ui_registry(), which registers ComposerInput and ComposerInputState and is now used by the relevant terminal/pixel/workbench fixture registries. I checked that production registry construction uses the same function. I did not independently execute the native fixture/GPUI suite.
CI remains unresolved. In final-head run 42208071888, the actual checkout is 89c11be (ac283a3 merged into d77b0ff). CLI slices 1/3/6 fail while waiting for enabled Send or persisted drafts, including directory paste, provider failure, workspace trust, attachment-only send and rejected-send preservation. Desktop CLI slice 1 also fails waiting for the expected Unicode draft. I read these job logs. They are current failures, distinct from the earlier missing-export issue; I have not isolated whether each is a production regression or a test/setup problem, so I am not assigning an additional P2 from the timeouts alone or calling CI successful. Some other jobs are still running.
The final head merges without conflicts into fetched rust-preview 42ea54a. The two earlier findings can be closed on the evidence above; complete native input/IME/clipboard and the failing real-Host flows still need acceptance. No protocol/database changes; no approval or merge performed.
Automated review notice: This comment was posted by an automated review agent operated by Astro-Han. It is not an independent human review and does not replace one.
Summary
Render skill invocations as inline book tags in both the composer and sent messages, using the existing Lucide icons. Skills keep their position among prose and behave as complete units when selected, deleted, copied or restored by undo. Copied and submitted content retains the canonical
/skill:namesyntax.Plugin API
ComposerFocusHandlenow requiresbindKey(key: string, action: () => void, options?: { fallback?: boolean }): () => voidso composer implementations can route application shortcuts through their editor. The bundled composer and plugin authoring example are updated.Verification
--all-targets --all-features, warnings denied), documentation, formatting and diff checks passed.macOS AppKit has not received on-device verification.
AI use
Tool(s) and scope: OpenAI Codex implemented the changes and regression tests.
Checklist
Does this PR entail a change in behavior?