@armadra/agent 0.4.0 → 0.5.1
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 +184 -1
- package/README.md +202 -83
- 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 +37605 -21619
- 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/choice-prompt.d.ts +58 -0
- package/dist/cli/choice-prompt.js +140 -0
- 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-cache-probe.d.ts +1 -1
- package/dist/cli/subcommands/models-cache-probe.js +3 -12
- 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.d.ts +1 -1
- package/dist/cli/subcommands/providers.js +8 -15
- 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 +13 -1
- package/dist/modes/commands-core.js +64 -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 +12 -1
- package/dist/modes/interactive/commands.js +31 -1
- package/dist/modes/interactive/confirm-dialog.d.ts +49 -0
- package/dist/modes/interactive/confirm-dialog.js +121 -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 +140 -136
- package/dist/modes/interactive/key-dispatch.d.ts +22 -2
- package/dist/modes/interactive/key-dispatch.js +66 -7
- package/dist/modes/interactive/line/line-mode.d.ts +4 -1
- package/dist/modes/interactive/line/line-mode.js +31 -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/startup-ui.js +5 -1
- 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/bypass.d.ts +32 -0
- package/dist/permissions/bypass.js +36 -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 +6 -1
- package/dist/tui/keybindings.js +6 -1
- 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 +78 -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 +179 -21
- package/package.json +13 -2
package/docs/providers.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
## 配置目录
|
|
6
6
|
|
|
7
7
|
缺省 `~/.config/ama/`(Windows `%APPDATA%\ama\`;`AMA_CONFIG_DIR` 优先,其次 `XDG_CONFIG_HOME/ama`)。数据
|
|
8
|
-
(会话、models.dev
|
|
8
|
+
(会话、models.dev 刷新覆盖)在另一个目录:`~/.local/share/ama/`(`AMA_DATA_DIR` / `XDG_DATA_HOME`)。
|
|
9
9
|
|
|
10
10
|
```
|
|
11
11
|
~/.config/ama/ 0700
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
└── skills/ prompts/ (按需)
|
|
18
18
|
~/.local/share/ama/
|
|
19
19
|
├── sessions/ 会话
|
|
20
|
-
└── models-dev.json models.dev
|
|
20
|
+
└── models-dev.json models.dev 刷新覆盖(只有 ama models refresh 写)
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
- `ama init`:建目录(0700)并补齐缺失的 `config.json` 与 `config.schema.json`,逐个打印「已创建」或
|
|
@@ -75,26 +75,89 @@
|
|
|
75
75
|
|
|
76
76
|
## 内置供应商
|
|
77
77
|
|
|
78
|
-
| id |
|
|
79
|
-
| ------------ |
|
|
80
|
-
| `anthropic` |
|
|
81
|
-
| `openai` |
|
|
82
|
-
| `google` |
|
|
83
|
-
| `deepseek` |
|
|
84
|
-
| `moonshot` |
|
|
85
|
-
| `zhipu` |
|
|
86
|
-
| `dashscope` |
|
|
87
|
-
| `openrouter` |
|
|
88
|
-
| `groq` |
|
|
89
|
-
| `xai` |
|
|
90
|
-
| `mistral` |
|
|
91
|
-
| `
|
|
92
|
-
| `
|
|
78
|
+
| id | 渠道(**粗体**为缺省) | 缺省地址 | API Key 环境变量(顺序) |
|
|
79
|
+
| ------------ | ------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------- |
|
|
80
|
+
| `anthropic` | 单渠道 messages | `https://api.anthropic.com` | `ANTHROPIC_API_KEY`、`AMA_API_KEY_ANTHROPIC` |
|
|
81
|
+
| `openai` | **responses**、chat | `https://api.openai.com/v1` | `OPENAI_API_KEY`、`AMA_API_KEY_OPENAI` |
|
|
82
|
+
| `google` | 单渠道 gemini | `https://generativelanguage.googleapis.com/v1beta` | `GEMINI_API_KEY`、`GOOGLE_API_KEY`、`AMA_API_KEY_GOOGLE` |
|
|
83
|
+
| `deepseek` | **chat**、messages(`/anthropic`) | `https://api.deepseek.com` | `DEEPSEEK_API_KEY`、`AMA_API_KEY_DEEPSEEK` |
|
|
84
|
+
| `moonshot` | **chat**、messages、responses、chat-intl、messages-intl(`.ai`) | `https://api.moonshot.cn/v1` | `MOONSHOT_API_KEY`、`KIMI_API_KEY`、`AMA_API_KEY_MOONSHOT` |
|
|
85
|
+
| `zhipu` | **chat**、messages(`/api/anthropic`)、chat-intl、messages-intl(`api.z.ai`) | `https://open.bigmodel.cn/api/paas/v4` | `ZHIPU_API_KEY`、`ZAI_API_KEY`、`AMA_API_KEY_ZHIPU` |
|
|
86
|
+
| `dashscope` | **messages**(`/apps/anthropic`)、responses、chat、messages-intl、chat-intl | `https://dashscope.aliyuncs.com/apps/anthropic` | `DASHSCOPE_API_KEY`、`QWEN_API_KEY`、`AMA_API_KEY_DASHSCOPE` |
|
|
87
|
+
| `openrouter` | 单渠道 chat | `https://openrouter.ai/api/v1` | `OPENROUTER_API_KEY`、`AMA_API_KEY_OPENROUTER` |
|
|
88
|
+
| `groq` | 单渠道 chat | `https://api.groq.com/openai/v1` | `GROQ_API_KEY`、`AMA_API_KEY_GROQ` |
|
|
89
|
+
| `xai` | **responses**、chat | `https://api.x.ai/v1` | `XAI_API_KEY`、`AMA_API_KEY_XAI` |
|
|
90
|
+
| `mistral` | 单渠道 chat | `https://api.mistral.ai/v1` | `MISTRAL_API_KEY`、`AMA_API_KEY_MISTRAL` |
|
|
91
|
+
| `minimax` | **messages**、responses(只 M3)、chat、messages-intl、chat-intl(`api.minimax.io`) | `https://api.minimax.cn/anthropic` | `MINIMAX_API_KEY`、`AMA_API_KEY_MINIMAX` |
|
|
92
|
+
| `stepfun` | **messages**、chat、responses(只 step-5-preview)、messages-intl、chat-intl(`.ai`) | `https://api.stepfun.com` | `STEPFUN_API_KEY`、`STEP_API_KEY`、`AMA_API_KEY_STEPFUN` |
|
|
93
|
+
| `volcengine` | **responses**、chat | `https://ark.cn-beijing.volces.com/api/v3` | `ARK_API_KEY`、`VOLCENGINE_API_KEY`、`AMA_API_KEY_VOLCENGINE` |
|
|
94
|
+
| `tencent` | **messages**、chat(`/v1`) | `https://tokenhub.tencentmaas.com` | `TOKENHUB_API_KEY`、`HUNYUAN_API_KEY`、`AMA_API_KEY_TENCENT` |
|
|
95
|
+
| `ollama` | 单渠道 chat | `http://127.0.0.1:11434/v1` | 可无(`OLLAMA_API_KEY`) |
|
|
96
|
+
| `lmstudio` | 单渠道 chat | `http://127.0.0.1:1234/v1` | 可无 |
|
|
93
97
|
|
|
94
98
|
另有测试用供应商 `fake`(模型 `fake/echo`、`fake/reasoning`),见下文。
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
**缺省协议**:Messages / Responses 优先、Chat 回落。能执行显式缓存的 Messages 端点(通义、MiniMax M2.x、腾讯)与
|
|
101
|
+
官方推荐 Messages 的阶跃缺省 messages;OpenAI、xAI、火山方舟缺省 responses;DeepSeek、智谱、Kimi 只有隐式缓存,
|
|
102
|
+
**缺省保持 chat,直到官方直连过了实测门**(见「渠道实测」)再改,切换只是 `builtin.ts` 里一行 `defaultChannel`。
|
|
103
|
+
|
|
104
|
+
**内置渠道**(与用户的[渠道](#渠道channels一个供应商多种接口)同一机制):
|
|
105
|
+
|
|
106
|
+
- `provider/model@channel` 选渠道,例如 `deepseek/deepseek-v4-pro@messages`、`dashscope/qwen3.8-max@chat-intl`;
|
|
107
|
+
目录模型缺省挂全部渠道,目录可按模型限定(MiniMax M2.x、阶跃 step-3.x 没有 responses)。
|
|
108
|
+
- 改缺省:`"providers": { "deepseek": { "defaultChannel": "messages" } }`;或只写协议
|
|
109
|
+
`"api": "anthropic-messages"`,选同协议的内置渠道。
|
|
110
|
+
- 改某个渠道:`channels.<内置渠道名>` 只写要改的字段(`headers` / `compat` 合并一层,其余覆盖);新名字的渠道追加
|
|
111
|
+
在后,目录模型同样可用。
|
|
112
|
+
- **改了供应商级 `baseUrl`**(config、auth.json 或 `OPENAI_BASE_URL` / `ANTHROPIC_BASE_URL`)而没写自己的
|
|
113
|
+
`channels` 时,内置渠道作废,按「供应商级 `api` + 新 `baseUrl`」单渠道处理,与引入内置渠道之前一致:回落协议是
|
|
114
|
+
Chat(`api` 可改);OpenAI / xAI / 火山方舟的**目录模型**在中转上仍走 Responses,目录外的 id(本地服务、中转
|
|
115
|
+
自有模型)走 Chat。落在任一内置渠道主机上(如国际站)不算中转。
|
|
116
|
+
- 鉴权头按渠道:Anthropic 兼容端点缺省 `x-api-key`,Kimi、MiniMax、阶跃的 Messages 渠道按其文档用
|
|
117
|
+
`Authorization: Bearer`。
|
|
118
|
+
|
|
119
|
+
### Coding Plan 类订阅端点
|
|
120
|
+
|
|
121
|
+
火山方舟、阿里百炼、智谱、Kimi、MiniMax、阶跃等的 Coding Plan / Token Plan 额度只限编程工具使用,`ama -p` 与 RPC
|
|
122
|
+
嵌入属于自动化调用,有被判违规的风险,因此**不做内置渠道**。确认条款允许后可自行加渠道(key 写在渠道上):
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"providers": {
|
|
127
|
+
"volcengine": {
|
|
128
|
+
"channels": {
|
|
129
|
+
"coding": {
|
|
130
|
+
"api": "anthropic-messages",
|
|
131
|
+
"baseUrl": "https://ark.cn-beijing.volces.com/api/coding",
|
|
132
|
+
"apiKey": "$ARK_CODING_PLAN_KEY"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
"zhipu": {
|
|
137
|
+
"channels": {
|
|
138
|
+
"coding": {
|
|
139
|
+
"api": "openai-completions",
|
|
140
|
+
"baseUrl": "https://open.bigmodel.cn/api/coding/paas/v4",
|
|
141
|
+
"apiKey": "$ZHIPU_CODING_PLAN_KEY"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
"stepfun": {
|
|
146
|
+
"channels": {
|
|
147
|
+
"plan": {
|
|
148
|
+
"api": "anthropic-messages",
|
|
149
|
+
"baseUrl": "https://api.stepfun.com/step_plan",
|
|
150
|
+
"apiKey": "$STEP_PLAN_KEY",
|
|
151
|
+
"authHeader": "authorization-bearer"
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
然后 `--model volcengine/<模型>@coding`(订阅端点的模型 id 以各家文档为准,目录外的 id 用 `models[]` 补上并写
|
|
160
|
+
`"channels": ["coding"]`)。
|
|
98
161
|
|
|
99
162
|
## 模型引用
|
|
100
163
|
|
|
@@ -167,7 +230,7 @@ export PACKY_API_KEY=sk-...
|
|
|
167
230
|
的(每模型最多 3 次,`--limit` 限制探测的模型数,缺省 30,执行前打印预估;模型之间并发,探测规则同下文
|
|
168
231
|
`providers add --probe`);
|
|
169
232
|
`--write` 把结果合并进用户级 `config.json`(已有同 id 不覆盖,只写 `id` 与和供应商不同的 `api`,
|
|
170
|
-
原文件备份为 `config.json.bak`)。上下文等元数据在运行时从 models.dev
|
|
233
|
+
原文件备份为 `config.json.bak`)。上下文等元数据在运行时从 models.dev 快照补(见下文「模型元数据」),
|
|
171
234
|
匹配不到的条目没有 `contextWindow`,自动压缩随之关闭,需要时手动补。
|
|
172
235
|
|
|
173
236
|
```sh
|
|
@@ -235,7 +298,7 @@ Anthropic Messages(`/v1/messages`),且每个模型只在其中一部分接
|
|
|
235
298
|
- **模型引用**:`provider/model` 走首选渠道;`provider/model@channel` 显式指定(`--model`、`defaultModel`、
|
|
236
299
|
`/model`、SDK、RPC `set_model` 一致)。指定的渠道不在该模型的 `channels` 里 → 报错并列出可用的
|
|
237
300
|
`provider/model@channel`。`@` 之后不是该供应商的渠道名时整串仍按模型 id 处理(兼容 id 里本来带 `@` 的模型)。
|
|
238
|
-
- **向后兼容**:没有 `channels`
|
|
301
|
+
- **向后兼容**:没有 `channels` 的供应商(自定义供应商与单协议的内置供应商;多协议内置供应商的内置渠道见「内置供应商」)按单渠道处理——供应商级 `api` + `baseUrl`
|
|
239
302
|
就是隐式的 `default` 渠道;模型级 `api` / `baseUrl` 仍然有效,覆盖在所选渠道之上(等价于一个匿名渠道)。
|
|
240
303
|
已有配置不用改。写了 `channels` 时供应商级 `api` / `baseUrl` 不再单独成渠道。
|
|
241
304
|
- **运行时**:选中的模型带上该渠道的协议、地址、key、headers 与 compat;会话记录(`model_change`)与
|
|
@@ -282,7 +345,7 @@ ama providers refresh <id> [--probe …]
|
|
|
282
345
|
- **限流**:401 / 403 立即停止;429 时并发减半、2 s 后重试该请求一次,重试仍 429 则停止。
|
|
283
346
|
- **渠道收敛**:写入前删掉没有任何模型挂载的候选渠道;`defaultChannel` 取剩下的第一个(按 `--prefer`)。
|
|
284
347
|
- **写入**:用户级 `config.json` 的 `providers.<id>`(先备份为 `config.json.bak`)。模型条目只写 `id` 与
|
|
285
|
-
`channels`;上下文、输出、图像、推理、价格**不写进配置**,运行时从 models.dev
|
|
348
|
+
`channels`;上下文、输出、图像、推理、价格**不写进配置**,运行时从 models.dev 快照补(见下节),所以
|
|
286
349
|
`refresh` 不会覆盖手改的字段,手写的值永远优先。models.dev 标明不支持工具调用的模型缺省不写入(Agent
|
|
287
350
|
离不开工具调用),`--include-no-tools` 照写。对已存在的供应商再执行 `add`:只追加新渠道与新模型,已有
|
|
288
351
|
渠道定义与模型条目一字不改。
|
|
@@ -291,8 +354,8 @@ ama providers refresh <id> [--probe …]
|
|
|
291
354
|
中转实际价格可能不同)、匹配方式。
|
|
292
355
|
- `list`:全部供应商(config.json 里的与有 key 的内置供应商)→ 渠道(协议、地址、key 来源:auth.json /
|
|
293
356
|
`$VAR` / 字面量 / 无,从不显示 key)→ 模型数。`channels <id>`:每个渠道的协议、地址与挂载的模型数。
|
|
294
|
-
`remove`:删 `providers.<id>`(备份)与 auth.json 里该供应商的条目。`refresh`:重拉 `/models
|
|
295
|
-
|
|
357
|
+
`remove`:删 `providers.<id>`(备份)与 auth.json 里该供应商的条目。`refresh`:重拉 `/models`(models.dev
|
|
358
|
+
用本地快照),只追加新模型(带 `--probe` 时同 add 的探测),已有条目不改;上游已下架的 id 只提示、不删。
|
|
296
359
|
|
|
297
360
|
实测(2026-10-02,一家同时提供三种接口的中转,22 个模型,共 29 次请求):
|
|
298
361
|
|
|
@@ -308,43 +371,86 @@ ama providers refresh <id> [--probe …]
|
|
|
308
371
|
|
|
309
372
|
### 模型元数据:models.dev
|
|
310
373
|
|
|
311
|
-
[models.dev](https://models.dev) 汇总了两百多家供应商的模型参数(`https://models.dev/api.json`,约 5 MB
|
|
312
|
-
ama
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
374
|
+
[models.dev](https://models.dev) 汇总了两百多家供应商的模型参数(`https://models.dev/api.json`,约 5 MB,MIT 许可,
|
|
375
|
+
声明见仓库根的 `THIRD_PARTY_NOTICES.md`)。ama 把主流厂商的一份**裁剪快照随包携带**,用它给内置目录与自定义模型
|
|
376
|
+
补上下文、输出上限、输入模态、推理、价格等数值事实。**启动与运行都不联网**。
|
|
377
|
+
|
|
378
|
+
- **快照**:`src/ai/providers/models-dev/<provider>.json`,一家一份,收录清单在同目录 `_providers.json`(22 家:
|
|
379
|
+
anthropic、openai、google、xai、deepseek、moonshotai / moonshotai-cn、zhipuai / zai、alibaba / alibaba-cn、
|
|
380
|
+
minimax / minimax-cn、stepfun / stepfun-ai、volcengine、tencent-tokenhub、mistral、meta、xiaomi、groq,以及
|
|
381
|
+
openrouter 里原厂前缀白名单内的模型)。`scripts/update-models-dev.mjs`(零依赖)拉取、过滤(丢 `deprecated`、
|
|
382
|
+
输出不含文本、上下文为 0、`tool_call: false` 的条目)、裁剪字段(name、family、knowledge、release_date、
|
|
383
|
+
reasoning、modalities.input、limit.context / input / output、cost 含 `context_over_200k` 与按上下文的 `tiers`、
|
|
384
|
+
interleaved、beta 状态、canonical_model_id)并按键排序写出,再生成内联进 bundle 的 `models-dev-data.ts`;内容
|
|
385
|
+
不变时字节不变(`_meta.json` 的 `fetchedAt` 只随 sha256 变)。为控制体积(内联数据 ≤ 200 KB,测试守住)不收
|
|
386
|
+
`last_updated`、`reasoning_options`。
|
|
387
|
+
- **每周刷新**:`.github/workflows/models-dev.yml` 每周一 03:17 UTC(与手动 `workflow_dispatch`)跑脚本,自动删掉
|
|
388
|
+
目录里与新快照相同的覆盖项,有改动才往固定分支 `chore/models-dev-refresh` 开 / 更新 PR(摘要列新增、删除、上下文 /
|
|
389
|
+
输出 / 价格变化;删除超过 30% 加 `needs-review`)。PR 用仓库 secret `MODELS_DEV_PR_TOKEN`(GitHub App token 或
|
|
390
|
+
fine-grained PAT,`contents` + `pull-requests` 写权限)创建以触发 CI;没有这个 secret 时 workflow 先自己跑
|
|
391
|
+
`pnpm run ci`,再用缺省 token 开 PR 并在描述里写明结果。合并由人做。
|
|
392
|
+
- **`ama models refresh [--provider <id>[,<id>…]]`**:显式联网拉最新 `api.json`,按同一清单裁剪,写到数据目录
|
|
393
|
+
`models-dev.json`(缺省 `~/.local/share/ama/`),打印新增 / 上游删除 / 变价。之后的索引 = 内置快照 ⊕ 这份覆盖:
|
|
394
|
+
覆盖文件的 `fetchedAt` 晚于快照才叠加(升级 ama 带来更新的快照后旧覆盖自动失效),同一 `provider/model` 以覆盖
|
|
395
|
+
为准,上游删掉的条目沿用快照。`refresh-catalog` 是旧名。`AMA_MODELS_DEV_URL` 换刷新的数据源。旧版 ama 写的全量
|
|
396
|
+
缓存(version 1)不再读取。`ama providers add|refresh` 与 `ama models discover` 只用本地索引,不再拉 models.dev
|
|
397
|
+
(它们对 `/models` 的请求照旧)。
|
|
398
|
+
- **内置目录(`catalog/*.json`)只写覆盖项**:文件级 `"modelsDev": "<快照供应商 id>"`(本地服务写 `false`);条目
|
|
399
|
+
按 `<modelsDev>/<id>` 从快照继承 name、reasoning、contextWindow、maxTokens、input、cost、family、knowledge、
|
|
400
|
+
releaseDate、inputLimit、status,目录只写 ama 特有字段(`api`、`thinkingLevelMap`、`promptCache`、`compat`)与
|
|
401
|
+
有意不同于快照的值(如 openai 的 272k 窗口、deepseek 的价格);`cost` 可只写要改的键。id 与快照不同时条目写
|
|
402
|
+
`"modelsDev": "provider/model"`,不继承写 `false`。快照里没有的模型(已 deprecated 等)写完整条目。
|
|
403
|
+
`catalog.test.ts` 把与快照取值相同的字段当冗余报错,`UPDATE_CATALOG=1 pnpm vitest run
|
|
404
|
+
src/ai/providers/catalog.test.ts` 自动删除并重新生成 `catalog-data.ts`(之后跑 prettier);确实要钉住与快照相同的
|
|
405
|
+
值时在条目上写 `"_reason": "…"`(注释,运行时忽略,该条目不做冗余检查)。目录继承的映射与自定义模型略有不同:
|
|
406
|
+
`maxTokens` 不封顶(取 `min(limit.output, contextWindow)`),缺的缓存价记 0。
|
|
407
|
+
- **优先级**:用户配置(`models[]` / `modelOverrides[]` 里写了的字段)> 内置目录(快照 ⊕ 目录覆盖)> models.dev
|
|
408
|
+
索引 > 自定义缺省(`maxTokens: 8192`、`input: ["text"]`、`reasoning: false`、不猜 `contextWindow`)。
|
|
409
|
+
`ama models list` 与 `ama config show` 标出每个字段来自哪里(`config` / `目录` / `models.dev` / `缺省`;内置目录
|
|
410
|
+
从快照继承的字段标 `models.dev`)。
|
|
411
|
+
- **字段映射**(自定义模型):`contextWindow = limit.context`;`maxTokens = min(limit.output, 65536, contextWindow)`——
|
|
322
412
|
`maxTokens` 每次请求都作为 `max_tokens` 发出,models.dev 给的是原厂上限(不少模型写的是与上下文相同的
|
|
323
413
|
1M),中转换了上游后常拒收超大值,Anthropic 协议的思考预算也从它推导,64k 对编码 Agent 的单轮输出足够,
|
|
324
414
|
需要更大时在配置里写;`input` 由 `modalities.input` 含不含 `image` 定为 `["text","image"]` 或 `["text"]`;
|
|
325
415
|
`reasoning`;`cost` 取 `input` / `output` / `cache_read` / `cache_write`($/M),缺缓存价时按输入价算
|
|
326
|
-
|
|
327
|
-
|
|
416
|
+
(不假设有折扣,保温的经济性判断因此偏保守);`cost.tiers` 取 models.dev 的按上下文档位,只有
|
|
417
|
+
`context_over_200k` 时折成 200k 一档;另补 `family`、`knowledge`、`releaseDate`、`inputLimit`(与上下文不同时)、
|
|
418
|
+
`status: "beta"`。
|
|
419
|
+
- **匹配规则**(同一个 id 常在多家转售商下重复出现,取值不一):
|
|
328
420
|
1. 模型上写了 `"modelsDev": "provider/model"` → 直接用该条目(写 `false` 关闭补全);
|
|
329
|
-
2. id 形如 `vendor/model`
|
|
421
|
+
2. id 形如 `vendor/model` 且索引里正好有这个 `provider/model` → 用它;
|
|
330
422
|
3. 按 id 不分大小写找全部同名条目;有 `canonical_model_id` 的,取指向与 id 同名的那个(否则取票数最多的),
|
|
331
423
|
它若能在原厂供应商下找到 → 用原厂条目;
|
|
332
424
|
4. 否则在(同一 canonical 的)条目里优先原厂供应商:anthropic、openai、google、deepseek、moonshotai(-cn)、
|
|
333
|
-
zhipuai、zai、alibaba(-cn)、xai、mistral、minimax(-cn)、llama
|
|
334
|
-
|
|
425
|
+
zhipuai、zai、alibaba(-cn)、xai、mistral、minimax(-cn)、meta、llama、cohere、xiaomi、stepfun(-ai)、volcengine、
|
|
426
|
+
tencent-tokenhub 等(models.dev 里没有 `qwen` 这样的供应商 id,通义在 `alibaba`);
|
|
335
427
|
5. 仍有多条 → 按 (上下文, 输出, 图像) 取多数,取值不一时记 warning;只有一条就用它;
|
|
336
428
|
6. 同名找不到时依次试归一化后的 id:去 `vendor/` 前缀、去 `:free` 一类后缀、去 `-latest`、去日期后缀
|
|
337
429
|
(`-0902`、`-20250514`、`-2025-05-14`);
|
|
338
|
-
7. 都没有 → 「未匹配」,保持自定义缺省(不猜 `contextWindow
|
|
430
|
+
7. 都没有 → 「未匹配」,保持自定义缺省(不猜 `contextWindow`,自动压缩关闭)。快照只收主流厂商,转售商专有的
|
|
431
|
+
id 可能匹配不到,可在模型上写 `modelsDev` 指向收录的条目。
|
|
339
432
|
|
|
340
433
|
### 图像输入
|
|
341
434
|
|
|
342
435
|
- 四条协议都把图片放进用户消息:Chat Completions `image_url`(data URL)、Responses `input_image`、
|
|
343
436
|
Anthropic `image`(base64 source)、Gemini `inlineData`;工具结果里的图片同样映射。
|
|
344
437
|
- 入口:`ama -p "描述这张图" --image a.png --image b.jpg`;交互界面与行式界面里写 `@图片路径`,或粘贴 /
|
|
345
|
-
拖入一个图片文件路径(整段输入里以 `.png` / `.jpg` / `.jpeg` / `.gif` / `.webp`
|
|
346
|
-
|
|
347
|
-
|
|
438
|
+
拖入一个图片文件路径(整段输入里以 `.png` / `.jpg` / `.jpeg` / `.gif` / `.webp` 结尾且文件存在的词);交互界面里
|
|
439
|
+
`Ctrl+V` 或 `/paste` 把剪贴板里的图片存成文件并在光标处插入 `@<路径>`(见下文「剪贴板图片」与 [tui.md](tui.md)「剪贴板图片」)。
|
|
440
|
+
`--image`、`@图片` 与粘贴的图片都按 `images.resize` 缩放。
|
|
441
|
+
- 与 `read` 工具共用 MIME 检测(按文件头识别 PNG / JPEG / GIF / WebP,扩展名不符时以文件头为准)与大小上限。
|
|
442
|
+
上限按 **base64 后**计算(`ceil(字节/3)*4`),按当前模型的端点分档:官方 Anthropic(`api.anthropic.com`)
|
|
443
|
+
10 MB、官方 Gemini 与 OpenAI 20 MB,中转(内置供应商改了 baseUrl)与其它主机 5 MB;任一边超过 8000 px 拒绝。
|
|
444
|
+
- 缩放(`images.resize`,缺省 `auto`):超限时依次找 `sips`(macOS)、`magick` / `convert`(ImageMagick)缩到
|
|
445
|
+
上限以内再附上;找不到工具或 `off` 时按上面的规则拒绝并提示。零依赖,不内置图像解码。
|
|
446
|
+
- 单次请求的图片总量预算按协议:`anthropic-messages` 32 MB,其它 20 MB(base64 后)。历史图片每轮重发,超预算时
|
|
447
|
+
从最旧的图开始换成占位文本 `[earlier image omitted to fit request size]`,一次降到预算的 60% 以下;超过当前端点
|
|
448
|
+
单图上限的旧图(换了模型 / 渠道之后)直接换成占位;单请求超过 20 张图且有长边 > 2000 px 的图时,继续从最旧的
|
|
449
|
+
降到 20 张以内。最新一条带图的消息不降。降级写成会话里的 `context_edit{reason:"image_budget"}`,之后前缀稳定,
|
|
450
|
+
缓存统计把这一次当重置点。
|
|
451
|
+
- 剪贴板图片(交互界面 `Ctrl+V` / `/paste`):`pasteClipboardImage` 依次调 `osascript` / `pngpaste`(macOS)、`wl-paste`(Wayland)/ `xclip`(X11)、
|
|
452
|
+
PowerShell `Get-Clipboard -Format Image`(Windows),写到 `<数据目录>/clipboard/<时间戳>.png`;
|
|
453
|
+
`ama sessions prune` 清理其中超过 7 天的文件。
|
|
348
454
|
- 模型 `input` 不含 `image` 时直接拒绝并提示换模型(`-p` 退出 2,界面里给错误提示,不发请求);`read`
|
|
349
455
|
工具读图时只返回路径、尺寸与「当前模型不接受图片」。
|
|
350
456
|
|
|
@@ -373,6 +479,20 @@ ama 用它给**没写元数据**的自定义模型补上下文、输出上限、
|
|
|
373
479
|
|
|
374
480
|
compat 只记录**已验证**的差异;新增条目请附文档链接或真实样本。
|
|
375
481
|
|
|
482
|
+
## Anthropic Messages 的 compat
|
|
483
|
+
|
|
484
|
+
按请求主机推断缺省(`src/ai/apis/anthropic-compat.ts`),`providers.<id>.compat`、渠道或模型级 `compat` 逐字段覆盖:
|
|
485
|
+
|
|
486
|
+
| 开关 | 作用 | 缺省 |
|
|
487
|
+
| ----------------------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
488
|
+
| `sendInterleavedThinkingBeta` | 预算型思考 + 工具时带 `interleaved-thinking` beta 头 | `api.anthropic.com` 开;DeepSeek、智谱、Kimi、通义、MiniMax、阶跃、腾讯、火山关;其它主机只对 `claude*` 模型开 |
|
|
489
|
+
| `sendCacheControl` | 打 `cache_control` 断点 | 开;DeepSeek 关(文档写明忽略) |
|
|
490
|
+
| `adaptiveThinking` | `{type:"adaptive"}` + `output_config.effort` | 关;官方新模型在目录里逐条开 |
|
|
491
|
+
| `supportsCacheControlOnTools` | 最后一个工具定义上打断点 | 开 |
|
|
492
|
+
| `maxCacheBreakpoints` | 断点个数上限 | 4 |
|
|
493
|
+
|
|
494
|
+
OpenRouter 的 Messages 接口只在 `message_delta` 里给缓存 usage,解析本就按非空字段合并,不需要开关。
|
|
495
|
+
|
|
376
496
|
## Responses 与 Gemini 的 compat
|
|
377
497
|
|
|
378
498
|
| 协议 | 开关 | 作用 | 缺省 |
|
|
@@ -415,15 +535,15 @@ Anthropic 的 `baseUrl` 以 `/v1` 结尾时请求 `{baseUrl}/messages`,不会
|
|
|
415
535
|
|
|
416
536
|
### 兼容开关(`providers.<id>.compat` 或模型级 `compat`)
|
|
417
537
|
|
|
418
|
-
| 开关 | 作用 | 缺省
|
|
419
|
-
| --------------------------------- | ------------------------------------------------------- |
|
|
420
|
-
| `sendPromptCacheKey` | 发 `prompt_cache_key` |
|
|
421
|
-
| `sendSessionAffinityHeaders` | 发亲和头 | 关(含 OpenRouter,未实测)
|
|
422
|
-
| `supportsLongCacheRetention` | `long` 可用(Anthropic 1h、OpenAI 24h);否则降为 short | `api.openai.com` / `api.anthropic.com` 开
|
|
423
|
-
| `supportsExplicitPromptCacheMode` | Responses 的 `prompt_cache_options`(30m) | 关
|
|
424
|
-
| `cacheReporting` | `auto` / `silent` / `reported`:强制「是否报缓存」三态 | `auto`
|
|
538
|
+
| 开关 | 作用 | 缺省 |
|
|
539
|
+
| --------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
540
|
+
| `sendPromptCacheKey` | 发 `prompt_cache_key` | OpenAI、xAI、Mistral、Kimi(`.cn` / `.ai`)、腾讯 TokenHub 的官方主机开,其余关 |
|
|
541
|
+
| `sendSessionAffinityHeaders` | 发亲和头 | 关(含 OpenRouter,未实测) |
|
|
542
|
+
| `supportsLongCacheRetention` | `long` 可用(Anthropic 1h、OpenAI 24h);否则降为 short | `api.openai.com` / `api.anthropic.com` / `tokenhub.tencentmaas.com` 开 |
|
|
543
|
+
| `supportsExplicitPromptCacheMode` | Responses 的 `prompt_cache_options`(30m) | 关 |
|
|
544
|
+
| `cacheReporting` | `auto` / `silent` / `reported`:强制「是否报缓存」三态 | `auto` |
|
|
425
545
|
|
|
426
|
-
|
|
546
|
+
推断只看最终请求的主机名(`cache-params.ts` 的 `HOST_CACHE_CAPABILITIES`,只收官方文档写明支持的主机),不看 provider id:用 `OPENAI_BASE_URL` 或自定义 `baseUrl` 把 `openai` 指到中转时
|
|
427
547
|
按中转处理。缺省只对官方端点开,是因为中转上实测「接受但未见收益」或「收下但不生效」(下表)。
|
|
428
548
|
|
|
429
549
|
**400 自动剥离**:端点以 400 拒收并在错误体里点名 `prompt_cache_key` / `prompt_cache_retention` /
|
|
@@ -545,6 +665,62 @@ ama models cache-probe <provider/id> [--tokens 2048] [--gap-ms 3000] [--json] [-
|
|
|
545
665
|
- `/v1` 去重与 `toolChoice: "none"` 经 ama 协议层实发验证:Messages 请求落在 `/v1/messages`,三种接口都接受
|
|
546
666
|
`tool_choice: none` 且未产生工具调用。
|
|
547
667
|
|
|
668
|
+
## 渠道实测
|
|
669
|
+
|
|
670
|
+
`scripts/channel-probe.mjs`(先 `pnpm build:lib`)对 `provider/model@channel` 跑实测门,每个模型 ≤ 8 个请求:
|
|
671
|
+
|
|
672
|
+
| 项 | 做法 | 通过 |
|
|
673
|
+
| ----------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
674
|
+
| ① check | 一次最小调用 | 无错误且有文本 |
|
|
675
|
+
| ② 工具往返 | 一次并行 `read` 两个临时文件、回答口令 | 有工具调用且回答含口令 |
|
|
676
|
+
| ③ thinking 两回合 | 接着同一对话、thinking=medium 再读一个文件(思考块随历史回放) | 第二次无错误;没有思考块或 Messages 上思考块无签名记 ⚠(签名回放未验证) |
|
|
677
|
+
| ④ 缓存 | 约 3k token 的固定前缀相隔 `--gap-ms` 发两次 | 第二次 cacheRead > 0 |
|
|
678
|
+
| tool_use.id | ②③ 同一对话里的全部工具调用 id | 互不相同 |
|
|
679
|
+
|
|
680
|
+
四项全过且 id 不重复 = 过门;DeepSeek、智谱、Kimi 的官方 Messages 渠道过门后缺省改 messages。
|
|
681
|
+
|
|
682
|
+
### 中转对比(2026-10-02,messages vs chat)
|
|
683
|
+
|
|
684
|
+
同一测试中转(Chat / Messages 两种接口),`--gap-ms 8000`,84 次请求(含一轮调试),保守估价约 $0.11:
|
|
685
|
+
|
|
686
|
+
| 模型@渠道 | 协议 · 主机 | ① check | ② 工具往返 | ③ thinking 两回合 | ④ 缓存(读 / 前缀) | id 唯一 | 请求 | 结论 |
|
|
687
|
+
| ---------------------------------- | ------------------------------------- | ------- | ---------- | -------------------- | ------------------- | ------- | ---- | -------- |
|
|
688
|
+
| `packy/kimi-k2.5@messages` | anthropic-messages · www.packyapi.com | ✓ | ✓ | ⚠ 2/2 个思考块无签名 | ✓ 2734 / 2738 | ✓ | 7 | 未过 |
|
|
689
|
+
| `packy/kimi-k2.5@chat` | openai-completions · www.packyapi.com | ✓ | ✓ | ✓ | ✓ 2688 / 2740 | ✓ | 7 | **过门** |
|
|
690
|
+
| `packy/deepseek-v4-flash@messages` | anthropic-messages · www.packyapi.com | ✓ | ✓ | ⚠ 没有思考块 | ✓ 2048 / 2732 | ✓ | 7 | 未过 |
|
|
691
|
+
| `packy/deepseek-v4-flash@chat` | openai-completions · www.packyapi.com | ✓ | ✓ | ✓ | ✓ 2048 / 2732 | ✓ | 7 | **过门** |
|
|
692
|
+
| `packy/glm-5@messages` | anthropic-messages · www.packyapi.com | ✓ | ✓ | ⚠ 2/2 个思考块无签名 | ✓ 2560 / 2733 | ✓ | 7 | 未过 |
|
|
693
|
+
| `packy/glm-5@chat` | openai-completions · www.packyapi.com | ✓ | ✓ | ✓ | ✓ 2560 / 2733 | ✓ | 7 | **过门** |
|
|
694
|
+
| `packy/qwen3.8-flash@messages` | anthropic-messages · www.packyapi.com | ✓ | ✓ | ⚠ 2/2 个思考块无签名 | ✓ 3053 / 3061 | ✓ | 7 | 未过 |
|
|
695
|
+
| `packy/qwen3.8-flash@chat` | openai-completions · www.packyapi.com | ✓ | ✓ | ✓ | ✓ 2048 / 3063 | ✓ | 7 | **过门** |
|
|
696
|
+
| `packy/MiniMax-M2.7@messages` | anthropic-messages · www.packyapi.com | ✓ | ✓ | ⚠ 2/2 个思考块无签名 | ✓ 2638 / 2743 | ✓ | 7 | 未过 |
|
|
697
|
+
| `packy/MiniMax-M2.7@chat` | openai-completions · www.packyapi.com | ✓ | ✓ | ✓ | ✓ 2638 / 2744 | ✓ | 7 | **过门** |
|
|
698
|
+
|
|
699
|
+
- 五家在中转的两种接口上 ①②④ 全过,tool_use.id 在同一对话里都不重复(Kimi 的 id 形如 `functions.read:<n>`,
|
|
700
|
+
按对话递增;不同对话会从 0 重来,所以只能在同一对话里比较)。
|
|
701
|
+
- Messages 接口上的思考块**都没有签名**(DeepSeek 没返回思考块):中转把上游 Chat 转成 Messages 时不带签名,
|
|
702
|
+
ama 按规则降级为文本回放,往返照常成功,但签名回放没被验证——**中转结果不能替代官方直连的实测门**。
|
|
703
|
+
- 缓存:通义在 Messages 上首个请求就写入 3053 token(执行 `cache_control`),第二次读满前缀;其余四家读命中照常、
|
|
704
|
+
`cache_creation_input_tokens` 为 0(端点自管的隐式缓存),与「缓存 · 中转实测」一致。
|
|
705
|
+
|
|
706
|
+
### 官方直连(待用户用自己的 key 跑)
|
|
707
|
+
|
|
708
|
+
每家 ≤ 8 个请求,Kimi 的缓存写入有延迟、用 `--gap-ms 8000`:
|
|
709
|
+
|
|
710
|
+
```sh
|
|
711
|
+
pnpm build:lib
|
|
712
|
+
node scripts/channel-probe.mjs --model deepseek/deepseek-v4-pro@messages,deepseek/deepseek-v4-pro@chat --json /tmp/probe-deepseek.json
|
|
713
|
+
node scripts/channel-probe.mjs --model zhipu/glm-5.3@messages,zhipu/glm-5.3@chat --json /tmp/probe-zhipu.json
|
|
714
|
+
node scripts/channel-probe.mjs --model moonshot/kimi-k3@messages,moonshot/kimi-k3@chat --gap-ms 8000 --json /tmp/probe-kimi.json
|
|
715
|
+
node scripts/channel-probe.mjs --model dashscope/qwen3.8-max@messages --json /tmp/probe-qwen.json
|
|
716
|
+
node scripts/channel-probe.mjs --model minimax/MiniMax-M3@messages,minimax/MiniMax-M2.7@messages --json /tmp/probe-minimax.json
|
|
717
|
+
node scripts/channel-probe.mjs --model stepfun/step-5-preview@messages --json /tmp/probe-stepfun.json
|
|
718
|
+
node scripts/channel-probe.mjs --model tencent/hy3@messages --json /tmp/probe-tencent.json
|
|
719
|
+
node scripts/channel-probe.mjs --model volcengine/doubao-seed-2-1-pro-260628@responses --json /tmp/probe-volcengine.json
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
key 用各家标准环境变量(上表);没有 key 的那家记「没有 key」、不发请求。结果用 `--render` 重画后补进本节。
|
|
723
|
+
|
|
548
724
|
## 测试用 fake 供应商
|
|
549
725
|
|
|
550
726
|
`--model fake/echo`:回显最后一条用户消息。零配置的模型选择器、`ama doctor`、`ama models list`、
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# 检查点与回滚:设计与实施计划
|
|
2
|
+
|
|
3
|
+
> 状态:实施设计(2026-10-02)。基线:`main` = `95c0435`(0.4.0)。
|
|
4
|
+
> 设计依据:`docs/design.md` §8 会话树、§9 压缩、§9.1 缓存保证、§13 SDK / RPC;对照同类终端 Agent 的检查点实现(只借鉴行为与边界,不复制代码)。
|
|
5
|
+
> 路径相对仓库根;`[RW-x]` 为本计划的批次编号(§6)。
|
|
6
|
+
|
|
7
|
+
## §0 结论
|
|
8
|
+
|
|
9
|
+
| # | 决定 | 理由 |
|
|
10
|
+
| --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
|
|
11
|
+
| D1 | 回滚 = 「对话」与「代码」两件事,入口 `/rewind` 与空闲时双击 Esc;选项:对话 + 代码 / 仅对话 / 仅代码 / 从这里摘要 / 摘要到这里 / 取消 | 两者独立才能覆盖「代码写坏了但对话想留」「对话跑偏了但代码要留」 |
|
|
12
|
+
| D2 | 检查点粒度 = 开启新回合的用户消息;运行中插话(steer)与排队消息并入当前回合,不单独建 | 回合是用户能理解的最小单位 |
|
|
13
|
+
| D3 | 代码跟踪 edit / write(含 codemode 内层调用、task 子会话)改过的文件;每次发新回合按**当前磁盘状态**重拍已跟踪文件,所以 bash 或手动对已跟踪文件的改动也会被收进下一个检查点 | bash 任意改动不可完整追踪;已跟踪文件这样处理就不会漏 |
|
|
14
|
+
| D4 | 备份按内容 sha256 存全局目录,多会话、多检查点共用;会话文件只记哈希 | 同内容只存一份;fork 不用迁移备份 |
|
|
15
|
+
| D5 | 恢复前做冲突检测:磁盘内容既不等于 ama 最后写入的、也不等于最近检查点的 → 冲突,缺省跳过并列出,`onConflict: "overwrite"` 才覆盖 | 不冲掉用户在回合外的手动修改 |
|
|
16
|
+
| D6 | git 状态不动;检查点记 HEAD,回滚时 HEAD 变了只提示并给命令 | `reset` 类操作风险高,交给用户 |
|
|
17
|
+
| D7 | 对话回滚复用会话树(`navigate` 换叶子),被离开的分支留在文件里 | 现有能力,零迁移 |
|
|
18
|
+
| D8 | 回滚后上下文只发新路径,前缀逐字节不变,缓存照常命中;需要告诉模型的事(文件与对话不一致)以 `custom_message` 追加在末尾 | §9.1 前缀稳定 |
|
|
19
|
+
| D9 | `影子 git` 模式(能覆盖 bash 改动)作为可选 `checkpoints.mode: "shadow-git"`,缺省关,最后一批做 | 大仓库慢、依赖 git,不适合作缺省 |
|
|
20
|
+
|
|
21
|
+
## §1 数据模型
|
|
22
|
+
|
|
23
|
+
### §1.1 备份存储
|
|
24
|
+
|
|
25
|
+
- 目录:`<dataDir>/file-history/blobs/<sha256 前 2 位>/<sha256 全长>`,内容为文件原字节(不压缩、不改换行与 BOM);先写 `<name>.tmp-<pid>` 再 rename,已存在即跳过。
|
|
26
|
+
- 不备份:超过 `checkpoints.maxFileBytes`(缺省 5 MiB)的文件、非普通文件。记录里标 `skipped: "too_large" | "not_regular"`,回滚时报告「无法恢复」。
|
|
27
|
+
- 内存会话(无会话文件)不建检查点,`/rewind` 只提供「仅对话」。
|
|
28
|
+
|
|
29
|
+
### §1.2 会话条目(均为 `custom`,不进上下文,不影响前缀)
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// customType "ama.checkpoint":新回合的用户消息条目追加之后立即追加
|
|
33
|
+
interface CheckpointData {
|
|
34
|
+
v: 1;
|
|
35
|
+
userEntryId: string; // 这个检查点属于哪条用户消息(「这条消息发出前」的状态)
|
|
36
|
+
files: Record<string, FileRecord>; // 全部已跟踪文件;键 = cwd 内相对路径(/ 分隔),cwd 外为绝对路径
|
|
37
|
+
git?: { head: string; branch?: string }; // 直接读 .git/HEAD(含 worktree 的 gitdir 文件),不起 git 进程
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// customType "ama.checkpoint-track":回合中途第一次碰某文件时追加,补进本回合的检查点
|
|
41
|
+
interface CheckpointTrackData {
|
|
42
|
+
v: 1;
|
|
43
|
+
userEntryId: string;
|
|
44
|
+
path: string;
|
|
45
|
+
record: FileRecord;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface FileRecord {
|
|
49
|
+
blob: string | null; // sha256;null = 当时文件不存在(回滚时删除)
|
|
50
|
+
mode?: number; // 普通文件的权限位
|
|
51
|
+
size?: number;
|
|
52
|
+
realParentDir?: string; // 记录时父目录的 realpath(恢复时校验没被移动)
|
|
53
|
+
skipped?: "too_large" | "not_regular";
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- 读取:按文件顺序重放全会话(不限活动分支)的两类条目,得到 `Map<userEntryId, CheckpointData>`;`checkpoint-track` 并入对应检查点。
|
|
58
|
+
- 每个文件的第一条记录(最早的 `blob`)永久保留,作为「找不到更近记录时」的回退。
|
|
59
|
+
|
|
60
|
+
### §1.3 运行时状态(`src/checkpoints/tracker.ts`)
|
|
61
|
+
|
|
62
|
+
- `trackedFiles: Set<string>`、最近检查点、`lastWritten: Map<路径, sha256>`(ama 最后一次写入后的内容哈希,用于冲突检测;只在内存,恢复会话后以最近检查点为准)。
|
|
63
|
+
- 检查点上限 `checkpoints.keep`(缺省 100):超出时较早检查点不再列为回滚点;备份由 GC 清理(§1.4)。
|
|
64
|
+
|
|
65
|
+
### §1.4 清理
|
|
66
|
+
|
|
67
|
+
- `ama sessions prune` 与删除会话时:标记 —— 扫描所有会话文件里的 `ama.checkpoint*` 引用;清除 —— 删除未被引用且 mtime 超过 1 天的 blob。
|
|
68
|
+
- `ama doctor` 显示 file-history 占用。
|
|
69
|
+
|
|
70
|
+
## §2 时机
|
|
71
|
+
|
|
72
|
+
| 时机 | 动作 |
|
|
73
|
+
| ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
74
|
+
| 新回合用户消息落盘后(`runPrompt`,steer / 排队并入的不算) | 对每个已跟踪文件:lstat → 不存在记 `null`;size / mode 与上一条记录一致且 mtime 不晚于记录时间 → 沿用;否则读内容算 sha256,等于上一条则沿用,不等则写 blob。追加 `ama.checkpoint` |
|
|
75
|
+
| edit / write 写文件**之前**(`ctx.checkpoint?.beforeWrite(abs)`) | 文件在任何检查点里都没出现过 → 备份当前内容(不存在记 `null`),追加 `ama.checkpoint-track`,加入 `trackedFiles`;出现过则什么都不做 |
|
|
76
|
+
| edit / write 写文件**之后**(`ctx.checkpoint?.afterWrite(abs, bytes)`) | 记 `lastWritten` |
|
|
77
|
+
| task 子会话 | 子会话的 `ctx.checkpoint` 指向父会话的 tracker,记到父会话当前回合 |
|
|
78
|
+
| codemode 内层调用 | 走同一工具上下文,天然覆盖 |
|
|
79
|
+
|
|
80
|
+
`beforeWrite` 失败(磁盘满、权限)只记 warn,不阻止写入(与对照实现一致:检查点是辅助,不能让编辑失败)。
|
|
81
|
+
|
|
82
|
+
## §3 回滚
|
|
83
|
+
|
|
84
|
+
### §3.1 API(`AgentSession`,SDK 同名,RPC 见 §5)
|
|
85
|
+
|
|
86
|
+
类型见 `src/checkpoints/types.ts`(`RewindPoint`、`RewindRequest`、`RewindResult`、`CodeRestoreResult`):
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
rewindPoints(): RewindPoint[]; // 活动路径上的新回合用户消息,从旧到新
|
|
90
|
+
rewind(request: RewindRequest): Promise<RewindResult>;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`dryRun` 的 `code` 字段给出将恢复的文件与 `insertions / deletions`,界面的每行统计与确认预览都用它(懒计算,只对选中项)。
|
|
94
|
+
|
|
95
|
+
- 运行中调用抛 `AmaError("busy")`。全部失败且无一恢复 → `AmaError("rewind_failed", "没有文件被恢复…")`。
|
|
96
|
+
|
|
97
|
+
### §3.2 恢复代码(`src/checkpoints/restore.ts`)
|
|
98
|
+
|
|
99
|
+
对每个已跟踪文件,取目标检查点里的记录,没有则取该文件最早的记录:
|
|
100
|
+
|
|
101
|
+
1. 记录 `skipped` → 报告 `too_large` / `not_regular`。
|
|
102
|
+
2. 当前内容与记录相同 → 跳过(不计入)。
|
|
103
|
+
3. 冲突检测:当前 sha256 ∉ {`lastWritten`,最近检查点的记录} → 冲突;`skip` 时列入 `conflicts` 不动。
|
|
104
|
+
4. 安全检查(不通过 → `skipped`):目标是符号链接 / 非普通文件 / `nlink > 1`;父目录 realpath ≠ `realParentDir`。
|
|
105
|
+
5. `blob: null` → 删除文件(只删普通文件)。
|
|
106
|
+
6. 否则写回:Windows 以外用 `O_NOFOLLOW` 打开目标,`fstat` 与路径 `lstat` 的 dev / ino 一致才写;清空后写入 blob 内容,恢复 `mode`;目标不存在时按需创建父目录(再次校验父目录)。
|
|
107
|
+
7. 被恢复 / 删除的文件从 `readFiles` 移除(模型再改前必须重新 read)。
|
|
108
|
+
|
|
109
|
+
`dryRun` 只做 1–4 并用行级 diff 计 `insertions / deletions`(复用 `tools/edit` 的 diff 实现)。
|
|
110
|
+
|
|
111
|
+
### §3.3 回滚对话(`src/agent/session-rewind.ts`)
|
|
112
|
+
|
|
113
|
+
1. `navigate(userEntry.parentId)`(已有:换叶子、重载消息、`cache.onContextChanged()`)。
|
|
114
|
+
2. `readFiles` 按新路径重算:路径上成功的 read 工具调用的绝对路径(不跨分支保留)。
|
|
115
|
+
3. 返回 `draft`:原消息文本与图片,交互界面回填输入框。
|
|
116
|
+
4. 模型、思考级别、权限模式保持当前(文档写明)。
|
|
117
|
+
|
|
118
|
+
### §3.4 文件与对话不一致时告诉模型
|
|
119
|
+
|
|
120
|
+
- 仅对话:若有已跟踪文件当前内容 ≠ 目标检查点 → 下一次提示前追加 `custom_message{customType:"ama.rewind-note"}`:「回滚到较早的对话,但以下文件保留了之后的修改:…(最多 20 个,其余计数)」。
|
|
121
|
+
- 仅代码:追加「以下文件已恢复到第 N 条消息之前的状态:…」。
|
|
122
|
+
- 对话 + 代码:两边一致,不追加。
|
|
123
|
+
- 该条目在回滚落点之后、下一条用户消息之前,只追加在末尾,不改前缀。
|
|
124
|
+
|
|
125
|
+
### §3.5 摘要两项
|
|
126
|
+
|
|
127
|
+
- 「从这里摘要」= `navigate(parentId, { summarize: true })`(已有 `branch_summary`,走会话前缀续写),并回填原消息。
|
|
128
|
+
- 「摘要到这里」= 以所选用户消息为切点做一次档二压缩(`compaction` 条目的 `firstKeptEntryId` = 该消息),之后的消息原样保留,停在末尾。可附说明(`instructions`)。
|
|
129
|
+
|
|
130
|
+
### §3.6 中断即撤回
|
|
131
|
+
|
|
132
|
+
运行中 Esc 中断,且本回合还没有任何 assistant 文本 / 工具调用、输入框为空 → 自动 `rewind(当前回合, "conversation")` 并回填原消息(配置 `ui.restoreOnCancel`,缺省 true)。
|
|
133
|
+
|
|
134
|
+
## §4 交互
|
|
135
|
+
|
|
136
|
+
- 空闲且输入框为空:双击 Esc(间隔 ≤ 800 ms,第一次提示「再按 Esc 回滚」)打开回滚列表;输入框有字:双击 Esc 清空输入并存进输入历史(↑ 可取回),第一次提示「再按 Esc 清空」。运行中 Esc 仍为中断。
|
|
137
|
+
- 列表:活动路径上的用户消息,最近在下、缺省选中最后一条;高亮行右侧显示 `N 文件 +x −y` / `无代码改动`(对高亮项做 dryRun,结果缓存)。
|
|
138
|
+
- 选中后:确认面板(左竖条样式,复用 `/session` 面板),显示消息原文与时间、选项(有代码改动才出现两个「恢复代码」项;两个摘要项可在行内输入说明)、预览(「将恢复 N 个文件 +x −y」/「代码不变」/ 冲突与跳过清单)、git HEAD 变化提示(附 `git log --oneline <记录>..HEAD` 与 `git reset --soft <记录>` 两条命令,不执行)。
|
|
139
|
+
- 结果通知:`已恢复 N 个文件,跳过 M 个(原因…)`。
|
|
140
|
+
- line 模式:`/rewind` 列编号;`/rewind <n> [both|conversation|code]`。
|
|
141
|
+
- 文案进 i18n 风格的现有中文常量;字形走主题 glyphs(ASCII 可用)。
|
|
142
|
+
|
|
143
|
+
## §5 RPC / SDK / Hook / 配置
|
|
144
|
+
|
|
145
|
+
- RPC:`get_rewind_points` → `{ points }`;`rewind { entryId, mode, dryRun?, onConflict? }` → `RewindResult`;事件 `session_rewound { entryId, mode, restored, deleted, conflicts, skipped }`。写进 `docs/rpc.md`。
|
|
146
|
+
- SDK:`session.rewindPoints()`、`session.rewind()`。
|
|
147
|
+
- Hook:新增命令式事件 `PostRewind`(payload `{ entryId, mode, files }`,不可阻止);`docs/hooks.md` 同步。
|
|
148
|
+
- 配置(`key-docs.ts` 每项要说明与缺省值):
|
|
149
|
+
- `checkpoints.mode`: `"tools"`(缺省)/ `"shadow-git"` / `"off"`;`AMA_CHECKPOINTS=off` 覆盖。
|
|
150
|
+
- `checkpoints.maxFileBytes`: 5 242 880。
|
|
151
|
+
- `checkpoints.keep`: 100。
|
|
152
|
+
- `ui.restoreOnCancel`: true。
|
|
153
|
+
|
|
154
|
+
## §6 影子 git(`checkpoints.mode: "shadow-git"`)[RW-D]
|
|
155
|
+
|
|
156
|
+
- 仓库:`<dataDir>/file-history/shadow/<sha256(cwd) 前 16>/`(`--git-dir`),`--work-tree=cwd`;尊重 cwd 的 `.gitignore` 与 `info/exclude`,额外排除 `.git`。
|
|
157
|
+
- 每个新回合:`git add -A` + `write-tree` + `commit-tree`,提交 id 记进 `CheckpointData.shadowCommit`(契约里预留可选字段)。
|
|
158
|
+
- 护栏:cwd 下文件数 > 20 000 或单次快照 > 3 s → 本会话降级为 `tools` 并提示;需要 `git` 在 PATH。
|
|
159
|
+
- 恢复:只处理目标提交与「当前工作区快照」之间的差异文件,逐个按 §3.2 的冲突与安全检查写回或删除;不碰 `.gitignore` 掉的文件。
|
|
160
|
+
- 与 `tools` 模式并存:edit / write 的跟踪照常(冲突检测仍以它为准)。
|
|
161
|
+
|
|
162
|
+
## §7 缓存与上下文
|
|
163
|
+
|
|
164
|
+
- 回滚后第一次请求:system + tools + 落点之前的消息与回滚前发过的请求逐字节相同 → 有效期内命中;`onContextChanged()` 使这次请求成为重置点(不做未命中归因、保温作废),与现状一致。
|
|
165
|
+
- `ama.checkpoint*` 是 `custom`,不进上下文;`ama.rewind-note` 是 `custom_message`,只出现在新落点之后。
|
|
166
|
+
- 测试:回滚前后请求体前缀逐字节比较(`src/agent/session-rewind.test.ts`)。
|
|
167
|
+
|
|
168
|
+
## §8 批次与文件所有权
|
|
169
|
+
|
|
170
|
+
契约 PR(本计划所在 PR)先合入:`src/checkpoints/types.ts`、`ToolContext.checkpoint?`。配置 `checkpoints.*` 归 RW-A,`ui.restoreOnCancel` 与 `PostRewind` 归 RW-B(各自同步 `config/{types,schema,json-schema,key-docs}.ts` 与 `hooks/types.ts`)。之后:
|
|
171
|
+
|
|
172
|
+
| 批次 | 内容 | 文件所有权 | 依赖 | 验收 |
|
|
173
|
+
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
174
|
+
| RW-A 检查点核心 | blob 存储、tracker、条目重放、恢复与安全检查、冲突检测、dry-run diff、GC、doctor 占用;edit / write 调 `ctx.checkpoint` | `src/checkpoints/**`(除 types.ts)、`src/tools/{edit,write}.ts` 的两处调用、`src/cli/subcommands/{sessions,doctor}.ts` 的 GC / 占用 | 契约 | 单测覆盖 §3.2 每条分支(符号链接、硬链接、父目录移动、删除、新建、冲突 skip / overwrite、too_large);三平台 CI 绿(Windows 无 O_NOFOLLOW 分支) |
|
|
175
|
+
| RW-B 会话与接口 | `session-rewind.ts`(编排、readFiles 重算、rewind-note、摘要两项、中断即撤回)、检查点接线(runPrompt 后建检查点、子会话指向父 tracker)、RPC / SDK / `PostRewind` / 文档 | `src/agent/session-rewind.ts`(新)、`src/agent/{session,session-run,session-tools,session-subagent}.ts` 的接线、`src/modes/rpc/**`、`src/sdk.ts`、`src/hooks/**` 的事件、`docs/{rpc,hooks,sessions}.md` | 契约;RW-A 的实现可先用内存桩,合入顺序 A → B | fake 供应商端到端:edit 两个文件 → rewind both → 文件与对话都回到之前、readFiles 不含被恢复文件、下一请求前缀逐字节不变;仅对话 / 仅代码各自的 note;子会话编辑可回滚;中断即撤回 |
|
|
176
|
+
| RW-C 交互界面 | 双击 Esc、回滚列表、确认面板、预览、git 提示、结果通知、line 模式 `/rewind` | `src/modes/interactive/**`、`src/modes/commands-core.ts`、`docs/tui.md` | RW-B | 帧黄金:列表、面板(有 / 无代码改动、冲突、git 提示)、ASCII;tmux 手测双击 Esc 两种行为 |
|
|
177
|
+
| RW-D 影子 git | §6 | `src/checkpoints/shadow-git.ts`(新)及其测试 | RW-A | 临时 git 仓库里 bash 改动可回滚;护栏降级;无 git 时提示 |
|
|
178
|
+
|
|
179
|
+
- A 与 B 并行开发(B 用桩),A 先合;C 与 D 在 B / A 合入后并行。
|
|
180
|
+
- 每个文件 ≤ 600 行(`src/agent/session.ts` 已 600 行,新逻辑放 `session-rewind.ts`)。
|
|
181
|
+
- 每批次细粒度提交、一个 PR、CI 绿后由主会话合并(merge commit);不发版。
|