@armadra/agent 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -1
- package/README.md +201 -82
- package/THIRD_PARTY_NOTICES.md +34 -0
- package/dist/acp.d.ts +18 -0
- package/dist/acp.js +19 -0
- package/dist/agent/limits.d.ts +38 -0
- package/dist/agent/limits.js +127 -0
- package/dist/agent/loop-guard.d.ts +38 -0
- package/dist/agent/loop-guard.js +95 -0
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/loop.js +7 -0
- package/dist/agent/prompt-rules.d.ts +12 -0
- package/dist/agent/prompt-rules.js +18 -0
- package/dist/agent/reminders.d.ts +59 -0
- package/dist/agent/reminders.js +327 -0
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +17 -1
- package/dist/agent/session-classifier.d.ts +1 -1
- package/dist/agent/session-classifier.js +3 -1
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +27 -1
- package/dist/agent/session-extensions.d.ts +61 -0
- package/dist/agent/session-extensions.js +129 -0
- package/dist/agent/session-images.d.ts +23 -0
- package/dist/agent/session-images.js +97 -0
- package/dist/agent/session-plan.d.ts +21 -0
- package/dist/agent/session-plan.js +524 -0
- package/dist/agent/session-rewind.d.ts +81 -0
- package/dist/agent/session-rewind.js +354 -0
- package/dist/agent/session-run.d.ts +28 -1
- package/dist/agent/session-run.js +157 -6
- package/dist/agent/session-settings.d.ts +49 -0
- package/dist/agent/session-settings.js +95 -0
- package/dist/agent/session-subagent.d.ts +36 -24
- package/dist/agent/session-subagent.js +259 -129
- package/dist/agent/session-sync.d.ts +10 -3
- package/dist/agent/session-sync.js +37 -8
- package/dist/agent/session-telemetry.d.ts +39 -0
- package/dist/agent/session-telemetry.js +231 -0
- package/dist/agent/session-tools.js +40 -1
- package/dist/agent/session.d.ts +30 -29
- package/dist/agent/session.js +79 -123
- package/dist/agent/subagent-registry.d.ts +91 -0
- package/dist/agent/subagent-registry.js +494 -0
- package/dist/agent/system-prompt.d.ts +6 -3
- package/dist/agent/system-prompt.js +7 -2
- package/dist/agent/tool-runner.d.ts +8 -1
- package/dist/agent/tool-runner.js +57 -4
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +47 -4
- package/dist/agent/types.js +2 -0
- package/dist/agent/worktree.d.ts +36 -0
- package/dist/agent/worktree.js +86 -0
- package/dist/agents/builtin.d.ts +14 -0
- package/dist/agents/builtin.js +39 -0
- package/dist/agents/catalog.d.ts +43 -0
- package/dist/agents/catalog.js +82 -0
- package/dist/agents/discover.d.ts +35 -0
- package/dist/agents/discover.js +83 -0
- package/dist/agents/external.d.ts +82 -0
- package/dist/agents/external.js +326 -0
- package/dist/agents/parse.d.ts +18 -0
- package/dist/agents/parse.js +116 -0
- package/dist/agents/result.d.ts +32 -0
- package/dist/agents/result.js +67 -0
- package/dist/agents/task-control.d.ts +17 -0
- package/dist/agents/task-control.js +17 -0
- package/dist/agents/task-record.d.ts +78 -0
- package/dist/agents/task-record.js +141 -0
- package/dist/agents/types.d.ts +46 -0
- package/dist/agents/types.js +8 -0
- package/dist/ai/apis/anthropic-compat.d.ts +36 -0
- package/dist/ai/apis/anthropic-compat.js +92 -0
- package/dist/ai/apis/anthropic-request.d.ts +7 -6
- package/dist/ai/apis/anthropic-request.js +10 -28
- package/dist/ai/apis/cache-params.d.ts +11 -2
- package/dist/ai/apis/cache-params.js +25 -6
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/image-limits.d.ts +45 -0
- package/dist/ai/image-limits.js +68 -0
- package/dist/ai/providers/builtin.d.ts +18 -6
- package/dist/ai/providers/builtin.js +135 -6
- package/dist/ai/providers/catalog-data.js +17 -13
- package/dist/ai/providers/catalog.d.ts +60 -7
- package/dist/ai/providers/catalog.js +197 -38
- package/dist/ai/providers/channels.d.ts +33 -3
- package/dist/ai/providers/channels.js +108 -7
- package/dist/ai/providers/enrich.d.ts +6 -3
- package/dist/ai/providers/enrich.js +19 -4
- package/dist/ai/providers/models-dev-cache.d.ts +28 -24
- package/dist/ai/providers/models-dev-cache.js +92 -78
- package/dist/ai/providers/models-dev-data.d.ts +7 -0
- package/dist/ai/providers/models-dev-data.js +32 -0
- package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
- package/dist/ai/providers/models-dev-snapshot.js +137 -0
- package/dist/ai/providers/models-dev.d.ts +51 -10
- package/dist/ai/providers/models-dev.js +132 -39
- package/dist/ai/providers/registry.d.ts +20 -10
- package/dist/ai/providers/registry.js +82 -43
- package/dist/ai/types.d.ts +28 -2
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +36203 -20499
- package/dist/checkpoints/backend.d.ts +61 -0
- package/dist/checkpoints/backend.js +135 -0
- package/dist/checkpoints/blobs.d.ts +60 -0
- package/dist/checkpoints/blobs.js +203 -0
- package/dist/checkpoints/gc.d.ts +47 -0
- package/dist/checkpoints/gc.js +144 -0
- package/dist/checkpoints/git-head.d.ts +15 -0
- package/dist/checkpoints/git-head.js +89 -0
- package/dist/checkpoints/index.d.ts +17 -0
- package/dist/checkpoints/index.js +17 -0
- package/dist/checkpoints/replay.d.ts +48 -0
- package/dist/checkpoints/replay.js +154 -0
- package/dist/checkpoints/restore.d.ts +86 -0
- package/dist/checkpoints/restore.js +263 -0
- package/dist/checkpoints/settings.d.ts +14 -0
- package/dist/checkpoints/settings.js +23 -0
- package/dist/checkpoints/shadow-git.d.ts +108 -0
- package/dist/checkpoints/shadow-git.js +491 -0
- package/dist/checkpoints/shadow-restore.d.ts +25 -0
- package/dist/checkpoints/shadow-restore.js +128 -0
- package/dist/checkpoints/tracker.d.ts +64 -0
- package/dist/checkpoints/tracker.js +192 -0
- package/dist/checkpoints/types.d.ts +99 -0
- package/dist/checkpoints/types.js +12 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +17 -97
- package/dist/cli/bootstrap.js +13 -1
- package/dist/cli/codemode-notice.d.ts +3 -2
- package/dist/cli/codemode-notice.js +3 -2
- package/dist/cli/compose-agents.d.ts +27 -0
- package/dist/cli/compose-agents.js +111 -0
- package/dist/cli/compose-extensions.d.ts +29 -0
- package/dist/cli/compose-extensions.js +44 -0
- package/dist/cli/compose-session.d.ts +3 -0
- package/dist/cli/compose-session.js +47 -4
- package/dist/cli/compose.d.ts +3 -0
- package/dist/cli/compose.js +33 -6
- package/dist/cli/deps.d.ts +6 -0
- package/dist/cli/exit-codes.d.ts +10 -0
- package/dist/cli/exit-codes.js +12 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/startup-screen.js +5 -3
- package/dist/cli/startup-steps.js +7 -1
- package/dist/cli/subcommands/config.d.ts +4 -1
- package/dist/cli/subcommands/config.js +17 -6
- package/dist/cli/subcommands/doctor.js +21 -0
- package/dist/cli/subcommands/models-discover.js +5 -6
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/providers.js +5 -6
- package/dist/cli/subcommands/sessions.d.ts +3 -1
- package/dist/cli/subcommands/sessions.js +36 -2
- package/dist/codemode/capability.d.ts +24 -7
- package/dist/codemode/capability.js +38 -10
- package/dist/codemode/host-side.d.ts +14 -0
- package/dist/codemode/host-side.js +24 -1
- package/dist/codemode/tool.d.ts +1 -1
- package/dist/codemode/tool.js +6 -4
- package/dist/compaction/breaker.d.ts +25 -9
- package/dist/compaction/breaker.js +47 -17
- package/dist/compaction/estimate.d.ts +11 -3
- package/dist/compaction/estimate.js +64 -22
- package/dist/compaction/image-budget.d.ts +45 -0
- package/dist/compaction/image-budget.js +115 -0
- package/dist/compaction/post-compact.d.ts +38 -0
- package/dist/compaction/post-compact.js +152 -0
- package/dist/compaction/protect.d.ts +27 -0
- package/dist/compaction/protect.js +56 -0
- package/dist/compaction/prune-tier.d.ts +58 -12
- package/dist/compaction/prune-tier.js +120 -54
- package/dist/compaction/summarize-tier.d.ts +23 -4
- package/dist/compaction/summarize-tier.js +100 -29
- package/dist/config/checker.d.ts +28 -0
- package/dist/config/checker.js +97 -0
- package/dist/config/json-schema.js +63 -2
- package/dist/config/key-docs.js +72 -3
- package/dist/config/merge.d.ts +5 -3
- package/dist/config/merge.js +81 -7
- package/dist/config/profile.d.ts +2 -0
- package/dist/config/profile.js +2 -0
- package/dist/config/schema-w5.d.ts +18 -0
- package/dist/config/schema-w5.js +109 -0
- package/dist/config/schema.d.ts +5 -9
- package/dist/config/schema.js +68 -114
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +50 -1
- package/dist/config/types.js +12 -0
- package/dist/drivers/acp/client.d.ts +57 -0
- package/dist/drivers/acp/client.js +160 -0
- package/dist/drivers/acp/driver.d.ts +31 -0
- package/dist/drivers/acp/driver.js +274 -0
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
- package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
- package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
- package/dist/drivers/acp/testing/fake-agent.js +211 -0
- package/dist/drivers/acp/types.d.ts +285 -0
- package/dist/drivers/acp/types.js +36 -0
- package/dist/drivers/agents.d.ts +58 -0
- package/dist/drivers/agents.js +142 -0
- package/dist/drivers/base.d.ts +35 -0
- package/dist/drivers/base.js +59 -0
- package/dist/drivers/catalog.d.ts +46 -0
- package/dist/drivers/catalog.js +167 -0
- package/dist/drivers/env.d.ts +20 -0
- package/dist/drivers/env.js +46 -0
- package/dist/drivers/host-runners.d.ts +18 -0
- package/dist/drivers/host-runners.js +45 -0
- package/dist/drivers/jsonrpc.d.ts +58 -0
- package/dist/drivers/jsonrpc.js +180 -0
- package/dist/drivers/native/claude-normalize.d.ts +46 -0
- package/dist/drivers/native/claude-normalize.js +106 -0
- package/dist/drivers/native/claude-stream.d.ts +29 -0
- package/dist/drivers/native/claude-stream.js +456 -0
- package/dist/drivers/native/codex-app-server.d.ts +26 -0
- package/dist/drivers/native/codex-app-server.js +407 -0
- package/dist/drivers/native/codex-normalize.d.ts +38 -0
- package/dist/drivers/native/codex-normalize.js +124 -0
- package/dist/drivers/native/oneshot.d.ts +28 -0
- package/dist/drivers/native/oneshot.js +312 -0
- package/dist/drivers/permissions.d.ts +40 -0
- package/dist/drivers/permissions.js +92 -0
- package/dist/drivers/pids.d.ts +32 -0
- package/dist/drivers/pids.js +93 -0
- package/dist/drivers/pool.d.ts +28 -0
- package/dist/drivers/pool.js +96 -0
- package/dist/drivers/probe.d.ts +47 -0
- package/dist/drivers/probe.js +172 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.js +100 -0
- package/dist/drivers/runner.d.ts +61 -0
- package/dist/drivers/runner.js +388 -0
- package/dist/drivers/store.d.ts +49 -0
- package/dist/drivers/store.js +91 -0
- package/dist/drivers/turn.d.ts +41 -0
- package/dist/drivers/turn.js +99 -0
- package/dist/drivers/types.d.ts +122 -0
- package/dist/drivers/types.js +11 -0
- package/dist/git/info.d.ts +75 -0
- package/dist/git/info.js +191 -0
- package/dist/hooks/protocol.js +6 -1
- package/dist/hooks/types.d.ts +10 -1
- package/dist/hooks/types.js +2 -0
- package/dist/host/api-impl.d.ts +7 -0
- package/dist/host/api-impl.js +15 -0
- package/dist/host/types.d.ts +24 -2
- package/dist/host/types.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/modes/acp/acp-events.d.ts +46 -0
- package/dist/modes/acp/acp-events.js +233 -0
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.js +47 -0
- package/dist/modes/acp/acp-server.d.ts +79 -0
- package/dist/modes/acp/acp-server.js +315 -0
- package/dist/modes/commands-core.d.ts +7 -1
- package/dist/modes/commands-core.js +55 -0
- package/dist/modes/image-input.d.ts +12 -4
- package/dist/modes/image-input.js +22 -5
- package/dist/modes/interactive/agent-panels.d.ts +14 -0
- package/dist/modes/interactive/agent-panels.js +103 -0
- package/dist/modes/interactive/agent-ui.d.ts +73 -0
- package/dist/modes/interactive/agent-ui.js +234 -0
- package/dist/modes/interactive/approval-dialog.d.ts +21 -4
- package/dist/modes/interactive/approval-dialog.js +98 -20
- package/dist/modes/interactive/approval-merge.d.ts +41 -0
- package/dist/modes/interactive/approval-merge.js +89 -0
- package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
- package/dist/modes/interactive/clipboard-paste.js +28 -0
- package/dist/modes/interactive/commands.d.ts +9 -1
- package/dist/modes/interactive/commands.js +19 -0
- package/dist/modes/interactive/double-esc.d.ts +20 -0
- package/dist/modes/interactive/double-esc.js +34 -0
- package/dist/modes/interactive/event-notices.d.ts +32 -0
- package/dist/modes/interactive/event-notices.js +79 -0
- package/dist/modes/interactive/external-editor.d.ts +16 -0
- package/dist/modes/interactive/external-editor.js +39 -0
- package/dist/modes/interactive/interactive-mode.d.ts +14 -1
- package/dist/modes/interactive/interactive-mode.js +134 -136
- package/dist/modes/interactive/key-dispatch.d.ts +16 -2
- package/dist/modes/interactive/key-dispatch.js +49 -1
- package/dist/modes/interactive/line/line-mode.d.ts +2 -1
- package/dist/modes/interactive/line/line-mode.js +22 -5
- package/dist/modes/interactive/line/line-render.d.ts +2 -1
- package/dist/modes/interactive/line/line-render.js +40 -4
- package/dist/modes/interactive/message-view.d.ts +1 -1
- package/dist/modes/interactive/message-view.js +24 -2
- package/dist/modes/interactive/panels.d.ts +18 -1
- package/dist/modes/interactive/panels.js +19 -5
- package/dist/modes/interactive/plan-command.d.ts +40 -0
- package/dist/modes/interactive/plan-command.js +129 -0
- package/dist/modes/interactive/plan-dialog.d.ts +98 -0
- package/dist/modes/interactive/plan-dialog.js +290 -0
- package/dist/modes/interactive/plan-flow.d.ts +34 -0
- package/dist/modes/interactive/plan-flow.js +98 -0
- package/dist/modes/interactive/rewind-command.d.ts +31 -0
- package/dist/modes/interactive/rewind-command.js +106 -0
- package/dist/modes/interactive/rewind-flow.d.ts +37 -0
- package/dist/modes/interactive/rewind-flow.js +151 -0
- package/dist/modes/interactive/rewind-list.d.ts +36 -0
- package/dist/modes/interactive/rewind-list.js +123 -0
- package/dist/modes/interactive/rewind-panel.d.ts +77 -0
- package/dist/modes/interactive/rewind-panel.js +309 -0
- package/dist/modes/interactive/rewind-text.d.ts +40 -0
- package/dist/modes/interactive/rewind-text.js +139 -0
- package/dist/modes/interactive/session-events.d.ts +24 -0
- package/dist/modes/interactive/session-events.js +96 -0
- package/dist/modes/interactive/status-area.d.ts +73 -0
- package/dist/modes/interactive/status-area.js +190 -0
- package/dist/modes/interactive/status-bar.d.ts +99 -11
- package/dist/modes/interactive/status-bar.js +273 -90
- package/dist/modes/interactive/status-line.d.ts +33 -0
- package/dist/modes/interactive/status-line.js +113 -0
- package/dist/modes/interactive/subagent-view.d.ts +56 -0
- package/dist/modes/interactive/subagent-view.js +154 -0
- package/dist/modes/interactive/tasks-report.d.ts +27 -0
- package/dist/modes/interactive/tasks-report.js +114 -0
- package/dist/modes/interactive/tool-view.d.ts +12 -2
- package/dist/modes/interactive/tool-view.js +34 -4
- package/dist/modes/print/print-mode.d.ts +13 -4
- package/dist/modes/print/print-mode.js +56 -12
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +44 -0
- package/dist/modes/rpc/rpc-mode.js +7 -1
- package/dist/modes/session-report.d.ts +11 -0
- package/dist/modes/session-report.js +48 -1
- package/dist/permissions/auto-safe.d.ts +5 -0
- package/dist/permissions/auto-safe.js +18 -0
- package/dist/permissions/classifier.d.ts +4 -0
- package/dist/permissions/classifier.js +2 -0
- package/dist/permissions/modes.js +1 -1
- package/dist/permissions/pipeline.d.ts +43 -4
- package/dist/permissions/pipeline.js +114 -9
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/types.d.ts +42 -0
- package/dist/plan/compose.d.ts +9 -0
- package/dist/plan/compose.js +19 -0
- package/dist/plan/controller.d.ts +71 -0
- package/dist/plan/controller.js +27 -0
- package/dist/plan/done-markers.d.ts +17 -0
- package/dist/plan/done-markers.js +51 -0
- package/dist/plan/extract.d.ts +29 -0
- package/dist/plan/extract.js +160 -0
- package/dist/plan/prompts.d.ts +36 -0
- package/dist/plan/prompts.js +89 -0
- package/dist/plan/store.d.ts +37 -0
- package/dist/plan/store.js +90 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +7 -0
- package/dist/sandbox/bash.d.ts +74 -0
- package/dist/sandbox/bash.js +126 -0
- package/dist/sandbox/detect.d.ts +48 -0
- package/dist/sandbox/detect.js +149 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/profile.d.ts +33 -0
- package/dist/sandbox/profile.js +76 -0
- package/dist/sandbox/wrap.d.ts +29 -0
- package/dist/sandbox/wrap.js +117 -0
- package/dist/sdk.d.ts +33 -2
- package/dist/sdk.js +24 -2
- package/dist/session/types.d.ts +3 -1
- package/dist/session/types.js +1 -0
- package/dist/skills/builtin.d.ts +31 -0
- package/dist/skills/builtin.js +109 -0
- package/dist/skills/discover.d.ts +2 -1
- package/dist/skills/index-prompt.js +5 -8
- package/dist/tools/background-jobs.d.ts +71 -0
- package/dist/tools/background-jobs.js +198 -0
- package/dist/tools/bash.d.ts +53 -1
- package/dist/tools/bash.js +158 -7
- package/dist/tools/clipboard-image.d.ts +44 -0
- package/dist/tools/clipboard-image.js +148 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.js +18 -3
- package/dist/tools/image-file.d.ts +38 -3
- package/dist/tools/image-file.js +81 -10
- package/dist/tools/image-resize.d.ts +58 -0
- package/dist/tools/image-resize.js +97 -0
- package/dist/tools/presets.d.ts +7 -2
- package/dist/tools/presets.js +11 -4
- package/dist/tools/read.d.ts +5 -2
- package/dist/tools/read.js +13 -10
- package/dist/tools/registry.d.ts +7 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/task-ctl.d.ts +22 -0
- package/dist/tools/task-ctl.js +116 -0
- package/dist/tools/task.d.ts +22 -10
- package/dist/tools/task.js +66 -26
- package/dist/tools/todo.d.ts +22 -2
- package/dist/tools/todo.js +58 -14
- package/dist/tools/truncate.d.ts +15 -0
- package/dist/tools/truncate.js +25 -0
- package/dist/tools/types.d.ts +113 -0
- package/dist/tools/types.js +5 -0
- package/dist/tools/write.js +3 -0
- package/dist/tui/glyphs.d.ts +4 -0
- package/dist/tui/glyphs.js +4 -0
- package/dist/tui/keybindings.d.ts +5 -0
- package/dist/tui/keybindings.js +5 -0
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +12 -8
- package/docs/hooks.md +26 -22
- package/docs/permissions.md +77 -13
- package/docs/plan.md +107 -0
- package/docs/providers.md +228 -52
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +92 -5
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +41 -21
- package/docs/sessions.md +41 -1
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +125 -6
- package/package.json +13 -2
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子 Agent 类型目录:内置 ⊕ 发现的定义 ⊕ 外部 runner(docs/wave5-plan.md §7.1–§7.3、§7.6)。[W5-G]
|
|
3
|
+
*
|
|
4
|
+
* - 发现的同名定义覆盖内置类型(不 warning);外部 runner(W5-E 的 ProcessRunner、宿主 runner)以
|
|
5
|
+
* `add()` 登记,名字已存在时保留先登记者。
|
|
6
|
+
* - `describe()`:task 工具描述里的类型清单,总预算约 400 token(1 600 字符),超出只列名字。
|
|
7
|
+
* - `resolveModel()`:调用参数 `model` > 定义 `model`(非 inherit)> config `agents.<name>.model` >
|
|
8
|
+
* `subagents.defaultModel` > 父当前模型(返回 undefined);`fast` / `strong` 经 `models.aliases`。
|
|
9
|
+
*/
|
|
10
|
+
import { agentEntry } from "../config/types-w5.js";
|
|
11
|
+
import { BUILTIN_AGENTS } from "./builtin.js";
|
|
12
|
+
export const AGENT_LIST_BUDGET_CHARS = 1600;
|
|
13
|
+
export class AgentCatalog {
|
|
14
|
+
byName = new Map();
|
|
15
|
+
resolver;
|
|
16
|
+
constructor(discovered = []) {
|
|
17
|
+
for (const agent of BUILTIN_AGENTS)
|
|
18
|
+
this.byName.set(agent.name, agent);
|
|
19
|
+
for (const agent of discovered)
|
|
20
|
+
this.byName.set(agent.name, agent);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* 目录里没有的名字按需解析(`acp:<program>`、未在启动时登记的外部 / 宿主 runner,见
|
|
24
|
+
* agents/external.ts)。解析出的类型不进 {@link describe}:task 工具描述在会话内保持字节不变。
|
|
25
|
+
*/
|
|
26
|
+
setResolver(resolver) {
|
|
27
|
+
this.resolver = resolver;
|
|
28
|
+
}
|
|
29
|
+
get(name) {
|
|
30
|
+
return this.byName.get(name) ?? this.resolver?.(name);
|
|
31
|
+
}
|
|
32
|
+
/** 外部 / 宿主类型;同名已存在返回 false。 */
|
|
33
|
+
add(agent) {
|
|
34
|
+
if (this.byName.has(agent.name))
|
|
35
|
+
return false;
|
|
36
|
+
this.byName.set(agent.name, agent);
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
list() {
|
|
40
|
+
return [...this.byName.values()];
|
|
41
|
+
}
|
|
42
|
+
names() {
|
|
43
|
+
return [...this.byName.keys()];
|
|
44
|
+
}
|
|
45
|
+
infos() {
|
|
46
|
+
return this.list().map((agent) => {
|
|
47
|
+
const info = {
|
|
48
|
+
name: agent.name,
|
|
49
|
+
description: agent.description,
|
|
50
|
+
runner: agent.runner,
|
|
51
|
+
source: agent.source,
|
|
52
|
+
};
|
|
53
|
+
if (agent.filePath !== undefined)
|
|
54
|
+
info.filePath = agent.filePath;
|
|
55
|
+
return info;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** task 工具描述里的类型清单(`- name: description`;超预算只列名字)。 */
|
|
59
|
+
describe(budget = AGENT_LIST_BUDGET_CHARS) {
|
|
60
|
+
const lines = this.list().map((agent) => `- ${agent.name}: ${agent.description}`);
|
|
61
|
+
const full = lines.join("\n");
|
|
62
|
+
if (full.length <= budget)
|
|
63
|
+
return full;
|
|
64
|
+
return this.names().join(", ");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function resolveAgentModel(agent, requested, config) {
|
|
68
|
+
const own = agent.model === "inherit" ? undefined : agent.model;
|
|
69
|
+
const picked = requested ??
|
|
70
|
+
own ??
|
|
71
|
+
agentEntry(config.agents, agent.name)?.model ??
|
|
72
|
+
config.subagents?.defaultModel;
|
|
73
|
+
if (picked === undefined || picked === "inherit")
|
|
74
|
+
return {};
|
|
75
|
+
if (picked === "fast" || picked === "strong") {
|
|
76
|
+
const alias = config.models?.aliases?.[picked];
|
|
77
|
+
if (alias === undefined)
|
|
78
|
+
return { warning: `models.aliases.${picked} is not set; using the parent model` };
|
|
79
|
+
return { ref: alias };
|
|
80
|
+
}
|
|
81
|
+
return { ref: picked };
|
|
82
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子 Agent 定义发现(docs/wave5-plan.md §7.1,D22)。[W5-G]
|
|
3
|
+
*
|
|
4
|
+
* 顺序:`--agent-dir`(可重复,profile `agentDirs` 由启动步骤并在其后)→ config `agents.dirs` →
|
|
5
|
+
* `<configDir>/agents/*.md`(用户级)→ `<cwd>/.ama/agents/*.md`(项目级,需信任;未信任跳过并记入
|
|
6
|
+
* `skippedUntrusted`)。每个来源目录只看直接下层的 `*.md`(按名排序);同名先发现者胜并 warning。
|
|
7
|
+
* 内置类型(builtin.ts)由 catalog.ts 合并,可被这里发现的同名定义覆盖。
|
|
8
|
+
*
|
|
9
|
+
* 同步实现:定义目录小而平,发现在会话装配时一次完成(compose-agents.ts)。
|
|
10
|
+
*/
|
|
11
|
+
import type { AgentDefinition, AgentSource } from "./types.js";
|
|
12
|
+
export interface AgentDirSource {
|
|
13
|
+
dir: string;
|
|
14
|
+
source: AgentSource;
|
|
15
|
+
requiresTrust: boolean;
|
|
16
|
+
}
|
|
17
|
+
export interface AgentDirSources {
|
|
18
|
+
cwd: string;
|
|
19
|
+
/** 用户级配置目录(`~/.config/ama`)。 */
|
|
20
|
+
configDir: string;
|
|
21
|
+
/** `--agent-dir` 与 profile `agentDirs`(已按顺序合并)。 */
|
|
22
|
+
cliDirs?: readonly string[];
|
|
23
|
+
/** config `agents.dirs`。 */
|
|
24
|
+
configDirs?: readonly string[];
|
|
25
|
+
}
|
|
26
|
+
export interface AgentDiscovery {
|
|
27
|
+
agents: AgentDefinition[];
|
|
28
|
+
warnings: string[];
|
|
29
|
+
/** 因未信任而跳过的目录(存在的才列出)。 */
|
|
30
|
+
skippedUntrusted: string[];
|
|
31
|
+
}
|
|
32
|
+
export declare function agentSources(options: AgentDirSources): AgentDirSource[];
|
|
33
|
+
export declare function discoverAgents(sources: readonly AgentDirSource[], options: {
|
|
34
|
+
trusted: boolean;
|
|
35
|
+
}): AgentDiscovery;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子 Agent 定义发现(docs/wave5-plan.md §7.1,D22)。[W5-G]
|
|
3
|
+
*
|
|
4
|
+
* 顺序:`--agent-dir`(可重复,profile `agentDirs` 由启动步骤并在其后)→ config `agents.dirs` →
|
|
5
|
+
* `<configDir>/agents/*.md`(用户级)→ `<cwd>/.ama/agents/*.md`(项目级,需信任;未信任跳过并记入
|
|
6
|
+
* `skippedUntrusted`)。每个来源目录只看直接下层的 `*.md`(按名排序);同名先发现者胜并 warning。
|
|
7
|
+
* 内置类型(builtin.ts)由 catalog.ts 合并,可被这里发现的同名定义覆盖。
|
|
8
|
+
*
|
|
9
|
+
* 同步实现:定义目录小而平,发现在会话装配时一次完成(compose-agents.ts)。
|
|
10
|
+
*/
|
|
11
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
12
|
+
import { join, resolve } from "node:path";
|
|
13
|
+
import { parseAgentDefinition } from "./parse.js";
|
|
14
|
+
export function agentSources(options) {
|
|
15
|
+
const out = [];
|
|
16
|
+
const add = (dir, source, requiresTrust) => out.push({ dir: resolve(options.cwd, dir), source, requiresTrust });
|
|
17
|
+
for (const dir of options.cliDirs ?? [])
|
|
18
|
+
add(dir, "cli", false);
|
|
19
|
+
for (const dir of options.configDirs ?? [])
|
|
20
|
+
add(dir, "user", false);
|
|
21
|
+
add(join(options.configDir, "agents"), "user", false);
|
|
22
|
+
add(join(options.cwd, ".ama", "agents"), "project", true);
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
function isDir(path) {
|
|
26
|
+
try {
|
|
27
|
+
return statSync(path).isDirectory();
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function markdownFiles(dir) {
|
|
34
|
+
try {
|
|
35
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
36
|
+
.filter((entry) => entry.isFile() && entry.name.endsWith(".md"))
|
|
37
|
+
.map((entry) => entry.name)
|
|
38
|
+
.sort()
|
|
39
|
+
.map((name) => join(dir, name));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function discoverAgents(sources, options) {
|
|
46
|
+
const result = { agents: [], warnings: [], skippedUntrusted: [] };
|
|
47
|
+
const byName = new Map();
|
|
48
|
+
const seen = new Set();
|
|
49
|
+
for (const source of sources) {
|
|
50
|
+
if (seen.has(source.dir))
|
|
51
|
+
continue;
|
|
52
|
+
seen.add(source.dir);
|
|
53
|
+
if (!isDir(source.dir))
|
|
54
|
+
continue;
|
|
55
|
+
if (source.requiresTrust && !options.trusted) {
|
|
56
|
+
result.skippedUntrusted.push(source.dir);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
for (const file of markdownFiles(source.dir)) {
|
|
60
|
+
let text;
|
|
61
|
+
try {
|
|
62
|
+
text = readFileSync(file, "utf8");
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
result.warnings.push(`${file}: ${error.message}`);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const parsed = parseAgentDefinition(text, file, source.source);
|
|
69
|
+
result.warnings.push(...parsed.warnings);
|
|
70
|
+
const agent = parsed.agent;
|
|
71
|
+
if (agent === undefined)
|
|
72
|
+
continue;
|
|
73
|
+
const existing = byName.get(agent.name);
|
|
74
|
+
if (existing !== undefined) {
|
|
75
|
+
result.warnings.push(`${file}: agent "${agent.name}" already defined at ${existing.filePath ?? existing.source}; ignored`);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
byName.set(agent.name, agent);
|
|
79
|
+
result.agents.push(agent);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 接入 `task(agent=…)`(docs/wave5-plan.md §5.3–§5.5、§7.3、§7.6,D13、D15、D17)。[W5-EG]
|
|
3
|
+
*
|
|
4
|
+
* - 名字:`claude` / `codex` / `acp:<program>` / 驱动表里的其它 id(`gemini` …,`ama` 除外——那是子会话
|
|
5
|
+
* 类型的 runner 名;ama 自己经 ACP 用 `acp:ama`)/ 宿主注入的 runner id。启动时 PATH 上找得到的
|
|
6
|
+
* claude / codex 与已注入的宿主 runner 登记进类型目录(进 task 工具描述);其余按需解析(不进描述,
|
|
7
|
+
* 描述在会话内字节不变)。
|
|
8
|
+
* - 每个主会话一个 {@link ExternalAgents}:审批接 `requestApproval`(只走 broker 链,不经 gateToolCall
|
|
9
|
+
* 与 auto 分类器);有宿主时不自 spawn(D17),只认宿主注入的。
|
|
10
|
+
* - 首次在本会话以某个外部 Agent 运行:一次 `execute` 类确认「将以你在 X 的现有登录运行,模式 Y」——
|
|
11
|
+
* deny 规则 `task(<id>)` 拒绝;allow 规则 `task` / `task(<id>)` 或 full-auto 放行;allowlist 与无人值守
|
|
12
|
+
* 拒绝;其余问人。宿主 runner 不问(宿主自己管审批)。
|
|
13
|
+
* - 句柄包一层:被 stop 的外部任务续聊时以外部会话 id `resume` 重开。
|
|
14
|
+
* - `/agents`、RPC `get_agents` 的外部部分要探测(异步),这里按会话缓存,启动与变化时刷新。
|
|
15
|
+
*/
|
|
16
|
+
import type { SessionCore } from "../agent/session-core.js";
|
|
17
|
+
import { type AgentsConfig } from "../config/types-w5.js";
|
|
18
|
+
import { ExternalAgents } from "../drivers/agents.js";
|
|
19
|
+
import type { DriverDeps } from "../drivers/base.js";
|
|
20
|
+
import type { HostRunnerRegistry } from "../drivers/host-runners.js";
|
|
21
|
+
import type { HostRunner } from "../host/types.js";
|
|
22
|
+
import type { SubagentRunner } from "../tools/types.js";
|
|
23
|
+
import type { AgentCatalog } from "./catalog.js";
|
|
24
|
+
import type { AgentDefinition, AgentInfo } from "./types.js";
|
|
25
|
+
/** 启动时按 PATH 登记进 task 描述的外部 Agent。 */
|
|
26
|
+
export declare const LISTED_EXTERNAL_AGENTS: readonly ["claude", "codex"];
|
|
27
|
+
/** 关闭外部 Agent 的 PATH 探测与版本探测(测试;`/agents` 只列类型目录)。 */
|
|
28
|
+
export declare const NO_AGENT_PROBE_ENV = "AMA_NO_AGENT_PROBE";
|
|
29
|
+
/** 测试注入(spawn / probe):进程内对端代替真实子进程。生产代码不设置。 */
|
|
30
|
+
export declare const externalTesting: {
|
|
31
|
+
driverDeps?: DriverDeps;
|
|
32
|
+
};
|
|
33
|
+
/** 是不是外部 Agent 的名字(`claude` / `codex` / `acp:<program>` / 驱动表 id,`ama` 除外)。 */
|
|
34
|
+
export declare function isExternalSpec(name: string): boolean;
|
|
35
|
+
/** 外部 CLI 的类型(`task(agent="claude")`)。 */
|
|
36
|
+
export declare function externalDefinition(spec: string): AgentDefinition;
|
|
37
|
+
export declare function hostDefinition(runner: HostRunner): AgentDefinition;
|
|
38
|
+
/** 只查 PATH(不起进程):候选链里任一程序在 PATH 上。 */
|
|
39
|
+
export declare function externalOnPath(spec: string, env: NodeJS.ProcessEnv): boolean;
|
|
40
|
+
export interface ExternalWiring {
|
|
41
|
+
env: NodeJS.ProcessEnv;
|
|
42
|
+
/** 有宿主适配器:不自 spawn 外部 CLI(D17)。 */
|
|
43
|
+
hosted: boolean;
|
|
44
|
+
hostRunners?: HostRunnerRegistry;
|
|
45
|
+
dataDir?: string;
|
|
46
|
+
config?: AgentsConfig;
|
|
47
|
+
/** config `subagents.defaultModel`:那是 ama 的模型,不传给外部 CLI。 */
|
|
48
|
+
defaultModel?: string;
|
|
49
|
+
/** 项目是否已被 ama 信任。 */
|
|
50
|
+
trusted: boolean;
|
|
51
|
+
/** PATH 与版本探测(`AMA_NO_AGENT_PROBE=1` 关闭)。 */
|
|
52
|
+
probe: boolean;
|
|
53
|
+
}
|
|
54
|
+
/** 启动时登记:PATH 上的 claude / codex(无宿主时)与已注入的宿主 runner;其余按需解析。 */
|
|
55
|
+
export declare function registerExternalAgents(catalog: AgentCatalog, wiring: ExternalWiring): void;
|
|
56
|
+
/** RPC `get_agents` / `/agents`:会话的类型与外部 Agent(含安装与版本);未缓存返回 undefined。 */
|
|
57
|
+
export declare function cachedAgentInfos(sessionId: string): AgentInfo[] | undefined;
|
|
58
|
+
/** 合并:类型目录在前;外部探测结果补 installed / version,目录里没有的追加在后。 */
|
|
59
|
+
export declare function mergeAgentInfos(base: readonly AgentInfo[], external: readonly AgentInfo[]): AgentInfo[];
|
|
60
|
+
/** 一个主会话的外部 Agent 入口(`SubagentEnvironment.runners` 的实现)。 */
|
|
61
|
+
export declare class SessionExternalAgents {
|
|
62
|
+
private readonly core;
|
|
63
|
+
private readonly wiring;
|
|
64
|
+
private readonly catalog;
|
|
65
|
+
readonly agents: ExternalAgents;
|
|
66
|
+
private readonly approved;
|
|
67
|
+
private readonly pending;
|
|
68
|
+
private disposed;
|
|
69
|
+
private unsubscribe;
|
|
70
|
+
constructor(core: SessionCore, wiring: ExternalWiring, catalog: AgentCatalog);
|
|
71
|
+
private mode;
|
|
72
|
+
/** 注册表的 `runners(agent)`:ama 子会话类型返回 undefined。 */
|
|
73
|
+
runner(agent: AgentDefinition): SubagentRunner | undefined;
|
|
74
|
+
/** 发给外部 runner 的请求:去掉 ama 自己的缺省模型(`subagents.defaultModel`)。 */
|
|
75
|
+
private forward;
|
|
76
|
+
/** 首次在本会话以 `spec` 运行的确认(同一 Agent 并发的首次只问一次)。 */
|
|
77
|
+
private firstRun;
|
|
78
|
+
private confirm;
|
|
79
|
+
/** 重新探测并缓存 `/agents` 的数据(不阻塞;会话关闭后不再写)。 */
|
|
80
|
+
refreshInfos(): Promise<AgentInfo[]>;
|
|
81
|
+
dispose(): void;
|
|
82
|
+
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部 Agent 接入 `task(agent=…)`(docs/wave5-plan.md §5.3–§5.5、§7.3、§7.6,D13、D15、D17)。[W5-EG]
|
|
3
|
+
*
|
|
4
|
+
* - 名字:`claude` / `codex` / `acp:<program>` / 驱动表里的其它 id(`gemini` …,`ama` 除外——那是子会话
|
|
5
|
+
* 类型的 runner 名;ama 自己经 ACP 用 `acp:ama`)/ 宿主注入的 runner id。启动时 PATH 上找得到的
|
|
6
|
+
* claude / codex 与已注入的宿主 runner 登记进类型目录(进 task 工具描述);其余按需解析(不进描述,
|
|
7
|
+
* 描述在会话内字节不变)。
|
|
8
|
+
* - 每个主会话一个 {@link ExternalAgents}:审批接 `requestApproval`(只走 broker 链,不经 gateToolCall
|
|
9
|
+
* 与 auto 分类器);有宿主时不自 spawn(D17),只认宿主注入的。
|
|
10
|
+
* - 首次在本会话以某个外部 Agent 运行:一次 `execute` 类确认「将以你在 X 的现有登录运行,模式 Y」——
|
|
11
|
+
* deny 规则 `task(<id>)` 拒绝;allow 规则 `task` / `task(<id>)` 或 full-auto 放行;allowlist 与无人值守
|
|
12
|
+
* 拒绝;其余问人。宿主 runner 不问(宿主自己管审批)。
|
|
13
|
+
* - 句柄包一层:被 stop 的外部任务续聊时以外部会话 id `resume` 重开。
|
|
14
|
+
* - `/agents`、RPC `get_agents` 的外部部分要探测(异步),这里按会话缓存,启动与变化时刷新。
|
|
15
|
+
*/
|
|
16
|
+
import { randomUUID } from "node:crypto";
|
|
17
|
+
import { requestApproval } from "../agent/session-tools.js";
|
|
18
|
+
import { agentEntry } from "../config/types-w5.js";
|
|
19
|
+
import { ExternalAgents } from "../drivers/agents.js";
|
|
20
|
+
import { candidatesFor, catalogEntry } from "../drivers/catalog.js";
|
|
21
|
+
import { clampMode } from "../drivers/permissions.js";
|
|
22
|
+
import { findOnPath } from "../drivers/probe.js";
|
|
23
|
+
import { createAgentStore } from "../drivers/store.js";
|
|
24
|
+
import { AmaError } from "../errors.js";
|
|
25
|
+
import { findAllowRule, findDenyRule } from "../permissions/rules.js";
|
|
26
|
+
/** 启动时按 PATH 登记进 task 描述的外部 Agent。 */
|
|
27
|
+
export const LISTED_EXTERNAL_AGENTS = ["claude", "codex"];
|
|
28
|
+
/** 关闭外部 Agent 的 PATH 探测与版本探测(测试;`/agents` 只列类型目录)。 */
|
|
29
|
+
export const NO_AGENT_PROBE_ENV = "AMA_NO_AGENT_PROBE";
|
|
30
|
+
/** 测试注入(spawn / probe):进程内对端代替真实子进程。生产代码不设置。 */
|
|
31
|
+
export const externalTesting = {};
|
|
32
|
+
/** 是不是外部 Agent 的名字(`claude` / `codex` / `acp:<program>` / 驱动表 id,`ama` 除外)。 */
|
|
33
|
+
export function isExternalSpec(name) {
|
|
34
|
+
if (name === "ama")
|
|
35
|
+
return false;
|
|
36
|
+
if (name.startsWith("acp:"))
|
|
37
|
+
return name.slice(4).trim() !== "";
|
|
38
|
+
return catalogEntry(name) !== undefined;
|
|
39
|
+
}
|
|
40
|
+
function labelOf(spec) {
|
|
41
|
+
return (catalogEntry(spec)?.label ?? (spec.startsWith("acp:") ? `ACP agent ${spec.slice(4)}` : spec));
|
|
42
|
+
}
|
|
43
|
+
function definition(name, runner, description, source) {
|
|
44
|
+
return {
|
|
45
|
+
name,
|
|
46
|
+
description,
|
|
47
|
+
permissionMode: "inherit",
|
|
48
|
+
model: "inherit",
|
|
49
|
+
maxTurns: 30,
|
|
50
|
+
isolation: "none",
|
|
51
|
+
background: false,
|
|
52
|
+
// 驱动表 id(gemini 等)与宿主 id 不在 AgentRunnerSpec 的字面量里,线上照样是字符串
|
|
53
|
+
runner: runner,
|
|
54
|
+
prompt: "",
|
|
55
|
+
source,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** 外部 CLI 的类型(`task(agent="claude")`)。 */
|
|
59
|
+
export function externalDefinition(spec) {
|
|
60
|
+
return definition(spec, spec, `External ${labelOf(spec)} CLI (its own login, model and permission policy; full instructions in prompt).`, "builtin");
|
|
61
|
+
}
|
|
62
|
+
export function hostDefinition(runner) {
|
|
63
|
+
return definition(runner.id, runner.id, runner.description, "host");
|
|
64
|
+
}
|
|
65
|
+
/** 只查 PATH(不起进程):候选链里任一程序在 PATH 上。 */
|
|
66
|
+
export function externalOnPath(spec, env) {
|
|
67
|
+
const found = candidatesFor(spec);
|
|
68
|
+
return found?.candidates.some((c) => findOnPath(c.program, env) !== undefined) ?? false;
|
|
69
|
+
}
|
|
70
|
+
/** 启动时登记:PATH 上的 claude / codex(无宿主时)与已注入的宿主 runner;其余按需解析。 */
|
|
71
|
+
export function registerExternalAgents(catalog, wiring) {
|
|
72
|
+
for (const runner of wiring.hostRunners?.list() ?? [])
|
|
73
|
+
catalog.add(hostDefinition(runner));
|
|
74
|
+
if (!wiring.hosted && wiring.probe)
|
|
75
|
+
for (const spec of LISTED_EXTERNAL_AGENTS)
|
|
76
|
+
if (externalOnPath(spec, wiring.env))
|
|
77
|
+
catalog.add(externalDefinition(spec));
|
|
78
|
+
catalog.setResolver((name) => {
|
|
79
|
+
const hosted = wiring.hostRunners?.get(name);
|
|
80
|
+
if (hosted !== undefined)
|
|
81
|
+
return hostDefinition(hosted);
|
|
82
|
+
return isExternalSpec(name) ? externalDefinition(name) : undefined;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** 续聊时能重开的句柄:被 stop 的外部会话以 `resume` 接上(同一任务、同一外部会话)。 */
|
|
86
|
+
class ExternalTaskHandle {
|
|
87
|
+
inner;
|
|
88
|
+
reopen;
|
|
89
|
+
stopped = false;
|
|
90
|
+
constructor(inner, reopen) {
|
|
91
|
+
this.inner = inner;
|
|
92
|
+
this.reopen = reopen;
|
|
93
|
+
}
|
|
94
|
+
get id() {
|
|
95
|
+
return this.inner.id;
|
|
96
|
+
}
|
|
97
|
+
async send(text) {
|
|
98
|
+
if (!this.stopped) {
|
|
99
|
+
try {
|
|
100
|
+
await this.inner.send(text);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
if (!(error instanceof AmaError) || error.code !== "agent_closed")
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (this.inner.id === "")
|
|
109
|
+
throw new AmaError("agent_closed", "外部 Agent 会话没有建立,不能续聊");
|
|
110
|
+
this.inner = await this.reopen(this.inner.id, text);
|
|
111
|
+
this.stopped = false;
|
|
112
|
+
}
|
|
113
|
+
wait() {
|
|
114
|
+
return this.inner.wait();
|
|
115
|
+
}
|
|
116
|
+
async stop() {
|
|
117
|
+
this.stopped = true;
|
|
118
|
+
await this.inner.stop();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 启动返回前到达的进度事件(第一回合的 `turn` 等)推迟到注册表发出 `subagent_start` 之后:
|
|
123
|
+
* 注册表在 `start()` resolve 后的微任务里发 start,这里在下一个宏任务再放行。
|
|
124
|
+
*/
|
|
125
|
+
function deferEvents(request) {
|
|
126
|
+
let queue = [];
|
|
127
|
+
const onEvent = (event) => {
|
|
128
|
+
if (queue !== undefined)
|
|
129
|
+
queue.push(event);
|
|
130
|
+
else
|
|
131
|
+
request.onEvent(event);
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
request: { ...request, onEvent },
|
|
135
|
+
release() {
|
|
136
|
+
setImmediate(() => {
|
|
137
|
+
const pending = queue ?? [];
|
|
138
|
+
queue = undefined;
|
|
139
|
+
for (const event of pending)
|
|
140
|
+
request.onEvent(event);
|
|
141
|
+
});
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
const infoCache = new Map();
|
|
146
|
+
/** RPC `get_agents` / `/agents`:会话的类型与外部 Agent(含安装与版本);未缓存返回 undefined。 */
|
|
147
|
+
export function cachedAgentInfos(sessionId) {
|
|
148
|
+
return infoCache.get(sessionId);
|
|
149
|
+
}
|
|
150
|
+
/** 合并:类型目录在前;外部探测结果补 installed / version,目录里没有的追加在后。 */
|
|
151
|
+
export function mergeAgentInfos(base, external) {
|
|
152
|
+
const out = base.map((info) => ({ ...info }));
|
|
153
|
+
for (const raw of external) {
|
|
154
|
+
// 驱动表里的 ama 经 ACP 驱动,名字是 acp:ama(裸 ama 是子会话类型的 runner 名)
|
|
155
|
+
const probe = raw.name === "ama" ? { ...raw, name: "acp:ama", runner: "acp:ama" } : raw;
|
|
156
|
+
const known = out.find((info) => info.name === probe.name);
|
|
157
|
+
if (known === undefined) {
|
|
158
|
+
out.push({ ...probe });
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (probe.installed !== undefined)
|
|
162
|
+
known.installed = probe.installed;
|
|
163
|
+
if (probe.version !== undefined)
|
|
164
|
+
known.version = probe.version;
|
|
165
|
+
}
|
|
166
|
+
return out;
|
|
167
|
+
}
|
|
168
|
+
/** 一个主会话的外部 Agent 入口(`SubagentEnvironment.runners` 的实现)。 */
|
|
169
|
+
export class SessionExternalAgents {
|
|
170
|
+
core;
|
|
171
|
+
wiring;
|
|
172
|
+
catalog;
|
|
173
|
+
agents;
|
|
174
|
+
approved = new Set();
|
|
175
|
+
pending = new Map();
|
|
176
|
+
disposed = false;
|
|
177
|
+
unsubscribe;
|
|
178
|
+
constructor(core, wiring, catalog) {
|
|
179
|
+
this.core = core;
|
|
180
|
+
this.wiring = wiring;
|
|
181
|
+
this.catalog = catalog;
|
|
182
|
+
const store = createAgentStore({
|
|
183
|
+
appendCustom: (customType, data) => void core.appendEntry({ type: "custom", customType, data }),
|
|
184
|
+
entries: () => core.manager.branch(),
|
|
185
|
+
});
|
|
186
|
+
const driverDeps = externalTesting.driverDeps;
|
|
187
|
+
this.agents = new ExternalAgents({
|
|
188
|
+
env: wiring.env,
|
|
189
|
+
cwd: core.cwd,
|
|
190
|
+
hosted: wiring.hosted,
|
|
191
|
+
...(wiring.hostRunners !== undefined ? { hostRunners: wiring.hostRunners } : {}),
|
|
192
|
+
...(wiring.dataDir !== undefined ? { dataDir: wiring.dataDir } : {}),
|
|
193
|
+
...(wiring.config !== undefined ? { config: wiring.config } : {}),
|
|
194
|
+
approve: (request, signal) => requestApproval(core, request, signal),
|
|
195
|
+
store,
|
|
196
|
+
parentMode: () => this.mode(),
|
|
197
|
+
unattended: () => core.options.unattended === true,
|
|
198
|
+
trusted: () => wiring.trusted,
|
|
199
|
+
...(driverDeps !== undefined ? { driverDeps } : {}),
|
|
200
|
+
log: (level, message) => core.log(level, message),
|
|
201
|
+
});
|
|
202
|
+
this.unsubscribe = wiring.hostRunners?.onChange(() => void this.refreshInfos());
|
|
203
|
+
}
|
|
204
|
+
mode() {
|
|
205
|
+
return this.core.options.permission?.mode ?? "default";
|
|
206
|
+
}
|
|
207
|
+
/** 注册表的 `runners(agent)`:ama 子会话类型返回 undefined。 */
|
|
208
|
+
runner(agent) {
|
|
209
|
+
if (agent.runner === "ama")
|
|
210
|
+
return undefined;
|
|
211
|
+
const spec = agent.runner;
|
|
212
|
+
const host = this.wiring.hostRunners?.get(spec);
|
|
213
|
+
let inner;
|
|
214
|
+
try {
|
|
215
|
+
inner = this.agents.resolve(spec);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
// 不可用的原因(宿主环境、未知 id)作为任务失败的说明返回给模型
|
|
219
|
+
return { id: spec, start: () => Promise.reject(error) };
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
id: inner.id,
|
|
223
|
+
start: async (request) => {
|
|
224
|
+
if (host === undefined)
|
|
225
|
+
await this.firstRun(spec, request);
|
|
226
|
+
const events = deferEvents(request);
|
|
227
|
+
const handle = await inner.start(this.forward(spec, events.request));
|
|
228
|
+
events.release();
|
|
229
|
+
void handle.wait().finally(() => void this.refreshInfos());
|
|
230
|
+
if (host !== undefined)
|
|
231
|
+
return handle;
|
|
232
|
+
const reopen = async (resume, prompt) => {
|
|
233
|
+
return inner.start({
|
|
234
|
+
...this.forward(spec, request),
|
|
235
|
+
prompt,
|
|
236
|
+
resume,
|
|
237
|
+
mode: this.mode(),
|
|
238
|
+
signal: new AbortController().signal,
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
return new ExternalTaskHandle(handle, reopen);
|
|
242
|
+
},
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
/** 发给外部 runner 的请求:去掉 ama 自己的缺省模型(`subagents.defaultModel`)。 */
|
|
246
|
+
forward(spec, request) {
|
|
247
|
+
const own = agentEntry(this.wiring.config, spec)?.model;
|
|
248
|
+
if (request.model !== undefined &&
|
|
249
|
+
request.model === this.wiring.defaultModel &&
|
|
250
|
+
request.model !== own) {
|
|
251
|
+
const { model: _ama, ...rest } = request;
|
|
252
|
+
return rest;
|
|
253
|
+
}
|
|
254
|
+
return request;
|
|
255
|
+
}
|
|
256
|
+
/** 首次在本会话以 `spec` 运行的确认(同一 Agent 并发的首次只问一次)。 */
|
|
257
|
+
firstRun(spec, request) {
|
|
258
|
+
if (this.approved.has(spec))
|
|
259
|
+
return Promise.resolve();
|
|
260
|
+
let pending = this.pending.get(spec);
|
|
261
|
+
if (pending === undefined) {
|
|
262
|
+
pending = this.confirm(spec, request).finally(() => this.pending.delete(spec));
|
|
263
|
+
this.pending.set(spec, pending);
|
|
264
|
+
}
|
|
265
|
+
return pending;
|
|
266
|
+
}
|
|
267
|
+
async confirm(spec, request) {
|
|
268
|
+
const core = this.core;
|
|
269
|
+
const mode = this.mode();
|
|
270
|
+
const rules = core.options.permission?.rules ?? [];
|
|
271
|
+
const subject = { command: spec };
|
|
272
|
+
const label = labelOf(spec);
|
|
273
|
+
if (findDenyRule(rules, "task", subject, core.cwd) !== undefined)
|
|
274
|
+
throw new AmaError("permission_denied", `A deny rule blocks running ${label} (task(${spec})).`);
|
|
275
|
+
let decision = findAllowRule(rules, "task", subject, core.cwd) !== undefined || mode === "full-auto"
|
|
276
|
+
? "allow"
|
|
277
|
+
: mode === "allowlist"
|
|
278
|
+
? "deny"
|
|
279
|
+
: "ask";
|
|
280
|
+
if (decision === "ask" && core.options.unattended === true)
|
|
281
|
+
decision = "deny";
|
|
282
|
+
if (decision === "deny")
|
|
283
|
+
throw new AmaError("permission_denied", `Running ${label} needs approval the first time in a session, and nobody can approve it here. ` +
|
|
284
|
+
`Add an allow rule task(${spec}) to permit it.`);
|
|
285
|
+
if (decision === "ask") {
|
|
286
|
+
const effective = clampMode(request.mode, mode, agentEntry(this.wiring.config, spec)?.maxMode);
|
|
287
|
+
const approval = {
|
|
288
|
+
requestId: randomUUID(),
|
|
289
|
+
toolName: "task",
|
|
290
|
+
input: {
|
|
291
|
+
agent: spec,
|
|
292
|
+
mode: effective,
|
|
293
|
+
note: `Runs ${label} with your existing login in that CLI (mode ${effective}).`,
|
|
294
|
+
},
|
|
295
|
+
reason: "mode",
|
|
296
|
+
context: { depth: 0, ...(request.taskId !== undefined ? { taskId: request.taskId } : {}) },
|
|
297
|
+
};
|
|
298
|
+
const answer = await requestApproval(core, approval, request.signal);
|
|
299
|
+
if (answer === "deny")
|
|
300
|
+
throw new AmaError("permission_denied", `The user declined running ${label}.`);
|
|
301
|
+
}
|
|
302
|
+
this.approved.add(spec);
|
|
303
|
+
}
|
|
304
|
+
/** 重新探测并缓存 `/agents` 的数据(不阻塞;会话关闭后不再写)。 */
|
|
305
|
+
async refreshInfos() {
|
|
306
|
+
const base = this.catalog.infos();
|
|
307
|
+
let external = [];
|
|
308
|
+
if (this.wiring.probe || this.wiring.hosted) {
|
|
309
|
+
try {
|
|
310
|
+
external = await this.agents.list();
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
this.core.log("warn", `external agent probe failed: ${String(error)}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const merged = mergeAgentInfos(base, external);
|
|
317
|
+
if (!this.disposed)
|
|
318
|
+
infoCache.set(this.core.manager.id, merged);
|
|
319
|
+
return merged;
|
|
320
|
+
}
|
|
321
|
+
dispose() {
|
|
322
|
+
this.disposed = true;
|
|
323
|
+
this.unsubscribe?.();
|
|
324
|
+
infoCache.delete(this.core.manager.id);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 子 Agent 定义文件解析(docs/wave5-plan.md §7.1,D22)。[W5-G]
|
|
3
|
+
*
|
|
4
|
+
* 一个 `*.md` = 一个类型:frontmatter 与 Skill 同一套 YAML 子集(skills/frontmatter.ts),字段名
|
|
5
|
+
* kebab-case;正文 = 追加到子会话系统提示末尾的角色说明。不合格的文件不加载并给出 warning(拼错的
|
|
6
|
+
* 字段比静默按缺省运行更容易发现)。不支持的字段(`hooks`、`mcpServers`、`memory`、`color`、
|
|
7
|
+
* `initialPrompt`、`skills`)与未知字段忽略。
|
|
8
|
+
*/
|
|
9
|
+
import type { AgentDefinition, AgentSource } from "./types.js";
|
|
10
|
+
export declare const AGENT_NAME_RE: RegExp;
|
|
11
|
+
export declare const MAX_AGENT_DESCRIPTION = 1024;
|
|
12
|
+
export declare const DEFAULT_AGENT_MAX_TURNS = 30;
|
|
13
|
+
export interface ParsedAgent {
|
|
14
|
+
agent?: AgentDefinition;
|
|
15
|
+
warnings: string[];
|
|
16
|
+
}
|
|
17
|
+
/** 解析一份定义文件;`filePath` 用于缺省名与 warning。 */
|
|
18
|
+
export declare function parseAgentDefinition(text: string, filePath: string, source: AgentSource): ParsedAgent;
|