-
Notifications
You must be signed in to change notification settings - Fork 0
✨ Add xmd prompt: turn a request into an approved executable Plan (#260)
#657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+6,386
−156
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
de53362
✨ Add xmd prompt, the authorship command (#260)
taras d6ca47d
🐛 Settle one agent stack, refuse -e, and report a run's failure (#260)
taras ddd2999
✨ Ship the plan program as a packaged Markdown document (#260)
taras a22c7b1
🐛 Make plan approval and exhaustion mutually exclusive (#260)
taras e06e783
✨ Turn a request into a Plan with a packaged command document (#260)
taras 9ee0c40
🐛 Give each prompt session its own directory and a reachable exhausti…
taras 6348b73
🐛 Own the profile root in tests, and give a default session's directo…
taras 1e44987
✨ Capture the problems with <Json as>, and claim the directory before…
taras 7f2a10f
✨ Make the approved Plan the result, and the workflow readable end to…
taras 869a001
🐛 State the whole Plan requirement in every turn that asks for one (#…
taras 0a927b4
🐛 Use the approved apostrophe, and refuse --save by name (#260)
taras 142272d
🤖 Say that the second root execution is optional (#260)
taras 944c734
🐛 Refuse a valued --run instead of reading it as the switch (#260)
taras 1e782a8
🐛 Assert the session and output-file tripwires on the --run= refusal …
taras 7d0889f
🐛 Pin the valued --run refusal at the parser boundary it crossed (#260)
taras File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,124 @@ | ||||
| /** | ||||
| * The one Agent configuration an invocation resolves, and the two things a | ||||
| * host does with it (specs/acp-client-spec.md §Command-line configuration). | ||||
| * | ||||
| * `xmd run` and `xmd prompt` take the same Agent, permission and provider | ||||
| * options, so they resolve them once, here, rather than each reading the flags | ||||
| * again. What they do with the result differs, and deliberately: a run installs | ||||
| * the registered provider into the Agent Api so a document may reach it, while | ||||
| * `xmd prompt` hands the same answer to two consumers — the prompt profile, which | ||||
| * takes the provider name and the default agent and nothing else, and the | ||||
| * approved document, which runs the ordinary run stack. | ||||
| * | ||||
| * `agent-config.ts` stays the pure flag-to-permission mapping. This module is | ||||
| * where the environment, the provider registry and the host's own machine | ||||
| * session assembly enter. | ||||
| */ | ||||
|
|
||||
| import { | ||||
| installAgentComponents, | ||||
| installPermissionMode, | ||||
| registerAgentProvider, | ||||
| } from "@executablemd/core"; | ||||
| import type { AgentProviderFactory, PermissionMode } from "@executablemd/core"; | ||||
| import { installForegroundLauncher, env as readEnv } from "@executablemd/runtime"; | ||||
| import { createAcpxProvider, DEFAULT_AGENT_NAME } from "@executablemd/acp"; | ||||
| import type { AcpxProviderDependencies } from "@executablemd/acp"; | ||||
| import { Err, Ok } from "effection"; | ||||
| import type { Operation, Result } from "effection"; | ||||
|
|
||||
| import { resolveAgentConfig } from "./agent-config.ts"; | ||||
| import type { AgentFlags } from "./agent-config.ts"; | ||||
| import type { MachineSessionAssembly } from "./session-coordinator.ts"; | ||||
|
|
||||
| /** Everything one invocation settled about agents, resolved exactly once. */ | ||||
| export interface AgentStack { | ||||
| /** The provider name the caller selected, already known to be registered. */ | ||||
| provider: string; | ||||
| /** The agent every consumer defaults to, environment fallback applied. */ | ||||
| defaultAgent: string; | ||||
| permissionMode: PermissionMode; | ||||
| /** What this host states about machine-wide agent sessions, if anything. */ | ||||
| sessions?: MachineSessionAssembly; | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Read the command line, the environment and the host's assembly into one | ||||
| * configuration. | ||||
| * | ||||
| * A failure comes back as a `Result` rather than as a printed line and an exit, | ||||
| * so the same resolution serves a command that runs a document and one that | ||||
| * generates one first. | ||||
| */ | ||||
| export function* resolveAgentStack( | ||||
| flags: AgentFlags, | ||||
| sessions: MachineSessionAssembly | undefined, | ||||
| ): Operation<Result<AgentStack>> { | ||||
| const config = resolveAgentConfig(flags); | ||||
| if ("error" in config) { | ||||
| return Err(new Error(config.error)); | ||||
| } | ||||
| if (flags.agentProvider !== "acpx") { | ||||
| return Err(new Error(`Unknown agent provider "${flags.agentProvider}"`)); | ||||
| } | ||||
| const defaultAgent = | ||||
| config.defaultAgent ?? (yield* readEnv("DEFAULT_AGENT_NAME")) ?? DEFAULT_AGENT_NAME; | ||||
| return Ok({ | ||||
| provider: flags.agentProvider, | ||||
| defaultAgent, | ||||
| permissionMode: config.permissionMode, | ||||
| ...(sessions === undefined ? {} : { sessions }), | ||||
| }); | ||||
| } | ||||
|
|
||||
| /** | ||||
| * What this host built, if it built anything. | ||||
| * | ||||
| * Each piece reaches the provider directly rather than through a context: who | ||||
| * owns a session and which build it belongs to are security decisions, and ones | ||||
| * a document could replace are not ones. The two advertised sets are stated by | ||||
| * the host, not inherited. | ||||
| */ | ||||
| export function hostAcpDependencies( | ||||
| sessions: MachineSessionAssembly | undefined, | ||||
| ): AcpxProviderDependencies { | ||||
| if (sessions === undefined) { | ||||
| return {}; | ||||
| } | ||||
| return { | ||||
| ...(sessions.coordinator ? { coordinator: sessions.coordinator } : {}), | ||||
| ...(sessions.routeStore ? { routeStore: sessions.routeStore } : {}), | ||||
| ...(sessions.executableObserver ? { executableObserver: sessions.executableObserver } : {}), | ||||
| advertiseNativeLaunch: sessions.advertiseNativeLaunch, | ||||
| advertiseClientNativeAttachment: sessions.advertiseClientNativeAttachment, | ||||
| }; | ||||
| } | ||||
|
|
||||
| /** | ||||
| * Install the agent stack a document runs under: the registration, the | ||||
| * components with the resolved root provider, the permission mode, and the | ||||
| * terminal this command has to give away. | ||||
| * | ||||
| * Nothing starts an agent — the provider validates availability on first use. | ||||
| */ | ||||
| export function* installRunAgentStack(stack: AgentStack): Operation<void> { | ||||
| const acpx = createAcpxProvider(hostAcpDependencies(stack.sessions)); | ||||
| yield* registerAgentProvider("acpx", acpx); | ||||
|
|
||||
| // The trusted host selects its own root provider by name. Document-level | ||||
| // selection goes through the installation protocol; this is the host saying | ||||
| // what it configured, which no document is composing around. | ||||
| const providers: Record<string, AgentProviderFactory> = { acpx }; | ||||
| const factory = providers[stack.provider]; | ||||
| const { defaultAgent, permissionMode } = stack; | ||||
| yield* installAgentComponents({ | ||||
| defaultAgent, | ||||
| permissionMode, | ||||
| rootProvider: { factory, options: { defaultAgent, permissionMode } }, | ||||
| }); | ||||
| yield* installPermissionMode(permissionMode); | ||||
| // `xmd run` is the one command that has a terminal to give away. Help, | ||||
| // document inspection and `xmd test` install no launcher, so a document that | ||||
| // reaches <Session.Launch> under any of them refuses instead of spawning. | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant comment — restates what the code does.
Suggested change
|
||||
| yield* installForegroundLauncher(); | ||||
| } | ||||
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant comment — restates what the code does.