@armadra/agent 0.0.0-stage → 0.3.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 +37 -0
- package/LICENSE +21 -0
- package/README.md +470 -2
- package/dist/agent/agent.d.ts +56 -0
- package/dist/agent/agent.js +129 -0
- package/dist/agent/loop.d.ts +51 -0
- package/dist/agent/loop.js +158 -0
- package/dist/agent/queue.d.ts +25 -0
- package/dist/agent/queue.js +55 -0
- package/dist/agent/retry.d.ts +22 -0
- package/dist/agent/retry.js +92 -0
- package/dist/agent/schema.d.ts +27 -0
- package/dist/agent/schema.js +186 -0
- package/dist/agent/session-cache.d.ts +100 -0
- package/dist/agent/session-cache.js +514 -0
- package/dist/agent/session-compaction.d.ts +49 -0
- package/dist/agent/session-compaction.js +251 -0
- package/dist/agent/session-core.d.ts +103 -0
- package/dist/agent/session-core.js +7 -0
- package/dist/agent/session-run.d.ts +55 -0
- package/dist/agent/session-run.js +246 -0
- package/dist/agent/session-state.d.ts +39 -0
- package/dist/agent/session-state.js +119 -0
- package/dist/agent/session-subagent.d.ts +54 -0
- package/dist/agent/session-subagent.js +157 -0
- package/dist/agent/session-sync.d.ts +20 -0
- package/dist/agent/session-sync.js +111 -0
- package/dist/agent/session-tools.d.ts +24 -0
- package/dist/agent/session-tools.js +277 -0
- package/dist/agent/session.d.ts +117 -0
- package/dist/agent/session.js +485 -0
- package/dist/agent/system-prompt.d.ts +49 -0
- package/dist/agent/system-prompt.js +121 -0
- package/dist/agent/tool-runner.d.ts +64 -0
- package/dist/agent/tool-runner.js +309 -0
- package/dist/agent/transform.d.ts +26 -0
- package/dist/agent/transform.js +171 -0
- package/dist/agent/types.d.ts +378 -0
- package/dist/agent/types.js +21 -0
- package/dist/ai/apis/anthropic-messages.d.ts +26 -0
- package/dist/ai/apis/anthropic-messages.js +214 -0
- package/dist/ai/apis/anthropic-request.d.ts +42 -0
- package/dist/ai/apis/anthropic-request.js +282 -0
- package/dist/ai/apis/api.d.ts +28 -0
- package/dist/ai/apis/api.js +102 -0
- package/dist/ai/apis/cache-params.d.ts +48 -0
- package/dist/ai/apis/cache-params.js +163 -0
- package/dist/ai/apis/google-generative-ai.d.ts +32 -0
- package/dist/ai/apis/google-generative-ai.js +249 -0
- package/dist/ai/apis/google-request.d.ts +40 -0
- package/dist/ai/apis/google-request.js +255 -0
- package/dist/ai/apis/openai-compat.d.ts +35 -0
- package/dist/ai/apis/openai-compat.js +142 -0
- package/dist/ai/apis/openai-completions.d.ts +28 -0
- package/dist/ai/apis/openai-completions.js +246 -0
- package/dist/ai/apis/openai-request.d.ts +35 -0
- package/dist/ai/apis/openai-request.js +303 -0
- package/dist/ai/apis/openai-responses-request.d.ts +52 -0
- package/dist/ai/apis/openai-responses-request.js +266 -0
- package/dist/ai/apis/openai-responses.d.ts +28 -0
- package/dist/ai/apis/openai-responses.js +304 -0
- package/dist/ai/apis/shared.d.ts +56 -0
- package/dist/ai/apis/shared.js +179 -0
- package/dist/ai/cache/economics.d.ts +24 -0
- package/dist/ai/cache/economics.js +69 -0
- package/dist/ai/cache/fingerprint.d.ts +17 -0
- package/dist/ai/cache/fingerprint.js +39 -0
- package/dist/ai/cache/miss.d.ts +49 -0
- package/dist/ai/cache/miss.js +96 -0
- package/dist/ai/cache/reporting.d.ts +39 -0
- package/dist/ai/cache/reporting.js +103 -0
- package/dist/ai/cache/types.d.ts +94 -0
- package/dist/ai/cache/types.js +19 -0
- package/dist/ai/cache/warmer.d.ts +94 -0
- package/dist/ai/cache/warmer.js +224 -0
- package/dist/ai/context.d.ts +35 -0
- package/dist/ai/context.js +114 -0
- package/dist/ai/cost.d.ts +21 -0
- package/dist/ai/cost.js +60 -0
- package/dist/ai/event-stream.d.ts +33 -0
- package/dist/ai/event-stream.js +101 -0
- package/dist/ai/fake/fake-provider.d.ts +68 -0
- package/dist/ai/fake/fake-provider.js +278 -0
- package/dist/ai/fake/fake-script.d.ts +69 -0
- package/dist/ai/fake/fake-script.js +142 -0
- package/dist/ai/http.d.ts +54 -0
- package/dist/ai/http.js +212 -0
- package/dist/ai/json-partial.d.ts +17 -0
- package/dist/ai/json-partial.js +243 -0
- package/dist/ai/overflow.d.ts +22 -0
- package/dist/ai/overflow.js +61 -0
- package/dist/ai/providers/auth.d.ts +71 -0
- package/dist/ai/providers/auth.js +202 -0
- package/dist/ai/providers/builtin.d.ts +23 -0
- package/dist/ai/providers/builtin.js +148 -0
- package/dist/ai/providers/catalog-data.d.ts +5 -0
- package/dist/ai/providers/catalog-data.js +19 -0
- package/dist/ai/providers/catalog.d.ts +28 -0
- package/dist/ai/providers/catalog.js +166 -0
- package/dist/ai/providers/channels.d.ts +51 -0
- package/dist/ai/providers/channels.js +96 -0
- package/dist/ai/providers/enrich.d.ts +34 -0
- package/dist/ai/providers/enrich.js +86 -0
- package/dist/ai/providers/models-dev-cache.d.ts +53 -0
- package/dist/ai/providers/models-dev-cache.js +147 -0
- package/dist/ai/providers/models-dev.d.ts +99 -0
- package/dist/ai/providers/models-dev.js +315 -0
- package/dist/ai/providers/registry.d.ts +114 -0
- package/dist/ai/providers/registry.js +458 -0
- package/dist/ai/sse.d.ts +32 -0
- package/dist/ai/sse.js +140 -0
- package/dist/ai/thinking.d.ts +42 -0
- package/dist/ai/thinking.js +101 -0
- package/dist/ai/types.d.ts +448 -0
- package/dist/ai/types.js +19 -0
- package/dist/bundle/ama-sandbox.cjs +324 -0
- package/dist/bundle/ama.cjs +27837 -0
- package/dist/bundle.d.ts +9 -0
- package/dist/bundle.js +15 -0
- package/dist/cli/args.d.ts +85 -0
- package/dist/cli/args.js +408 -0
- package/dist/cli/bootstrap.d.ts +18 -0
- package/dist/cli/bootstrap.js +399 -0
- package/dist/cli/compose-providers.d.ts +37 -0
- package/dist/cli/compose-providers.js +107 -0
- package/dist/cli/compose-session.d.ts +72 -0
- package/dist/cli/compose-session.js +370 -0
- package/dist/cli/compose-store.d.ts +24 -0
- package/dist/cli/compose-store.js +125 -0
- package/dist/cli/compose.d.ts +108 -0
- package/dist/cli/compose.js +221 -0
- package/dist/cli/default-model.d.ts +16 -0
- package/dist/cli/default-model.js +24 -0
- package/dist/cli/deps.d.ts +207 -0
- package/dist/cli/deps.js +12 -0
- package/dist/cli/exit-codes.d.ts +29 -0
- package/dist/cli/exit-codes.js +40 -0
- package/dist/cli/main.d.ts +27 -0
- package/dist/cli/main.js +177 -0
- package/dist/cli/runtime.d.ts +90 -0
- package/dist/cli/runtime.js +8 -0
- package/dist/cli/startup-screen.d.ts +15 -0
- package/dist/cli/startup-screen.js +56 -0
- package/dist/cli/startup-steps.d.ts +35 -0
- package/dist/cli/startup-steps.js +202 -0
- package/dist/cli/subcommands/auth.d.ts +12 -0
- package/dist/cli/subcommands/auth.js +91 -0
- package/dist/cli/subcommands/config.d.ts +53 -0
- package/dist/cli/subcommands/config.js +277 -0
- package/dist/cli/subcommands/context.d.ts +21 -0
- package/dist/cli/subcommands/context.js +42 -0
- package/dist/cli/subcommands/doctor.d.ts +11 -0
- package/dist/cli/subcommands/doctor.js +246 -0
- package/dist/cli/subcommands/init.d.ts +6 -0
- package/dist/cli/subcommands/init.js +22 -0
- package/dist/cli/subcommands/model-meta.d.ts +16 -0
- package/dist/cli/subcommands/model-meta.js +54 -0
- package/dist/cli/subcommands/models-cache-probe.d.ts +34 -0
- package/dist/cli/subcommands/models-cache-probe.js +190 -0
- package/dist/cli/subcommands/models-discover.d.ts +46 -0
- package/dist/cli/subcommands/models-discover.js +232 -0
- package/dist/cli/subcommands/models.d.ts +40 -0
- package/dist/cli/subcommands/models.js +152 -0
- package/dist/cli/subcommands/providers-list.d.ts +8 -0
- package/dist/cli/subcommands/providers-list.js +97 -0
- package/dist/cli/subcommands/providers-plan.d.ts +79 -0
- package/dist/cli/subcommands/providers-plan.js +215 -0
- package/dist/cli/subcommands/providers.d.ts +27 -0
- package/dist/cli/subcommands/providers.js +433 -0
- package/dist/cli/subcommands/sessions.d.ts +11 -0
- package/dist/cli/subcommands/sessions.js +100 -0
- package/dist/codemode/capability.d.ts +37 -0
- package/dist/codemode/capability.js +55 -0
- package/dist/codemode/declarations.d.ts +44 -0
- package/dist/codemode/declarations.js +111 -0
- package/dist/codemode/host-side.d.ts +59 -0
- package/dist/codemode/host-side.js +253 -0
- package/dist/codemode/modes.d.ts +23 -0
- package/dist/codemode/modes.js +40 -0
- package/dist/codemode/protocol.d.ts +91 -0
- package/dist/codemode/protocol.js +114 -0
- package/dist/codemode/sandbox-entry.d.ts +25 -0
- package/dist/codemode/sandbox-entry.js +323 -0
- package/dist/codemode/store.d.ts +26 -0
- package/dist/codemode/store.js +53 -0
- package/dist/codemode/tool.d.ts +105 -0
- package/dist/codemode/tool.js +283 -0
- package/dist/compaction/branch-summary.d.ts +30 -0
- package/dist/compaction/branch-summary.js +79 -0
- package/dist/compaction/breaker.d.ts +32 -0
- package/dist/compaction/breaker.js +65 -0
- package/dist/compaction/cut-point.d.ts +23 -0
- package/dist/compaction/cut-point.js +70 -0
- package/dist/compaction/estimate.d.ts +30 -0
- package/dist/compaction/estimate.js +114 -0
- package/dist/compaction/prune-tier.d.ts +31 -0
- package/dist/compaction/prune-tier.js +83 -0
- package/dist/compaction/serialize.d.ts +20 -0
- package/dist/compaction/serialize.js +115 -0
- package/dist/compaction/summarize-tier.d.ts +111 -0
- package/dist/compaction/summarize-tier.js +305 -0
- package/dist/config/auth-file.d.ts +39 -0
- package/dist/config/auth-file.js +92 -0
- package/dist/config/context-files.d.ts +30 -0
- package/dist/config/context-files.js +77 -0
- package/dist/config/init.d.ts +30 -0
- package/dist/config/init.js +92 -0
- package/dist/config/json-schema.d.ts +14 -0
- package/dist/config/json-schema.js +182 -0
- package/dist/config/load.d.ts +45 -0
- package/dist/config/load.js +97 -0
- package/dist/config/merge.d.ts +73 -0
- package/dist/config/merge.js +248 -0
- package/dist/config/paths.d.ts +38 -0
- package/dist/config/paths.js +108 -0
- package/dist/config/profile.d.ts +27 -0
- package/dist/config/profile.js +65 -0
- package/dist/config/schema.d.ts +34 -0
- package/dist/config/schema.js +476 -0
- package/dist/config/trust.d.ts +42 -0
- package/dist/config/trust.js +122 -0
- package/dist/config/types.d.ts +190 -0
- package/dist/config/types.js +29 -0
- package/dist/config/write.d.ts +10 -0
- package/dist/config/write.js +25 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.js +30 -0
- package/dist/hooks/config.d.ts +49 -0
- package/dist/hooks/config.js +102 -0
- package/dist/hooks/dispatcher.d.ts +41 -0
- package/dist/hooks/dispatcher.js +104 -0
- package/dist/hooks/matcher.d.ts +22 -0
- package/dist/hooks/matcher.js +108 -0
- package/dist/hooks/protocol.d.ts +33 -0
- package/dist/hooks/protocol.js +240 -0
- package/dist/hooks/runner.d.ts +30 -0
- package/dist/hooks/runner.js +143 -0
- package/dist/hooks/types.d.ts +147 -0
- package/dist/hooks/types.js +20 -0
- package/dist/host/api-impl.d.ts +75 -0
- package/dist/host/api-impl.js +173 -0
- package/dist/host/loader.d.ts +31 -0
- package/dist/host/loader.js +147 -0
- package/dist/host/types.d.ts +169 -0
- package/dist/host/types.js +14 -0
- package/dist/host.d.ts +5 -0
- package/dist/host.js +4 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +28 -0
- package/dist/modes/commands-core.d.ts +44 -0
- package/dist/modes/commands-core.js +171 -0
- package/dist/modes/image-input.d.ts +27 -0
- package/dist/modes/image-input.js +78 -0
- package/dist/modes/interactive/approval-dialog.d.ts +48 -0
- package/dist/modes/interactive/approval-dialog.js +202 -0
- package/dist/modes/interactive/commands.d.ts +41 -0
- package/dist/modes/interactive/commands.js +201 -0
- package/dist/modes/interactive/completion.d.ts +53 -0
- package/dist/modes/interactive/completion.js +157 -0
- package/dist/modes/interactive/interactive-mode.d.ts +46 -0
- package/dist/modes/interactive/interactive-mode.js +491 -0
- package/dist/modes/interactive/key-dispatch.d.ts +29 -0
- package/dist/modes/interactive/key-dispatch.js +107 -0
- package/dist/modes/interactive/line/line-editor.d.ts +50 -0
- package/dist/modes/interactive/line/line-editor.js +232 -0
- package/dist/modes/interactive/line/line-mode.d.ts +20 -0
- package/dist/modes/interactive/line/line-mode.js +218 -0
- package/dist/modes/interactive/line/line-render.d.ts +35 -0
- package/dist/modes/interactive/line/line-render.js +171 -0
- package/dist/modes/interactive/line/paste-state.d.ts +26 -0
- package/dist/modes/interactive/line/paste-state.js +72 -0
- package/dist/modes/interactive/message-view.d.ts +77 -0
- package/dist/modes/interactive/message-view.js +269 -0
- package/dist/modes/interactive/pickers.d.ts +42 -0
- package/dist/modes/interactive/pickers.js +115 -0
- package/dist/modes/interactive/startup-ui.d.ts +33 -0
- package/dist/modes/interactive/startup-ui.js +268 -0
- package/dist/modes/interactive/status-bar.d.ts +48 -0
- package/dist/modes/interactive/status-bar.js +139 -0
- package/dist/modes/interactive/tool-view.d.ts +95 -0
- package/dist/modes/interactive/tool-view.js +344 -0
- package/dist/modes/print/json-event.d.ts +15 -0
- package/dist/modes/print/json-event.js +39 -0
- package/dist/modes/print/print-mode.d.ts +17 -0
- package/dist/modes/print/print-mode.js +107 -0
- package/dist/modes/rpc/commands.d.ts +40 -0
- package/dist/modes/rpc/commands.js +263 -0
- package/dist/modes/rpc/jsonl.d.ts +16 -0
- package/dist/modes/rpc/jsonl.js +55 -0
- package/dist/modes/rpc/rpc-mode.d.ts +22 -0
- package/dist/modes/rpc/rpc-mode.js +153 -0
- package/dist/modes/session-report.d.ts +55 -0
- package/dist/modes/session-report.js +278 -0
- package/dist/modes/shared.d.ts +13 -0
- package/dist/modes/shared.js +52 -0
- package/dist/modes/startup-ui-text.d.ts +16 -0
- package/dist/modes/startup-ui-text.js +103 -0
- package/dist/permissions/broker.d.ts +47 -0
- package/dist/permissions/broker.js +107 -0
- package/dist/permissions/dangerous.d.ts +47 -0
- package/dist/permissions/dangerous.js +370 -0
- package/dist/permissions/pipeline.d.ts +51 -0
- package/dist/permissions/pipeline.js +181 -0
- package/dist/permissions/preview.d.ts +43 -0
- package/dist/permissions/preview.js +463 -0
- package/dist/permissions/rules.d.ts +58 -0
- package/dist/permissions/rules.js +249 -0
- package/dist/permissions/types.d.ts +100 -0
- package/dist/permissions/types.js +18 -0
- package/dist/rpc.d.ts +173 -0
- package/dist/rpc.js +13 -0
- package/dist/sdk.d.ts +98 -0
- package/dist/sdk.js +195 -0
- package/dist/session/manager.d.ts +70 -0
- package/dist/session/manager.js +278 -0
- package/dist/session/migrate.d.ts +19 -0
- package/dist/session/migrate.js +53 -0
- package/dist/session/projection.d.ts +50 -0
- package/dist/session/projection.js +184 -0
- package/dist/session/store.d.ts +47 -0
- package/dist/session/store.js +210 -0
- package/dist/session/tree.d.ts +21 -0
- package/dist/session/tree.js +88 -0
- package/dist/session/types.d.ts +201 -0
- package/dist/session/types.js +18 -0
- package/dist/skills/discover.d.ts +60 -0
- package/dist/skills/discover.js +160 -0
- package/dist/skills/expand.d.ts +35 -0
- package/dist/skills/expand.js +46 -0
- package/dist/skills/frontmatter.d.ts +27 -0
- package/dist/skills/frontmatter.js +157 -0
- package/dist/skills/index-prompt.d.ts +13 -0
- package/dist/skills/index-prompt.js +42 -0
- package/dist/skills/templates.d.ts +52 -0
- package/dist/skills/templates.js +177 -0
- package/dist/tools/bash.d.ts +49 -0
- package/dist/tools/bash.js +222 -0
- package/dist/tools/edit-fuzzy.d.ts +36 -0
- package/dist/tools/edit-fuzzy.js +129 -0
- package/dist/tools/edit.d.ts +38 -0
- package/dist/tools/edit.js +241 -0
- package/dist/tools/file-mutex.d.ts +8 -0
- package/dist/tools/file-mutex.js +29 -0
- package/dist/tools/glob.d.ts +44 -0
- package/dist/tools/glob.js +217 -0
- package/dist/tools/grep.d.ts +39 -0
- package/dist/tools/grep.js +179 -0
- package/dist/tools/ignore.d.ts +40 -0
- package/dist/tools/ignore.js +174 -0
- package/dist/tools/image-file.d.ts +31 -0
- package/dist/tools/image-file.js +114 -0
- package/dist/tools/ls.d.ts +21 -0
- package/dist/tools/ls.js +96 -0
- package/dist/tools/output-accumulator.d.ts +48 -0
- package/dist/tools/output-accumulator.js +106 -0
- package/dist/tools/paths.d.ts +20 -0
- package/dist/tools/paths.js +58 -0
- package/dist/tools/presets.d.ts +71 -0
- package/dist/tools/presets.js +128 -0
- package/dist/tools/process-tree.d.ts +35 -0
- package/dist/tools/process-tree.js +125 -0
- package/dist/tools/read.d.ts +24 -0
- package/dist/tools/read.js +132 -0
- package/dist/tools/registry.d.ts +43 -0
- package/dist/tools/registry.js +106 -0
- package/dist/tools/shell.d.ts +38 -0
- package/dist/tools/shell.js +91 -0
- package/dist/tools/task.d.ts +29 -0
- package/dist/tools/task.js +107 -0
- package/dist/tools/todo.d.ts +28 -0
- package/dist/tools/todo.js +107 -0
- package/dist/tools/truncate.d.ts +44 -0
- package/dist/tools/truncate.js +175 -0
- package/dist/tools/types.d.ts +135 -0
- package/dist/tools/types.js +19 -0
- package/dist/tools/write.d.ts +20 -0
- package/dist/tools/write.js +84 -0
- package/dist/tui/ansi.d.ts +29 -0
- package/dist/tui/ansi.js +420 -0
- package/dist/tui/component.d.ts +38 -0
- package/dist/tui/component.js +13 -0
- package/dist/tui/components/box.d.ts +26 -0
- package/dist/tui/components/box.js +65 -0
- package/dist/tui/components/container.d.ts +14 -0
- package/dist/tui/components/container.js +39 -0
- package/dist/tui/components/editor-buffer.d.ts +67 -0
- package/dist/tui/components/editor-buffer.js +300 -0
- package/dist/tui/components/editor-paste.d.ts +29 -0
- package/dist/tui/components/editor-paste.js +64 -0
- package/dist/tui/components/editor.d.ts +114 -0
- package/dist/tui/components/editor.js +530 -0
- package/dist/tui/components/key-value.d.ts +29 -0
- package/dist/tui/components/key-value.js +48 -0
- package/dist/tui/components/loader.d.ts +35 -0
- package/dist/tui/components/loader.js +71 -0
- package/dist/tui/components/markdown.d.ts +90 -0
- package/dist/tui/components/markdown.js +462 -0
- package/dist/tui/components/meter.d.ts +29 -0
- package/dist/tui/components/meter.js +47 -0
- package/dist/tui/components/overlay.d.ts +24 -0
- package/dist/tui/components/overlay.js +52 -0
- package/dist/tui/components/select-list.d.ts +57 -0
- package/dist/tui/components/select-list.js +179 -0
- package/dist/tui/components/spacer.d.ts +11 -0
- package/dist/tui/components/spacer.js +16 -0
- package/dist/tui/components/text.d.ts +30 -0
- package/dist/tui/components/text.js +65 -0
- package/dist/tui/keybindings.d.ts +66 -0
- package/dist/tui/keybindings.js +120 -0
- package/dist/tui/keys.d.ts +38 -0
- package/dist/tui/keys.js +275 -0
- package/dist/tui/stdin-buffer.d.ts +41 -0
- package/dist/tui/stdin-buffer.js +206 -0
- package/dist/tui/terminal.d.ts +79 -0
- package/dist/tui/terminal.js +153 -0
- package/dist/tui/theme.d.ts +31 -0
- package/dist/tui/theme.js +199 -0
- package/dist/tui/tui.d.ts +103 -0
- package/dist/tui/tui.js +363 -0
- package/dist/tui/vt-screen.d.ts +46 -0
- package/dist/tui/vt-screen.js +251 -0
- package/dist/tui.d.ts +30 -0
- package/dist/tui.js +31 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.js +24 -0
- package/docs/codemode.md +102 -0
- package/docs/hooks.md +196 -0
- package/docs/host-api.md +161 -0
- package/docs/providers.md +531 -0
- package/docs/rpc.md +253 -0
- package/docs/session-format.md +119 -0
- package/docs/tui.md +170 -0
- package/package.json +101 -4
package/dist/ai/http.js
ADDED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fetch 包装(设计 §1.2 ai/http.ts):超时、头合并(值为 null 删除)、错误体读取。
|
|
3
|
+
*
|
|
4
|
+
* 代理:Node 的全局 fetch 缺省不读 HTTP(S)_PROXY。Node ≥ 24 设 `NODE_USE_ENV_PROXY=1`
|
|
5
|
+
* 即可让 fetch 走环境变量代理;Node 22 需在启动参数里加 `--use-env-proxy`(22.21+)。
|
|
6
|
+
* 本模块不自行实现代理,env 原样透传给运行时处理。
|
|
7
|
+
*
|
|
8
|
+
* 协议层自身**不重试**(重试在会话层,§3.6)。
|
|
9
|
+
*/
|
|
10
|
+
import { AMA_VERSION } from "../version.js";
|
|
11
|
+
/** 大小写不敏感地合并头;后者覆盖前者;值为 null 表示删除该头。键保留最后一次出现的写法。 */
|
|
12
|
+
export function mergeHeaders(...sources) {
|
|
13
|
+
const merged = new Map();
|
|
14
|
+
for (const source of sources) {
|
|
15
|
+
if (!source)
|
|
16
|
+
continue;
|
|
17
|
+
for (const [name, value] of Object.entries(source)) {
|
|
18
|
+
const key = name.toLowerCase();
|
|
19
|
+
if (value === null)
|
|
20
|
+
merged.delete(key);
|
|
21
|
+
else if (value !== undefined)
|
|
22
|
+
merged.set(key, { name, value });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const out = {};
|
|
26
|
+
for (const { name, value } of merged.values())
|
|
27
|
+
out[name] = value;
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
export function hasHeader(headers, name) {
|
|
31
|
+
if (!headers)
|
|
32
|
+
return false;
|
|
33
|
+
const wanted = name.toLowerCase();
|
|
34
|
+
return Object.entries(headers).some(([key, value]) => key.toLowerCase() === wanted && typeof value === "string" && value.length > 0);
|
|
35
|
+
}
|
|
36
|
+
/** 头里已经带了鉴权(调用方自管 key)时,流函数不再要求 apiKey。 */
|
|
37
|
+
export function hasAuthHeader(headers) {
|
|
38
|
+
return (hasHeader(headers, "authorization") ||
|
|
39
|
+
hasHeader(headers, "x-api-key") ||
|
|
40
|
+
hasHeader(headers, "x-goog-api-key"));
|
|
41
|
+
}
|
|
42
|
+
/** 按 AuthHeader 形状生成鉴权头;无 key 时返回空对象。 */
|
|
43
|
+
export function authHeaders(apiKey, shape, fallback) {
|
|
44
|
+
if (!apiKey)
|
|
45
|
+
return {};
|
|
46
|
+
const resolved = shape ?? fallback;
|
|
47
|
+
if (resolved === "authorization-bearer")
|
|
48
|
+
return { Authorization: `Bearer ${apiKey}` };
|
|
49
|
+
if (resolved === "x-api-key")
|
|
50
|
+
return { "x-api-key": apiKey };
|
|
51
|
+
if (resolved === "x-goog-api-key")
|
|
52
|
+
return { "x-goog-api-key": apiKey };
|
|
53
|
+
return { [resolved.header]: `${resolved.prefix ?? ""}${apiKey}` };
|
|
54
|
+
}
|
|
55
|
+
export const USER_AGENT = `ama/${AMA_VERSION}`;
|
|
56
|
+
/** baseUrl 与路径拼接(去掉多余斜杠)。 */
|
|
57
|
+
export function joinUrl(baseUrl, path) {
|
|
58
|
+
return `${baseUrl.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
59
|
+
}
|
|
60
|
+
/** 非 2xx 响应;`message` 已是可展示、可被 overflow / 重试分类器匹配的文本。 */
|
|
61
|
+
export class HttpError extends Error {
|
|
62
|
+
status;
|
|
63
|
+
body;
|
|
64
|
+
retryAfterMs;
|
|
65
|
+
constructor(status, message, body, retryAfterMs) {
|
|
66
|
+
super(message);
|
|
67
|
+
this.name = "HttpError";
|
|
68
|
+
this.status = status;
|
|
69
|
+
this.body = body;
|
|
70
|
+
this.retryAfterMs = retryAfterMs;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export class RequestTimeoutError extends Error {
|
|
74
|
+
constructor(timeoutMs) {
|
|
75
|
+
super(`Request timed out after ${timeoutMs} ms`);
|
|
76
|
+
this.name = "RequestTimeoutError";
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const MAX_ERROR_BODY = 4000;
|
|
80
|
+
/**
|
|
81
|
+
* 从错误体提取文本:识别 `{error:{type,message,code}}`、`{error:"..."}`、`{message}`、
|
|
82
|
+
* `{detail}` 等常见形状;不是 JSON 则截断原文。结果形如 `429 rate_limit_error: ...`。
|
|
83
|
+
*/
|
|
84
|
+
export function formatErrorBody(status, statusText, body) {
|
|
85
|
+
const trimmed = body.trim();
|
|
86
|
+
let detail = "";
|
|
87
|
+
if (trimmed.length > 0) {
|
|
88
|
+
try {
|
|
89
|
+
detail = describeErrorJson(JSON.parse(trimmed)) ?? trimmed;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
detail = trimmed;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (detail.length > MAX_ERROR_BODY)
|
|
96
|
+
detail = `${detail.slice(0, MAX_ERROR_BODY)}…`;
|
|
97
|
+
const head = statusText ? `${status} ${statusText}` : `${status}`;
|
|
98
|
+
return detail ? `${status} ${detail}` : `${head} (no body)`;
|
|
99
|
+
}
|
|
100
|
+
/** 识别 JSON 错误体;无法识别返回 undefined。也用于 SSE 流内的 error 事件。 */
|
|
101
|
+
export function describeErrorJson(value) {
|
|
102
|
+
if (typeof value !== "object" || value === null)
|
|
103
|
+
return undefined;
|
|
104
|
+
const record = value;
|
|
105
|
+
const inner = record["error"];
|
|
106
|
+
if (typeof inner === "string")
|
|
107
|
+
return inner;
|
|
108
|
+
if (typeof inner === "object" && inner !== null) {
|
|
109
|
+
const err = inner;
|
|
110
|
+
const kind = pickString(err["type"]) ?? pickString(err["code"]) ?? pickString(err["status"]);
|
|
111
|
+
const message = pickString(err["message"]) ?? JSON.stringify(err);
|
|
112
|
+
const metadata = err["metadata"];
|
|
113
|
+
const raw = typeof metadata === "object" && metadata !== null
|
|
114
|
+
? pickString(metadata["raw"])
|
|
115
|
+
: undefined;
|
|
116
|
+
const base = kind && !message.startsWith(kind) ? `${kind}: ${message}` : message;
|
|
117
|
+
return raw && !base.includes(raw) ? `${base}\n${raw}` : base;
|
|
118
|
+
}
|
|
119
|
+
const message = pickString(record["message"]) ?? pickString(record["detail"]);
|
|
120
|
+
if (message) {
|
|
121
|
+
const code = pickString(record["code"]) ?? pickString(record["type"]);
|
|
122
|
+
return code && !message.startsWith(code) ? `${code}: ${message}` : message;
|
|
123
|
+
}
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
function pickString(value) {
|
|
127
|
+
if (typeof value === "string" && value.length > 0)
|
|
128
|
+
return value;
|
|
129
|
+
if (typeof value === "number")
|
|
130
|
+
return String(value);
|
|
131
|
+
return undefined;
|
|
132
|
+
}
|
|
133
|
+
function parseRetryAfter(headers) {
|
|
134
|
+
const value = headers.get("retry-after");
|
|
135
|
+
if (!value)
|
|
136
|
+
return undefined;
|
|
137
|
+
const seconds = Number(value);
|
|
138
|
+
if (Number.isFinite(seconds))
|
|
139
|
+
return Math.max(0, seconds * 1000);
|
|
140
|
+
const date = Date.parse(value);
|
|
141
|
+
return Number.isNaN(date) ? undefined : Math.max(0, date - Date.now());
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* POST JSON 并返回 2xx 响应(body 是 SSE 字节流)。非 2xx → HttpError;超时 → RequestTimeoutError;
|
|
145
|
+
* 调用方的 signal 中止 → 原样抛 AbortError(调用方据 signal.aborted 判 aborted)。
|
|
146
|
+
* 超时只覆盖到拿到响应头为止,流式读取期间由调用方的 signal 控制。
|
|
147
|
+
*/
|
|
148
|
+
export async function postJson(url, options) {
|
|
149
|
+
const timeout = options.timeoutMs;
|
|
150
|
+
const timer = new AbortController();
|
|
151
|
+
const handle = timeout !== undefined && timeout > 0 ? setTimeout(() => timer.abort(), timeout) : undefined;
|
|
152
|
+
const signal = AbortSignal.any([options.signal, timer.signal]);
|
|
153
|
+
let response;
|
|
154
|
+
try {
|
|
155
|
+
response = await fetch(url, {
|
|
156
|
+
method: "POST",
|
|
157
|
+
headers: options.headers,
|
|
158
|
+
body: JSON.stringify(options.body),
|
|
159
|
+
signal,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
if (timer.signal.aborted && !options.signal.aborted && timeout !== undefined) {
|
|
164
|
+
throw new RequestTimeoutError(timeout);
|
|
165
|
+
}
|
|
166
|
+
throw normalizeNetworkError(error);
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
if (handle)
|
|
170
|
+
clearTimeout(handle);
|
|
171
|
+
}
|
|
172
|
+
options.onResponse?.(response.status, response.headers);
|
|
173
|
+
if (!response.ok) {
|
|
174
|
+
let body = "";
|
|
175
|
+
try {
|
|
176
|
+
body = await response.text();
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
body = "";
|
|
180
|
+
}
|
|
181
|
+
throw new HttpError(response.status, formatErrorBody(response.status, response.statusText, body), body, parseRetryAfter(response.headers));
|
|
182
|
+
}
|
|
183
|
+
if (!response.body)
|
|
184
|
+
throw new Error("Response has no body");
|
|
185
|
+
return response;
|
|
186
|
+
}
|
|
187
|
+
/** undici 的 `fetch failed` 把真正原因藏在 cause 里;拼出来便于重试分类与排错。 */
|
|
188
|
+
export function normalizeNetworkError(error) {
|
|
189
|
+
if (!(error instanceof Error))
|
|
190
|
+
return error;
|
|
191
|
+
if (error.name === "AbortError")
|
|
192
|
+
return error;
|
|
193
|
+
const cause = error.cause;
|
|
194
|
+
if (cause instanceof Error && !error.message.includes(cause.message)) {
|
|
195
|
+
const code = cause.code;
|
|
196
|
+
const suffix = typeof code === "string" ? `${code} ${cause.message}` : cause.message;
|
|
197
|
+
return new Error(`${error.message}: ${suffix}`, { cause });
|
|
198
|
+
}
|
|
199
|
+
return error;
|
|
200
|
+
}
|
|
201
|
+
export function errorText(error) {
|
|
202
|
+
if (error instanceof Error)
|
|
203
|
+
return error.message;
|
|
204
|
+
if (typeof error === "string")
|
|
205
|
+
return error;
|
|
206
|
+
try {
|
|
207
|
+
return JSON.stringify(error);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return String(error);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 容错 JSON 片段解析(设计 §1.2 ai/json-partial.ts):流式 tool_call 参数在每个增量后都要
|
|
3
|
+
* 能给出「到目前为止」的对象;结束时参数也可能有小毛病(字符串里的裸控制字符、非法转义)。
|
|
4
|
+
*
|
|
5
|
+
* `parsePartialJson` 是一个宽松的递归下降解析器:
|
|
6
|
+
* - 输入在任意位置截断都返回已解析的部分(未完成的字符串保留已收到的字符;未完成的键、
|
|
7
|
+
* 只有键没有值的成员被丢弃;未完成的数字取能解析的前缀;未完成的字面量按前缀补全);
|
|
8
|
+
* - 字符串内的裸控制字符照收,非法转义 `\x` 保留为两个字符;
|
|
9
|
+
* - 遇到无法继续的语法错误时返回到错误点为止已解析的部分。
|
|
10
|
+
*/
|
|
11
|
+
/** 宽松解析(见文件头);无可解析内容时返回 undefined。 */
|
|
12
|
+
export declare function parsePartialJson(text: string): unknown;
|
|
13
|
+
/** 先严格解析,失败再宽松解析。 */
|
|
14
|
+
export declare function parseJsonLenient(text: string): unknown;
|
|
15
|
+
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
16
|
+
/** 工具调用参数:结果总是对象(流契约要求 toolcall_end 时参数为合法对象)。 */
|
|
17
|
+
export declare function parseToolArguments(text: string): Record<string, unknown>;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 容错 JSON 片段解析(设计 §1.2 ai/json-partial.ts):流式 tool_call 参数在每个增量后都要
|
|
3
|
+
* 能给出「到目前为止」的对象;结束时参数也可能有小毛病(字符串里的裸控制字符、非法转义)。
|
|
4
|
+
*
|
|
5
|
+
* `parsePartialJson` 是一个宽松的递归下降解析器:
|
|
6
|
+
* - 输入在任意位置截断都返回已解析的部分(未完成的字符串保留已收到的字符;未完成的键、
|
|
7
|
+
* 只有键没有值的成员被丢弃;未完成的数字取能解析的前缀;未完成的字面量按前缀补全);
|
|
8
|
+
* - 字符串内的裸控制字符照收,非法转义 `\x` 保留为两个字符;
|
|
9
|
+
* - 遇到无法继续的语法错误时返回到错误点为止已解析的部分。
|
|
10
|
+
*/
|
|
11
|
+
class Cursor {
|
|
12
|
+
text;
|
|
13
|
+
pos = 0;
|
|
14
|
+
constructor(text) {
|
|
15
|
+
this.text = text;
|
|
16
|
+
}
|
|
17
|
+
get done() {
|
|
18
|
+
return this.pos >= this.text.length;
|
|
19
|
+
}
|
|
20
|
+
peek() {
|
|
21
|
+
return this.text.charAt(this.pos);
|
|
22
|
+
}
|
|
23
|
+
skipWs() {
|
|
24
|
+
while (this.pos < this.text.length && /\s/.test(this.text.charAt(this.pos)))
|
|
25
|
+
this.pos++;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** 解析失败(语法错误)时抛出,携带已解析的部分值。 */
|
|
29
|
+
class Stop extends Error {
|
|
30
|
+
partial;
|
|
31
|
+
constructor(partial) {
|
|
32
|
+
super("stop");
|
|
33
|
+
this.partial = partial;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const NONE = Symbol("none");
|
|
37
|
+
function parseValue(c) {
|
|
38
|
+
c.skipWs();
|
|
39
|
+
if (c.done)
|
|
40
|
+
return NONE;
|
|
41
|
+
const ch = c.peek();
|
|
42
|
+
if (ch === "{")
|
|
43
|
+
return parseObject(c);
|
|
44
|
+
if (ch === "[")
|
|
45
|
+
return parseArray(c);
|
|
46
|
+
if (ch === '"')
|
|
47
|
+
return parseString(c);
|
|
48
|
+
if (ch === "-" || (ch >= "0" && ch <= "9"))
|
|
49
|
+
return parseNumber(c);
|
|
50
|
+
return parseLiteral(c);
|
|
51
|
+
}
|
|
52
|
+
function parseObject(c) {
|
|
53
|
+
const out = {};
|
|
54
|
+
c.pos++; // {
|
|
55
|
+
while (true) {
|
|
56
|
+
c.skipWs();
|
|
57
|
+
if (c.done)
|
|
58
|
+
return out;
|
|
59
|
+
const ch = c.peek();
|
|
60
|
+
if (ch === "}") {
|
|
61
|
+
c.pos++;
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
if (ch === ",") {
|
|
65
|
+
c.pos++;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (ch !== '"')
|
|
69
|
+
throw new Stop(out);
|
|
70
|
+
const start = c.pos;
|
|
71
|
+
const key = parseString(c);
|
|
72
|
+
if (c.pos === start)
|
|
73
|
+
throw new Stop(out);
|
|
74
|
+
c.skipWs();
|
|
75
|
+
if (c.done)
|
|
76
|
+
return out;
|
|
77
|
+
if (c.peek() !== ":")
|
|
78
|
+
throw new Stop(out);
|
|
79
|
+
c.pos++;
|
|
80
|
+
let value;
|
|
81
|
+
try {
|
|
82
|
+
value = parseValue(c);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error instanceof Stop) {
|
|
86
|
+
if (error.partial !== NONE)
|
|
87
|
+
out[key] = error.partial;
|
|
88
|
+
throw new Stop(out);
|
|
89
|
+
}
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
if (value === NONE)
|
|
93
|
+
return out;
|
|
94
|
+
out[key] = value;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function parseArray(c) {
|
|
98
|
+
const out = [];
|
|
99
|
+
c.pos++; // [
|
|
100
|
+
while (true) {
|
|
101
|
+
c.skipWs();
|
|
102
|
+
if (c.done)
|
|
103
|
+
return out;
|
|
104
|
+
const ch = c.peek();
|
|
105
|
+
if (ch === "]") {
|
|
106
|
+
c.pos++;
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
if (ch === ",") {
|
|
110
|
+
c.pos++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
let value;
|
|
114
|
+
try {
|
|
115
|
+
value = parseValue(c);
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error instanceof Stop) {
|
|
119
|
+
if (error.partial !== NONE)
|
|
120
|
+
out.push(error.partial);
|
|
121
|
+
throw new Stop(out);
|
|
122
|
+
}
|
|
123
|
+
throw error;
|
|
124
|
+
}
|
|
125
|
+
if (value === NONE)
|
|
126
|
+
return out;
|
|
127
|
+
out.push(value);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const ESCAPES = {
|
|
131
|
+
'"': '"',
|
|
132
|
+
"\\": "\\",
|
|
133
|
+
"/": "/",
|
|
134
|
+
b: "\b",
|
|
135
|
+
f: "\f",
|
|
136
|
+
n: "\n",
|
|
137
|
+
r: "\r",
|
|
138
|
+
t: "\t",
|
|
139
|
+
};
|
|
140
|
+
function parseString(c) {
|
|
141
|
+
let out = "";
|
|
142
|
+
c.pos++; // "
|
|
143
|
+
while (!c.done) {
|
|
144
|
+
const ch = c.text.charAt(c.pos);
|
|
145
|
+
if (ch === '"') {
|
|
146
|
+
c.pos++;
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
if (ch !== "\\") {
|
|
150
|
+
out += ch;
|
|
151
|
+
c.pos++;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
const next = c.text.charAt(c.pos + 1);
|
|
155
|
+
if (next === "") {
|
|
156
|
+
c.pos = c.text.length; // 截断在转义中间:丢掉反斜杠
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
if (next === "u") {
|
|
160
|
+
const hex = c.text.slice(c.pos + 2, c.pos + 6);
|
|
161
|
+
if (/^[0-9a-fA-F]{4}$/.test(hex)) {
|
|
162
|
+
out += String.fromCharCode(parseInt(hex, 16));
|
|
163
|
+
c.pos += 6;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
if (c.pos + 6 > c.text.length && /^[0-9a-fA-F]*$/.test(hex)) {
|
|
167
|
+
c.pos = c.text.length; // 截断在 \uXXXX 中间
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const mapped = ESCAPES[next];
|
|
172
|
+
if (mapped !== undefined)
|
|
173
|
+
out += mapped;
|
|
174
|
+
else
|
|
175
|
+
out += `\\${next}`; // 非法转义:原样保留
|
|
176
|
+
c.pos += 2;
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
function parseNumber(c) {
|
|
181
|
+
const match = /^-?(?:\d+)?(?:\.\d*)?(?:[eE][+-]?\d*)?/.exec(c.text.slice(c.pos));
|
|
182
|
+
const raw = match?.[0] ?? "";
|
|
183
|
+
c.pos += raw.length;
|
|
184
|
+
for (let end = raw.length; end > 0; end--) {
|
|
185
|
+
const value = Number(raw.slice(0, end));
|
|
186
|
+
if (raw.slice(0, end) !== "-" && Number.isFinite(value))
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
if (raw.length === 0)
|
|
190
|
+
throw new Stop(NONE);
|
|
191
|
+
return NONE;
|
|
192
|
+
}
|
|
193
|
+
const LITERALS = [
|
|
194
|
+
["true", true],
|
|
195
|
+
["false", false],
|
|
196
|
+
["null", null],
|
|
197
|
+
];
|
|
198
|
+
function parseLiteral(c) {
|
|
199
|
+
const rest = c.text.slice(c.pos);
|
|
200
|
+
for (const [word, value] of LITERALS) {
|
|
201
|
+
if (rest.startsWith(word)) {
|
|
202
|
+
c.pos += word.length;
|
|
203
|
+
return value;
|
|
204
|
+
}
|
|
205
|
+
if (rest.length < word.length && word.startsWith(rest)) {
|
|
206
|
+
c.pos = c.text.length;
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
throw new Stop(NONE);
|
|
211
|
+
}
|
|
212
|
+
/** 宽松解析(见文件头);无可解析内容时返回 undefined。 */
|
|
213
|
+
export function parsePartialJson(text) {
|
|
214
|
+
const cursor = new Cursor(text);
|
|
215
|
+
try {
|
|
216
|
+
const value = parseValue(cursor);
|
|
217
|
+
return value === NONE ? undefined : value;
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
if (error instanceof Stop)
|
|
221
|
+
return error.partial === NONE ? undefined : error.partial;
|
|
222
|
+
throw error;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/** 先严格解析,失败再宽松解析。 */
|
|
226
|
+
export function parseJsonLenient(text) {
|
|
227
|
+
try {
|
|
228
|
+
return JSON.parse(text);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
return parsePartialJson(text);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
export function isPlainObject(value) {
|
|
235
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
236
|
+
}
|
|
237
|
+
/** 工具调用参数:结果总是对象(流契约要求 toolcall_end 时参数为合法对象)。 */
|
|
238
|
+
export function parseToolArguments(text) {
|
|
239
|
+
if (text.trim() === "")
|
|
240
|
+
return {};
|
|
241
|
+
const value = parseJsonLenient(text);
|
|
242
|
+
return isPlainObject(value) ? value : {};
|
|
243
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 上下文溢出识别(设计 §3.6「溢出」)。溢出不走会话层重试,走「压缩后以新 run 重试一次」(§9)。
|
|
3
|
+
*
|
|
4
|
+
* 三种情形:
|
|
5
|
+
* 1. 错误文案:各家 400 / 413 的报错(下表;先排除限流类文案,避免「too many tokens, please
|
|
6
|
+
* wait」被误判);
|
|
7
|
+
* 2. 静默溢出:请求成功但 `usage.input + cacheRead` 超过窗口(个别网关);
|
|
8
|
+
* 3. `stopReason: "length"` 且没有工具调用:由调用方结合 `isLengthStop()` 判断(§3.6)。
|
|
9
|
+
*
|
|
10
|
+
* 文案表只记录各家文档或实测中出现过的句式;新增供应商时用真实溢出请求取样后补一条。
|
|
11
|
+
*/
|
|
12
|
+
import type { AssistantMessage } from "./types.js";
|
|
13
|
+
/** [正则, 来源说明]。 */
|
|
14
|
+
export declare const OVERFLOW_PATTERNS: readonly (readonly [RegExp, string])[];
|
|
15
|
+
/** 错误文本是否表示上下文溢出。 */
|
|
16
|
+
export declare function isOverflowErrorText(text: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* 助手消息是否表示上下文溢出(情形 1、2)。`contextWindow` 缺省时不判静默溢出。
|
|
19
|
+
*/
|
|
20
|
+
export declare function isContextOverflow(message: AssistantMessage, contextWindow?: number): boolean;
|
|
21
|
+
/** `length` 停止且没有工具调用:§9 的「压缩后重试一次」候选。 */
|
|
22
|
+
export declare function isLengthStop(message: AssistantMessage): boolean;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 上下文溢出识别(设计 §3.6「溢出」)。溢出不走会话层重试,走「压缩后以新 run 重试一次」(§9)。
|
|
3
|
+
*
|
|
4
|
+
* 三种情形:
|
|
5
|
+
* 1. 错误文案:各家 400 / 413 的报错(下表;先排除限流类文案,避免「too many tokens, please
|
|
6
|
+
* wait」被误判);
|
|
7
|
+
* 2. 静默溢出:请求成功但 `usage.input + cacheRead` 超过窗口(个别网关);
|
|
8
|
+
* 3. `stopReason: "length"` 且没有工具调用:由调用方结合 `isLengthStop()` 判断(§3.6)。
|
|
9
|
+
*
|
|
10
|
+
* 文案表只记录各家文档或实测中出现过的句式;新增供应商时用真实溢出请求取样后补一条。
|
|
11
|
+
*/
|
|
12
|
+
/** [正则, 来源说明]。 */
|
|
13
|
+
export const OVERFLOW_PATTERNS = [
|
|
14
|
+
[/prompt is too long/i, "Anthropic: prompt is too long: N tokens > M maximum"],
|
|
15
|
+
[/request_too_large/i, "Anthropic: 413 request_too_large"],
|
|
16
|
+
[/exceeds the context window/i, "OpenAI: Your input exceeds the context window of this model"],
|
|
17
|
+
[/maximum context length is \d+ tokens/i, "OpenAI / OpenRouter / DeepSeek"],
|
|
18
|
+
[/exceeds (?:the )?(?:model'?s )?maximum context length/i, "OpenAI 兼容网关(vLLM / LiteLLM)"],
|
|
19
|
+
[/input token count.*exceeds the maximum/i, "Google Gemini"],
|
|
20
|
+
[
|
|
21
|
+
/exceeds the maximum number of tokens allowed/i,
|
|
22
|
+
"Google Gemini(无 input token count 前缀的变体)",
|
|
23
|
+
],
|
|
24
|
+
[/maximum prompt length is \d+/i, "xAI"],
|
|
25
|
+
[/reduce the length of the messages/i, "Groq"],
|
|
26
|
+
[/too large for model with \d+ maximum context length/i, "Mistral"],
|
|
27
|
+
[/exceeded model token limit/i, "Moonshot / Kimi"],
|
|
28
|
+
[/prompt (?:too long|exceeds max length)/i, "智谱 GLM(code 1261)/ Ollama"],
|
|
29
|
+
[/range of input length should be/i, "DashScope / Qwen"],
|
|
30
|
+
[/greater than the context length/i, "LM Studio"],
|
|
31
|
+
[/exceeds the available context size/i, "llama.cpp server"],
|
|
32
|
+
[/context[_ ]length[_ ]exceeded/i, "通用:context_length_exceeded"],
|
|
33
|
+
[/model_context_window_exceeded/i, "通用:finish_reason 文本化"],
|
|
34
|
+
[/token limit exceeded/i, "通用"],
|
|
35
|
+
];
|
|
36
|
+
/** 命中这些的不算溢出(限流 / 配额)。 */
|
|
37
|
+
const NOT_OVERFLOW = [/rate[ _-]?limit/i, /too many requests/i, /\b429\b/];
|
|
38
|
+
/** 错误文本是否表示上下文溢出。 */
|
|
39
|
+
export function isOverflowErrorText(text) {
|
|
40
|
+
if (NOT_OVERFLOW.some((re) => re.test(text)))
|
|
41
|
+
return false;
|
|
42
|
+
return OVERFLOW_PATTERNS.some(([re]) => re.test(text));
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* 助手消息是否表示上下文溢出(情形 1、2)。`contextWindow` 缺省时不判静默溢出。
|
|
46
|
+
*/
|
|
47
|
+
export function isContextOverflow(message, contextWindow) {
|
|
48
|
+
if (message.stopReason === "error" && message.errorMessage) {
|
|
49
|
+
if (isOverflowErrorText(message.errorMessage))
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (contextWindow !== undefined && contextWindow > 0 && message.stopReason === "stop") {
|
|
53
|
+
if (message.usage.input + message.usage.cacheRead > contextWindow)
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
/** `length` 停止且没有工具调用:§9 的「压缩后重试一次」候选。 */
|
|
59
|
+
export function isLengthStop(message) {
|
|
60
|
+
return (message.stopReason === "length" && !message.content.some((block) => block.type === "toolCall"));
|
|
61
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Key 发现(设计 §3.5)。顺序:
|
|
3
|
+
* ① `--api-key`(只对 `--model` 指定的那家供应商)
|
|
4
|
+
* ② `--auth-file` / profile.authFile 指向的 auth.json
|
|
5
|
+
* ③ 用户级 `<configDir>/auth.json`(不是 0600 → warning 并照用)
|
|
6
|
+
* ④ config.json 的 `providers.<id>.apiKey`(`$ENV_NAME`、`${ENV_NAME}`、`!command`;`$$` 转义)
|
|
7
|
+
* ⑤ 环境变量:`provider.envKeys` 顺序(profile.authEnv=false 时跳过)
|
|
8
|
+
* ⑥ `requiresApiKey: false` 的供应商:无 key 也放行(source "none")
|
|
9
|
+
*
|
|
10
|
+
* auth.json 的 `apiKey` 以 `!` 开头 = 执行命令取值(stdout 去首尾空白;超时 10 s;空输出或
|
|
11
|
+
* 非零退出视为未配置,继续找下一来源);同一命令进程内只执行一次。
|
|
12
|
+
* 密钥只出现在 `resolve()` 的返回值里:warning 文案不含密钥与命令输出。
|
|
13
|
+
*/
|
|
14
|
+
import type { AuthFile } from "../../config/types.js";
|
|
15
|
+
import type { ApiKeyResolution, ProviderData } from "../types.js";
|
|
16
|
+
export type KeyProvider = Pick<ProviderData, "id" | "envKeys" | "requiresApiKey">;
|
|
17
|
+
export interface KeyResolverOptions {
|
|
18
|
+
/** ① `--api-key`:只对 provider 生效。 */
|
|
19
|
+
cliApiKey?: {
|
|
20
|
+
provider: string;
|
|
21
|
+
apiKey: string;
|
|
22
|
+
} | undefined;
|
|
23
|
+
/** ② `--auth-file` / profile.authFile。 */
|
|
24
|
+
authFile?: string | undefined;
|
|
25
|
+
/** ③ 用户级 auth.json;缺省 `<configDir>/auth.json`;null 关闭。 */
|
|
26
|
+
userAuthFile?: string | null | undefined;
|
|
27
|
+
/** ④ config.json 的 `providers.<id>.apiKey` 原始值。 */
|
|
28
|
+
configKeys?: Readonly<Record<string, string | undefined>> | undefined;
|
|
29
|
+
/** ⑤ 是否读环境变量(缺省 true)。 */
|
|
30
|
+
useEnv?: boolean | undefined;
|
|
31
|
+
env?: NodeJS.ProcessEnv | undefined;
|
|
32
|
+
onWarning?: ((message: string) => void) | undefined;
|
|
33
|
+
/** `!command` 超时,缺省 10 000。 */
|
|
34
|
+
commandTimeoutMs?: number | undefined;
|
|
35
|
+
}
|
|
36
|
+
/** 用户级配置目录:AMA_CONFIG_DIR > %APPDATA%\ama > $XDG_CONFIG_HOME/ama > ~/.config/ama。 */
|
|
37
|
+
export declare function defaultConfigDir(env?: NodeJS.ProcessEnv): string;
|
|
38
|
+
type AuthEntry = AuthFile["providers"][string];
|
|
39
|
+
/** 读 auth.json;不存在返回 undefined;格式错误 / 权限过宽记 warning。 */
|
|
40
|
+
export declare function readAuthFile(path: string, onWarning?: (message: string) => void): AuthFile | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* 展开 config.json 的 `$NAME` / `${NAME}`(`$$` → `$`)。引用的变量未设置或为空 →
|
|
43
|
+
* undefined(视为未配置)。
|
|
44
|
+
*/
|
|
45
|
+
export declare function expandEnvRefs(value: string, env: NodeJS.ProcessEnv): string | undefined;
|
|
46
|
+
export declare class ApiKeyResolver {
|
|
47
|
+
private readonly options;
|
|
48
|
+
private readonly env;
|
|
49
|
+
private readonly commandCache;
|
|
50
|
+
private readonly fileCache;
|
|
51
|
+
constructor(options?: KeyResolverOptions);
|
|
52
|
+
private warn;
|
|
53
|
+
private authFiles;
|
|
54
|
+
private loadFile;
|
|
55
|
+
/** auth.json 里该供应商的条目(按 ② ③ 顺序第一个)。 */
|
|
56
|
+
authEntry(providerId: string): {
|
|
57
|
+
entry: AuthEntry;
|
|
58
|
+
path: string;
|
|
59
|
+
} | undefined;
|
|
60
|
+
private runCommand;
|
|
61
|
+
private fromAuthFiles;
|
|
62
|
+
private fromConfig;
|
|
63
|
+
private fromEnv;
|
|
64
|
+
resolve(provider: KeyProvider): Promise<ApiKeyResolution>;
|
|
65
|
+
/**
|
|
66
|
+
* 同步判断「看起来配置了 key」(不执行 `!command`,只看配置是否存在;env 引用需已设置)。
|
|
67
|
+
* 供 `findModel()` 在无斜杠引用时过滤候选。
|
|
68
|
+
*/
|
|
69
|
+
hasConfiguredKey(provider: KeyProvider): boolean;
|
|
70
|
+
}
|
|
71
|
+
export {};
|