feat: slash commands and goal halt-gate - #30
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New JSX emit kind:
emitCommand({name, description?, handler}). Collected by the render walker intoRendered.commandsalongside fragments and tools.Slash-command router in
agent.run: a string input matching/<name>(\s+args)?is routed to the matching command's handler instead of inference. Unknown slash inputs fall through to inference with a warning.Halt-predicate registry on
AgentCtx:registerHaltPredicate,clearHaltPredicate,getHaltPredicates. Stored as aSubscriptionRef<Map<string, HaltPredicate>>so future consumers can subscribe.runHaltGate(infer)supervisor: forked scoped fiber that watches the event log for "about to return control to the user" states — both explicitassistant.haltedand natural terminals (last event =assistant.messagewith no pending tool calls). Runs all registered predicates; on anyok: false, appends a syntheticuser.messagewith the failing reasons so the inference loop reprompts the model.<Goal />component: ships the/goal <condition>(and/goal clear) slash command. The handler registers aHaltPredicatethat judges the transcript against the condition via a separateinfercall, returning{ok, reason}JSON.<Skills>reflectscommands:frontmatter intoemitCommandentries — each skill's commands become slash invocations whose handlers append the skill's prompt as a user message.Test plan
pnpm check-types— clean.pnpm test— 45 files, 166 tests pass.test/agentctx/core/agent-run-contract.test.ts(5 tests): non-slash input goes to inference; unknown slash falls through with warning; registered command's handler runs and the slash input is not appended as user.message;assistant.haltedis terminal without predicates; halt-gate reprompts when a predicate returns ok=false.test/agentctx/core/goal-component.test.ts:<Goal>emits one fragment and one command with name "goal".<Goal />-based example: set/goal "greeted in pirate speak", agent says "Hello!" → halt-gate runs judge → ok=false, reason "no pirate speak" → reprompt appended → agent re-infers "Ahoy, matey!" → judge ok=true → halt stands.