@armadra/agent 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +174 -1
- package/README.md +201 -82
- package/THIRD_PARTY_NOTICES.md +34 -0
- package/dist/acp.d.ts +18 -0
- package/dist/acp.js +19 -0
- package/dist/agent/limits.d.ts +38 -0
- package/dist/agent/limits.js +127 -0
- package/dist/agent/loop-guard.d.ts +38 -0
- package/dist/agent/loop-guard.js +95 -0
- package/dist/agent/loop.d.ts +4 -0
- package/dist/agent/loop.js +7 -0
- package/dist/agent/prompt-rules.d.ts +12 -0
- package/dist/agent/prompt-rules.js +18 -0
- package/dist/agent/reminders.d.ts +59 -0
- package/dist/agent/reminders.js +327 -0
- package/dist/agent/session-cache.d.ts +5 -0
- package/dist/agent/session-cache.js +17 -1
- package/dist/agent/session-classifier.d.ts +1 -1
- package/dist/agent/session-classifier.js +3 -1
- package/dist/agent/session-compaction.d.ts +35 -6
- package/dist/agent/session-compaction.js +157 -31
- package/dist/agent/session-core.d.ts +27 -1
- package/dist/agent/session-extensions.d.ts +61 -0
- package/dist/agent/session-extensions.js +129 -0
- package/dist/agent/session-images.d.ts +23 -0
- package/dist/agent/session-images.js +97 -0
- package/dist/agent/session-plan.d.ts +21 -0
- package/dist/agent/session-plan.js +524 -0
- package/dist/agent/session-rewind.d.ts +81 -0
- package/dist/agent/session-rewind.js +354 -0
- package/dist/agent/session-run.d.ts +28 -1
- package/dist/agent/session-run.js +157 -6
- package/dist/agent/session-settings.d.ts +49 -0
- package/dist/agent/session-settings.js +95 -0
- package/dist/agent/session-subagent.d.ts +36 -24
- package/dist/agent/session-subagent.js +259 -129
- package/dist/agent/session-sync.d.ts +10 -3
- package/dist/agent/session-sync.js +37 -8
- package/dist/agent/session-telemetry.d.ts +39 -0
- package/dist/agent/session-telemetry.js +231 -0
- package/dist/agent/session-tools.js +40 -1
- package/dist/agent/session.d.ts +30 -29
- package/dist/agent/session.js +79 -123
- package/dist/agent/subagent-registry.d.ts +91 -0
- package/dist/agent/subagent-registry.js +494 -0
- package/dist/agent/system-prompt.d.ts +6 -3
- package/dist/agent/system-prompt.js +7 -2
- package/dist/agent/tool-runner.d.ts +8 -1
- package/dist/agent/tool-runner.js +57 -4
- package/dist/agent/types-w5.d.ts +192 -0
- package/dist/agent/types-w5.js +10 -0
- package/dist/agent/types.d.ts +47 -4
- package/dist/agent/types.js +2 -0
- package/dist/agent/worktree.d.ts +36 -0
- package/dist/agent/worktree.js +86 -0
- package/dist/agents/builtin.d.ts +14 -0
- package/dist/agents/builtin.js +39 -0
- package/dist/agents/catalog.d.ts +43 -0
- package/dist/agents/catalog.js +82 -0
- package/dist/agents/discover.d.ts +35 -0
- package/dist/agents/discover.js +83 -0
- package/dist/agents/external.d.ts +82 -0
- package/dist/agents/external.js +326 -0
- package/dist/agents/parse.d.ts +18 -0
- package/dist/agents/parse.js +116 -0
- package/dist/agents/result.d.ts +32 -0
- package/dist/agents/result.js +67 -0
- package/dist/agents/task-control.d.ts +17 -0
- package/dist/agents/task-control.js +17 -0
- package/dist/agents/task-record.d.ts +78 -0
- package/dist/agents/task-record.js +141 -0
- package/dist/agents/types.d.ts +46 -0
- package/dist/agents/types.js +8 -0
- package/dist/ai/apis/anthropic-compat.d.ts +36 -0
- package/dist/ai/apis/anthropic-compat.js +92 -0
- package/dist/ai/apis/anthropic-request.d.ts +7 -6
- package/dist/ai/apis/anthropic-request.js +10 -28
- package/dist/ai/apis/cache-params.d.ts +11 -2
- package/dist/ai/apis/cache-params.js +25 -6
- package/dist/ai/apis/openai-compat.d.ts +4 -1
- package/dist/ai/apis/openai-compat.js +8 -1
- package/dist/ai/image-limits.d.ts +45 -0
- package/dist/ai/image-limits.js +68 -0
- package/dist/ai/providers/builtin.d.ts +18 -6
- package/dist/ai/providers/builtin.js +135 -6
- package/dist/ai/providers/catalog-data.js +17 -13
- package/dist/ai/providers/catalog.d.ts +60 -7
- package/dist/ai/providers/catalog.js +197 -38
- package/dist/ai/providers/channels.d.ts +33 -3
- package/dist/ai/providers/channels.js +108 -7
- package/dist/ai/providers/enrich.d.ts +6 -3
- package/dist/ai/providers/enrich.js +19 -4
- package/dist/ai/providers/models-dev-cache.d.ts +28 -24
- package/dist/ai/providers/models-dev-cache.js +92 -78
- package/dist/ai/providers/models-dev-data.d.ts +7 -0
- package/dist/ai/providers/models-dev-data.js +32 -0
- package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
- package/dist/ai/providers/models-dev-snapshot.js +137 -0
- package/dist/ai/providers/models-dev.d.ts +51 -10
- package/dist/ai/providers/models-dev.js +132 -39
- package/dist/ai/providers/registry.d.ts +20 -10
- package/dist/ai/providers/registry.js +82 -43
- package/dist/ai/types.d.ts +28 -2
- package/dist/ai/types.js +5 -0
- package/dist/bundle/ama.cjs +36203 -20499
- package/dist/checkpoints/backend.d.ts +61 -0
- package/dist/checkpoints/backend.js +135 -0
- package/dist/checkpoints/blobs.d.ts +60 -0
- package/dist/checkpoints/blobs.js +203 -0
- package/dist/checkpoints/gc.d.ts +47 -0
- package/dist/checkpoints/gc.js +144 -0
- package/dist/checkpoints/git-head.d.ts +15 -0
- package/dist/checkpoints/git-head.js +89 -0
- package/dist/checkpoints/index.d.ts +17 -0
- package/dist/checkpoints/index.js +17 -0
- package/dist/checkpoints/replay.d.ts +48 -0
- package/dist/checkpoints/replay.js +154 -0
- package/dist/checkpoints/restore.d.ts +86 -0
- package/dist/checkpoints/restore.js +263 -0
- package/dist/checkpoints/settings.d.ts +14 -0
- package/dist/checkpoints/settings.js +23 -0
- package/dist/checkpoints/shadow-git.d.ts +108 -0
- package/dist/checkpoints/shadow-git.js +491 -0
- package/dist/checkpoints/shadow-restore.d.ts +25 -0
- package/dist/checkpoints/shadow-restore.js +128 -0
- package/dist/checkpoints/tracker.d.ts +64 -0
- package/dist/checkpoints/tracker.js +192 -0
- package/dist/checkpoints/types.d.ts +99 -0
- package/dist/checkpoints/types.js +12 -0
- package/dist/cli/args.d.ts +8 -4
- package/dist/cli/args.js +17 -97
- package/dist/cli/bootstrap.js +13 -1
- package/dist/cli/codemode-notice.d.ts +3 -2
- package/dist/cli/codemode-notice.js +3 -2
- package/dist/cli/compose-agents.d.ts +27 -0
- package/dist/cli/compose-agents.js +111 -0
- package/dist/cli/compose-extensions.d.ts +29 -0
- package/dist/cli/compose-extensions.js +44 -0
- package/dist/cli/compose-session.d.ts +3 -0
- package/dist/cli/compose-session.js +47 -4
- package/dist/cli/compose.d.ts +3 -0
- package/dist/cli/compose.js +33 -6
- package/dist/cli/deps.d.ts +6 -0
- package/dist/cli/exit-codes.d.ts +10 -0
- package/dist/cli/exit-codes.js +12 -0
- package/dist/cli/help-text.d.ts +4 -0
- package/dist/cli/help-text.js +102 -0
- package/dist/cli/startup-screen.js +5 -3
- package/dist/cli/startup-steps.js +7 -1
- package/dist/cli/subcommands/config.d.ts +4 -1
- package/dist/cli/subcommands/config.js +17 -6
- package/dist/cli/subcommands/doctor.js +21 -0
- package/dist/cli/subcommands/models-discover.js +5 -6
- package/dist/cli/subcommands/models.d.ts +2 -0
- package/dist/cli/subcommands/models.js +33 -14
- package/dist/cli/subcommands/providers.js +5 -6
- package/dist/cli/subcommands/sessions.d.ts +3 -1
- package/dist/cli/subcommands/sessions.js +36 -2
- package/dist/codemode/capability.d.ts +24 -7
- package/dist/codemode/capability.js +38 -10
- package/dist/codemode/host-side.d.ts +14 -0
- package/dist/codemode/host-side.js +24 -1
- package/dist/codemode/tool.d.ts +1 -1
- package/dist/codemode/tool.js +6 -4
- package/dist/compaction/breaker.d.ts +25 -9
- package/dist/compaction/breaker.js +47 -17
- package/dist/compaction/estimate.d.ts +11 -3
- package/dist/compaction/estimate.js +64 -22
- package/dist/compaction/image-budget.d.ts +45 -0
- package/dist/compaction/image-budget.js +115 -0
- package/dist/compaction/post-compact.d.ts +38 -0
- package/dist/compaction/post-compact.js +152 -0
- package/dist/compaction/protect.d.ts +27 -0
- package/dist/compaction/protect.js +56 -0
- package/dist/compaction/prune-tier.d.ts +58 -12
- package/dist/compaction/prune-tier.js +120 -54
- package/dist/compaction/summarize-tier.d.ts +23 -4
- package/dist/compaction/summarize-tier.js +100 -29
- package/dist/config/checker.d.ts +28 -0
- package/dist/config/checker.js +97 -0
- package/dist/config/json-schema.js +63 -2
- package/dist/config/key-docs.js +72 -3
- package/dist/config/merge.d.ts +5 -3
- package/dist/config/merge.js +81 -7
- package/dist/config/profile.d.ts +2 -0
- package/dist/config/profile.js +2 -0
- package/dist/config/schema-w5.d.ts +18 -0
- package/dist/config/schema-w5.js +109 -0
- package/dist/config/schema.d.ts +5 -9
- package/dist/config/schema.js +68 -114
- package/dist/config/types-w5.d.ts +118 -0
- package/dist/config/types-w5.js +20 -0
- package/dist/config/types.d.ts +50 -1
- package/dist/config/types.js +12 -0
- package/dist/drivers/acp/client.d.ts +57 -0
- package/dist/drivers/acp/client.js +160 -0
- package/dist/drivers/acp/driver.d.ts +31 -0
- package/dist/drivers/acp/driver.js +274 -0
- package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
- package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
- package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
- package/dist/drivers/acp/testing/fake-agent.js +211 -0
- package/dist/drivers/acp/types.d.ts +285 -0
- package/dist/drivers/acp/types.js +36 -0
- package/dist/drivers/agents.d.ts +58 -0
- package/dist/drivers/agents.js +142 -0
- package/dist/drivers/base.d.ts +35 -0
- package/dist/drivers/base.js +59 -0
- package/dist/drivers/catalog.d.ts +46 -0
- package/dist/drivers/catalog.js +167 -0
- package/dist/drivers/env.d.ts +20 -0
- package/dist/drivers/env.js +46 -0
- package/dist/drivers/host-runners.d.ts +18 -0
- package/dist/drivers/host-runners.js +45 -0
- package/dist/drivers/jsonrpc.d.ts +58 -0
- package/dist/drivers/jsonrpc.js +180 -0
- package/dist/drivers/native/claude-normalize.d.ts +46 -0
- package/dist/drivers/native/claude-normalize.js +106 -0
- package/dist/drivers/native/claude-stream.d.ts +29 -0
- package/dist/drivers/native/claude-stream.js +456 -0
- package/dist/drivers/native/codex-app-server.d.ts +26 -0
- package/dist/drivers/native/codex-app-server.js +407 -0
- package/dist/drivers/native/codex-normalize.d.ts +38 -0
- package/dist/drivers/native/codex-normalize.js +124 -0
- package/dist/drivers/native/oneshot.d.ts +28 -0
- package/dist/drivers/native/oneshot.js +312 -0
- package/dist/drivers/permissions.d.ts +40 -0
- package/dist/drivers/permissions.js +92 -0
- package/dist/drivers/pids.d.ts +32 -0
- package/dist/drivers/pids.js +93 -0
- package/dist/drivers/pool.d.ts +28 -0
- package/dist/drivers/pool.js +96 -0
- package/dist/drivers/probe.d.ts +47 -0
- package/dist/drivers/probe.js +172 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.js +100 -0
- package/dist/drivers/runner.d.ts +61 -0
- package/dist/drivers/runner.js +388 -0
- package/dist/drivers/store.d.ts +49 -0
- package/dist/drivers/store.js +91 -0
- package/dist/drivers/turn.d.ts +41 -0
- package/dist/drivers/turn.js +99 -0
- package/dist/drivers/types.d.ts +122 -0
- package/dist/drivers/types.js +11 -0
- package/dist/git/info.d.ts +75 -0
- package/dist/git/info.js +191 -0
- package/dist/hooks/protocol.js +6 -1
- package/dist/hooks/types.d.ts +10 -1
- package/dist/hooks/types.js +2 -0
- package/dist/host/api-impl.d.ts +7 -0
- package/dist/host/api-impl.js +15 -0
- package/dist/host/types.d.ts +24 -2
- package/dist/host/types.js +4 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -0
- package/dist/modes/acp/acp-events.d.ts +46 -0
- package/dist/modes/acp/acp-events.js +233 -0
- package/dist/modes/acp/acp-mode.d.ts +17 -0
- package/dist/modes/acp/acp-mode.js +47 -0
- package/dist/modes/acp/acp-server.d.ts +79 -0
- package/dist/modes/acp/acp-server.js +315 -0
- package/dist/modes/commands-core.d.ts +7 -1
- package/dist/modes/commands-core.js +55 -0
- package/dist/modes/image-input.d.ts +12 -4
- package/dist/modes/image-input.js +22 -5
- package/dist/modes/interactive/agent-panels.d.ts +14 -0
- package/dist/modes/interactive/agent-panels.js +103 -0
- package/dist/modes/interactive/agent-ui.d.ts +73 -0
- package/dist/modes/interactive/agent-ui.js +234 -0
- package/dist/modes/interactive/approval-dialog.d.ts +21 -4
- package/dist/modes/interactive/approval-dialog.js +98 -20
- package/dist/modes/interactive/approval-merge.d.ts +41 -0
- package/dist/modes/interactive/approval-merge.js +89 -0
- package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
- package/dist/modes/interactive/clipboard-paste.js +28 -0
- package/dist/modes/interactive/commands.d.ts +9 -1
- package/dist/modes/interactive/commands.js +19 -0
- package/dist/modes/interactive/double-esc.d.ts +20 -0
- package/dist/modes/interactive/double-esc.js +34 -0
- package/dist/modes/interactive/event-notices.d.ts +32 -0
- package/dist/modes/interactive/event-notices.js +79 -0
- package/dist/modes/interactive/external-editor.d.ts +16 -0
- package/dist/modes/interactive/external-editor.js +39 -0
- package/dist/modes/interactive/interactive-mode.d.ts +14 -1
- package/dist/modes/interactive/interactive-mode.js +134 -136
- package/dist/modes/interactive/key-dispatch.d.ts +16 -2
- package/dist/modes/interactive/key-dispatch.js +49 -1
- package/dist/modes/interactive/line/line-mode.d.ts +2 -1
- package/dist/modes/interactive/line/line-mode.js +22 -5
- package/dist/modes/interactive/line/line-render.d.ts +2 -1
- package/dist/modes/interactive/line/line-render.js +40 -4
- package/dist/modes/interactive/message-view.d.ts +1 -1
- package/dist/modes/interactive/message-view.js +24 -2
- package/dist/modes/interactive/panels.d.ts +18 -1
- package/dist/modes/interactive/panels.js +19 -5
- package/dist/modes/interactive/plan-command.d.ts +40 -0
- package/dist/modes/interactive/plan-command.js +129 -0
- package/dist/modes/interactive/plan-dialog.d.ts +98 -0
- package/dist/modes/interactive/plan-dialog.js +290 -0
- package/dist/modes/interactive/plan-flow.d.ts +34 -0
- package/dist/modes/interactive/plan-flow.js +98 -0
- package/dist/modes/interactive/rewind-command.d.ts +31 -0
- package/dist/modes/interactive/rewind-command.js +106 -0
- package/dist/modes/interactive/rewind-flow.d.ts +37 -0
- package/dist/modes/interactive/rewind-flow.js +151 -0
- package/dist/modes/interactive/rewind-list.d.ts +36 -0
- package/dist/modes/interactive/rewind-list.js +123 -0
- package/dist/modes/interactive/rewind-panel.d.ts +77 -0
- package/dist/modes/interactive/rewind-panel.js +309 -0
- package/dist/modes/interactive/rewind-text.d.ts +40 -0
- package/dist/modes/interactive/rewind-text.js +139 -0
- package/dist/modes/interactive/session-events.d.ts +24 -0
- package/dist/modes/interactive/session-events.js +96 -0
- package/dist/modes/interactive/status-area.d.ts +73 -0
- package/dist/modes/interactive/status-area.js +190 -0
- package/dist/modes/interactive/status-bar.d.ts +99 -11
- package/dist/modes/interactive/status-bar.js +273 -90
- package/dist/modes/interactive/status-line.d.ts +33 -0
- package/dist/modes/interactive/status-line.js +113 -0
- package/dist/modes/interactive/subagent-view.d.ts +56 -0
- package/dist/modes/interactive/subagent-view.js +154 -0
- package/dist/modes/interactive/tasks-report.d.ts +27 -0
- package/dist/modes/interactive/tasks-report.js +114 -0
- package/dist/modes/interactive/tool-view.d.ts +12 -2
- package/dist/modes/interactive/tool-view.js +34 -4
- package/dist/modes/print/print-mode.d.ts +13 -4
- package/dist/modes/print/print-mode.js +56 -12
- package/dist/modes/rpc/commands.d.ts +9 -0
- package/dist/modes/rpc/commands.js +44 -0
- package/dist/modes/rpc/rpc-mode.js +7 -1
- package/dist/modes/session-report.d.ts +11 -0
- package/dist/modes/session-report.js +48 -1
- package/dist/permissions/auto-safe.d.ts +5 -0
- package/dist/permissions/auto-safe.js +18 -0
- package/dist/permissions/classifier.d.ts +4 -0
- package/dist/permissions/classifier.js +2 -0
- package/dist/permissions/modes.js +1 -1
- package/dist/permissions/pipeline.d.ts +43 -4
- package/dist/permissions/pipeline.js +114 -9
- package/dist/permissions/readonly-bash.d.ts +30 -0
- package/dist/permissions/readonly-bash.js +118 -0
- package/dist/permissions/types.d.ts +42 -0
- package/dist/plan/compose.d.ts +9 -0
- package/dist/plan/compose.js +19 -0
- package/dist/plan/controller.d.ts +71 -0
- package/dist/plan/controller.js +27 -0
- package/dist/plan/done-markers.d.ts +17 -0
- package/dist/plan/done-markers.js +51 -0
- package/dist/plan/extract.d.ts +29 -0
- package/dist/plan/extract.js +160 -0
- package/dist/plan/prompts.d.ts +36 -0
- package/dist/plan/prompts.js +89 -0
- package/dist/plan/store.d.ts +37 -0
- package/dist/plan/store.js +90 -0
- package/dist/rpc.d.ts +58 -2
- package/dist/rpc.js +7 -0
- package/dist/sandbox/bash.d.ts +74 -0
- package/dist/sandbox/bash.js +126 -0
- package/dist/sandbox/detect.d.ts +48 -0
- package/dist/sandbox/detect.js +149 -0
- package/dist/sandbox/index.d.ts +5 -0
- package/dist/sandbox/index.js +5 -0
- package/dist/sandbox/profile.d.ts +33 -0
- package/dist/sandbox/profile.js +76 -0
- package/dist/sandbox/wrap.d.ts +29 -0
- package/dist/sandbox/wrap.js +117 -0
- package/dist/sdk.d.ts +33 -2
- package/dist/sdk.js +24 -2
- package/dist/session/types.d.ts +3 -1
- package/dist/session/types.js +1 -0
- package/dist/skills/builtin.d.ts +31 -0
- package/dist/skills/builtin.js +109 -0
- package/dist/skills/discover.d.ts +2 -1
- package/dist/skills/index-prompt.js +5 -8
- package/dist/tools/background-jobs.d.ts +71 -0
- package/dist/tools/background-jobs.js +198 -0
- package/dist/tools/bash.d.ts +53 -1
- package/dist/tools/bash.js +158 -7
- package/dist/tools/clipboard-image.d.ts +44 -0
- package/dist/tools/clipboard-image.js +148 -0
- package/dist/tools/edit.d.ts +2 -0
- package/dist/tools/edit.js +18 -3
- package/dist/tools/image-file.d.ts +38 -3
- package/dist/tools/image-file.js +81 -10
- package/dist/tools/image-resize.d.ts +58 -0
- package/dist/tools/image-resize.js +97 -0
- package/dist/tools/presets.d.ts +7 -2
- package/dist/tools/presets.js +11 -4
- package/dist/tools/read.d.ts +5 -2
- package/dist/tools/read.js +13 -10
- package/dist/tools/registry.d.ts +7 -1
- package/dist/tools/registry.js +27 -4
- package/dist/tools/task-ctl.d.ts +22 -0
- package/dist/tools/task-ctl.js +116 -0
- package/dist/tools/task.d.ts +22 -10
- package/dist/tools/task.js +66 -26
- package/dist/tools/todo.d.ts +22 -2
- package/dist/tools/todo.js +58 -14
- package/dist/tools/truncate.d.ts +15 -0
- package/dist/tools/truncate.js +25 -0
- package/dist/tools/types.d.ts +113 -0
- package/dist/tools/types.js +5 -0
- package/dist/tools/write.js +3 -0
- package/dist/tui/glyphs.d.ts +4 -0
- package/dist/tui/glyphs.js +4 -0
- package/dist/tui/keybindings.d.ts +5 -0
- package/dist/tui/keybindings.js +5 -0
- package/docs/acp.md +78 -0
- package/docs/agents.md +250 -0
- package/docs/codemode.md +12 -8
- package/docs/hooks.md +26 -22
- package/docs/permissions.md +77 -13
- package/docs/plan.md +107 -0
- package/docs/providers.md +228 -52
- package/docs/rewind-plan.md +181 -0
- package/docs/rpc.md +92 -5
- package/docs/sandbox.md +215 -0
- package/docs/session-format.md +41 -21
- package/docs/sessions.md +41 -1
- package/docs/tui-design.md +751 -0
- package/docs/tui.md +125 -6
- package/package.json +13 -2
|
@@ -10,17 +10,32 @@
|
|
|
10
10
|
* auth.json 的同名条目),没有时用供应商的 key。
|
|
11
11
|
*/
|
|
12
12
|
import type { ProviderConfig } from "../../config/types.js";
|
|
13
|
-
import type { Api, ProviderChannel } from "../types.js";
|
|
13
|
+
import type { Api, Model, ProviderChannel, ProviderData } from "../types.js";
|
|
14
14
|
/** 隐式渠道名(单渠道供应商)。 */
|
|
15
15
|
export declare const DEFAULT_CHANNEL = "default";
|
|
16
16
|
/** 渠道 key 在 key 解析里的键。 */
|
|
17
17
|
export declare function channelKeyId(providerId: string, channel: string): string;
|
|
18
|
-
/**
|
|
19
|
-
|
|
18
|
+
/**
|
|
19
|
+
* 内置渠道 ⊕ 用户渠道([W5-M2]):同名按字段覆盖(`headers` / `compat` 再合并一层)、新名追加在后。
|
|
20
|
+
*/
|
|
21
|
+
export declare function mergeChannels(base: readonly ProviderChannel[], user: readonly ProviderChannel[]): ProviderChannel[];
|
|
22
|
+
/**
|
|
23
|
+
* config 的 `channels` → 物化渠道表(跳过名字非法或缺 api / baseUrl 的,返回警告)。给了 `builtin`
|
|
24
|
+
* (内置供应商的内置渠道)时与之合并:同名渠道可只写要改的字段;`defaultChannel` 用户优先,其次内置。
|
|
25
|
+
*/
|
|
26
|
+
export declare function parseChannels(providerId: string, config: ProviderConfig, builtin?: {
|
|
27
|
+
channels: readonly ProviderChannel[];
|
|
28
|
+
defaultChannel: string | undefined;
|
|
29
|
+
}): {
|
|
20
30
|
channels: ProviderChannel[];
|
|
21
31
|
defaultChannel: string | undefined;
|
|
22
32
|
warnings: string[];
|
|
23
33
|
};
|
|
34
|
+
/**
|
|
35
|
+
* 内置供应商目录模型的渠道表:目录条目写了 `channels` 就用它(去掉不存在的),否则挂全部渠道;
|
|
36
|
+
* 缺省渠道在表里时排到首位(首个 = 首选)。
|
|
37
|
+
*/
|
|
38
|
+
export declare function catalogChannels(wanted: readonly string[] | undefined, known: readonly ProviderChannel[], defaultChannel: string): string[];
|
|
24
39
|
/** 模型的渠道表:去掉不存在的;空 → [defaultChannel]。 */
|
|
25
40
|
export declare function modelChannels(wanted: readonly string[] | undefined, known: readonly ProviderChannel[], defaultChannel: string, onUnknown: (name: string) => void): string[];
|
|
26
41
|
/**
|
|
@@ -49,3 +64,18 @@ export declare function modelRefOf(model: {
|
|
|
49
64
|
};
|
|
50
65
|
/** 协议的短名(表格用)。 */
|
|
51
66
|
export declare function apiShortName(api: Api): string;
|
|
67
|
+
/**
|
|
68
|
+
* 物化:模型补齐供应商级字段(不可变:返回新对象)。给了 `channel` 时协议与地址取渠道的(模型级
|
|
69
|
+
* `explicit` 覆盖优先),headers / compat 按 供应商 ← 渠道 ← 模型 合并,并记下渠道名。
|
|
70
|
+
*/
|
|
71
|
+
export declare function materializeModel(model: Model, provider: ProviderData, channel?: ProviderChannel, explicit?: {
|
|
72
|
+
api?: Api | undefined;
|
|
73
|
+
baseUrl?: string | undefined;
|
|
74
|
+
}): Model;
|
|
75
|
+
/** 内置渠道作废:按供应商级 api / baseUrl 单渠道处理。 */
|
|
76
|
+
export declare function dropChannels(provider: ProviderData): void;
|
|
77
|
+
/**
|
|
78
|
+
* 内置渠道 + 用户只改供应商级字段:改了 baseUrl → 内置渠道作废(单渠道回落);只写 `api` → 选同协议的
|
|
79
|
+
* 内置渠道作缺省(没有就作废);`defaultChannel` 必须是内置渠道名。
|
|
80
|
+
*/
|
|
81
|
+
export declare function pickBuiltinChannel(provider: ProviderData, config: ProviderConfig, warn: (message: string) => void): void;
|
|
@@ -10,37 +10,84 @@
|
|
|
10
10
|
* auth.json 的同名条目),没有时用供应商的 key。
|
|
11
11
|
*/
|
|
12
12
|
import { CHANNEL_NAME_PATTERN } from "../../config/types.js";
|
|
13
|
+
import { mergeHeaders } from "../http.js";
|
|
13
14
|
/** 隐式渠道名(单渠道供应商)。 */
|
|
14
15
|
export const DEFAULT_CHANNEL = "default";
|
|
15
16
|
/** 渠道 key 在 key 解析里的键。 */
|
|
16
17
|
export function channelKeyId(providerId, channel) {
|
|
17
18
|
return `${providerId}@${channel}`;
|
|
18
19
|
}
|
|
19
|
-
/**
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* 内置渠道 ⊕ 用户渠道([W5-M2]):同名按字段覆盖(`headers` / `compat` 再合并一层)、新名追加在后。
|
|
22
|
+
*/
|
|
23
|
+
export function mergeChannels(base, user) {
|
|
24
|
+
const out = base.map((c) => structuredClone(c));
|
|
25
|
+
for (const channel of user) {
|
|
26
|
+
const index = out.findIndex((c) => c.name === channel.name);
|
|
27
|
+
const current = out[index];
|
|
28
|
+
if (current === undefined) {
|
|
29
|
+
out.push(channel);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const next = { ...current, ...channel };
|
|
33
|
+
if (current.headers && channel.headers)
|
|
34
|
+
next.headers = { ...current.headers, ...channel.headers };
|
|
35
|
+
if (current.compat && channel.compat)
|
|
36
|
+
next.compat = { ...current.compat, ...channel.compat };
|
|
37
|
+
out[index] = next;
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* config 的 `channels` → 物化渠道表(跳过名字非法或缺 api / baseUrl 的,返回警告)。给了 `builtin`
|
|
43
|
+
* (内置供应商的内置渠道)时与之合并:同名渠道可只写要改的字段;`defaultChannel` 用户优先,其次内置。
|
|
44
|
+
*/
|
|
45
|
+
export function parseChannels(providerId, config, builtin) {
|
|
21
46
|
const warnings = [];
|
|
22
|
-
const
|
|
47
|
+
const own = [];
|
|
48
|
+
const known = new Set((builtin?.channels ?? []).map((c) => c.name));
|
|
23
49
|
for (const [name, raw] of Object.entries(config.channels ?? {})) {
|
|
24
50
|
const c = raw;
|
|
25
|
-
|
|
51
|
+
const partial = known.has(name);
|
|
52
|
+
if (!CHANNEL_NAME_PATTERN.test(name) || !c || (!partial && (!c.api || !c.baseUrl))) {
|
|
26
53
|
warnings.push(`provider "${providerId}" channel "${name}" is invalid; ignored`);
|
|
27
54
|
continue;
|
|
28
55
|
}
|
|
29
|
-
const channel = { name
|
|
56
|
+
const channel = { name };
|
|
57
|
+
if (c.api)
|
|
58
|
+
channel.api = c.api;
|
|
59
|
+
if (c.baseUrl)
|
|
60
|
+
channel.baseUrl = c.baseUrl;
|
|
30
61
|
if (c.authHeader !== undefined)
|
|
31
62
|
channel.authHeader = c.authHeader;
|
|
32
63
|
if (c.headers !== undefined)
|
|
33
64
|
channel.headers = { ...c.headers };
|
|
34
65
|
if (c.compat !== undefined)
|
|
35
66
|
channel.compat = { ...c.compat };
|
|
36
|
-
|
|
67
|
+
own.push(channel);
|
|
37
68
|
}
|
|
69
|
+
const channels = mergeChannels(builtin?.channels ?? [], own);
|
|
38
70
|
let defaultChannel = config.defaultChannel;
|
|
39
71
|
if (defaultChannel !== undefined && !channels.some((c) => c.name === defaultChannel)) {
|
|
40
72
|
warnings.push(`provider "${providerId}" defaultChannel "${defaultChannel}" not found`);
|
|
41
73
|
defaultChannel = undefined;
|
|
42
74
|
}
|
|
43
|
-
|
|
75
|
+
const fallback = channels.some((c) => c.name === builtin?.defaultChannel)
|
|
76
|
+
? builtin?.defaultChannel
|
|
77
|
+
: channels[0]?.name;
|
|
78
|
+
return { channels, defaultChannel: defaultChannel ?? fallback, warnings };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 内置供应商目录模型的渠道表:目录条目写了 `channels` 就用它(去掉不存在的),否则挂全部渠道;
|
|
82
|
+
* 缺省渠道在表里时排到首位(首个 = 首选)。
|
|
83
|
+
*/
|
|
84
|
+
export function catalogChannels(wanted, known, defaultChannel) {
|
|
85
|
+
const names = known.map((c) => c.name);
|
|
86
|
+
const list = wanted === undefined ? names : wanted.filter((name) => names.includes(name));
|
|
87
|
+
const out = list.includes(defaultChannel)
|
|
88
|
+
? [defaultChannel, ...list.filter((name) => name !== defaultChannel)]
|
|
89
|
+
: [...list];
|
|
90
|
+
return out.length > 0 ? out : [defaultChannel];
|
|
44
91
|
}
|
|
45
92
|
/** 模型的渠道表:去掉不存在的;空 → [defaultChannel]。 */
|
|
46
93
|
export function modelChannels(wanted, known, defaultChannel, onUnknown) {
|
|
@@ -94,3 +141,57 @@ export function apiShortName(api) {
|
|
|
94
141
|
return api;
|
|
95
142
|
}
|
|
96
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* 物化:模型补齐供应商级字段(不可变:返回新对象)。给了 `channel` 时协议与地址取渠道的(模型级
|
|
146
|
+
* `explicit` 覆盖优先),headers / compat 按 供应商 ← 渠道 ← 模型 合并,并记下渠道名。
|
|
147
|
+
*/
|
|
148
|
+
export function materializeModel(model, provider, channel, explicit) {
|
|
149
|
+
const out = {
|
|
150
|
+
...model,
|
|
151
|
+
provider: provider.id,
|
|
152
|
+
baseUrl: model.baseUrl ?? provider.baseUrl,
|
|
153
|
+
};
|
|
154
|
+
if (channel !== undefined) {
|
|
155
|
+
out.api = explicit?.api ?? channel.api;
|
|
156
|
+
out.baseUrl = explicit?.baseUrl ?? channel.baseUrl;
|
|
157
|
+
out.channel = channel.name;
|
|
158
|
+
}
|
|
159
|
+
if (provider.headers || channel?.headers || model.headers)
|
|
160
|
+
out.headers = mergeHeaders(provider.headers, channel?.headers, model.headers);
|
|
161
|
+
if (provider.compat || channel?.compat || model.compat)
|
|
162
|
+
out.compat = { ...provider.compat, ...channel?.compat, ...model.compat };
|
|
163
|
+
const authHeader = channel?.authHeader ?? provider.authHeader;
|
|
164
|
+
if (authHeader !== undefined)
|
|
165
|
+
out.authHeader = model.authHeader ?? authHeader;
|
|
166
|
+
out.requiresApiKey = provider.requiresApiKey;
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
/** 内置渠道作废:按供应商级 api / baseUrl 单渠道处理。 */
|
|
170
|
+
export function dropChannels(provider) {
|
|
171
|
+
delete provider.channels;
|
|
172
|
+
delete provider.defaultChannel;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 内置渠道 + 用户只改供应商级字段:改了 baseUrl → 内置渠道作废(单渠道回落);只写 `api` → 选同协议的
|
|
176
|
+
* 内置渠道作缺省(没有就作废);`defaultChannel` 必须是内置渠道名。
|
|
177
|
+
*/
|
|
178
|
+
export function pickBuiltinChannel(provider, config, warn) {
|
|
179
|
+
if (config.baseUrl !== undefined) {
|
|
180
|
+
dropChannels(provider);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const channels = provider.channels ?? [];
|
|
184
|
+
if (config.defaultChannel !== undefined) {
|
|
185
|
+
if (channels.some((c) => c.name === config.defaultChannel))
|
|
186
|
+
provider.defaultChannel = config.defaultChannel;
|
|
187
|
+
else
|
|
188
|
+
warn(`provider "${provider.id}" defaultChannel "${config.defaultChannel}" not found`);
|
|
189
|
+
}
|
|
190
|
+
else if (config.api !== undefined) {
|
|
191
|
+
const same = channels.find((c) => c.api === config.api);
|
|
192
|
+
if (same !== undefined)
|
|
193
|
+
provider.defaultChannel = same.name;
|
|
194
|
+
else
|
|
195
|
+
dropChannels(provider);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* 用 models.dev 缓存给自定义模型补元数据(docs/providers.md「模型元数据:models.dev」)。
|
|
3
3
|
*
|
|
4
4
|
* 优先级:用户配置写了的字段 > models.dev > 自定义缺省(maxTokens 8192、input ["text"]、
|
|
5
|
-
* reasoning false、不猜 contextWindow
|
|
6
|
-
*
|
|
5
|
+
* reasoning false、不猜 contextWindow)。内置目录的模型不经过这里:目录在 catalog.ts 里已经
|
|
6
|
+
* 「快照 ⊕ 覆盖」合并好([W5-M1]),这里只给它们标来源。只读传入的索引,不联网。
|
|
7
7
|
*/
|
|
8
8
|
import type { ModelConfig } from "../../config/types.js";
|
|
9
9
|
import type { Model } from "../types.js";
|
|
@@ -29,6 +29,9 @@ export declare function enrichEntry(entry: ModelConfig, index: () => ModelsDevIn
|
|
|
29
29
|
entry: Omit<ModelConfig, "modelsDev" | "channels">;
|
|
30
30
|
metadata: ModelMetadata;
|
|
31
31
|
};
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* 内置目录模型的来源:目录自己写的为 catalog,从入库快照继承的为 models.dev(catalog.ts),
|
|
34
|
+
* 都没有的为缺省。
|
|
35
|
+
*/
|
|
33
36
|
export declare function catalogMetadata(model: Model): ModelMetadata;
|
|
34
37
|
export declare function sourceText(source: FieldSource): string;
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* 用 models.dev 缓存给自定义模型补元数据(docs/providers.md「模型元数据:models.dev」)。
|
|
3
3
|
*
|
|
4
4
|
* 优先级:用户配置写了的字段 > models.dev > 自定义缺省(maxTokens 8192、input ["text"]、
|
|
5
|
-
* reasoning false、不猜 contextWindow
|
|
6
|
-
*
|
|
5
|
+
* reasoning false、不猜 contextWindow)。内置目录的模型不经过这里:目录在 catalog.ts 里已经
|
|
6
|
+
* 「快照 ⊕ 覆盖」合并好([W5-M1]),这里只给它们标来源。只读传入的索引,不联网。
|
|
7
7
|
*/
|
|
8
|
+
import { catalogInherited } from "./catalog.js";
|
|
8
9
|
import { ENRICHABLE_FIELDS, modelsDevFields, } from "./models-dev.js";
|
|
9
10
|
/** 惰性取索引:只有真的要补字段时才读缓存(启动时没有自定义模型就不读约 2 MB 的缓存)。 */
|
|
10
11
|
export function lazyIndex(source) {
|
|
@@ -25,6 +26,8 @@ export function lazyIndex(source) {
|
|
|
25
26
|
return index;
|
|
26
27
|
};
|
|
27
28
|
}
|
|
29
|
+
/** 只作说明的元数据(不进来源表):缺了就从 models.dev 补。 */
|
|
30
|
+
const METADATA_FIELDS = ["family", "knowledge", "releaseDate", "inputLimit", "status"];
|
|
28
31
|
function needsLookup(entry) {
|
|
29
32
|
return ENRICHABLE_FIELDS.some((field) => entry[field] === undefined);
|
|
30
33
|
}
|
|
@@ -65,13 +68,25 @@ export function enrichEntry(entry, index) {
|
|
|
65
68
|
}
|
|
66
69
|
if (out.name === undefined && fields.name !== undefined)
|
|
67
70
|
out.name = fields.name;
|
|
71
|
+
for (const field of METADATA_FIELDS) {
|
|
72
|
+
if (out[field] === undefined && fields[field] !== undefined)
|
|
73
|
+
out[field] = fields[field];
|
|
74
|
+
}
|
|
68
75
|
return { entry: out, metadata };
|
|
69
76
|
}
|
|
70
|
-
/**
|
|
77
|
+
/**
|
|
78
|
+
* 内置目录模型的来源:目录自己写的为 catalog,从入库快照继承的为 models.dev(catalog.ts),
|
|
79
|
+
* 都没有的为缺省。
|
|
80
|
+
*/
|
|
71
81
|
export function catalogMetadata(model) {
|
|
82
|
+
const inherited = catalogInherited(model.provider, model.id);
|
|
72
83
|
const sources = {};
|
|
73
84
|
for (const field of ENRICHABLE_FIELDS) {
|
|
74
|
-
sources[field] =
|
|
85
|
+
sources[field] = inherited.includes(field)
|
|
86
|
+
? "models.dev"
|
|
87
|
+
: model[field] !== undefined
|
|
88
|
+
? "catalog"
|
|
89
|
+
: "default";
|
|
75
90
|
}
|
|
76
91
|
return { sources, looked: false };
|
|
77
92
|
}
|
|
@@ -1,53 +1,57 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* models.dev
|
|
2
|
+
* models.dev 索引 = 内置快照 ⊕ 用户级覆盖(docs/wave5-plan.md §2.2、docs/providers.md「模型元数据」)。
|
|
3
3
|
*
|
|
4
|
-
* -
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* - 内置快照随 bundle 携带(models-dev-snapshot.ts),**启动与运行都不联网**。
|
|
5
|
+
* - 覆盖文件 `<dataDir>/models-dev.json`:`{ version: 2, url, fetchedAt, providers }`,只有
|
|
6
|
+
* `ama models refresh` 会写(`refreshModelsDev()`,显式联网,按快照同一清单裁剪)。存在且
|
|
7
|
+
* fetchedAt 晚于快照才叠加;同 provider/model 以覆盖为准。旧版(version 1,全量 2 MB 缓存)忽略。
|
|
8
|
+
* - `loadModelsDevIndex()` 按覆盖文件路径 + mtime + 大小记忆,同一进程只解析一次。
|
|
9
|
+
* - `AMA_MODELS_DEV_URL` 换刷新的数据源。
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import type { ModelsDevData, ModelsDevIndex } from "./models-dev.js";
|
|
12
|
+
import { type SnapshotDiff } from "./models-dev-snapshot.js";
|
|
12
13
|
export declare const MODELS_DEV_URL = "https://models.dev/api.json";
|
|
13
14
|
export declare const MODELS_DEV_URL_ENV = "AMA_MODELS_DEV_URL";
|
|
14
15
|
export declare const MODELS_DEV_FILE = "models-dev.json";
|
|
15
|
-
export declare const
|
|
16
|
-
export declare const MODELS_DEV_TIMEOUT_MS = 30000;
|
|
16
|
+
export declare const MODELS_DEV_TIMEOUT_MS = 60000;
|
|
17
17
|
export interface ModelsDevCacheFile {
|
|
18
|
-
version:
|
|
18
|
+
version: 2;
|
|
19
19
|
url: string;
|
|
20
20
|
/** ISO 8601。 */
|
|
21
21
|
fetchedAt: string;
|
|
22
|
-
etag?: string;
|
|
23
22
|
providers: ModelsDevData;
|
|
24
23
|
}
|
|
25
24
|
export declare function modelsDevCachePath(dataDir: string): string;
|
|
26
25
|
export declare function modelsDevUrl(env?: Readonly<Record<string, string | undefined>>): string;
|
|
27
|
-
/**
|
|
26
|
+
/** 读覆盖文件;不存在、旧版或损坏返回 undefined(损坏不报错:下次 refresh 会覆盖)。 */
|
|
28
27
|
export declare function readModelsDevCache(dataDir: string): ModelsDevCacheFile | undefined;
|
|
29
28
|
export declare function writeModelsDevCache(dataDir: string, file: ModelsDevCacheFile): void;
|
|
30
|
-
/**
|
|
31
|
-
export declare function
|
|
32
|
-
|
|
29
|
+
/** 覆盖文件是否生效:fetchedAt 晚于内置快照。 */
|
|
30
|
+
export declare function overrideApplies(file: ModelsDevCacheFile): boolean;
|
|
31
|
+
/** 快照 ⊕ 覆盖(零网络;没有覆盖文件时只做一次 stat)。 */
|
|
32
|
+
export declare function loadModelsDevIndex(dataDir: string): ModelsDevIndex;
|
|
33
|
+
/** 当前索引的来源说明(`providers add` / `models discover` 输出用)。 */
|
|
34
|
+
export declare function describeModelsDev(dataDir: string): string;
|
|
35
|
+
export type RefreshStatus = "updated" | "unchanged" | "failed";
|
|
33
36
|
export interface RefreshResult {
|
|
34
37
|
status: RefreshStatus;
|
|
35
|
-
index?: ModelsDevIndex;
|
|
36
|
-
fetchedAt?: string;
|
|
37
38
|
url: string;
|
|
39
|
+
fetchedAt?: string;
|
|
40
|
+
/** 与刷新前的索引(快照 ⊕ 旧覆盖)相比。 */
|
|
41
|
+
diff?: SnapshotDiff;
|
|
42
|
+
index: ModelsDevIndex;
|
|
38
43
|
warning?: string;
|
|
39
44
|
}
|
|
40
45
|
export interface RefreshOptions {
|
|
41
46
|
dataDir: string;
|
|
42
47
|
env?: Readonly<Record<string, string | undefined>>;
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
ttlMs?: number;
|
|
48
|
+
/** 只刷新这几家(须在快照清单里)。 */
|
|
49
|
+
providers?: readonly string[];
|
|
46
50
|
timeoutMs?: number;
|
|
47
51
|
now?: () => number;
|
|
48
52
|
fetch?: typeof fetch;
|
|
49
53
|
}
|
|
50
|
-
/**
|
|
54
|
+
/** 显式联网刷新(只被 `ama models refresh` 调用):拉 api.json、按清单裁剪、写用户级覆盖。 */
|
|
51
55
|
export declare function refreshModelsDev(options: RefreshOptions): Promise<RefreshResult>;
|
|
52
|
-
/**
|
|
53
|
-
export declare function describeRefresh(result: RefreshResult): string;
|
|
56
|
+
/** 刷新结果的说明(命令输出用):一行状态 + 新增 / 删除 / 变化清单。 */
|
|
57
|
+
export declare function describeRefresh(result: RefreshResult, limit?: number): string;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* models.dev
|
|
2
|
+
* models.dev 索引 = 内置快照 ⊕ 用户级覆盖(docs/wave5-plan.md §2.2、docs/providers.md「模型元数据」)。
|
|
3
3
|
*
|
|
4
|
-
* -
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
4
|
+
* - 内置快照随 bundle 携带(models-dev-snapshot.ts),**启动与运行都不联网**。
|
|
5
|
+
* - 覆盖文件 `<dataDir>/models-dev.json`:`{ version: 2, url, fetchedAt, providers }`,只有
|
|
6
|
+
* `ama models refresh` 会写(`refreshModelsDev()`,显式联网,按快照同一清单裁剪)。存在且
|
|
7
|
+
* fetchedAt 晚于快照才叠加;同 provider/model 以覆盖为准。旧版(version 1,全量 2 MB 缓存)忽略。
|
|
8
|
+
* - `loadModelsDevIndex()` 按覆盖文件路径 + mtime + 大小记忆,同一进程只解析一次。
|
|
9
|
+
* - `AMA_MODELS_DEV_URL` 换刷新的数据源。
|
|
10
10
|
*/
|
|
11
11
|
import { mkdirSync, readFileSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
12
12
|
import { dirname, join } from "node:path";
|
|
13
|
-
import { ModelsDevIndex
|
|
13
|
+
import { ModelsDevIndex as Index } from "./models-dev.js";
|
|
14
|
+
import { buildSnapshot, builtinSnapshot, builtinSnapshotIndex, diffSnapshots, mergeSnapshot, snapshotList, snapshotMeta, } from "./models-dev-snapshot.js";
|
|
14
15
|
export const MODELS_DEV_URL = "https://models.dev/api.json";
|
|
15
16
|
export const MODELS_DEV_URL_ENV = "AMA_MODELS_DEV_URL";
|
|
16
17
|
export const MODELS_DEV_FILE = "models-dev.json";
|
|
17
|
-
export const
|
|
18
|
-
export const MODELS_DEV_TIMEOUT_MS = 30_000;
|
|
18
|
+
export const MODELS_DEV_TIMEOUT_MS = 60_000;
|
|
19
19
|
export function modelsDevCachePath(dataDir) {
|
|
20
20
|
return join(dataDir, MODELS_DEV_FILE);
|
|
21
21
|
}
|
|
@@ -23,14 +23,16 @@ export function modelsDevUrl(env = process.env) {
|
|
|
23
23
|
const custom = env[MODELS_DEV_URL_ENV]?.trim();
|
|
24
24
|
return custom ? custom : MODELS_DEV_URL;
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
26
|
+
/** 读覆盖文件;不存在、旧版或损坏返回 undefined(损坏不报错:下次 refresh 会覆盖)。 */
|
|
27
27
|
export function readModelsDevCache(dataDir) {
|
|
28
28
|
try {
|
|
29
29
|
const value = JSON.parse(readFileSync(modelsDevCachePath(dataDir), "utf8"));
|
|
30
30
|
if (typeof value !== "object" || value === null)
|
|
31
31
|
return undefined;
|
|
32
32
|
const file = value;
|
|
33
|
-
if (file.version !==
|
|
33
|
+
if (file.version !== 2 || typeof file.fetchedAt !== "string")
|
|
34
|
+
return undefined;
|
|
35
|
+
if (Number.isNaN(Date.parse(file.fetchedAt)))
|
|
34
36
|
return undefined;
|
|
35
37
|
if (typeof file.providers !== "object" || file.providers === null)
|
|
36
38
|
return undefined;
|
|
@@ -48,8 +50,12 @@ export function writeModelsDevCache(dataDir, file) {
|
|
|
48
50
|
renameSync(tmp, path);
|
|
49
51
|
memo = undefined;
|
|
50
52
|
}
|
|
53
|
+
/** 覆盖文件是否生效:fetchedAt 晚于内置快照。 */
|
|
54
|
+
export function overrideApplies(file) {
|
|
55
|
+
return Date.parse(file.fetchedAt) > Date.parse(snapshotMeta().fetchedAt);
|
|
56
|
+
}
|
|
51
57
|
let memo;
|
|
52
|
-
/**
|
|
58
|
+
/** 快照 ⊕ 覆盖(零网络;没有覆盖文件时只做一次 stat)。 */
|
|
53
59
|
export function loadModelsDevIndex(dataDir) {
|
|
54
60
|
const path = modelsDevCachePath(dataDir);
|
|
55
61
|
let key;
|
|
@@ -58,90 +64,98 @@ export function loadModelsDevIndex(dataDir) {
|
|
|
58
64
|
key = `${path}\0${stat.mtimeMs}\0${stat.size}`;
|
|
59
65
|
}
|
|
60
66
|
catch {
|
|
61
|
-
return
|
|
67
|
+
return builtinSnapshotIndex();
|
|
62
68
|
}
|
|
63
69
|
if (memo?.key === key)
|
|
64
70
|
return memo.index;
|
|
65
71
|
const file = readModelsDevCache(dataDir);
|
|
66
|
-
const index = file !== undefined
|
|
72
|
+
const index = file !== undefined && overrideApplies(file)
|
|
73
|
+
? new Index(mergeSnapshot(builtinSnapshot(), file.providers))
|
|
74
|
+
: builtinSnapshotIndex();
|
|
67
75
|
memo = { key, index };
|
|
68
76
|
return index;
|
|
69
77
|
}
|
|
70
|
-
/**
|
|
78
|
+
/** 当前索引的来源说明(`providers add` / `models discover` 输出用)。 */
|
|
79
|
+
export function describeModelsDev(dataDir) {
|
|
80
|
+
const index = loadModelsDevIndex(dataDir);
|
|
81
|
+
const file = readModelsDevCache(dataDir);
|
|
82
|
+
const size = `${index.providerCount} 家供应商、${index.modelCount} 个模型`;
|
|
83
|
+
const via = file !== undefined && overrideApplies(file)
|
|
84
|
+
? `快照 ${snapshotMeta().fetchedAt} ⊕ 刷新 ${file.fetchedAt}`
|
|
85
|
+
: `快照 ${snapshotMeta().fetchedAt}`;
|
|
86
|
+
return `models.dev:${via}(${size})`;
|
|
87
|
+
}
|
|
88
|
+
/** 显式联网刷新(只被 `ama models refresh` 调用):拉 api.json、按清单裁剪、写用户级覆盖。 */
|
|
71
89
|
export async function refreshModelsDev(options) {
|
|
72
90
|
const url = modelsDevUrl(options.env);
|
|
73
91
|
const now = options.now ?? Date.now;
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
url,
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
const doFetch = options.fetch ?? fetch;
|
|
92
|
+
const before = loadModelsDevIndex(options.dataDir);
|
|
93
|
+
const fail = (reason) => ({
|
|
94
|
+
status: "failed",
|
|
95
|
+
url,
|
|
96
|
+
index: before,
|
|
97
|
+
warning: `models.dev 刷新失败(${reason}),沿用现有数据`,
|
|
98
|
+
});
|
|
99
|
+
const list = snapshotList();
|
|
100
|
+
const unknown = (options.providers ?? []).filter((p) => !list.providers.includes(p));
|
|
101
|
+
if (unknown.length > 0)
|
|
102
|
+
return fail(`不在收录清单里:${unknown.join(", ")};可选 ${list.providers.join(", ")}`);
|
|
103
|
+
let fresh;
|
|
90
104
|
try {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
headers["if-none-match"] = cached.etag;
|
|
94
|
-
const response = await doFetch(url, {
|
|
95
|
-
headers,
|
|
105
|
+
const response = await (options.fetch ?? fetch)(url, {
|
|
106
|
+
headers: { accept: "application/json" },
|
|
96
107
|
signal: AbortSignal.timeout(options.timeoutMs ?? MODELS_DEV_TIMEOUT_MS),
|
|
97
108
|
});
|
|
98
|
-
const fetchedAt = new Date(now()).toISOString();
|
|
99
|
-
if (response.status === 304 && cached !== undefined) {
|
|
100
|
-
writeModelsDevCache(options.dataDir, { ...cached, fetchedAt });
|
|
101
|
-
return { status: "not-modified", index: cachedIndex(), fetchedAt, url };
|
|
102
|
-
}
|
|
103
109
|
if (!response.ok)
|
|
104
110
|
throw new Error(`HTTP ${response.status}`);
|
|
105
|
-
|
|
106
|
-
const etag = response.headers.get("etag") ?? undefined;
|
|
107
|
-
writeModelsDevCache(options.dataDir, {
|
|
108
|
-
version: 1,
|
|
109
|
-
url,
|
|
110
|
-
fetchedAt,
|
|
111
|
-
...(etag !== undefined ? { etag } : {}),
|
|
112
|
-
providers,
|
|
113
|
-
});
|
|
114
|
-
return { status: "updated", index: new ModelsDevIndex(providers), fetchedAt, url };
|
|
111
|
+
fresh = buildSnapshot(await response.json(), list, options.providers);
|
|
115
112
|
}
|
|
116
113
|
catch (error) {
|
|
117
|
-
|
|
118
|
-
if (cached !== undefined) {
|
|
119
|
-
return {
|
|
120
|
-
status: "stale",
|
|
121
|
-
index: cachedIndex(),
|
|
122
|
-
fetchedAt: cached.fetchedAt,
|
|
123
|
-
url,
|
|
124
|
-
warning: `models.dev 拉取失败(${reason}),沿用 ${cached.fetchedAt} 的缓存`,
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
return {
|
|
128
|
-
status: "unavailable",
|
|
129
|
-
url,
|
|
130
|
-
warning: `models.dev 拉取失败(${reason}),没有缓存可用`,
|
|
131
|
-
};
|
|
114
|
+
return fail(error instanceof Error ? error.message : String(error));
|
|
132
115
|
}
|
|
116
|
+
const fetchedAt = new Date(now()).toISOString();
|
|
117
|
+
const previous = readModelsDevCache(options.dataDir);
|
|
118
|
+
const kept = previous !== undefined && overrideApplies(previous) ? previous.providers : {};
|
|
119
|
+
writeModelsDevCache(options.dataDir, {
|
|
120
|
+
version: 2,
|
|
121
|
+
url,
|
|
122
|
+
fetchedAt,
|
|
123
|
+
providers: { ...kept, ...fresh },
|
|
124
|
+
});
|
|
125
|
+
const diff = diffSnapshots(before.data, fresh);
|
|
126
|
+
const changed = diff.added.length + diff.removed.length + diff.changed.length > 0;
|
|
127
|
+
return {
|
|
128
|
+
status: changed ? "updated" : "unchanged",
|
|
129
|
+
url,
|
|
130
|
+
fetchedAt,
|
|
131
|
+
diff,
|
|
132
|
+
index: loadModelsDevIndex(options.dataDir),
|
|
133
|
+
};
|
|
133
134
|
}
|
|
134
|
-
/**
|
|
135
|
-
export function describeRefresh(result) {
|
|
136
|
-
const size = result.index
|
|
137
|
-
? `${result.index.providerCount} 家供应商、${result.index.modelCount} 个模型`
|
|
138
|
-
: "无数据";
|
|
135
|
+
/** 刷新结果的说明(命令输出用):一行状态 + 新增 / 删除 / 变化清单。 */
|
|
136
|
+
export function describeRefresh(result, limit = 20) {
|
|
137
|
+
const size = `${result.index.providerCount} 家供应商、${result.index.modelCount} 个模型`;
|
|
139
138
|
const text = {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
stale: "拉取失败,用旧缓存",
|
|
144
|
-
unavailable: "不可用",
|
|
139
|
+
updated: "已刷新",
|
|
140
|
+
unchanged: "已刷新,无变化",
|
|
141
|
+
failed: "刷新失败",
|
|
145
142
|
};
|
|
146
|
-
|
|
143
|
+
const lines = [
|
|
144
|
+
`models.dev:${text[result.status]}(${size}${result.fetchedAt ? `,${result.fetchedAt}` : ""})`,
|
|
145
|
+
];
|
|
146
|
+
const section = (title, items) => {
|
|
147
|
+
if (items.length === 0)
|
|
148
|
+
return;
|
|
149
|
+
lines.push(`${title}(${items.length}):`);
|
|
150
|
+
for (const item of items.slice(0, limit))
|
|
151
|
+
lines.push(` ${item}`);
|
|
152
|
+
if (items.length > limit)
|
|
153
|
+
lines.push(` …另 ${items.length - limit} 条`);
|
|
154
|
+
};
|
|
155
|
+
if (result.diff !== undefined) {
|
|
156
|
+
section("新增", result.diff.added);
|
|
157
|
+
section("上游删除(快照里的条目保留)", result.diff.removed);
|
|
158
|
+
section("变化", result.diff.changed);
|
|
159
|
+
}
|
|
160
|
+
return lines.join("\n");
|
|
147
161
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 由 scripts/update-models-dev.mjs 生成,勿手改(docs/providers.md「模型元数据」)。
|
|
3
|
+
*
|
|
4
|
+
* 数据来自 models.dev(https://models.dev/api.json,github.com/anomalyco/models.dev),MIT 许可:
|
|
5
|
+
* Copyright (c) 2025 models.dev。完整声明见 THIRD_PARTY_NOTICES.md。
|
|
6
|
+
*/
|
|
7
|
+
export declare const MODELS_DEV_SOURCES: Readonly<Record<string, string>>;
|