@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
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 会话侧的压缩调度(设计 §9)。[B2]
|
|
3
3
|
*
|
|
4
|
-
* - 阈值检查(新提示前、`prepareNextTurn` 里):估算 > 0.7 ×(窗口 − 预留)→
|
|
5
|
-
*
|
|
4
|
+
* - 阈值检查(新提示前、`prepareNextTurn` 里):估算 > 0.7 ×(窗口 − 预留)→ 档一裁剪([W5-H1] 按工具
|
|
5
|
+
* 结果新旧计边界,可省 ≥ clearAtLeast 才动,一次清到 0.5 ×);仍 > 窗口 − 预留且熔断允许 → 档二摘要
|
|
6
|
+
* (trigger `threshold`)。缓存已冷(上次请求距今超过 TTL,只认 reported 端点)时未到 0.7 也裁,
|
|
7
|
+
* 且一次换掉全部候选。
|
|
8
|
+
* - 自检([W5-H1] C8):摘要缺 `## Goal` 重试一次再回落;自动压缩后估算不比压缩前小判失败,不写条目。
|
|
9
|
+
* - 回注([W5-H1] C6 / C13):摘要末尾接 `<post-compact-state>` 块(todo、计划、已加载 Skill、最近
|
|
10
|
+
* 文件、转录与 outputs 路径,不含文件正文;理由见 compaction/post-compact.ts),再跑 PostCompact
|
|
11
|
+
* Hook,其 additionalContext 以 `ama.hook_context` 追加在末尾。
|
|
12
|
+
* - 熔断([W5-H1] C5):连续 3 次失败或连续 3 次快速回填跳闸;固定前缀超预算不再尝试;都只告警一次。
|
|
6
13
|
* - 溢出恢复(会话 run 结束后,失败尝试已用 context_edit 剔除):PreCompact Hook → 档二摘要(trigger
|
|
7
|
-
* `overflow
|
|
14
|
+
* `overflow`,受跳闸限制)→ 压缩后估算 ≤ 0.8 × 窗口才重试。
|
|
8
15
|
* - 手动 `/compact`:PreCompact(trigger `manual`)→ 摘要;成功清零熔断。
|
|
9
16
|
* PreCompact 的 `decision: "block"` 取消本次压缩;`customInstructions` 追加到摘要提示。
|
|
10
17
|
* [W3-C1b] 阈值 / 手动压缩与分支摘要优先走会话前缀续写(缓存控制器给前缀),溢出恢复不走
|
|
@@ -12,9 +19,11 @@
|
|
|
12
19
|
*/
|
|
13
20
|
import { AmaError } from "../errors.js";
|
|
14
21
|
import { CompactionBreaker } from "../compaction/breaker.js";
|
|
15
|
-
import { estimateProjectedTokens } from "../compaction/estimate.js";
|
|
16
|
-
import { planPrune,
|
|
17
|
-
import {
|
|
22
|
+
import { estimateMessageTokens, estimateProjectedTokens, } from "../compaction/estimate.js";
|
|
23
|
+
import { planPrune, prunePolicy } from "../compaction/prune-tier.js";
|
|
24
|
+
import { createProtection, skillLocations } from "../compaction/protect.js";
|
|
25
|
+
import { buildPostCompactBlock } from "../compaction/post-compact.js";
|
|
26
|
+
import { prepareCompaction, prepareCompactionAt, runCompaction, } from "../compaction/summarize-tier.js";
|
|
18
27
|
import { prepareBranchSummary, runBranchSummary } from "../compaction/branch-summary.js";
|
|
19
28
|
import { buildProjection } from "../session/projection.js";
|
|
20
29
|
export const DEFAULT_COMPACTION_SETTINGS = {
|
|
@@ -24,14 +33,25 @@ export const DEFAULT_COMPACTION_SETTINGS = {
|
|
|
24
33
|
};
|
|
25
34
|
/** 保留区不超过 (窗口 − 预留) 的 40%,否则小窗口模型上摘要后仍然溢出。 */
|
|
26
35
|
export const KEEP_RECENT_MAX_RATIO = 0.4;
|
|
36
|
+
/** Hook additionalContext 的 custom 类型(与 UserPromptSubmit 的相同)。 */
|
|
37
|
+
const HOOK_CONTEXT_CUSTOM_TYPE = "ama.hook_context";
|
|
27
38
|
export class CompactionController {
|
|
28
39
|
breaker;
|
|
29
40
|
settings;
|
|
30
41
|
core;
|
|
31
42
|
compacting = false;
|
|
43
|
+
warnedReason;
|
|
44
|
+
/** [W5-H1] config `compaction.prune / pruneExclude`(组装根把整段 config.compaction 展开传入)。 */
|
|
45
|
+
pruneConfig;
|
|
32
46
|
constructor(core, settings = {}) {
|
|
33
47
|
this.core = core;
|
|
34
48
|
this.settings = { ...DEFAULT_COMPACTION_SETTINGS, ...settings };
|
|
49
|
+
const extra = settings;
|
|
50
|
+
this.pruneConfig = {};
|
|
51
|
+
if (extra.prune !== undefined)
|
|
52
|
+
this.pruneConfig.prune = extra.prune;
|
|
53
|
+
if (extra.pruneExclude !== undefined)
|
|
54
|
+
this.pruneConfig.pruneExclude = extra.pruneExclude;
|
|
35
55
|
this.breaker = new CompactionBreaker(this.settings.enabled, core.model().contextWindow);
|
|
36
56
|
}
|
|
37
57
|
get isCompacting() {
|
|
@@ -69,16 +89,31 @@ export class CompactionController {
|
|
|
69
89
|
signal,
|
|
70
90
|
customInstructions: instructions,
|
|
71
91
|
onFallback: (reason) => core.log("warn", `summary by prefix continuation failed (${reason}); used a separate request`),
|
|
92
|
+
onInvalid: (reason) => core.log("warn", `${reason}; kept it after one retry`),
|
|
72
93
|
};
|
|
73
94
|
if (continuation)
|
|
74
95
|
options.continuation = core.cache?.summaryContinuation();
|
|
75
96
|
return options;
|
|
76
97
|
}
|
|
77
|
-
/**
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
98
|
+
/** 档一参数;无窗口时 undefined。 */
|
|
99
|
+
prunePolicy() {
|
|
100
|
+
const budget = this.budget();
|
|
101
|
+
return budget === undefined ? undefined : prunePolicy(budget, this.pruneConfig.prune);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 档一;`need` = 清到目标还要省多少(undefined = 全部候选)。返回省下的 token 估算(0 = 未裁)。
|
|
105
|
+
*/
|
|
106
|
+
prune(policy, need) {
|
|
107
|
+
const core = this.core;
|
|
108
|
+
const items = buildProjection(core.manager.branch()).items;
|
|
109
|
+
const isProtected = createProtection({
|
|
110
|
+
cwd: core.cwd,
|
|
111
|
+
skillPaths: skillLocations(items),
|
|
112
|
+
exclude: this.pruneConfig.pruneExclude ?? [],
|
|
113
|
+
keepInContext: (name) => core.tool(name)?.annotations?.keepInContext === true,
|
|
114
|
+
});
|
|
115
|
+
const plan = planPrune(items, { policy, need, outputDir: core.outputDir(), isProtected });
|
|
116
|
+
for (const item of plan.items) {
|
|
82
117
|
this.core.appendEntry({
|
|
83
118
|
type: "context_edit",
|
|
84
119
|
targetId: item.targetId,
|
|
@@ -86,23 +121,101 @@ export class CompactionController {
|
|
|
86
121
|
reason: "prune",
|
|
87
122
|
});
|
|
88
123
|
}
|
|
89
|
-
if (plan.length > 0)
|
|
124
|
+
if (plan.items.length > 0)
|
|
90
125
|
this.core.reloadMessages();
|
|
91
|
-
return plan.
|
|
126
|
+
return plan.savedTokens;
|
|
92
127
|
}
|
|
93
128
|
/** 阈值检查(档一 → 档二)。失败只记录,不打断 run。 */
|
|
94
129
|
async checkThreshold(signal) {
|
|
95
130
|
if (!this.breaker.autoEnabled || this.compacting || signal.aborted)
|
|
96
131
|
return;
|
|
97
|
-
|
|
98
|
-
const
|
|
132
|
+
this.breaker.tick();
|
|
133
|
+
const policy = this.prunePolicy();
|
|
134
|
+
const budget = this.budget();
|
|
135
|
+
if (policy === undefined || budget === undefined)
|
|
136
|
+
return;
|
|
99
137
|
let tokens = this.estimate().tokens;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
if (tokens
|
|
138
|
+
// 缓存已冷(C3):前缀反正要重写,未到阈值也把候选一次换掉(仍要可省 ≥ clearAtLeast)
|
|
139
|
+
const cold = this.core.cache?.isCold() ?? false;
|
|
140
|
+
if (tokens > policy.triggerTokens || cold) {
|
|
141
|
+
const need = cold ? undefined : tokens - policy.targetTokens;
|
|
142
|
+
if (this.prune(policy, need) > 0)
|
|
143
|
+
tokens = this.estimate().tokens;
|
|
144
|
+
}
|
|
145
|
+
if (tokens <= budget)
|
|
103
146
|
return;
|
|
147
|
+
this.breaker.setPrefixOverflow(this.fixedPrefixTokens() > budget);
|
|
148
|
+
if (!this.breaker.canSummarize())
|
|
149
|
+
return this.warnBlocked();
|
|
104
150
|
await this.summarize("threshold", signal);
|
|
105
151
|
}
|
|
152
|
+
/** 回注块(todo、计划、已加载 Skill、最近文件、转录与 outputs 路径;不含文件正文)。 */
|
|
153
|
+
postCompactBlock() {
|
|
154
|
+
const core = this.core;
|
|
155
|
+
const branch = core.manager.branch();
|
|
156
|
+
return buildPostCompactBlock({
|
|
157
|
+
branch,
|
|
158
|
+
cwd: core.cwd,
|
|
159
|
+
skillPaths: skillLocations(buildProjection(branch).items),
|
|
160
|
+
transcriptPath: core.manager.file(),
|
|
161
|
+
outputDir: core.outputDir(),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* PostCompact Hook(C13,不可阻止):`additionalContext` 作为 `ama.hook_context` 追加在末尾。
|
|
166
|
+
* 返回最终的压缩后估算。
|
|
167
|
+
*/
|
|
168
|
+
async runPostCompactHook(trigger, tokensBefore, signal) {
|
|
169
|
+
const core = this.core;
|
|
170
|
+
const tokensAfter = this.estimate().tokens;
|
|
171
|
+
const hook = await core.runHook("PostCompact", { tokensBefore, tokensAfter, trigger: trigger === "manual" ? "manual" : "auto" }, signal);
|
|
172
|
+
const context = hook?.additionalContext;
|
|
173
|
+
if (context === undefined || context === "")
|
|
174
|
+
return tokensAfter;
|
|
175
|
+
core.appendEntry({
|
|
176
|
+
type: "custom_message",
|
|
177
|
+
customType: HOOK_CONTEXT_CUSTOM_TYPE,
|
|
178
|
+
content: context,
|
|
179
|
+
display: false,
|
|
180
|
+
});
|
|
181
|
+
core.reloadMessages();
|
|
182
|
+
return this.estimate().tokens;
|
|
183
|
+
}
|
|
184
|
+
/** 假设追加了这条 compaction 之后的估算(按投影全量重估)。 */
|
|
185
|
+
projectedTokens(input) {
|
|
186
|
+
const branch = this.core.manager.branch();
|
|
187
|
+
const pending = {
|
|
188
|
+
...input,
|
|
189
|
+
id: "\u0000pending-compaction",
|
|
190
|
+
parentId: branch.at(-1)?.id ?? null,
|
|
191
|
+
timestamp: new Date().toISOString(),
|
|
192
|
+
};
|
|
193
|
+
const next = [...branch, pending];
|
|
194
|
+
return estimateProjectedTokens(buildProjection(next).items, next).tokens;
|
|
195
|
+
}
|
|
196
|
+
/** 固定前缀(system 节 + 工具表)的估算:摘要压不掉这部分。 */
|
|
197
|
+
fixedPrefixTokens() {
|
|
198
|
+
let tokens = 0;
|
|
199
|
+
for (const { message } of buildProjection(this.core.manager.branch()).items)
|
|
200
|
+
if (message.role === "system")
|
|
201
|
+
tokens += estimateMessageTokens(message);
|
|
202
|
+
return tokens;
|
|
203
|
+
}
|
|
204
|
+
/** 熔断挡住自动摘要时告警(同一原因只报一次)。 */
|
|
205
|
+
warnBlocked() {
|
|
206
|
+
const reason = this.breaker.blockReason();
|
|
207
|
+
if (reason === undefined || reason === this.warnedReason)
|
|
208
|
+
return;
|
|
209
|
+
this.warnedReason = reason;
|
|
210
|
+
const text = {
|
|
211
|
+
tripped: "auto-compaction disabled after repeated summary failures",
|
|
212
|
+
rapid_refill: "auto-compaction disabled: the context refilled within 3 turns after each of the last 3 compactions",
|
|
213
|
+
prefix_overflow: "auto-compaction skipped: the system prompt and tool definitions alone exceed the context budget",
|
|
214
|
+
};
|
|
215
|
+
const message = text[reason];
|
|
216
|
+
if (message !== undefined)
|
|
217
|
+
this.core.log("warn", message);
|
|
218
|
+
}
|
|
106
219
|
/** 溢出恢复:返回是否应以新 run 重试。 */
|
|
107
220
|
async recoverOverflow(signal) {
|
|
108
221
|
if (!this.settings.enabled)
|
|
@@ -136,14 +249,16 @@ export class CompactionController {
|
|
|
136
249
|
}
|
|
137
250
|
return { retry: true };
|
|
138
251
|
}
|
|
139
|
-
|
|
140
|
-
|
|
252
|
+
/** `cutAt`:[RW-B] 以该条目为切点(「摘要到这里」),不按保留预算找切点。 */
|
|
253
|
+
async compactManual(instructions, signal, cutAt) {
|
|
254
|
+
const outcome = await this.summarize("manual", signal, instructions, cutAt);
|
|
141
255
|
if (outcome.result === undefined) {
|
|
142
256
|
if (outcome.aborted)
|
|
143
257
|
throw new AmaError("aborted", "compaction aborted");
|
|
144
258
|
throw new AmaError("compaction_failed", outcome.error ?? "compaction failed");
|
|
145
259
|
}
|
|
146
260
|
this.breaker.reset();
|
|
261
|
+
this.warnedReason = undefined;
|
|
147
262
|
return outcome.result;
|
|
148
263
|
}
|
|
149
264
|
/** `/tree` 离开分支:换叶子,并为离开的那段写 branch_summary(挂在新叶子下)。 */
|
|
@@ -163,7 +278,7 @@ export class CompactionController {
|
|
|
163
278
|
details: draft.details,
|
|
164
279
|
});
|
|
165
280
|
}
|
|
166
|
-
async summarize(trigger, signal, instructions) {
|
|
281
|
+
async summarize(trigger, signal, instructions, cutAt) {
|
|
167
282
|
const core = this.core;
|
|
168
283
|
this.compacting = true;
|
|
169
284
|
core.emit({ type: "compaction_start", trigger });
|
|
@@ -202,34 +317,43 @@ export class CompactionController {
|
|
|
202
317
|
const projection = buildProjection(core.manager.branch());
|
|
203
318
|
const keep = this.keepRecent();
|
|
204
319
|
let plan;
|
|
205
|
-
|
|
206
|
-
plan =
|
|
207
|
-
|
|
208
|
-
|
|
320
|
+
if (cutAt !== undefined)
|
|
321
|
+
plan = prepareCompactionAt(projection, cutAt);
|
|
322
|
+
else {
|
|
323
|
+
for (const budget of [keep, Math.floor(keep / 4), 1]) {
|
|
324
|
+
plan = prepareCompaction(projection, Math.max(1, budget));
|
|
325
|
+
if (plan !== undefined)
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
209
328
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.breaker.recordSummary(false);
|
|
329
|
+
// 「nothing to compact」不计失败(C5)
|
|
330
|
+
if (plan === undefined)
|
|
213
331
|
return fail("nothing to compact");
|
|
214
|
-
}
|
|
215
332
|
try {
|
|
216
333
|
const options = await this.summarizer(signal, customInstructions, trigger !== "overflow");
|
|
217
334
|
const draft = await runCompaction(plan, options);
|
|
218
335
|
if (signal.aborted)
|
|
219
336
|
return fail("aborted", true);
|
|
337
|
+
// 回注(C6):清单与指针接在摘要末尾,模型看到「摘要 → 回注 → 保留区」
|
|
220
338
|
const entry = {
|
|
221
339
|
type: "compaction",
|
|
222
|
-
summary: draft.summary
|
|
340
|
+
summary: `${draft.summary}\n\n${this.postCompactBlock()}`,
|
|
223
341
|
firstKeptEntryId: draft.firstKeptEntryId,
|
|
224
342
|
tokensBefore,
|
|
225
343
|
details: draft.details,
|
|
226
344
|
};
|
|
227
345
|
if (draft.usage !== undefined)
|
|
228
346
|
entry.usage = draft.usage;
|
|
347
|
+
// 自检(C8):自动压缩后不比压缩前小 = 失败(不写条目,计入熔断);手动 /compact 照用户意思写
|
|
348
|
+
const projected = trigger === "manual" ? 0 : this.projectedTokens(entry);
|
|
349
|
+
if (projected >= tokensBefore)
|
|
350
|
+
throw new AmaError("compaction_failed", `compaction did not shrink the context (${tokensBefore} → ${projected} tokens)`);
|
|
229
351
|
core.appendEntry(entry);
|
|
230
352
|
core.reloadMessages();
|
|
231
353
|
this.breaker.recordSummary(true);
|
|
232
|
-
|
|
354
|
+
if (this.breaker.tripped)
|
|
355
|
+
this.warnBlocked();
|
|
356
|
+
const tokensAfter = await this.runPostCompactHook(trigger, tokensBefore, signal);
|
|
233
357
|
const result = {
|
|
234
358
|
summary: draft.summary,
|
|
235
359
|
firstKeptEntryId: draft.firstKeptEntryId,
|
|
@@ -245,6 +369,8 @@ export class CompactionController {
|
|
|
245
369
|
const aborted = signal.aborted || (error instanceof AmaError && error.code === "aborted");
|
|
246
370
|
if (!aborted)
|
|
247
371
|
this.breaker.recordSummary(false);
|
|
372
|
+
if (this.breaker.tripped)
|
|
373
|
+
this.warnBlocked();
|
|
248
374
|
return fail(error instanceof Error ? error.message : String(error), aborted);
|
|
249
375
|
}
|
|
250
376
|
}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* `SessionCore` 是 session.ts 交给 session-tools.ts / session-compaction.ts 的内部视图(避免循环 import)。
|
|
6
6
|
*/
|
|
7
7
|
import type { WarmingDecisionHandler } from "../ai/cache/types.js";
|
|
8
|
+
import type { CheckpointHooks } from "../checkpoints/types.js";
|
|
8
9
|
import type { Model, ModelThinkingLevel, ProviderRegistryApi } from "../ai/types.js";
|
|
9
10
|
import type { HookDispatcherApi, HookEvent, HookEventPayload, HookOutcome } from "../hooks/types.js";
|
|
10
11
|
import type { PermissionClassifier } from "../permissions/classifier.js";
|
|
@@ -15,8 +16,10 @@ import type { SubagentRequest, SubagentResult, ToolDefinition } from "../tools/t
|
|
|
15
16
|
import type { Agent } from "./agent.js";
|
|
16
17
|
import type { StreamFn } from "./loop.js";
|
|
17
18
|
import type { SessionCacheController } from "./session-cache.js";
|
|
19
|
+
import type { CheckpointBackendFactory } from "../checkpoints/index.js";
|
|
20
|
+
import type { SessionExtensionFactory } from "./session-extensions.js";
|
|
18
21
|
import type { SystemPromptInput } from "./system-prompt.js";
|
|
19
|
-
import type { CacheSettings, CompactionSettings, QueueMode, RetrySettings, SessionEvent } from "./types.js";
|
|
22
|
+
import type { CacheSettings, CompactionSettings, QueueMode, RetrySettings, SessionEvent, SessionLimits } from "./types.js";
|
|
20
23
|
export type PromptExpansion = {
|
|
21
24
|
text: string;
|
|
22
25
|
} | {
|
|
@@ -72,6 +75,18 @@ export interface AgentSessionOptions {
|
|
|
72
75
|
idleTimeoutMs?: number;
|
|
73
76
|
/** 子 Agent 的回合上限(maxTurns)。 */
|
|
74
77
|
maxTurns?: number;
|
|
78
|
+
/**
|
|
79
|
+
* [W5-C0] 会话预算(`--max-turns` / `--max-cost` / config `limits.*`);到限发 `limit_reached`
|
|
80
|
+
* 并结束 run(实现归 W5-H2 的 limits 扩展,C0 只透传)。
|
|
81
|
+
*/
|
|
82
|
+
limits?: SessionLimits;
|
|
83
|
+
/**
|
|
84
|
+
* [W5-C0] 会话扩展的工厂(session-extensions.ts):每个会话实例(含 fork 与 task 子会话)各调一次;
|
|
85
|
+
* 组装根从 `cli/compose-extensions.ts` 的表取得。缺省无扩展。
|
|
86
|
+
*/
|
|
87
|
+
extensions?: readonly SessionExtensionFactory[];
|
|
88
|
+
/** [W5-C0] 回退模型 `provider/model[@channel]`(config `fallbackModel`,实现归 W5-H2)。 */
|
|
89
|
+
fallbackModel?: string;
|
|
75
90
|
/** 子 Agent 并发上限,缺省 4;`false` 关闭 spawnSubagent。 */
|
|
76
91
|
subagents?: {
|
|
77
92
|
maxConcurrent?: number;
|
|
@@ -82,6 +97,15 @@ export interface AgentSessionOptions {
|
|
|
82
97
|
cache?: Partial<CacheSettings>;
|
|
83
98
|
/** [W3-C1b] 宿主 `cache.onWarmingDecision` 的处理器(每次保温前现取)。 */
|
|
84
99
|
warmingDecider?(): WarmingDecisionHandler | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* [RW-B] 检查点后端工厂(rewind-plan §2):只在主会话(depth 0)且会话有目录时调用;返回
|
|
102
|
+
* undefined = 不建检查点(`checkpoints.mode: "off"`)。
|
|
103
|
+
*/
|
|
104
|
+
checkpoints?: CheckpointBackendFactory;
|
|
105
|
+
/** [RW-B] task 子会话:父会话的检查点钩子(编辑记到父会话当前回合)。 */
|
|
106
|
+
checkpointHooks?: CheckpointHooks;
|
|
107
|
+
/** [RW-B] 中断即撤回(config `ui.restoreOnCancel`,缺省 true)。 */
|
|
108
|
+
restoreOnCancel?: boolean;
|
|
85
109
|
log?(level: "debug" | "info" | "warn" | "error", message: string): void;
|
|
86
110
|
}
|
|
87
111
|
export interface SessionCore {
|
|
@@ -110,6 +134,8 @@ export interface SessionCore {
|
|
|
110
134
|
/** Hook 返回 continue:false 时记下,finishTurn 据此结束 run。 */
|
|
111
135
|
requestStop(reason: string | undefined): void;
|
|
112
136
|
spawnSubagent(request: SubagentRequest): Promise<SubagentResult>;
|
|
137
|
+
/** [RW-B] ToolContext.checkpoint:本会话的检查点钩子(无则 undefined)。 */
|
|
138
|
+
checkpointHooks?(): CheckpointHooks | undefined;
|
|
113
139
|
/** auto 权限模式的分类器(懒建,会话内缓存判定)。 */
|
|
114
140
|
autoClassifier(): PermissionClassifier;
|
|
115
141
|
log(level: "debug" | "info" | "warn" | "error", message: string): void;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 会话扩展点(docs/wave5-plan.md §10.1,D30)。[W5-C0]
|
|
3
|
+
*
|
|
4
|
+
* 第五波的遥测、计划、提醒、图片预算、预算上限等都以扩展实现在各自文件,`session.ts` 只留调用点:
|
|
5
|
+
*
|
|
6
|
+
* | 钩子 | 调用点 |
|
|
7
|
+
* | ---------------- | --------------------------------------------------------------------------------------- |
|
|
8
|
+
* | `beforePrompts` | `runPrompt` 组装好 prompts(用户消息 + Hook additionalContext)、阈值压缩与检查点之后, |
|
|
9
|
+
* | | 按表顺序调用;返回的消息**追加在 prompts 之后**(只能是 custom_message,不得改已有消息) |
|
|
10
|
+
* | `wrapStream` | 会话构造时按表顺序包流:表中靠前的离协议层近;缓存控制器始终在最外层(看到最终请求) |
|
|
11
|
+
* | `onEvent` | 每个 `SessionEvent` 广播给订阅者之后 |
|
|
12
|
+
* | `onAgentSettled` | `agent_settled` 发出之后、本周期结束(`waitForIdle` resolve)之前 await |
|
|
13
|
+
* | `contributeStats`| `getStats()` 末尾,就地补 `SessionStats` 的字段 |
|
|
14
|
+
* | `dispose` | 会话 dispose 时 |
|
|
15
|
+
*
|
|
16
|
+
* 约束:
|
|
17
|
+
* - **缓存前缀**(design §9.1):扩展不得改 system 节与工具表、不得改已有消息;只能在尾部追加。
|
|
18
|
+
* - 选项里放的是**工厂**(`SessionExtensionFactory`),每个会话实例(主会话、fork、task 子会话)
|
|
19
|
+
* 各调一次得到自己的扩展实例;工厂按 `ctx.core.depth` 决定子会话要不要装(返回 undefined 即不装)。
|
|
20
|
+
* 工厂在会话构造中途调用:只可读 `core.options / depth / cwd / manager`,不要 emit 或请求模型。
|
|
21
|
+
* - 钩子抛错不影响会话:同步钩子的异常记 warn 日志后忽略;`beforePrompts` / `onAgentSettled`
|
|
22
|
+
* 的异常同样记日志、按「无追加」处理。
|
|
23
|
+
* - `onAgentSettled` 不要等待人工输入(计划审批等):需要等待的流程自行异步进行,之后用
|
|
24
|
+
* `prompt / followUp` 开新回合。
|
|
25
|
+
*/
|
|
26
|
+
import type { AgentMessage } from "../session/types.js";
|
|
27
|
+
import type { StreamFn } from "./loop.js";
|
|
28
|
+
import type { SessionCore } from "./session-core.js";
|
|
29
|
+
import type { SessionEvent, SessionStats } from "./types.js";
|
|
30
|
+
export interface SessionExtensionContext {
|
|
31
|
+
/** appendEntry / reloadMessages / emit / manager / model() / cache / options / depth。 */
|
|
32
|
+
readonly core: SessionCore;
|
|
33
|
+
}
|
|
34
|
+
export interface SessionExtension {
|
|
35
|
+
readonly id: string;
|
|
36
|
+
/** 新回合 prompts 投递前;返回要追加在 prompts 之后的消息(只能 custom_message)。 */
|
|
37
|
+
beforePrompts?(ctx: SessionExtensionContext, prompts: readonly AgentMessage[]): Promise<AgentMessage[]> | AgentMessage[];
|
|
38
|
+
wrapStream?(stream: StreamFn): StreamFn;
|
|
39
|
+
onEvent?(event: SessionEvent): void;
|
|
40
|
+
onAgentSettled?(ctx: SessionExtensionContext): Promise<void> | void;
|
|
41
|
+
contributeStats?(stats: SessionStats): void;
|
|
42
|
+
dispose?(): void;
|
|
43
|
+
}
|
|
44
|
+
/** 每个会话实例调一次;返回 undefined = 本会话不装(例如子会话)。 */
|
|
45
|
+
export type SessionExtensionFactory = (ctx: SessionExtensionContext) => SessionExtension | undefined;
|
|
46
|
+
/** 会话持有的扩展集合:把各钩子的遍历、顺序与异常隔离集中在这里,session.ts 只调一行。 */
|
|
47
|
+
export declare class SessionExtensions {
|
|
48
|
+
private readonly list;
|
|
49
|
+
private readonly ctx;
|
|
50
|
+
constructor(core: SessionCore, factories: readonly SessionExtensionFactory[] | undefined);
|
|
51
|
+
get size(): number;
|
|
52
|
+
ids(): string[];
|
|
53
|
+
/** 表中靠前的离协议层近;调用方再把结果交给缓存控制器包在最外层。 */
|
|
54
|
+
wrapStream(stream: StreamFn): StreamFn;
|
|
55
|
+
beforePrompts(prompts: readonly AgentMessage[]): Promise<AgentMessage[]>;
|
|
56
|
+
onEvent(event: SessionEvent): void;
|
|
57
|
+
onAgentSettled(): Promise<void>;
|
|
58
|
+
contributeStats(stats: SessionStats): SessionStats;
|
|
59
|
+
dispose(): void;
|
|
60
|
+
private warn;
|
|
61
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 会话扩展点(docs/wave5-plan.md §10.1,D30)。[W5-C0]
|
|
3
|
+
*
|
|
4
|
+
* 第五波的遥测、计划、提醒、图片预算、预算上限等都以扩展实现在各自文件,`session.ts` 只留调用点:
|
|
5
|
+
*
|
|
6
|
+
* | 钩子 | 调用点 |
|
|
7
|
+
* | ---------------- | --------------------------------------------------------------------------------------- |
|
|
8
|
+
* | `beforePrompts` | `runPrompt` 组装好 prompts(用户消息 + Hook additionalContext)、阈值压缩与检查点之后, |
|
|
9
|
+
* | | 按表顺序调用;返回的消息**追加在 prompts 之后**(只能是 custom_message,不得改已有消息) |
|
|
10
|
+
* | `wrapStream` | 会话构造时按表顺序包流:表中靠前的离协议层近;缓存控制器始终在最外层(看到最终请求) |
|
|
11
|
+
* | `onEvent` | 每个 `SessionEvent` 广播给订阅者之后 |
|
|
12
|
+
* | `onAgentSettled` | `agent_settled` 发出之后、本周期结束(`waitForIdle` resolve)之前 await |
|
|
13
|
+
* | `contributeStats`| `getStats()` 末尾,就地补 `SessionStats` 的字段 |
|
|
14
|
+
* | `dispose` | 会话 dispose 时 |
|
|
15
|
+
*
|
|
16
|
+
* 约束:
|
|
17
|
+
* - **缓存前缀**(design §9.1):扩展不得改 system 节与工具表、不得改已有消息;只能在尾部追加。
|
|
18
|
+
* - 选项里放的是**工厂**(`SessionExtensionFactory`),每个会话实例(主会话、fork、task 子会话)
|
|
19
|
+
* 各调一次得到自己的扩展实例;工厂按 `ctx.core.depth` 决定子会话要不要装(返回 undefined 即不装)。
|
|
20
|
+
* 工厂在会话构造中途调用:只可读 `core.options / depth / cwd / manager`,不要 emit 或请求模型。
|
|
21
|
+
* - 钩子抛错不影响会话:同步钩子的异常记 warn 日志后忽略;`beforePrompts` / `onAgentSettled`
|
|
22
|
+
* 的异常同样记日志、按「无追加」处理。
|
|
23
|
+
* - `onAgentSettled` 不要等待人工输入(计划审批等):需要等待的流程自行异步进行,之后用
|
|
24
|
+
* `prompt / followUp` 开新回合。
|
|
25
|
+
*/
|
|
26
|
+
/** 会话持有的扩展集合:把各钩子的遍历、顺序与异常隔离集中在这里,session.ts 只调一行。 */
|
|
27
|
+
export class SessionExtensions {
|
|
28
|
+
list;
|
|
29
|
+
ctx;
|
|
30
|
+
constructor(core, factories) {
|
|
31
|
+
this.ctx = { core };
|
|
32
|
+
const list = [];
|
|
33
|
+
for (const factory of factories ?? []) {
|
|
34
|
+
const extension = guard(core.log.bind(core), "factory", () => factory(this.ctx));
|
|
35
|
+
if (extension !== undefined)
|
|
36
|
+
list.push(extension);
|
|
37
|
+
}
|
|
38
|
+
this.list = list;
|
|
39
|
+
}
|
|
40
|
+
get size() {
|
|
41
|
+
return this.list.length;
|
|
42
|
+
}
|
|
43
|
+
ids() {
|
|
44
|
+
return this.list.map((extension) => extension.id);
|
|
45
|
+
}
|
|
46
|
+
/** 表中靠前的离协议层近;调用方再把结果交给缓存控制器包在最外层。 */
|
|
47
|
+
wrapStream(stream) {
|
|
48
|
+
let wrapped = stream;
|
|
49
|
+
for (const extension of this.list) {
|
|
50
|
+
const next = extension.wrapStream?.(wrapped);
|
|
51
|
+
if (next !== undefined)
|
|
52
|
+
wrapped = next;
|
|
53
|
+
}
|
|
54
|
+
return wrapped;
|
|
55
|
+
}
|
|
56
|
+
async beforePrompts(prompts) {
|
|
57
|
+
const added = [];
|
|
58
|
+
for (const extension of this.list) {
|
|
59
|
+
if (extension.beforePrompts === undefined)
|
|
60
|
+
continue;
|
|
61
|
+
try {
|
|
62
|
+
added.push(...(await extension.beforePrompts(this.ctx, [...prompts, ...added])));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
this.warn(extension, "beforePrompts", error);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return added;
|
|
69
|
+
}
|
|
70
|
+
onEvent(event) {
|
|
71
|
+
for (const extension of this.list) {
|
|
72
|
+
if (extension.onEvent === undefined)
|
|
73
|
+
continue;
|
|
74
|
+
try {
|
|
75
|
+
extension.onEvent(event);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
this.warn(extension, "onEvent", error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async onAgentSettled() {
|
|
83
|
+
for (const extension of this.list) {
|
|
84
|
+
if (extension.onAgentSettled === undefined)
|
|
85
|
+
continue;
|
|
86
|
+
try {
|
|
87
|
+
await extension.onAgentSettled(this.ctx);
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
this.warn(extension, "onAgentSettled", error);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
contributeStats(stats) {
|
|
95
|
+
for (const extension of this.list) {
|
|
96
|
+
if (extension.contributeStats === undefined)
|
|
97
|
+
continue;
|
|
98
|
+
try {
|
|
99
|
+
extension.contributeStats(stats);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
this.warn(extension, "contributeStats", error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return stats;
|
|
106
|
+
}
|
|
107
|
+
dispose() {
|
|
108
|
+
for (const extension of this.list) {
|
|
109
|
+
try {
|
|
110
|
+
extension.dispose?.();
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
this.warn(extension, "dispose", error);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
warn(extension, hook, error) {
|
|
118
|
+
this.ctx.core.log("warn", `extension ${extension.id} failed in ${hook}: ${String(error)}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function guard(log, hook, run) {
|
|
122
|
+
try {
|
|
123
|
+
return run();
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
log("warn", `extension ${hook} failed: ${String(error)}`);
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 图片预算扩展(docs/wave5-plan.md §4、D11、D30)。[W5-I]
|
|
3
|
+
*
|
|
4
|
+
* 每次请求前检查图片总量:超预算(或有超单图上限的旧图、> 20 张时的大图)就按
|
|
5
|
+
* `planImageBudget` 把旧图换成占位文本,写成 `context_edit{reason:"image_budget"}` 持久化、
|
|
6
|
+
* 重建上下文,并通知缓存控制器「下一条是重置点」(前缀只在这里变一次,之后稳定)。
|
|
7
|
+
*
|
|
8
|
+
* 两个检查点:
|
|
9
|
+
* - `beforePrompts`:新回合投递前;本回合提示里的附件计入总量但不降级;
|
|
10
|
+
* - `wrapStream`:回合内(工具结果里新读的图)每次 `turn` 请求前;已发出的消息都已落盘时才降级,
|
|
11
|
+
* 并把本次请求的转录换成降级后的(就地改 context,缓存控制器看到的也是降级后的请求)。
|
|
12
|
+
*
|
|
13
|
+
* 模型不收图片时不处理:`normalizeContext` 已把图片换成占位(ai/context.ts)。
|
|
14
|
+
*/
|
|
15
|
+
import { type ImageLimits } from "../ai/image-limits.js";
|
|
16
|
+
import type { Model } from "../ai/types.js";
|
|
17
|
+
import type { SessionCore } from "./session-core.js";
|
|
18
|
+
import type { SessionExtension } from "./session-extensions.js";
|
|
19
|
+
export interface ImageBudgetExtensionDeps {
|
|
20
|
+
/** 测试注入:按模型的上限。缺省 `imageLimits(model)`。 */
|
|
21
|
+
limits?(model: Model): ImageLimits;
|
|
22
|
+
}
|
|
23
|
+
export declare function createImageBudgetExtension(core: SessionCore, deps?: ImageBudgetExtensionDeps): SessionExtension;
|