@alumbwe/anvil 1.0.20 → 1.0.22
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/package.json +74 -70
- package/src/agents/bundled-agents.generated.ts +4 -4
- package/src/chat.tsx +1703 -1698
- package/src/cli-args.ts +134 -134
- package/src/components/status-bar.tsx +331 -313
- package/src/hooks/helpers/send-message.ts +663 -654
- package/src/hooks/use-send-message.ts +806 -773
- package/src/index.tsx +473 -473
- package/src/state/chat-store.ts +553 -544
- package/src/utils/create-run-config.ts +121 -121
- package/src/utils/format-compact-number.ts +37 -0
- package/vendor/@anvil/common/package.json +27 -0
- package/vendor/@anvil/common/src/__tests__/agent-validation.test.ts +846 -0
- package/vendor/@anvil/common/src/__tests__/anvil-model-availability.test.ts +101 -0
- package/vendor/@anvil/common/src/__tests__/anvil-models.test.ts +1408 -0
- package/vendor/@anvil/common/src/__tests__/anvil-public-data-use-copy.test.ts +258 -0
- package/vendor/@anvil/common/src/__tests__/anvil-referral-tiers.test.ts +48 -0
- package/vendor/@anvil/common/src/__tests__/anvil-spend-ceilings.test.ts +282 -0
- package/vendor/@anvil/common/src/__tests__/anvil-trust.test.ts +526 -0
- package/vendor/@anvil/common/src/__tests__/deepseek-direct.test.ts +68 -0
- package/vendor/@anvil/common/src/__tests__/disposable-email.test.ts +132 -0
- package/vendor/@anvil/common/src/__tests__/dynamic-agent-template-schema.test.ts +422 -0
- package/vendor/@anvil/common/src/__tests__/env-ci.test.ts +167 -0
- package/vendor/@anvil/common/src/__tests__/env-process.test.ts +145 -0
- package/vendor/@anvil/common/src/__tests__/foreign-client-shipped-agents.test.ts +234 -0
- package/vendor/@anvil/common/src/__tests__/foreign-client-signals.test.ts +379 -0
- package/vendor/@anvil/common/src/__tests__/free-agents.test.ts +807 -0
- package/vendor/@anvil/common/src/__tests__/gravity-capi.test.ts +154 -0
- package/vendor/@anvil/common/src/__tests__/handlesteps-parsing.test.ts +246 -0
- package/vendor/@anvil/common/src/__tests__/kimi-k3-god-only.test.ts +77 -0
- package/vendor/@anvil/common/src/__tests__/model-config.test.ts +89 -0
- package/vendor/@anvil/common/src/__tests__/project-file-tree.test.ts +298 -0
- package/vendor/@anvil/common/src/__tests__/provisioned-model-tiers.test.ts +116 -0
- package/vendor/@anvil/common/src/__tests__/reasoning-effort.test.ts +167 -0
- package/vendor/@anvil/common/src/__tests__/reddit-capi.test.ts +132 -0
- package/vendor/@anvil/common/src/__tests__/response-ad-positions.test.ts +72 -0
- package/vendor/@anvil/common/src/__tests__/user-state.test.ts +30 -0
- package/vendor/@anvil/common/src/actions.ts +215 -0
- package/vendor/@anvil/common/src/analytics-core.ts +69 -0
- package/vendor/@anvil/common/src/analytics.ts +93 -0
- package/vendor/@anvil/common/src/api-keys/constants.ts +26 -0
- package/vendor/@anvil/common/src/browser-actions.ts +413 -0
- package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding-gate.test.ts +63 -0
- package/vendor/@anvil/common/src/constants/__tests__/anvil-onboarding.test.ts +246 -0
- package/vendor/@anvil/common/src/constants/__tests__/cf-worker-signals.test.ts +106 -0
- package/vendor/@anvil/common/src/constants/agents.ts +99 -0
- package/vendor/@anvil/common/src/constants/analytics-events.ts +435 -0
- package/vendor/@anvil/common/src/constants/anthropic.ts +73 -0
- package/vendor/@anvil/common/src/constants/anvil-data-use.ts +81 -0
- package/vendor/@anvil/common/src/constants/anvil-errors.ts +7 -0
- package/vendor/@anvil/common/src/constants/anvil-gemini-thinker.ts +21 -0
- package/vendor/@anvil/common/src/constants/anvil-model-ids.ts +11 -0
- package/vendor/@anvil/common/src/constants/anvil-models.ts +2130 -0
- package/vendor/@anvil/common/src/constants/anvil-onboarding-gate.ts +55 -0
- package/vendor/@anvil/common/src/constants/anvil-onboarding.ts +307 -0
- package/vendor/@anvil/common/src/constants/anvil-referral-tiers.ts +87 -0
- package/vendor/@anvil/common/src/constants/anvil-signup-block.ts +68 -0
- package/vendor/@anvil/common/src/constants/anvil-spend-ceilings.ts +450 -0
- package/vendor/@anvil/common/src/constants/anvil-trust.ts +976 -0
- package/vendor/@anvil/common/src/constants/auth.ts +18 -0
- package/vendor/@anvil/common/src/constants/byok.ts +2 -0
- package/vendor/@anvil/common/src/constants/cf-worker-signals.ts +132 -0
- package/vendor/@anvil/common/src/constants/composio.ts +34 -0
- package/vendor/@anvil/common/src/constants/deepseek-direct.ts +55 -0
- package/vendor/@anvil/common/src/constants/feedback.ts +13 -0
- package/vendor/@anvil/common/src/constants/foreign-client-signals.ts +272 -0
- package/vendor/@anvil/common/src/constants/free-agents.ts +777 -0
- package/vendor/@anvil/common/src/constants/gemini.ts +15 -0
- package/vendor/@anvil/common/src/constants/grant-priorities.ts +13 -0
- package/vendor/@anvil/common/src/constants/hosts.ts +6 -0
- package/vendor/@anvil/common/src/constants/images.ts +51 -0
- package/vendor/@anvil/common/src/constants/index.ts +7 -0
- package/vendor/@anvil/common/src/constants/knowledge.ts +35 -0
- package/vendor/@anvil/common/src/constants/limits.ts +23 -0
- package/vendor/@anvil/common/src/constants/model-config.ts +277 -0
- package/vendor/@anvil/common/src/constants/openrouter-attribution.ts +8 -0
- package/vendor/@anvil/common/src/constants/paths.ts +69 -0
- package/vendor/@anvil/common/src/constants/provider-routes.ts +317 -0
- package/vendor/@anvil/common/src/constants/reasoning-effort.ts +79 -0
- package/vendor/@anvil/common/src/constants/skills.ts +60 -0
- package/vendor/@anvil/common/src/constants/subscription-plans.ts +49 -0
- package/vendor/@anvil/common/src/constants/ui.ts +25 -0
- package/vendor/@anvil/common/src/env-ci.ts +36 -0
- package/vendor/@anvil/common/src/env-process.ts +95 -0
- package/vendor/@anvil/common/src/env-schema.ts +95 -0
- package/vendor/@anvil/common/src/env.ts +24 -0
- package/vendor/@anvil/common/src/gravity-capi.ts +207 -0
- package/vendor/@anvil/common/src/mcp/client.ts +233 -0
- package/vendor/@anvil/common/src/old-constants.ts +10 -0
- package/vendor/@anvil/common/src/project-file-tree.ts +355 -0
- package/vendor/@anvil/common/src/reddit-capi.ts +254 -0
- package/vendor/@anvil/common/src/schemas/feedback.ts +52 -0
- package/vendor/@anvil/common/src/schemas/logs.ts +66 -0
- package/vendor/@anvil/common/src/templates/agent-validation.ts +392 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/LICENSE +202 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/README.md +294 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/01-basic-diff-reviewer.ts +17 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/02-intermediate-git-committer.ts +78 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/examples/03-advanced-file-explorer.ts +73 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/my-custom-agent.ts +40 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/package.json +6 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/skills/README.md +65 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/skills/example-skill/SKILL.md +29 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/types/agent-definition.ts +497 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/types/tools.ts +444 -0
- package/vendor/@anvil/common/src/templates/initial-agents-dir/types/util-types.ts +178 -0
- package/vendor/@anvil/common/src/testing/TESTING_PATTERNS.md +351 -0
- package/vendor/@anvil/common/src/testing/anvil-offer-invariants.ts +169 -0
- package/vendor/@anvil/common/src/testing/errors.ts +33 -0
- package/vendor/@anvil/common/src/testing/fixtures/agent-runtime.ts +334 -0
- package/vendor/@anvil/common/src/testing/impl/agent-runtime.ts +6 -0
- package/vendor/@anvil/common/src/testing/index.ts +84 -0
- package/vendor/@anvil/common/src/testing/mock-modules.ts +53 -0
- package/vendor/@anvil/common/src/testing/mock-types.ts +123 -0
- package/vendor/@anvil/common/src/testing/mocks/analytics.ts +261 -0
- package/vendor/@anvil/common/src/testing/mocks/child-process.ts +93 -0
- package/vendor/@anvil/common/src/testing/mocks/crypto.ts +218 -0
- package/vendor/@anvil/common/src/testing/mocks/database.ts +337 -0
- package/vendor/@anvil/common/src/testing/mocks/fetch.ts +219 -0
- package/vendor/@anvil/common/src/testing/mocks/filesystem.ts +166 -0
- package/vendor/@anvil/common/src/testing/mocks/index.ts +101 -0
- package/vendor/@anvil/common/src/testing/mocks/logger.ts +135 -0
- package/vendor/@anvil/common/src/testing/mocks/stream.ts +313 -0
- package/vendor/@anvil/common/src/testing/mocks/timers.ts +132 -0
- package/vendor/@anvil/common/src/testing/mocks/tree-sitter.ts +127 -0
- package/vendor/@anvil/common/src/testing/setup.ts +282 -0
- package/vendor/@anvil/common/src/testing-env-ci.ts +15 -0
- package/vendor/@anvil/common/src/testing-env-process.ts +78 -0
- package/vendor/@anvil/common/src/tools/__tests__/compile-tool-definitions.test.ts +34 -0
- package/vendor/@anvil/common/src/tools/compile-tool-definitions.ts +157 -0
- package/vendor/@anvil/common/src/tools/constants.ts +117 -0
- package/vendor/@anvil/common/src/tools/list.ts +190 -0
- package/vendor/@anvil/common/src/tools/params/__tests__/coerce-to-array.test.ts +213 -0
- package/vendor/@anvil/common/src/tools/params/__tests__/read-docs.test.ts +47 -0
- package/vendor/@anvil/common/src/tools/params/__tests__/render-ui.test.ts +65 -0
- package/vendor/@anvil/common/src/tools/params/tool/__tests__/run-terminal-command-timeout.test.ts +49 -0
- package/vendor/@anvil/common/src/tools/params/tool/add-message.ts +39 -0
- package/vendor/@anvil/common/src/tools/params/tool/add-subgoal.ts +57 -0
- package/vendor/@anvil/common/src/tools/params/tool/apply-patch.ts +110 -0
- package/vendor/@anvil/common/src/tools/params/tool/ask-user.ts +181 -0
- package/vendor/@anvil/common/src/tools/params/tool/browser-logs.ts +85 -0
- package/vendor/@anvil/common/src/tools/params/tool/cloud-plan-ready.ts +94 -0
- package/vendor/@anvil/common/src/tools/params/tool/code-search.ts +159 -0
- package/vendor/@anvil/common/src/tools/params/tool/composio.ts +131 -0
- package/vendor/@anvil/common/src/tools/params/tool/create-plan.ts +80 -0
- package/vendor/@anvil/common/src/tools/params/tool/end-turn.ts +57 -0
- package/vendor/@anvil/common/src/tools/params/tool/find-files.ts +60 -0
- package/vendor/@anvil/common/src/tools/params/tool/glob.ts +80 -0
- package/vendor/@anvil/common/src/tools/params/tool/gravity-index.ts +93 -0
- package/vendor/@anvil/common/src/tools/params/tool/list-directory.ts +58 -0
- package/vendor/@anvil/common/src/tools/params/tool/lookup-agent-info.ts +37 -0
- package/vendor/@anvil/common/src/tools/params/tool/propose-str-replace.ts +103 -0
- package/vendor/@anvil/common/src/tools/params/tool/propose-write-file.ts +71 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-docs.ts +90 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-files.ts +109 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-subtree.ts +79 -0
- package/vendor/@anvil/common/src/tools/params/tool/read-url.ts +81 -0
- package/vendor/@anvil/common/src/tools/params/tool/render-ui.ts +168 -0
- package/vendor/@anvil/common/src/tools/params/tool/run-file-change-hooks.ts +57 -0
- package/vendor/@anvil/common/src/tools/params/tool/run-terminal-command.ts +211 -0
- package/vendor/@anvil/common/src/tools/params/tool/screenshot.ts +97 -0
- package/vendor/@anvil/common/src/tools/params/tool/set-messages.ts +44 -0
- package/vendor/@anvil/common/src/tools/params/tool/set-output.ts +61 -0
- package/vendor/@anvil/common/src/tools/params/tool/skill.ts +59 -0
- package/vendor/@anvil/common/src/tools/params/tool/spawn-agent-inline.ts +56 -0
- package/vendor/@anvil/common/src/tools/params/tool/spawn-agents.ts +154 -0
- package/vendor/@anvil/common/src/tools/params/tool/str-replace.ts +107 -0
- package/vendor/@anvil/common/src/tools/params/tool/suggest-followups.ts +97 -0
- package/vendor/@anvil/common/src/tools/params/tool/task-completed.ts +61 -0
- package/vendor/@anvil/common/src/tools/params/tool/think-deeply.ts +56 -0
- package/vendor/@anvil/common/src/tools/params/tool/update-subgoal.ts +89 -0
- package/vendor/@anvil/common/src/tools/params/tool/vision-analyze.ts +82 -0
- package/vendor/@anvil/common/src/tools/params/tool/web-search.ts +73 -0
- package/vendor/@anvil/common/src/tools/params/tool/write-file.ts +71 -0
- package/vendor/@anvil/common/src/tools/params/tool/write-todos.ts +67 -0
- package/vendor/@anvil/common/src/tools/params/utils.ts +150 -0
- package/vendor/@anvil/common/src/tools/utils.ts +24 -0
- package/vendor/@anvil/common/src/types/__tests__/dynamic-agent-template.test.ts +20 -0
- package/vendor/@anvil/common/src/types/agent-template.ts +215 -0
- package/vendor/@anvil/common/src/types/anvil-session.ts +535 -0
- package/vendor/@anvil/common/src/types/anvil-streak.ts +6 -0
- package/vendor/@anvil/common/src/types/anvil-usage.ts +64 -0
- package/vendor/@anvil/common/src/types/api/agents/publish.ts +61 -0
- package/vendor/@anvil/common/src/types/bun-test.d.ts +5 -0
- package/vendor/@anvil/common/src/types/contracts/agent-runtime.ts +75 -0
- package/vendor/@anvil/common/src/types/contracts/analytics.ts +9 -0
- package/vendor/@anvil/common/src/types/contracts/bigquery.ts +55 -0
- package/vendor/@anvil/common/src/types/contracts/billing.ts +46 -0
- package/vendor/@anvil/common/src/types/contracts/client.ts +53 -0
- package/vendor/@anvil/common/src/types/contracts/database.ts +112 -0
- package/vendor/@anvil/common/src/types/contracts/env.ts +203 -0
- package/vendor/@anvil/common/src/types/contracts/llm.ts +191 -0
- package/vendor/@anvil/common/src/types/contracts/logger.ts +14 -0
- package/vendor/@anvil/common/src/types/contracts/logs.ts +34 -0
- package/vendor/@anvil/common/src/types/contracts/trace.ts +21 -0
- package/vendor/@anvil/common/src/types/dynamic-agent-template.ts +328 -0
- package/vendor/@anvil/common/src/types/filesystem.ts +10 -0
- package/vendor/@anvil/common/src/types/function-params.ts +33 -0
- package/vendor/@anvil/common/src/types/grant.ts +20 -0
- package/vendor/@anvil/common/src/types/gravity-index.ts +170 -0
- package/vendor/@anvil/common/src/types/json.ts +29 -0
- package/vendor/@anvil/common/src/types/mcp.ts +24 -0
- package/vendor/@anvil/common/src/types/messages/anvil-message.ts +58 -0
- package/vendor/@anvil/common/src/types/messages/content-part.ts +59 -0
- package/vendor/@anvil/common/src/types/messages/data-content.ts +14 -0
- package/vendor/@anvil/common/src/types/messages/provider-metadata.ts +13 -0
- package/vendor/@anvil/common/src/types/organization.ts +118 -0
- package/vendor/@anvil/common/src/types/print-mode.ts +121 -0
- package/vendor/@anvil/common/src/types/publisher.ts +67 -0
- package/vendor/@anvil/common/src/types/session-state.ts +149 -0
- package/vendor/@anvil/common/src/types/skill.ts +86 -0
- package/vendor/@anvil/common/src/types/source.ts +11 -0
- package/vendor/@anvil/common/src/types/spawn.ts +13 -0
- package/vendor/@anvil/common/src/types/subscription.ts +67 -0
- package/vendor/@anvil/common/src/types/usage.ts +16 -0
- package/vendor/@anvil/common/src/types/util.ts +3 -0
- package/vendor/@anvil/common/src/util/__tests__/ad-user-agent.test.ts +26 -0
- package/vendor/@anvil/common/src/util/__tests__/analytics-dispatcher.test.ts +122 -0
- package/vendor/@anvil/common/src/util/__tests__/analytics-log.test.ts +102 -0
- package/vendor/@anvil/common/src/util/__tests__/analytics-sampling.test.ts +143 -0
- package/vendor/@anvil/common/src/util/__tests__/anvil-streak.test.ts +202 -0
- package/vendor/@anvil/common/src/util/__tests__/anvil-usage-summary.test.ts +193 -0
- package/vendor/@anvil/common/src/util/__tests__/axiom-only-log.test.ts +140 -0
- package/vendor/@anvil/common/src/util/__tests__/client-user-agent.test.ts +148 -0
- package/vendor/@anvil/common/src/util/__tests__/engagement-tracker.test.ts +115 -0
- package/vendor/@anvil/common/src/util/__tests__/env-file-path.test.ts +57 -0
- package/vendor/@anvil/common/src/util/__tests__/error-abort.test.ts +774 -0
- package/vendor/@anvil/common/src/util/__tests__/error-api-details.test.ts +206 -0
- package/vendor/@anvil/common/src/util/__tests__/file-read-limits.test.ts +173 -0
- package/vendor/@anvil/common/src/util/__tests__/format-code-search.test.ts +60 -0
- package/vendor/@anvil/common/src/util/__tests__/log-mirror.test.ts +31 -0
- package/vendor/@anvil/common/src/util/__tests__/messages.test.ts +1252 -0
- package/vendor/@anvil/common/src/util/__tests__/partial-json-delta.test.ts +505 -0
- package/vendor/@anvil/common/src/util/__tests__/path.test.ts +22 -0
- package/vendor/@anvil/common/src/util/__tests__/project-ignore.test.ts +90 -0
- package/vendor/@anvil/common/src/util/__tests__/promise.test.ts +325 -0
- package/vendor/@anvil/common/src/util/__tests__/rate-limit.test.ts +28 -0
- package/vendor/@anvil/common/src/util/__tests__/reddit-anvil-retention.test.ts +130 -0
- package/vendor/@anvil/common/src/util/__tests__/saxy.test.ts +1008 -0
- package/vendor/@anvil/common/src/util/__tests__/split-data.test.ts +289 -0
- package/vendor/@anvil/common/src/util/__tests__/string.test.ts +239 -0
- package/vendor/@anvil/common/src/util/__tests__/thread-title.test.ts +70 -0
- package/vendor/@anvil/common/src/util/__tests__/tool-result-media-order.test.ts +108 -0
- package/vendor/@anvil/common/src/util/__tests__/ttft-histogram.test.ts +180 -0
- package/vendor/@anvil/common/src/util/__tests__/with-timeout.test.ts +24 -0
- package/vendor/@anvil/common/src/util/__tests__/zoned-time.test.ts +88 -0
- package/vendor/@anvil/common/src/util/ad-user-agent.ts +25 -0
- package/vendor/@anvil/common/src/util/agent-file-utils.ts +110 -0
- package/vendor/@anvil/common/src/util/agent-id-parsing.ts +136 -0
- package/vendor/@anvil/common/src/util/agent-name-normalization.ts +38 -0
- package/vendor/@anvil/common/src/util/agent-name-resolver.ts +86 -0
- package/vendor/@anvil/common/src/util/analytics-dispatcher.ts +82 -0
- package/vendor/@anvil/common/src/util/analytics-log.ts +78 -0
- package/vendor/@anvil/common/src/util/analytics-sampling.ts +255 -0
- package/vendor/@anvil/common/src/util/anvil-model-availability.ts +102 -0
- package/vendor/@anvil/common/src/util/anvil-privacy.ts +82 -0
- package/vendor/@anvil/common/src/util/anvil-streak-line.ts +103 -0
- package/vendor/@anvil/common/src/util/anvil-streak.ts +156 -0
- package/vendor/@anvil/common/src/util/anvil-usage-summary.ts +125 -0
- package/vendor/@anvil/common/src/util/array.ts +31 -0
- package/vendor/@anvil/common/src/util/axiom-only-log.ts +124 -0
- package/vendor/@anvil/common/src/util/cache-debug.ts +171 -0
- package/vendor/@anvil/common/src/util/client-user-agent.ts +114 -0
- package/vendor/@anvil/common/src/util/credentials.ts +26 -0
- package/vendor/@anvil/common/src/util/currency.ts +25 -0
- package/vendor/@anvil/common/src/util/dates.ts +81 -0
- package/vendor/@anvil/common/src/util/disposable-email.ts +277 -0
- package/vendor/@anvil/common/src/util/engagement-tracker.ts +129 -0
- package/vendor/@anvil/common/src/util/env-file-path.ts +40 -0
- package/vendor/@anvil/common/src/util/error.ts +562 -0
- package/vendor/@anvil/common/src/util/file-read-limits.ts +236 -0
- package/vendor/@anvil/common/src/util/file.ts +339 -0
- package/vendor/@anvil/common/src/util/format-code-search.ts +115 -0
- package/vendor/@anvil/common/src/util/lazy-response-ads.ts +92 -0
- package/vendor/@anvil/common/src/util/log-data.ts +57 -0
- package/vendor/@anvil/common/src/util/log-ingest.ts +58 -0
- package/vendor/@anvil/common/src/util/log-mirror.ts +34 -0
- package/vendor/@anvil/common/src/util/lru-cache.ts +67 -0
- package/vendor/@anvil/common/src/util/messages.ts +685 -0
- package/vendor/@anvil/common/src/util/min-heap.ts +87 -0
- package/vendor/@anvil/common/src/util/model-utils.ts +4 -0
- package/vendor/@anvil/common/src/util/object.ts +128 -0
- package/vendor/@anvil/common/src/util/partial-json-delta.ts +89 -0
- package/vendor/@anvil/common/src/util/path.ts +15 -0
- package/vendor/@anvil/common/src/util/project-ignore.ts +119 -0
- package/vendor/@anvil/common/src/util/promise.ts +73 -0
- package/vendor/@anvil/common/src/util/random.ts +15 -0
- package/vendor/@anvil/common/src/util/rate-limit.ts +56 -0
- package/vendor/@anvil/common/src/util/reddit-anvil-retention.ts +60 -0
- package/vendor/@anvil/common/src/util/reddit-capi-events.ts +36 -0
- package/vendor/@anvil/common/src/util/response-ad-positions.ts +54 -0
- package/vendor/@anvil/common/src/util/saxy.ts +741 -0
- package/vendor/@anvil/common/src/util/skills.test.ts +44 -0
- package/vendor/@anvil/common/src/util/skills.ts +36 -0
- package/vendor/@anvil/common/src/util/split-data.ts +259 -0
- package/vendor/@anvil/common/src/util/stop-sequence.ts +61 -0
- package/vendor/@anvil/common/src/util/string.ts +426 -0
- package/vendor/@anvil/common/src/util/system-info.ts +53 -0
- package/vendor/@anvil/common/src/util/thread-title.ts +46 -0
- package/vendor/@anvil/common/src/util/ttft-histogram.ts +73 -0
- package/vendor/@anvil/common/src/util/xml-parser.ts +27 -0
- package/vendor/@anvil/common/src/util/xml.ts +17 -0
- package/vendor/@anvil/common/src/util/zod-schema.ts +25 -0
- package/vendor/@anvil/common/src/util/zoned-time.ts +136 -0
- package/vendor/@anvil/common/src/utils/ask-user-bridge.ts +44 -0
- package/vendor/@anvil/sdk/dist/index.cjs +52297 -0
- package/vendor/@anvil/sdk/dist/index.cjs.map +440 -0
- package/vendor/@anvil/sdk/dist/index.d.ts +4277 -0
- package/vendor/@anvil/sdk/dist/index.mjs +52290 -0
- package/vendor/@anvil/sdk/dist/index.mjs.map +440 -0
- package/vendor/@anvil/sdk/dist/vendor/ai.cjs +30886 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/arm64-darwin/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/arm64-linux/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-darwin/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-linux/rg +0 -0
- package/vendor/@anvil/sdk/dist/vendor/ripgrep/x64-win32/rg.exe +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-c-sharp.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-cpp.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-go.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-java.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-python.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-ruby.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-rust.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-tsx.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter-typescript.wasm +0 -0
- package/vendor/@anvil/sdk/dist/wasm/tree-sitter.wasm +0 -0
- package/vendor/@anvil/sdk/package.json +21 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
export const PROVIDER_ROUTE_IDS = [
|
|
2
|
+
'fireworks/deployment',
|
|
3
|
+
'fireworks/serverless',
|
|
4
|
+
'minimax/official',
|
|
5
|
+
'xiaomi/official',
|
|
6
|
+
'openrouter/novita/fp8',
|
|
7
|
+
'mimo/openrouter',
|
|
8
|
+
'infron/makora',
|
|
9
|
+
'deepseek/openrouter',
|
|
10
|
+
'deepseek/crof',
|
|
11
|
+
'deepseek/official',
|
|
12
|
+
] as const
|
|
13
|
+
|
|
14
|
+
export type ProviderRouteId = (typeof PROVIDER_ROUTE_IDS)[number]
|
|
15
|
+
|
|
16
|
+
export const FIREWORKS_DEPLOYMENT_PROVIDER_ROUTE =
|
|
17
|
+
'fireworks/deployment' satisfies ProviderRouteId
|
|
18
|
+
export const FIREWORKS_SERVERLESS_PROVIDER_ROUTE =
|
|
19
|
+
'fireworks/serverless' satisfies ProviderRouteId
|
|
20
|
+
export const MINIMAX_OFFICIAL_PROVIDER_ROUTE =
|
|
21
|
+
'minimax/official' satisfies ProviderRouteId
|
|
22
|
+
/**
|
|
23
|
+
* Marks a MiMo session as diverted off Xiaomi's direct API to the OpenRouter
|
|
24
|
+
* lane. Like {@link DEEPSEEK_INFRON_MAKORA_PROVIDER_ROUTE} it says *that* the
|
|
25
|
+
* session is on the fallback, NOT which upstream serves it — that is
|
|
26
|
+
* {@link MIMO_OPENROUTER_UPSTREAM} below, so repointing it also moves every
|
|
27
|
+
* session already pinned here, with no migration.
|
|
28
|
+
*
|
|
29
|
+
* Named generically on purpose. Its predecessor
|
|
30
|
+
* {@link MIMO_NOVITA_PROVIDER_ROUTE} baked the upstream into a value that gets
|
|
31
|
+
* persisted in `free_session.provider_route` and read back unvalidated, so
|
|
32
|
+
* changing upstreams meant either a migration or a name that lies.
|
|
33
|
+
*/
|
|
34
|
+
export const MIMO_OPENROUTER_PROVIDER_ROUTE =
|
|
35
|
+
'mimo/openrouter' satisfies ProviderRouteId
|
|
36
|
+
/**
|
|
37
|
+
* The upstreams that serve {@link MIMO_OPENROUTER_PROVIDER_ROUTE}, preferred
|
|
38
|
+
* first: Xiaomi's OWN endpoint, reached through OpenRouter's account rather
|
|
39
|
+
* than our direct API key, with Novita behind it purely as depth.
|
|
40
|
+
*
|
|
41
|
+
* It lives next to the route id because the two are meant to be read together —
|
|
42
|
+
* the id says which lane a session is pinned to, this says who serves it — and
|
|
43
|
+
* in `common/` rather than in mimo-router.ts so `scripts/mimo-smoke.ts` can
|
|
44
|
+
* assert against the REAL value without importing the billing chain. A smoke
|
|
45
|
+
* test that restates this config would keep passing after the upstream moved,
|
|
46
|
+
* reporting a lane it no longer covers.
|
|
47
|
+
*
|
|
48
|
+
* Novita served the lane until 2026-08-01, which was most of what made the
|
|
49
|
+
* fallback expensive. Measured over 6h of prod that day, attributing rows by
|
|
50
|
+
* whether their cost reproduces our Xiaomi formula:
|
|
51
|
+
*
|
|
52
|
+
* openrouter/novita 18,268 reqs (42.6%) 19.2% cache $364.11 $0.138/M in
|
|
53
|
+
* xiaomi direct 24,631 reqs (57.4%) 90.5% cache $63.76 $0.018/M in
|
|
54
|
+
*
|
|
55
|
+
* Novita is also 20% dearer per token before caching ($0.168/$0.336 against
|
|
56
|
+
* Xiaomi's $0.14/$0.28) and prices cache reads at $0.0034/M against $0.0028/M.
|
|
57
|
+
* Xiaomi's OpenRouter endpoint is priced identically to our direct rate, so the
|
|
58
|
+
* lane costs the same as the primary and differs only in whose rate limit and
|
|
59
|
+
* prompt cache it draws on — which is the entire point of having it.
|
|
60
|
+
*/
|
|
61
|
+
export const MIMO_OPENROUTER_UPSTREAM_ORDER = [
|
|
62
|
+
'xiaomi/fp8',
|
|
63
|
+
'novita/fp8',
|
|
64
|
+
] as const
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Fresh OpenRouter `provider` block for the MiMo lane.
|
|
68
|
+
*
|
|
69
|
+
* TWO ENTRIES DELIBERATELY, and it must never go back to one. A pinned session
|
|
70
|
+
* has no health check and no un-pin path — `routeWithStickyFallback` short
|
|
71
|
+
* -circuits straight to the fallback — so if the lane's only upstream is down,
|
|
72
|
+
* one transient Xiaomi blip wedges every remaining request in that session
|
|
73
|
+
* rather than degrading a single one. That is not hypothetical: a one-deep pin
|
|
74
|
+
* on DeepSeek's Infron lane took out 1,160 requests across 191 users for ~32h
|
|
75
|
+
* when `makora` went offline (2026-07-26/27, fixed in #1045).
|
|
76
|
+
*
|
|
77
|
+
* Verified live on this lane 2026-08-01: within an `allow_fallbacks:false`
|
|
78
|
+
* order list, an unroutable first entry is SKIPPED rather than failing the
|
|
79
|
+
* request — `order:['nosuchprovider','xiaomi/fp8']` returned 200 from Xiaomi —
|
|
80
|
+
* while `order:['xiaomi/fp8','novita/fp8']` still serves from Xiaomi when it is
|
|
81
|
+
* healthy. So the depth costs nothing in the normal case and is the difference
|
|
82
|
+
* between a degraded session and a wedged one in the bad case. Novita is second
|
|
83
|
+
* because it is the best-understood host for this model: it served ~43% of MiMo
|
|
84
|
+
* traffic through late July, so its compatibility with our request shape is
|
|
85
|
+
* proven, and it only ever serves when Xiaomi cannot.
|
|
86
|
+
*
|
|
87
|
+
* Returns a NEW object with a NEW array every call. These arrays get aliased
|
|
88
|
+
* into an outgoing request body, and this file's peer
|
|
89
|
+
* `INFRON_PROVIDER_ORDER` was made copy-on-assignment in #1045 for exactly that
|
|
90
|
+
* reason — one downstream mutation would corrupt routing process-wide.
|
|
91
|
+
*/
|
|
92
|
+
export function mimoOpenRouterProvider(): Record<string, unknown> {
|
|
93
|
+
return {
|
|
94
|
+
order: [...MIMO_OPENROUTER_UPSTREAM_ORDER],
|
|
95
|
+
allow_fallbacks: false,
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* LEGACY MiMo fallback pin, written while the OpenRouter lane was hardcoded to
|
|
100
|
+
* Novita FP8. Still recognized on READ so sessions pinned before
|
|
101
|
+
* {@link MIMO_OPENROUTER_PROVIDER_ROUTE} shipped keep serving from the fallback
|
|
102
|
+
* instead of silently reverting to a Xiaomi-direct attempt they already failed.
|
|
103
|
+
* Never written anymore; expires with its session.
|
|
104
|
+
*/
|
|
105
|
+
export const MIMO_NOVITA_PROVIDER_ROUTE =
|
|
106
|
+
'openrouter/novita/fp8' satisfies ProviderRouteId
|
|
107
|
+
/**
|
|
108
|
+
* DeepSeek V4 Flash's CrofAI lane — and, since the 2026-08-15 cutover, the
|
|
109
|
+
* COHORT MARK that says a session belongs on it.
|
|
110
|
+
*
|
|
111
|
+
* This id now carries two meanings that deliberately coincide. Written at
|
|
112
|
+
* ADMISSION it means "this session was admitted after the cutover, so it enters
|
|
113
|
+
* the cascade on CrofAI". Written by the CASCADE it means "this session
|
|
114
|
+
* diverted onto CrofAI". Both want the same thing — enter on CrofAI — which is
|
|
115
|
+
* why pins written by the pre-cutover code needed no migration when the
|
|
116
|
+
* cutover shipped, and why nothing has to distinguish them on read.
|
|
117
|
+
*
|
|
118
|
+
* A session with NO pin is, by construction, one admitted before the cutover
|
|
119
|
+
* shipped: it runs the pre-cutover order and keeps the prompt cache it has
|
|
120
|
+
* already paid to warm. See `deepseekEntryLane` and
|
|
121
|
+
* docs/anvil-deepseek-provider-cutover.md.
|
|
122
|
+
*
|
|
123
|
+
* Reference prices, from live billing 2026-08-04, per M:
|
|
124
|
+
*
|
|
125
|
+
* input cache read output
|
|
126
|
+
* CrofAI 0731 0.1200 0.0030 0.2100
|
|
127
|
+
* Infron alibaba 0.0690 0.0144 0.1375
|
|
128
|
+
* OpenRouter 0.0881 0.0176 0.1761
|
|
129
|
+
* DeepSeek direct 0.1400 0.0028 0.2800
|
|
130
|
+
*
|
|
131
|
+
* CrofAI is DEARER on fresh input and output and cheaper than everything except
|
|
132
|
+
* DeepSeek direct on cache reads — but a coding turn re-sends its whole prefix
|
|
133
|
+
* every step, so cache reads are most of the tokens and that is the term that
|
|
134
|
+
* decides the bill. Against Infron, 0.0030 vs 0.0144 is a 4.8x cut on the
|
|
135
|
+
* dominant term; break-even is around an 82% cache-hit rate, which a
|
|
136
|
+
* sticky-pinned session clears comfortably and a single cold turn does not.
|
|
137
|
+
* That is the trade this ordering makes, and it is why the ordering would be
|
|
138
|
+
* wrong if these lanes were not sticky.
|
|
139
|
+
*
|
|
140
|
+
* It also serves `deepseek-v4-flash-0731` — the GA build, the same one
|
|
141
|
+
* DeepSeek's own API serves — where Infron's undated slug is a frozen preview
|
|
142
|
+
* snapshot. So this lane matches the DeepSeek-direct lane behind it in
|
|
143
|
+
* behaviour as well as price.
|
|
144
|
+
*/
|
|
145
|
+
export const DEEPSEEK_CROF_PROVIDER_ROUTE =
|
|
146
|
+
'deepseek/crof' satisfies ProviderRouteId
|
|
147
|
+
/**
|
|
148
|
+
* DeepSeek's own API — the lane a cutover session diverts to, and the lane
|
|
149
|
+
* every PRE-cutover session still enters on.
|
|
150
|
+
*
|
|
151
|
+
* It was the unpinned default until 2026-08-15, which is why it had no route id
|
|
152
|
+
* before: a lane nothing ever moves to needs no name. Now that a cutover
|
|
153
|
+
* session can divert here, it has to be able to say so, and to stay — its
|
|
154
|
+
* prompt cache is warm on this upstream, and sending the next turn back to a
|
|
155
|
+
* CrofAI that just failed would pay a cold prefill to reach a lane we already
|
|
156
|
+
* know is unhealthy. The pin skips CrofAI as an ENTRY point only: it stays in
|
|
157
|
+
* the order behind this lane, because by the next turn the blip has usually
|
|
158
|
+
* cleared and CrofAI is still far cheaper than Infron.
|
|
159
|
+
*
|
|
160
|
+
* Behind CrofAI for cutover sessions despite the marginally better cache-read
|
|
161
|
+
* price ($0.0028/M against $0.0030/M) because DeepSeek is the side that
|
|
162
|
+
* repriced, and because of the
|
|
163
|
+
* failure record that made this a cascade at all: on 2026-08-03/04 it shed peak
|
|
164
|
+
* load with 3,934 x 503 "Service is too busy" and diverted 4,997 sessions at
|
|
165
|
+
* once, and on 2026-08-11 it accepted 650 requests in six hours and then sent
|
|
166
|
+
* nothing, tripping the four-minute first-token watchdog. Note that the
|
|
167
|
+
* watchdog is DeepSeek-direct-only (see `handleDeepSeekStream`); no equivalent
|
|
168
|
+
* guards the CrofAI lane now serving in front of it.
|
|
169
|
+
*/
|
|
170
|
+
export const DEEPSEEK_OFFICIAL_PROVIDER_ROUTE =
|
|
171
|
+
'deepseek/official' satisfies ProviderRouteId
|
|
172
|
+
/**
|
|
173
|
+
* DeepSeek V4 Flash's LAST resort: the Infron lane, tier 3 of THREE.
|
|
174
|
+
*
|
|
175
|
+
* It gets ONE attempt and leaves no resumable pin (see `asDeepSeekLane`): its
|
|
176
|
+
* cache reads are 4.8x CrofAI's, so a session must never settle here.
|
|
177
|
+
*
|
|
178
|
+
* Ordering is deliberate and was arrived at the hard way. Infron is the
|
|
179
|
+
* cheapest route we have for this model — measured live 2026-08-04 on a
|
|
180
|
+
* 45,008-token prompt, $0.069/M input and ~$0.0144/M cache read against the
|
|
181
|
+
* OpenRouter lane's $0.0881 and $0.0176, so ~22% cheaper cold and ~13% warm.
|
|
182
|
+
* But it is a single aggregator account behind one Alibaba provider group, and
|
|
183
|
+
* when 4,997 sessions diverted onto it in one window it returned 13,286
|
|
184
|
+
* saturation 429s and then ran out of credits entirely.
|
|
185
|
+
*
|
|
186
|
+
* So it sits behind {@link DEEPSEEK_CROF_PROVIDER_ROUTE} and {@link
|
|
187
|
+
* DEEPSEEK_OFFICIAL_PROVIDER_ROUTE}: cheapest on FRESH input, which is what a
|
|
188
|
+
* cold session pays, while the two lanes ahead of it win the warm case on cache
|
|
189
|
+
* reads, and it must never be the lane a session settles on. This only works
|
|
190
|
+
* because the cascade RE-PINS on each hop — a session that finds Infron
|
|
191
|
+
* saturated does not pay a doomed Infron attempt on every later turn.
|
|
192
|
+
*
|
|
193
|
+
* The `makora` in the name is historical (that upstream went offline in
|
|
194
|
+
* 2026-07). The id says only *that* a session is on this lane, never which
|
|
195
|
+
* upstream serves it — that is INFRON_PROVIDER_ORDER, keyed by model — so
|
|
196
|
+
* repointing the upstream also moves sessions already pinned here. Renaming the
|
|
197
|
+
* value itself would need a migration; it is persisted in
|
|
198
|
+
* `free_session.provider_route` and read back unvalidated.
|
|
199
|
+
*/
|
|
200
|
+
export const DEEPSEEK_INFRON_MAKORA_PROVIDER_ROUTE =
|
|
201
|
+
'infron/makora' satisfies ProviderRouteId
|
|
202
|
+
/**
|
|
203
|
+
* RETIRED as a DeepSeek lane on 2026-08-11. Kept as a recognized id because it
|
|
204
|
+
* is persisted in `free_session.provider_route` and read back unvalidated —
|
|
205
|
+
* sessions still carrying the pin must not crash; they simply start from the
|
|
206
|
+
* primary again, which is the right answer for a lane that no longer exists.
|
|
207
|
+
*
|
|
208
|
+
* Why it went: it prices cache reads at $0.0176/M against CrofAI's $0.0030,
|
|
209
|
+
* and an agent turn re-sends its whole prefix every step, so ~98% of the
|
|
210
|
+
* tokens land on exactly that term. Being "last resort" did not bound the
|
|
211
|
+
* damage — the pin only moved forward, so one transient 429 on the lane above
|
|
212
|
+
* parked a session here for the rest of its hour. It was reached 1,205 times
|
|
213
|
+
* in 24h, more often than the lane ahead of it, and DeepSeek's daily bill went
|
|
214
|
+
* from $9k to $39.7k over four days while volume rose only 41%. Depth that
|
|
215
|
+
* costs 5.9x on the dominant token class is not depth.
|
|
216
|
+
*
|
|
217
|
+
* The replacement for that depth is retries: the two cheap lanes are attempted
|
|
218
|
+
* three times each before anything diverts.
|
|
219
|
+
*
|
|
220
|
+
* (Historical, for the MiMo lane which still uses OpenRouter:)
|
|
221
|
+
* DeepSeek V4 Flash's LAST resort: the OpenRouter lane, tier 4 of four.
|
|
222
|
+
*
|
|
223
|
+
* Reached when DeepSeek direct and then {@link
|
|
224
|
+
* DEEPSEEK_INFRON_MAKORA_PROVIDER_ROUTE} have both failed retryably. Dearer per
|
|
225
|
+
* token than Infron but backed by many independent upstreams and a balance that
|
|
226
|
+
* is not one account's, which is exactly what a divert storm needs — see the
|
|
227
|
+
* Infron route's doc for why the cheap lane cannot be the last one.
|
|
228
|
+
*
|
|
229
|
+
* Like its MiMo peer it names the LANE, not the upstream — that is {@link
|
|
230
|
+
* DEEPSEEK_OPENROUTER_UPSTREAM_ORDER} below, so repointing the order also moves
|
|
231
|
+
* every session already pinned here, with no migration.
|
|
232
|
+
*/
|
|
233
|
+
export const DEEPSEEK_OPENROUTER_PROVIDER_ROUTE =
|
|
234
|
+
'deepseek/openrouter' satisfies ProviderRouteId
|
|
235
|
+
/**
|
|
236
|
+
* The upstreams that serve {@link DEEPSEEK_OPENROUTER_PROVIDER_ROUTE},
|
|
237
|
+
* preferred first.
|
|
238
|
+
*
|
|
239
|
+
* Chosen as *cheapest that still preserves the prompt cache*, which for an
|
|
240
|
+
* agent workload are not the same axis. Cache-read price is what actually
|
|
241
|
+
* drives this bill — a coding turn re-sends a long prefix every step, so most
|
|
242
|
+
* input tokens are cache reads — and the OpenRouter catalog splits cleanly on
|
|
243
|
+
* it (checked live 2026-08-04, per M):
|
|
244
|
+
*
|
|
245
|
+
* streamlake/fp8 $0.0881 in $0.0176 cache $0.1761 out fp8 384k max out
|
|
246
|
+
* baidu/fp8 $0.0882 in $0.0176 cache $0.1764 out fp8 131k max out
|
|
247
|
+
* gmicloud/fp8 $0.0938 in $0.0188 cache $0.1876 out fp8 no stated cap
|
|
248
|
+
* ── everything below is >=1.5x the cache-read price ──
|
|
249
|
+
* most of the tail $0.14 in $0.0280 cache $0.2800 out
|
|
250
|
+
* parasail/coreweave/phala $0.0700 cache (4x)
|
|
251
|
+
* morph, mancer/fp4 NO cache read at all
|
|
252
|
+
*
|
|
253
|
+
* So the three cheapest on input are also the three cheapest on cache read;
|
|
254
|
+
* there is no tradeoff to make here, which is why the list is short.
|
|
255
|
+
*
|
|
256
|
+
* DELIBERATELY NOT `deepseek` (OpenRouter's DeepSeek-first-party endpoint).
|
|
257
|
+
* It has by far the best cache read ($0.0028/M) and is tempting for that alone,
|
|
258
|
+
* but it is the same upstream whose failure triggers this fallback, reached
|
|
259
|
+
* through a middleman — pointing the lane there would divert an outage onto
|
|
260
|
+
* itself. The Infron lane can use the 0731 model without this problem because
|
|
261
|
+
* it pins independent Alibaba upstreams.
|
|
262
|
+
*
|
|
263
|
+
* `deepinfra/fp4` is skipped despite sitting third on price: fp4 quantization,
|
|
264
|
+
* and a 65,536-token output cap that would truncate long agent turns. fp8 is
|
|
265
|
+
* the floor for this lane.
|
|
266
|
+
*
|
|
267
|
+
* THREE ENTRIES, and it must never go to one — see the identical warning on
|
|
268
|
+
* {@link mimoOpenRouterProvider}. A pinned session has no health check and no
|
|
269
|
+
* un-pin path, so a one-deep lane turns a single upstream blip into a wedged
|
|
270
|
+
* session. That is not hypothetical here: this model's previous fallback was
|
|
271
|
+
* pinned one-deep to `makora` and took out 1,160 requests across 191 users for
|
|
272
|
+
* ~32h when it went offline (2026-07-26/27, #1045).
|
|
273
|
+
*
|
|
274
|
+
* Caveat on the third entry: `gmicloud/fp8` does not list `stop` in its
|
|
275
|
+
* supported parameters. Without `require_parameters` OpenRouter drops the
|
|
276
|
+
* unsupported field rather than refusing to route, so a turn served there does
|
|
277
|
+
* not honor the global stop sequence. Accepted for depth — it only serves when
|
|
278
|
+
* both fp8 upstreams above it are unavailable — but do not promote it.
|
|
279
|
+
*/
|
|
280
|
+
export const DEEPSEEK_OPENROUTER_UPSTREAM_ORDER = [
|
|
281
|
+
'streamlake/fp8',
|
|
282
|
+
'baidu/fp8',
|
|
283
|
+
'gmicloud/fp8',
|
|
284
|
+
] as const
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* The OpenRouter output cap this lane requests.
|
|
288
|
+
*
|
|
289
|
+
* Matches `streamlake/fp8`'s 384,000-token ceiling — the first upstream in the
|
|
290
|
+
* order — so a caller's explicit budget can never make the preferred endpoint
|
|
291
|
+
* ineligible. Slightly under DeepSeek direct's 393,216, same as the Infron lane
|
|
292
|
+
* this replaces: keep fallback requests inside the contract of the route that
|
|
293
|
+
* will actually serve them.
|
|
294
|
+
*/
|
|
295
|
+
export const DEEPSEEK_OPENROUTER_MAX_TOKENS = 384_000
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Fresh OpenRouter `provider` block for the DeepSeek V4 Flash lane.
|
|
299
|
+
*
|
|
300
|
+
* Returns a NEW object with a NEW array every call — these arrays get aliased
|
|
301
|
+
* into an outgoing request body, and one downstream mutation would corrupt
|
|
302
|
+
* routing process-wide (the bug `INFRON_PROVIDER_ORDER` was made
|
|
303
|
+
* copy-on-assignment for in #1045).
|
|
304
|
+
*
|
|
305
|
+
* `allow_fallbacks: false` is what preserves the prompt cache: it holds the
|
|
306
|
+
* session to this order instead of letting OpenRouter spread turns across
|
|
307
|
+
* twenty endpoints that each keep their own cache. Cache fragmentation is the
|
|
308
|
+
* expensive failure mode, not a slightly dearer per-token rate — measured on
|
|
309
|
+
* the MiMo lane, a scattered fallback averaged 27.6k cache_read against ~150k
|
|
310
|
+
* prompts, paying a full cold prefill per divert.
|
|
311
|
+
*/
|
|
312
|
+
export function deepseekOpenRouterProvider(): Record<string, unknown> {
|
|
313
|
+
return {
|
|
314
|
+
order: [...DEEPSEEK_OPENROUTER_UPSTREAM_ORDER],
|
|
315
|
+
allow_fallbacks: false,
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one reasoning-effort vocabulary, shared by every surface.
|
|
3
|
+
*
|
|
4
|
+
* This list started in `anvil-desktop/src/shared/types.ts`, where it drives
|
|
5
|
+
* the Claude Code and Codex effort pickers. It lives here now so the Anvil
|
|
6
|
+
* model catalog and Desktop speak the same words: Desktop re-exports these,
|
|
7
|
+
* so a value persisted on a Desktop thread and a value on a Anvil catalog
|
|
8
|
+
* row are the same strings, comparable without a translation table.
|
|
9
|
+
*
|
|
10
|
+
* ORDERED, ascending, and that order is load-bearing — `clampReasoningEffort`
|
|
11
|
+
* does index arithmetic on it to answer "the most effort this model allows,
|
|
12
|
+
* but no more than was asked for". Keep it strictly ascending.
|
|
13
|
+
*
|
|
14
|
+
* Not every rung reaches every provider. `ultra` exists only for local CLI
|
|
15
|
+
* harnesses; Meta tops out at `xhigh`, while both DeepSeek V4 models expose
|
|
16
|
+
* `low`/`high`/`max` and nothing between. What a given model actually offers is
|
|
17
|
+
* its own `efforts` array, and the clamp stops one model's rung reaching
|
|
18
|
+
* another's API.
|
|
19
|
+
*/
|
|
20
|
+
export const REASONING_EFFORTS = [
|
|
21
|
+
'minimal',
|
|
22
|
+
'low',
|
|
23
|
+
'medium',
|
|
24
|
+
'high',
|
|
25
|
+
'xhigh',
|
|
26
|
+
'max',
|
|
27
|
+
'ultra',
|
|
28
|
+
] as const
|
|
29
|
+
|
|
30
|
+
export type ReasoningEffort = (typeof REASONING_EFFORTS)[number]
|
|
31
|
+
|
|
32
|
+
/** Kept explicit so a picker and a turn agree, rather than each deferring to
|
|
33
|
+
* some CLI's own default. */
|
|
34
|
+
export const DEFAULT_REASONING_EFFORT: ReasoningEffort = 'high'
|
|
35
|
+
|
|
36
|
+
export function isReasoningEffort(value: unknown): value is ReasoningEffort {
|
|
37
|
+
return REASONING_EFFORTS.includes(value as ReasoningEffort)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Position on the shared ladder, or -1. Exported for tests that assert one
|
|
41
|
+
* rung sits below another without hard-coding the list. */
|
|
42
|
+
export function reasoningEffortRank(value: unknown): number {
|
|
43
|
+
return REASONING_EFFORTS.indexOf(value as ReasoningEffort)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The highest rung `allowed` offers that is no higher than `requested`.
|
|
48
|
+
*
|
|
49
|
+
* Clamp-DOWN, not "reject and fall back", and the difference matters. A user on
|
|
50
|
+
* Muse Spark's `xhigh` whose request is rerouted to a model topping out at
|
|
51
|
+
* `high` should land on `high` — the closest thing to what they asked for —
|
|
52
|
+
* rather than snapping back to that model's default, which could be lower.
|
|
53
|
+
* When `requested` is below everything on offer, the lowest rung wins; when it
|
|
54
|
+
* is absent or unrecognized, the caller's fallback does.
|
|
55
|
+
*/
|
|
56
|
+
export function clampReasoningEffort(
|
|
57
|
+
requested: unknown,
|
|
58
|
+
allowed: readonly ReasoningEffort[],
|
|
59
|
+
fallback: ReasoningEffort,
|
|
60
|
+
): ReasoningEffort {
|
|
61
|
+
if (allowed.length === 0) return fallback
|
|
62
|
+
if (!isReasoningEffort(requested)) return fallback
|
|
63
|
+
|
|
64
|
+
const wanted = reasoningEffortRank(requested)
|
|
65
|
+
let best: ReasoningEffort | undefined
|
|
66
|
+
for (const candidate of allowed) {
|
|
67
|
+
const rank = reasoningEffortRank(candidate)
|
|
68
|
+
if (rank > wanted) continue
|
|
69
|
+
if (best === undefined || rank > reasoningEffortRank(best)) best = candidate
|
|
70
|
+
}
|
|
71
|
+
if (best !== undefined) return best
|
|
72
|
+
|
|
73
|
+
// Everything on offer is above what was asked for: give the least of them.
|
|
74
|
+
return allowed.reduce((lowest, candidate) =>
|
|
75
|
+
reasoningEffortRank(candidate) < reasoningEffortRank(lowest)
|
|
76
|
+
? candidate
|
|
77
|
+
: lowest,
|
|
78
|
+
)
|
|
79
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skills constants and validation rules.
|
|
3
|
+
*
|
|
4
|
+
* Skills are SKILL.md files with YAML frontmatter that define reusable
|
|
5
|
+
* instructions that agents can load on-demand via the skill tool.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The directory name where skills are stored (within .agents/).
|
|
10
|
+
*/
|
|
11
|
+
export const SKILLS_DIR_NAME = 'skills'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The file name for skill definitions.
|
|
15
|
+
*/
|
|
16
|
+
export const SKILL_FILE_NAME = 'SKILL.md'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validation regex for skill names.
|
|
20
|
+
* - 1-64 characters
|
|
21
|
+
* - Lowercase alphanumeric with single hyphen separators
|
|
22
|
+
* - Cannot start or end with hyphen
|
|
23
|
+
* - No consecutive hyphens
|
|
24
|
+
*/
|
|
25
|
+
export const SKILL_NAME_REGEX = /^[a-z0-9]+(-[a-z0-9]+)*$/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Maximum length for skill name.
|
|
29
|
+
*/
|
|
30
|
+
export const SKILL_NAME_MAX_LENGTH = 64
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Maximum length for skill description.
|
|
34
|
+
*/
|
|
35
|
+
export const SKILL_DESCRIPTION_MAX_LENGTH = 1024
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Validates a skill name according to the naming rules.
|
|
39
|
+
* @param name - The skill name to validate
|
|
40
|
+
* @returns true if valid, false otherwise
|
|
41
|
+
*/
|
|
42
|
+
export function isValidSkillName(name: string): boolean {
|
|
43
|
+
if (!name || name.length > SKILL_NAME_MAX_LENGTH) {
|
|
44
|
+
return false
|
|
45
|
+
}
|
|
46
|
+
return SKILL_NAME_REGEX.test(name)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Validates a skill description according to length rules.
|
|
51
|
+
* @param description - The skill description to validate
|
|
52
|
+
* @returns true if valid, false otherwise
|
|
53
|
+
*/
|
|
54
|
+
export function isValidSkillDescription(description: string): boolean {
|
|
55
|
+
return (
|
|
56
|
+
typeof description === 'string' &&
|
|
57
|
+
description.length >= 1 &&
|
|
58
|
+
description.length <= SKILL_DESCRIPTION_MAX_LENGTH
|
|
59
|
+
)
|
|
60
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export const SUBSCRIPTION_DISPLAY_NAME = 'Strong' as const
|
|
2
|
+
|
|
3
|
+
export interface TierConfig {
|
|
4
|
+
monthlyPrice: number
|
|
5
|
+
creditsPerBlock: number
|
|
6
|
+
blockDurationHours: number
|
|
7
|
+
weeklyCreditsLimit: number
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const SUBSCRIPTION_TIERS = {
|
|
11
|
+
100: {
|
|
12
|
+
monthlyPrice: 100,
|
|
13
|
+
creditsPerBlock: 420,
|
|
14
|
+
blockDurationHours: 5,
|
|
15
|
+
weeklyCreditsLimit: 4200,
|
|
16
|
+
},
|
|
17
|
+
200: {
|
|
18
|
+
monthlyPrice: 200,
|
|
19
|
+
creditsPerBlock: 1050,
|
|
20
|
+
blockDurationHours: 5,
|
|
21
|
+
weeklyCreditsLimit: 10500,
|
|
22
|
+
},
|
|
23
|
+
500: {
|
|
24
|
+
monthlyPrice: 500,
|
|
25
|
+
creditsPerBlock: 2940,
|
|
26
|
+
blockDurationHours: 5,
|
|
27
|
+
weeklyCreditsLimit: 29400,
|
|
28
|
+
},
|
|
29
|
+
} as const satisfies Record<number, TierConfig>
|
|
30
|
+
|
|
31
|
+
export type SubscriptionTierPrice = keyof typeof SUBSCRIPTION_TIERS
|
|
32
|
+
|
|
33
|
+
export const DEFAULT_TIER = SUBSCRIPTION_TIERS[200]
|
|
34
|
+
|
|
35
|
+
export function createSubscriptionPriceMappings(priceIds: Record<SubscriptionTierPrice, string>) {
|
|
36
|
+
const priceToTier = Object.fromEntries(
|
|
37
|
+
Object.entries(priceIds).map(([tier, priceId]) => [priceId, Number(tier) as SubscriptionTierPrice]),
|
|
38
|
+
) as Record<string, SubscriptionTierPrice>
|
|
39
|
+
|
|
40
|
+
function getTierFromPriceId(priceId: string): SubscriptionTierPrice | null {
|
|
41
|
+
return priceToTier[priceId] ?? null
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getPriceIdFromTier(tier: SubscriptionTierPrice): string | null {
|
|
45
|
+
return priceIds[tier] ?? null
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return { getTierFromPriceId, getPriceIdFromTier }
|
|
49
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const AuthState = {
|
|
2
|
+
LOGGED_OUT: 'LOGGED_OUT',
|
|
3
|
+
LOGGED_IN: 'LOGGED_IN',
|
|
4
|
+
} as const
|
|
5
|
+
|
|
6
|
+
export type AuthState = (typeof AuthState)[keyof typeof AuthState]
|
|
7
|
+
|
|
8
|
+
export const UserState = {
|
|
9
|
+
LOGGED_OUT: 'LOGGED_OUT',
|
|
10
|
+
GOOD_STANDING: 'GOOD_STANDING', // >= 100 credits
|
|
11
|
+
ATTENTION_NEEDED: 'ATTENTION_NEEDED', // 20-99 credits
|
|
12
|
+
CRITICAL: 'CRITICAL', // 1-19 credits
|
|
13
|
+
DEPLETED: 'DEPLETED', // <= 0 credits
|
|
14
|
+
} as const
|
|
15
|
+
|
|
16
|
+
export type UserState = (typeof UserState)[keyof typeof UserState]
|
|
17
|
+
|
|
18
|
+
export function getUserState(isLoggedIn: boolean, credits: number): UserState {
|
|
19
|
+
if (!isLoggedIn) return UserState.LOGGED_OUT
|
|
20
|
+
|
|
21
|
+
if (credits >= 100) return UserState.GOOD_STANDING
|
|
22
|
+
if (credits >= 20) return UserState.ATTENTION_NEEDED
|
|
23
|
+
if (credits >= 1) return UserState.CRITICAL
|
|
24
|
+
return UserState.DEPLETED
|
|
25
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CI environment helper for dependency injection.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a typed interface to CI-specific environment variables.
|
|
5
|
+
* These are used in CI/CD pipelines and eval contexts.
|
|
6
|
+
* In tests, use `@anvil/common/testing-env-ci`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { CiEnv } from './types/contracts/env'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get CI environment values.
|
|
13
|
+
* Returns a snapshot of the current process.env values for CI-specific vars.
|
|
14
|
+
*/
|
|
15
|
+
export const getCiEnv = (): CiEnv => ({
|
|
16
|
+
CI: process.env.CI,
|
|
17
|
+
GITHUB_ACTIONS: process.env.GITHUB_ACTIONS,
|
|
18
|
+
RENDER: process.env.RENDER,
|
|
19
|
+
IS_PULL_REQUEST: process.env.IS_PULL_REQUEST,
|
|
20
|
+
ANVIL_GITHUB_TOKEN: process.env.ANVIL_GITHUB_TOKEN,
|
|
21
|
+
ANVIL_API_KEY: process.env.ANVIL_API_KEY,
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Default CI env instance.
|
|
26
|
+
* Use this for production code, inject mocks in tests.
|
|
27
|
+
*/
|
|
28
|
+
export const ciEnv: CiEnv = getCiEnv()
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if running in CI environment
|
|
32
|
+
*/
|
|
33
|
+
export const isCI = (): boolean => {
|
|
34
|
+
const env = getCiEnv()
|
|
35
|
+
return env.CI === 'true' || env.CI === '1' || env.GITHUB_ACTIONS === 'true'
|
|
36
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process environment helper for dependency injection.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a typed interface to process.env values that aren't
|
|
5
|
+
* part of our validated schemas (ClientEnv/ServerEnv). These are runtime
|
|
6
|
+
* environment variables like SHELL, HOME, TERM, etc.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* - Import `getBaseEnv` for base OS-level vars only
|
|
10
|
+
* - Import `getProcessEnv` for the full ProcessEnv (base + extensions)
|
|
11
|
+
* - In tests, use `@anvil/common/testing-env-process`
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type { BaseEnv, ProcessEnv } from './types/contracts/env'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get base environment values (OS-level vars only).
|
|
18
|
+
* This is the foundation that package-specific helpers should spread into.
|
|
19
|
+
*/
|
|
20
|
+
export const getBaseEnv = (): BaseEnv => ({
|
|
21
|
+
SHELL: process.env.SHELL,
|
|
22
|
+
COMSPEC: process.env.COMSPEC,
|
|
23
|
+
HOME: process.env.HOME,
|
|
24
|
+
USERPROFILE: process.env.USERPROFILE,
|
|
25
|
+
APPDATA: process.env.APPDATA,
|
|
26
|
+
XDG_CONFIG_HOME: process.env.XDG_CONFIG_HOME,
|
|
27
|
+
TERM: process.env.TERM,
|
|
28
|
+
TERM_PROGRAM: process.env.TERM_PROGRAM,
|
|
29
|
+
TERM_BACKGROUND: process.env.TERM_BACKGROUND,
|
|
30
|
+
TERMINAL_EMULATOR: process.env.TERMINAL_EMULATOR,
|
|
31
|
+
COLORFGBG: process.env.COLORFGBG,
|
|
32
|
+
NODE_ENV: process.env.NODE_ENV,
|
|
33
|
+
NODE_PATH: process.env.NODE_PATH,
|
|
34
|
+
PATH: process.env.PATH,
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Get full process environment values (base + all extensions).
|
|
39
|
+
* Returns a snapshot of the current process.env values for the ProcessEnv type.
|
|
40
|
+
*/
|
|
41
|
+
export const getProcessEnv = (): ProcessEnv => ({
|
|
42
|
+
...getBaseEnv(),
|
|
43
|
+
|
|
44
|
+
// Terminal-specific
|
|
45
|
+
KITTY_WINDOW_ID: process.env.KITTY_WINDOW_ID,
|
|
46
|
+
SIXEL_SUPPORT: process.env.SIXEL_SUPPORT,
|
|
47
|
+
ZED_NODE_ENV: process.env.ZED_NODE_ENV,
|
|
48
|
+
|
|
49
|
+
// VS Code family detection
|
|
50
|
+
VSCODE_THEME_KIND: process.env.VSCODE_THEME_KIND,
|
|
51
|
+
VSCODE_COLOR_THEME_KIND: process.env.VSCODE_COLOR_THEME_KIND,
|
|
52
|
+
VSCODE_GIT_IPC_HANDLE: process.env.VSCODE_GIT_IPC_HANDLE,
|
|
53
|
+
VSCODE_PID: process.env.VSCODE_PID,
|
|
54
|
+
VSCODE_CWD: process.env.VSCODE_CWD,
|
|
55
|
+
VSCODE_NLS_CONFIG: process.env.VSCODE_NLS_CONFIG,
|
|
56
|
+
|
|
57
|
+
// Cursor editor detection
|
|
58
|
+
CURSOR_PORT: process.env.CURSOR_PORT,
|
|
59
|
+
CURSOR: process.env.CURSOR,
|
|
60
|
+
|
|
61
|
+
// JetBrains IDE detection
|
|
62
|
+
JETBRAINS_REMOTE_RUN: process.env.JETBRAINS_REMOTE_RUN,
|
|
63
|
+
IDEA_INITIAL_DIRECTORY: process.env.IDEA_INITIAL_DIRECTORY,
|
|
64
|
+
IDE_CONFIG_DIR: process.env.IDE_CONFIG_DIR,
|
|
65
|
+
JB_IDE_CONFIG_DIR: process.env.JB_IDE_CONFIG_DIR,
|
|
66
|
+
|
|
67
|
+
// Editor preferences
|
|
68
|
+
VISUAL: process.env.VISUAL,
|
|
69
|
+
EDITOR: process.env.EDITOR,
|
|
70
|
+
ANVIL_CLI_EDITOR: process.env.ANVIL_CLI_EDITOR,
|
|
71
|
+
ANVIL_EDITOR: process.env.ANVIL_EDITOR,
|
|
72
|
+
|
|
73
|
+
// Theme preferences
|
|
74
|
+
OPEN_TUI_THEME: process.env.OPEN_TUI_THEME,
|
|
75
|
+
OPENTUI_THEME: process.env.OPENTUI_THEME,
|
|
76
|
+
|
|
77
|
+
// Anvil CLI-specific
|
|
78
|
+
ANVIL_IS_BINARY: process.env.ANVIL_IS_BINARY,
|
|
79
|
+
ANVIL_CLI_VERSION: process.env.ANVIL_CLI_VERSION,
|
|
80
|
+
ANVIL_CLI_TARGET: process.env.ANVIL_CLI_TARGET,
|
|
81
|
+
ANVIL_RG_PATH: process.env.ANVIL_RG_PATH,
|
|
82
|
+
ANVIL_WASM_DIR: process.env.ANVIL_WASM_DIR,
|
|
83
|
+
|
|
84
|
+
// Build/CI flags
|
|
85
|
+
VERBOSE: process.env.VERBOSE,
|
|
86
|
+
OVERRIDE_TARGET: process.env.OVERRIDE_TARGET,
|
|
87
|
+
OVERRIDE_PLATFORM: process.env.OVERRIDE_PLATFORM,
|
|
88
|
+
OVERRIDE_ARCH: process.env.OVERRIDE_ARCH,
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Default process env instance.
|
|
93
|
+
* Use this for production code, inject mocks in tests.
|
|
94
|
+
*/
|
|
95
|
+
export const processEnv: ProcessEnv = getProcessEnv()
|