@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,562 @@
|
|
|
1
|
+
export type ErrorOr<T, E extends ErrorObject = ErrorObject> =
|
|
2
|
+
| Success<T>
|
|
3
|
+
| Failure<E>
|
|
4
|
+
|
|
5
|
+
export type Success<T> = {
|
|
6
|
+
success: true
|
|
7
|
+
value: T
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type Failure<E extends ErrorObject = ErrorObject> = {
|
|
11
|
+
success: false
|
|
12
|
+
error: E
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Result type for prompt functions that can be aborted.
|
|
17
|
+
* Provides rich semantics to distinguish between successful completion and user abort.
|
|
18
|
+
*
|
|
19
|
+
* ## When to use `PromptResult<T>` vs `ErrorOr<T>`
|
|
20
|
+
*
|
|
21
|
+
* Use `PromptResult<T>` when:
|
|
22
|
+
* - The operation can be cancelled by the user (via AbortSignal)
|
|
23
|
+
* - An abort is an expected outcome, not an error
|
|
24
|
+
* - You need to distinguish between errors (which might trigger fallbacks) and
|
|
25
|
+
* user-initiated aborts (which should propagate immediately)
|
|
26
|
+
*
|
|
27
|
+
* Use `ErrorOr<T>` when:
|
|
28
|
+
* - The operation can fail with an error that should be handled
|
|
29
|
+
* - There's no concept of user-initiated abort
|
|
30
|
+
* - You want to return error details rather than throw
|
|
31
|
+
*
|
|
32
|
+
* ## Abort handling patterns
|
|
33
|
+
*
|
|
34
|
+
* 1. **Check and return early** - For graceful handling where abort means "stop, no error":
|
|
35
|
+
* ```ts
|
|
36
|
+
* const result = await promptAiSdk({ ... })
|
|
37
|
+
* if (result.aborted) return // or return null, false, etc.
|
|
38
|
+
* doSomething(result.value)
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
41
|
+
* 2. **Unwrap and throw** - For propagating aborts as exceptions:
|
|
42
|
+
* ```ts
|
|
43
|
+
* const value = unwrapPromptResult(await promptAiSdk({ ... }))
|
|
44
|
+
* // Throws if aborted, callers should use isAbortError() in catch blocks
|
|
45
|
+
* ```
|
|
46
|
+
*
|
|
47
|
+
* 3. **Rethrow in catch blocks** - Prevent swallowing abort errors:
|
|
48
|
+
* ```ts
|
|
49
|
+
* try {
|
|
50
|
+
* await someOperation()
|
|
51
|
+
* } catch (error) {
|
|
52
|
+
* if (isAbortError(error)) throw error // Don't swallow aborts
|
|
53
|
+
* // Handle other errors
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export type PromptResult<T> = PromptSuccess<T> | PromptAborted
|
|
58
|
+
|
|
59
|
+
export type PromptSuccess<T> = {
|
|
60
|
+
aborted: false
|
|
61
|
+
value: T
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type PromptAborted = {
|
|
65
|
+
aborted: true
|
|
66
|
+
reason?: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type ErrorObject = {
|
|
70
|
+
name: string
|
|
71
|
+
message: string
|
|
72
|
+
stack?: string
|
|
73
|
+
/** HTTP status code from error.status (used by some libraries) */
|
|
74
|
+
status?: number
|
|
75
|
+
/** HTTP status code from error.statusCode (used by AI SDK and Anvil errors) */
|
|
76
|
+
statusCode?: number
|
|
77
|
+
/** Optional machine-friendly error code, if available */
|
|
78
|
+
code?: string
|
|
79
|
+
/** Optional raw error object */
|
|
80
|
+
rawError?: string
|
|
81
|
+
/** Response body from API errors (AI SDK APICallError) */
|
|
82
|
+
responseBody?: string
|
|
83
|
+
/** URL that was called (API errors) */
|
|
84
|
+
url?: string
|
|
85
|
+
/** Whether the error is retryable (API errors) */
|
|
86
|
+
isRetryable?: boolean
|
|
87
|
+
/** Request body values that were sent (API errors) - stringified for safety */
|
|
88
|
+
requestBodyValues?: string
|
|
89
|
+
/** Cause of the error, if nested */
|
|
90
|
+
cause?: ErrorObject
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function success<T>(value: T): Success<T> {
|
|
94
|
+
return {
|
|
95
|
+
success: true,
|
|
96
|
+
value,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function failure(error: unknown): Failure<ErrorObject> {
|
|
101
|
+
return {
|
|
102
|
+
success: false,
|
|
103
|
+
error: getErrorObject(error),
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Create a successful prompt result.
|
|
109
|
+
*/
|
|
110
|
+
export function promptSuccess<T>(value: T): PromptSuccess<T> {
|
|
111
|
+
return {
|
|
112
|
+
aborted: false,
|
|
113
|
+
value,
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Create an aborted prompt result.
|
|
119
|
+
*/
|
|
120
|
+
export function promptAborted(reason?: string): PromptAborted {
|
|
121
|
+
return {
|
|
122
|
+
aborted: true,
|
|
123
|
+
...(reason !== undefined && { reason }),
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Standard error message for aborted requests.
|
|
129
|
+
* Use this constant when throwing abort errors to ensure consistency.
|
|
130
|
+
*/
|
|
131
|
+
export const ABORT_ERROR_MESSAGE = 'Request aborted'
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Custom error class for abort errors.
|
|
135
|
+
* Use this class instead of generic Error for abort errors to ensure
|
|
136
|
+
* robust detection via isAbortError() (checks error.name === 'AbortError').
|
|
137
|
+
*/
|
|
138
|
+
export class AbortError extends Error {
|
|
139
|
+
constructor(reason?: string) {
|
|
140
|
+
super(reason ? `${ABORT_ERROR_MESSAGE}: ${reason}` : ABORT_ERROR_MESSAGE)
|
|
141
|
+
this.name = 'AbortError'
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Check if an error is an abort error.
|
|
147
|
+
* Use this helper to detect abort errors in catch blocks.
|
|
148
|
+
*
|
|
149
|
+
* Detects both:
|
|
150
|
+
* - Errors with message starting with 'Request aborted' (thrown by our code via AbortError)
|
|
151
|
+
* - Native AbortError (thrown by fetch/AI SDK when AbortSignal is triggered)
|
|
152
|
+
*/
|
|
153
|
+
export function isAbortError(error: unknown): boolean {
|
|
154
|
+
if (!(error instanceof Error)) {
|
|
155
|
+
return false
|
|
156
|
+
}
|
|
157
|
+
// Check for our custom abort error message:
|
|
158
|
+
// - Exact match: 'Request aborted'
|
|
159
|
+
// - With reason: 'Request aborted: <reason>' (from AbortError class)
|
|
160
|
+
if (
|
|
161
|
+
error.message === ABORT_ERROR_MESSAGE ||
|
|
162
|
+
error.message.startsWith(`${ABORT_ERROR_MESSAGE}: `)
|
|
163
|
+
) {
|
|
164
|
+
return true
|
|
165
|
+
}
|
|
166
|
+
// Check for native AbortError (DOMException or Error with name 'AbortError')
|
|
167
|
+
// This is thrown by fetch, AI SDK, and other web APIs when AbortSignal is triggered
|
|
168
|
+
if (error.name === 'AbortError') {
|
|
169
|
+
return true
|
|
170
|
+
}
|
|
171
|
+
return false
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Unwrap a PromptResult, returning the value if successful or throwing if aborted.
|
|
176
|
+
*
|
|
177
|
+
* Use this helper for consistent abort handling when you want aborts to propagate
|
|
178
|
+
* as exceptions. Callers should use `isAbortError()` in catch blocks to detect
|
|
179
|
+
* and handle abort errors appropriately (e.g., rethrow instead of logging as errors).
|
|
180
|
+
*
|
|
181
|
+
* @throws {AbortError} When result.aborted is true.
|
|
182
|
+
*/
|
|
183
|
+
export function unwrapPromptResult<T>(result: PromptResult<T>): T {
|
|
184
|
+
if (result.aborted) {
|
|
185
|
+
throw new AbortError(result.reason)
|
|
186
|
+
}
|
|
187
|
+
return result.value
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Parses a JSON response body string from an API error to extract structured error details.
|
|
192
|
+
* Used to extract machine-readable error codes and human-readable messages from API responses
|
|
193
|
+
* (e.g., AI SDK's APICallError includes a responseBody with the server's JSON response).
|
|
194
|
+
*
|
|
195
|
+
* Returns extracted fields, or an empty object if the responseBody is not a valid JSON string
|
|
196
|
+
* with the expected shape.
|
|
197
|
+
*/
|
|
198
|
+
export function parseApiErrorResponseBody(responseBody: unknown): {
|
|
199
|
+
errorCode?: string
|
|
200
|
+
message?: string
|
|
201
|
+
countryCode?: string
|
|
202
|
+
countryBlockReason?: string
|
|
203
|
+
ipPrivacySignals?: string[]
|
|
204
|
+
} {
|
|
205
|
+
if (typeof responseBody !== 'string') return {}
|
|
206
|
+
try {
|
|
207
|
+
const parsed: unknown = JSON.parse(responseBody)
|
|
208
|
+
if (!parsed || typeof parsed !== 'object') return {}
|
|
209
|
+
const result: {
|
|
210
|
+
errorCode?: string
|
|
211
|
+
message?: string
|
|
212
|
+
countryCode?: string
|
|
213
|
+
countryBlockReason?: string
|
|
214
|
+
ipPrivacySignals?: string[]
|
|
215
|
+
} = {}
|
|
216
|
+
if (
|
|
217
|
+
'error' in parsed &&
|
|
218
|
+
typeof (parsed as { error: unknown }).error === 'string'
|
|
219
|
+
) {
|
|
220
|
+
result.errorCode = (parsed as { error: string }).error
|
|
221
|
+
}
|
|
222
|
+
if (
|
|
223
|
+
'message' in parsed &&
|
|
224
|
+
typeof (parsed as { message: unknown }).message === 'string'
|
|
225
|
+
) {
|
|
226
|
+
result.message = (parsed as { message: string }).message
|
|
227
|
+
}
|
|
228
|
+
// OpenAI-style nested error object: { error: { message, code, type } }.
|
|
229
|
+
// Upstream provider errors (Fireworks, OpenRouter, etc.) are relayed to
|
|
230
|
+
// the client in this shape.
|
|
231
|
+
if (
|
|
232
|
+
'error' in parsed &&
|
|
233
|
+
typeof (parsed as { error: unknown }).error === 'object' &&
|
|
234
|
+
(parsed as { error: unknown }).error !== null
|
|
235
|
+
) {
|
|
236
|
+
const nested = (parsed as { error: Record<string, unknown> }).error
|
|
237
|
+
if (result.errorCode === undefined) {
|
|
238
|
+
if (typeof nested.code === 'string') {
|
|
239
|
+
result.errorCode = nested.code
|
|
240
|
+
} else if (typeof nested.type === 'string') {
|
|
241
|
+
result.errorCode = nested.type
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (result.message === undefined && typeof nested.message === 'string') {
|
|
245
|
+
result.message = nested.message
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
if (
|
|
249
|
+
'countryCode' in parsed &&
|
|
250
|
+
typeof (parsed as { countryCode: unknown }).countryCode === 'string'
|
|
251
|
+
) {
|
|
252
|
+
result.countryCode = (parsed as { countryCode: string }).countryCode
|
|
253
|
+
}
|
|
254
|
+
if (
|
|
255
|
+
'countryBlockReason' in parsed &&
|
|
256
|
+
typeof (parsed as { countryBlockReason: unknown }).countryBlockReason ===
|
|
257
|
+
'string'
|
|
258
|
+
) {
|
|
259
|
+
result.countryBlockReason = (
|
|
260
|
+
parsed as { countryBlockReason: string }
|
|
261
|
+
).countryBlockReason
|
|
262
|
+
}
|
|
263
|
+
if ('ipPrivacySignals' in parsed) {
|
|
264
|
+
const signals = (parsed as { ipPrivacySignals: unknown }).ipPrivacySignals
|
|
265
|
+
if (Array.isArray(signals)) {
|
|
266
|
+
result.ipPrivacySignals = signals.filter(
|
|
267
|
+
(signal): signal is string => typeof signal === 'string',
|
|
268
|
+
)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return result
|
|
272
|
+
} catch {
|
|
273
|
+
return {}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export type ApiErrorDetails = ReturnType<typeof parseApiErrorResponseBody> & {
|
|
278
|
+
statusCode?: number
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function getApiErrorCandidates(
|
|
282
|
+
error: unknown,
|
|
283
|
+
seen = new Set<object>(),
|
|
284
|
+
): unknown[] {
|
|
285
|
+
if (!error || typeof error !== 'object') return [error]
|
|
286
|
+
if (seen.has(error)) return []
|
|
287
|
+
seen.add(error)
|
|
288
|
+
|
|
289
|
+
const candidates: unknown[] = [error]
|
|
290
|
+
const errorWithNested = error as {
|
|
291
|
+
lastError?: unknown
|
|
292
|
+
errors?: unknown[]
|
|
293
|
+
cause?: unknown
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
candidates.push(...getApiErrorCandidates(errorWithNested.lastError, seen))
|
|
297
|
+
|
|
298
|
+
if (Array.isArray(errorWithNested.errors)) {
|
|
299
|
+
for (const nestedError of [...errorWithNested.errors].reverse()) {
|
|
300
|
+
candidates.push(...getApiErrorCandidates(nestedError, seen))
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
candidates.push(...getApiErrorCandidates(errorWithNested.cause, seen))
|
|
305
|
+
|
|
306
|
+
return candidates
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function getApiErrorStatusCode(error: unknown): number | undefined {
|
|
310
|
+
if (!error || typeof error !== 'object') return undefined
|
|
311
|
+
|
|
312
|
+
if ('statusCode' in error) {
|
|
313
|
+
const statusCode = (error as { statusCode: unknown }).statusCode
|
|
314
|
+
if (typeof statusCode === 'number') return statusCode
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if ('status' in error) {
|
|
318
|
+
const status = (error as { status: unknown }).status
|
|
319
|
+
if (typeof status === 'number') return status
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return undefined
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function getApiErrorResponseBody(error: unknown): unknown {
|
|
326
|
+
if (!error || typeof error !== 'object') return undefined
|
|
327
|
+
if (!('responseBody' in error)) return undefined
|
|
328
|
+
return (error as { responseBody: unknown }).responseBody
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function hasParsedApiErrorDetails(
|
|
332
|
+
details: ReturnType<typeof parseApiErrorResponseBody>,
|
|
333
|
+
): boolean {
|
|
334
|
+
return (
|
|
335
|
+
details.errorCode !== undefined ||
|
|
336
|
+
details.message !== undefined ||
|
|
337
|
+
details.countryCode !== undefined ||
|
|
338
|
+
details.countryBlockReason !== undefined ||
|
|
339
|
+
details.ipPrivacySignals !== undefined
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Extracts HTTP status and structured server error fields from API errors,
|
|
345
|
+
* including AI SDK RetryError wrappers whose useful APICallError is nested in
|
|
346
|
+
* `lastError` / `errors`.
|
|
347
|
+
*/
|
|
348
|
+
export function extractApiErrorDetails(error: unknown): ApiErrorDetails {
|
|
349
|
+
for (const candidate of getApiErrorCandidates(error)) {
|
|
350
|
+
const statusCode = getApiErrorStatusCode(candidate)
|
|
351
|
+
const parsed = parseApiErrorResponseBody(getApiErrorResponseBody(candidate))
|
|
352
|
+
|
|
353
|
+
if (statusCode !== undefined || hasParsedApiErrorDetails(parsed)) {
|
|
354
|
+
return {
|
|
355
|
+
...parsed,
|
|
356
|
+
...(statusCode !== undefined && { statusCode }),
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
return {}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Detects the runtime's fetch inactivity timeout (a DOMException named
|
|
366
|
+
* "TimeoutError"). Bun hardcodes this to fire after 5 minutes without
|
|
367
|
+
* receiving any bytes on a fetch response — including while still waiting on
|
|
368
|
+
* the response headers, verified 2026-08-02 against a server that delayed only
|
|
369
|
+
* its headers. Walks AI SDK RetryError wrappers and cause chains.
|
|
370
|
+
*/
|
|
371
|
+
export function isFetchIdleTimeoutError(error: unknown): boolean {
|
|
372
|
+
for (const candidate of getApiErrorCandidates(error)) {
|
|
373
|
+
if (!candidate || typeof candidate !== 'object') continue
|
|
374
|
+
const { name, message } = candidate as { name?: unknown; message?: unknown }
|
|
375
|
+
if (
|
|
376
|
+
name === 'TimeoutError' ||
|
|
377
|
+
(typeof message === 'string' &&
|
|
378
|
+
message.toLowerCase().includes('the operation timed out'))
|
|
379
|
+
) {
|
|
380
|
+
return true
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return false
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* User-facing explanation for the fetch idle timeout. The raw runtime message
|
|
388
|
+
* ("The operation timed out.") reads like a server failure, so this states the
|
|
389
|
+
* symptom instead.
|
|
390
|
+
*
|
|
391
|
+
* It deliberately does NOT blame the user's network. That copy shipped in June
|
|
392
|
+
* 2026 on the assumption that a heartbeat covered every silent window, but the
|
|
393
|
+
* heartbeat only started once the upstream model had answered — a slow model
|
|
394
|
+
* start produced exactly this error with nothing wrong on the user's end, and
|
|
395
|
+
* sent them chasing their own VPN. See grace-flush.ts on the server.
|
|
396
|
+
*/
|
|
397
|
+
export const FETCH_IDLE_TIMEOUT_USER_MESSAGE =
|
|
398
|
+
'Connection timed out: no data was received from the server for 5 minutes, so the request was aborted.\n\n' +
|
|
399
|
+
'This can be a slow model start on our side, or a connection dropped in transit (VPN, proxy, firewall, or flaky network).\n\n' +
|
|
400
|
+
'Retrying your message usually works. If it keeps happening, try a different model, or check your network/VPN/proxy.'
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Substrings of error messages that indicate the TCP connection died in
|
|
404
|
+
* transit (as opposed to the server returning an error response). Bun's fetch
|
|
405
|
+
* throws a plain Error with "The socket connection was closed unexpectedly..."
|
|
406
|
+
* and code ECONNRESET/ConnectionClosed; undici throws TypeError "fetch failed".
|
|
407
|
+
*/
|
|
408
|
+
const TRANSIENT_NETWORK_ERROR_MESSAGE_PATTERNS = [
|
|
409
|
+
'socket connection was closed unexpectedly',
|
|
410
|
+
'fetch failed',
|
|
411
|
+
'failed to fetch',
|
|
412
|
+
'network connection was lost',
|
|
413
|
+
]
|
|
414
|
+
|
|
415
|
+
const TRANSIENT_NETWORK_ERROR_CODES = new Set([
|
|
416
|
+
'ECONNRESET',
|
|
417
|
+
'ECONNREFUSED',
|
|
418
|
+
'EPIPE',
|
|
419
|
+
'ETIMEDOUT',
|
|
420
|
+
// Bun-specific fetch error codes
|
|
421
|
+
'ConnectionClosed',
|
|
422
|
+
'ConnectionRefused',
|
|
423
|
+
'FailedToOpenSocket',
|
|
424
|
+
])
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Detects transient connection-level failures (socket closed/reset, connection
|
|
428
|
+
* refused, etc.) where no HTTP response was received. These are safe to retry
|
|
429
|
+
* and should be shown to the user as a connectivity problem instead of a raw
|
|
430
|
+
* runtime error with a stack trace. Walks AI SDK RetryError wrappers and
|
|
431
|
+
* cause chains.
|
|
432
|
+
*/
|
|
433
|
+
export function isTransientNetworkError(error: unknown): boolean {
|
|
434
|
+
for (const candidate of getApiErrorCandidates(error)) {
|
|
435
|
+
if (!candidate || typeof candidate !== 'object') continue
|
|
436
|
+
const { message, code } = candidate as {
|
|
437
|
+
message?: unknown
|
|
438
|
+
code?: unknown
|
|
439
|
+
}
|
|
440
|
+
if (typeof code === 'string' && TRANSIENT_NETWORK_ERROR_CODES.has(code)) {
|
|
441
|
+
return true
|
|
442
|
+
}
|
|
443
|
+
if (typeof message === 'string') {
|
|
444
|
+
const lower = message.toLowerCase()
|
|
445
|
+
if (
|
|
446
|
+
TRANSIENT_NETWORK_ERROR_MESSAGE_PATTERNS.some((pattern) =>
|
|
447
|
+
lower.includes(pattern),
|
|
448
|
+
)
|
|
449
|
+
) {
|
|
450
|
+
return true
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return false
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* User-facing explanation for a dropped connection. The raw runtime message
|
|
459
|
+
* ("The socket connection was closed unexpectedly. For more information, pass
|
|
460
|
+
* `verbose: true`...") plus a stack trace reads like a crash; in practice the
|
|
461
|
+
* connection to the server was cut mid-request, which is transient and safe
|
|
462
|
+
* to retry.
|
|
463
|
+
*/
|
|
464
|
+
export const TRANSIENT_NETWORK_ERROR_USER_MESSAGE =
|
|
465
|
+
'Connection interrupted: the connection to the server was closed unexpectedly, even after retrying.\n\n' +
|
|
466
|
+
'This is usually a transient issue — a flaky network, VPN/proxy, or the server briefly under heavy load.\n\n' +
|
|
467
|
+
'Your progress is saved. Please try sending your message again.'
|
|
468
|
+
|
|
469
|
+
// Extended error properties that various libraries add to Error objects
|
|
470
|
+
interface ExtendedErrorProperties {
|
|
471
|
+
status?: number
|
|
472
|
+
statusCode?: number
|
|
473
|
+
code?: string
|
|
474
|
+
// API error properties (AI SDK APICallError, etc.)
|
|
475
|
+
responseBody?: string
|
|
476
|
+
url?: string
|
|
477
|
+
isRetryable?: boolean
|
|
478
|
+
requestBodyValues?: Record<string, unknown>
|
|
479
|
+
cause?: unknown
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Safely stringify an object, handling circular references and large objects.
|
|
484
|
+
*/
|
|
485
|
+
function safeStringify(value: unknown, maxLength = 10000): string | undefined {
|
|
486
|
+
if (value === undefined || value === null) return undefined
|
|
487
|
+
if (typeof value === 'string') return value.slice(0, maxLength)
|
|
488
|
+
try {
|
|
489
|
+
const seen = new WeakSet()
|
|
490
|
+
const str = JSON.stringify(
|
|
491
|
+
value,
|
|
492
|
+
(_, val) => {
|
|
493
|
+
if (typeof val === 'object' && val !== null) {
|
|
494
|
+
if (seen.has(val)) return '[Circular]'
|
|
495
|
+
seen.add(val)
|
|
496
|
+
}
|
|
497
|
+
return val
|
|
498
|
+
},
|
|
499
|
+
2,
|
|
500
|
+
)
|
|
501
|
+
return str?.slice(0, maxLength)
|
|
502
|
+
} catch {
|
|
503
|
+
return '[Unable to stringify]'
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
export function getErrorObject(
|
|
508
|
+
error: unknown,
|
|
509
|
+
options: { includeRawError?: boolean } = {},
|
|
510
|
+
): ErrorObject {
|
|
511
|
+
if (error instanceof Error) {
|
|
512
|
+
const extError = error as Error & Partial<ExtendedErrorProperties>
|
|
513
|
+
|
|
514
|
+
// Extract responseBody - could be string or object
|
|
515
|
+
let responseBody: string | undefined
|
|
516
|
+
if (extError.responseBody !== undefined) {
|
|
517
|
+
responseBody = safeStringify(extError.responseBody)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Extract requestBodyValues - typically an object, stringify for logging
|
|
521
|
+
let requestBodyValues: string | undefined
|
|
522
|
+
if (
|
|
523
|
+
extError.requestBodyValues !== undefined &&
|
|
524
|
+
typeof extError.requestBodyValues === 'object'
|
|
525
|
+
) {
|
|
526
|
+
requestBodyValues = safeStringify(extError.requestBodyValues)
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// Extract cause - recursively convert to ErrorObject if present
|
|
530
|
+
let cause: ErrorObject | undefined
|
|
531
|
+
if (extError.cause !== undefined) {
|
|
532
|
+
cause = getErrorObject(extError.cause, options)
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return {
|
|
536
|
+
name: error.name,
|
|
537
|
+
message: error.message,
|
|
538
|
+
stack: error.stack,
|
|
539
|
+
status: typeof extError.status === 'number' ? extError.status : undefined,
|
|
540
|
+
statusCode:
|
|
541
|
+
typeof extError.statusCode === 'number'
|
|
542
|
+
? extError.statusCode
|
|
543
|
+
: undefined,
|
|
544
|
+
code: typeof extError.code === 'string' ? extError.code : undefined,
|
|
545
|
+
rawError: options.includeRawError ? safeStringify(error) : undefined,
|
|
546
|
+
// API error fields
|
|
547
|
+
responseBody,
|
|
548
|
+
url: typeof extError.url === 'string' ? extError.url : undefined,
|
|
549
|
+
isRetryable:
|
|
550
|
+
typeof extError.isRetryable === 'boolean'
|
|
551
|
+
? extError.isRetryable
|
|
552
|
+
: undefined,
|
|
553
|
+
requestBodyValues,
|
|
554
|
+
cause,
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
name: 'Error',
|
|
560
|
+
message: `${error}`,
|
|
561
|
+
}
|
|
562
|
+
}
|