@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,38 @@
|
|
|
1
|
+
export const DEFAULT_ORG_PREFIX = 'anvil/'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolves an agent ID by trying multiple strategies:
|
|
5
|
+
* 1. Direct lookup in registry
|
|
6
|
+
* 2. Try with DEFAULT_ORG_PREFIX for spawnable agents
|
|
7
|
+
* 3. Return null if not found
|
|
8
|
+
*
|
|
9
|
+
* This provides a more robust alternative to string concatenation
|
|
10
|
+
* and handles the common case where users reference spawnable agents
|
|
11
|
+
* without the org prefix.
|
|
12
|
+
*/
|
|
13
|
+
export function resolveAgentId(
|
|
14
|
+
agentId: string,
|
|
15
|
+
agentRegistry: Record<string, any>,
|
|
16
|
+
): string | null {
|
|
17
|
+
// Handle empty or invalid input
|
|
18
|
+
if (!agentId || typeof agentId !== 'string') {
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Try direct lookup first
|
|
23
|
+
if (agentId in agentRegistry) {
|
|
24
|
+
return agentId
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Try with DEFAULT_ORG_PREFIX for spawnable agents
|
|
28
|
+
// Only add prefix if the agent ID doesn't already contain a slash
|
|
29
|
+
// (to avoid double-prefixing or interfering with other org prefixes)
|
|
30
|
+
if (!agentId.includes('/')) {
|
|
31
|
+
const prefixedAgentId = `${DEFAULT_ORG_PREFIX}${agentId}`
|
|
32
|
+
if (prefixedAgentId in agentRegistry) {
|
|
33
|
+
return prefixedAgentId
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { AGENT_PERSONAS } from '../constants/agents'
|
|
2
|
+
|
|
3
|
+
export interface AgentInfo {
|
|
4
|
+
id: string
|
|
5
|
+
displayName: string
|
|
6
|
+
purpose?: string
|
|
7
|
+
isBuiltIn: boolean
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Get all built-in agents (excluding hidden ones)
|
|
12
|
+
*/
|
|
13
|
+
export function getBuiltInAgents(): AgentInfo[] {
|
|
14
|
+
return Object.entries(AGENT_PERSONAS)
|
|
15
|
+
.filter(([, persona]) => !('hidden' in persona) || !persona.hidden)
|
|
16
|
+
.map(([agentId, persona]) => ({
|
|
17
|
+
id: agentId,
|
|
18
|
+
displayName: persona.displayName,
|
|
19
|
+
purpose: persona.purpose,
|
|
20
|
+
isBuiltIn: true,
|
|
21
|
+
}))
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert local agent configs to AgentInfo array
|
|
26
|
+
*/
|
|
27
|
+
export function getLocalAgents(
|
|
28
|
+
localAgents: Record<string, { displayName: string; purpose?: string }>,
|
|
29
|
+
): AgentInfo[] {
|
|
30
|
+
return Object.entries(localAgents).map(([agentId, config]) => ({
|
|
31
|
+
id: agentId,
|
|
32
|
+
displayName: config.displayName,
|
|
33
|
+
purpose: config.purpose,
|
|
34
|
+
isBuiltIn: false,
|
|
35
|
+
}))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get all agents (built-in + local)
|
|
40
|
+
*/
|
|
41
|
+
export function getAllAgents(
|
|
42
|
+
localAgents: Record<string, { displayName: string; purpose?: string }> = {},
|
|
43
|
+
): AgentInfo[] {
|
|
44
|
+
return [...getBuiltInAgents(), ...getLocalAgents(localAgents)]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Resolve display name to agent ID
|
|
49
|
+
*/
|
|
50
|
+
export function resolveNameToId(
|
|
51
|
+
displayName: string,
|
|
52
|
+
localAgents: Record<string, { displayName: string; purpose?: string }> = {},
|
|
53
|
+
): string | null {
|
|
54
|
+
const agents = getAllAgents(localAgents)
|
|
55
|
+
const agent = agents.find(
|
|
56
|
+
(a) => a.displayName.toLowerCase() === displayName.toLowerCase(),
|
|
57
|
+
)
|
|
58
|
+
return agent?.id || null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Resolve agent ID to display name
|
|
63
|
+
*/
|
|
64
|
+
function resolveIdToName(
|
|
65
|
+
agentId: string,
|
|
66
|
+
localAgents: Record<string, { displayName: string; purpose?: string }> = {},
|
|
67
|
+
): string | null {
|
|
68
|
+
const agents = getAllAgents(localAgents)
|
|
69
|
+
const agent = agents.find((a) => a.id === agentId)
|
|
70
|
+
return agent?.displayName || null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Get agent display name from ID or name, with fallback
|
|
75
|
+
*/
|
|
76
|
+
export function getAgentDisplayName(
|
|
77
|
+
agentIdOrName: string,
|
|
78
|
+
localAgents: Record<string, { displayName: string; purpose?: string }> = {},
|
|
79
|
+
): string {
|
|
80
|
+
return (
|
|
81
|
+
resolveIdToName(agentIdOrName, localAgents) ||
|
|
82
|
+
(resolveNameToId(agentIdOrName, localAgents)
|
|
83
|
+
? agentIdOrName
|
|
84
|
+
: agentIdOrName)
|
|
85
|
+
)
|
|
86
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
|
|
2
|
+
import {
|
|
3
|
+
getAnalyticsEventId,
|
|
4
|
+
toTrackableAnalyticsPayload,
|
|
5
|
+
type AnalyticsLogData,
|
|
6
|
+
type TrackableAnalyticsPayload,
|
|
7
|
+
} from './analytics-log'
|
|
8
|
+
|
|
9
|
+
type EnvName = 'dev' | 'test' | 'prod' | string
|
|
10
|
+
|
|
11
|
+
export type AnalyticsDispatchInput = {
|
|
12
|
+
data: unknown
|
|
13
|
+
level: string
|
|
14
|
+
msg: string
|
|
15
|
+
fallbackUserId?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type AnalyticsDispatchPayload = TrackableAnalyticsPayload
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Minimal, runtime-agnostic router for analytics events.
|
|
22
|
+
* Handles:
|
|
23
|
+
* - Dev gating (no-op in dev)
|
|
24
|
+
* - Optional buffering until a userId is available
|
|
25
|
+
* - Reusing the shared payload builder for consistency
|
|
26
|
+
*/
|
|
27
|
+
export function createAnalyticsDispatcher({
|
|
28
|
+
envName,
|
|
29
|
+
bufferWhenNoUser = false,
|
|
30
|
+
}: {
|
|
31
|
+
envName: EnvName
|
|
32
|
+
bufferWhenNoUser?: boolean
|
|
33
|
+
}) {
|
|
34
|
+
const buffered: AnalyticsDispatchInput[] = []
|
|
35
|
+
const isDevEnv = envName === 'dev'
|
|
36
|
+
|
|
37
|
+
function flushBufferWithUser(
|
|
38
|
+
userId: string,
|
|
39
|
+
): AnalyticsDispatchPayload[] {
|
|
40
|
+
if (!buffered.length) {
|
|
41
|
+
return []
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const toSend: AnalyticsDispatchPayload[] = []
|
|
45
|
+
for (const item of buffered.splice(0)) {
|
|
46
|
+
const rebuilt = toTrackableAnalyticsPayload({
|
|
47
|
+
...item,
|
|
48
|
+
fallbackUserId: userId,
|
|
49
|
+
})
|
|
50
|
+
if (rebuilt) {
|
|
51
|
+
toSend.push(rebuilt)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return toSend
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function process(
|
|
58
|
+
input: AnalyticsDispatchInput,
|
|
59
|
+
): AnalyticsDispatchPayload[] {
|
|
60
|
+
if (isDevEnv) {
|
|
61
|
+
return []
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const payload = toTrackableAnalyticsPayload(input)
|
|
65
|
+
if (payload) {
|
|
66
|
+
const toSend = flushBufferWithUser(payload.userId)
|
|
67
|
+
toSend.push(payload)
|
|
68
|
+
return toSend
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (
|
|
72
|
+
bufferWhenNoUser &&
|
|
73
|
+
getAnalyticsEventId(input.data as AnalyticsLogData)
|
|
74
|
+
) {
|
|
75
|
+
buffered.push(input)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return []
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return { process }
|
|
82
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { AnalyticsEvent } from '@anvil/common/constants/analytics-events'
|
|
2
|
+
|
|
3
|
+
// Build PostHog payloads from log data in a single, shared place
|
|
4
|
+
export type AnalyticsLogData = {
|
|
5
|
+
eventId?: unknown
|
|
6
|
+
userId?: unknown
|
|
7
|
+
user_id?: unknown
|
|
8
|
+
user?: { id?: unknown }
|
|
9
|
+
[key: string]: unknown
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type TrackableAnalyticsPayload = {
|
|
13
|
+
event: AnalyticsEvent
|
|
14
|
+
userId: string
|
|
15
|
+
properties: Record<string, unknown>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const analyticsEvents = new Set<AnalyticsEvent>(Object.values(AnalyticsEvent))
|
|
19
|
+
|
|
20
|
+
const toStringOrNull = (value: unknown): string | null =>
|
|
21
|
+
typeof value === 'string' ? value : null
|
|
22
|
+
|
|
23
|
+
const getUserId = (
|
|
24
|
+
record: AnalyticsLogData,
|
|
25
|
+
fallbackUserId?: string,
|
|
26
|
+
): string | null =>
|
|
27
|
+
toStringOrNull(record.userId) ??
|
|
28
|
+
toStringOrNull(record.user_id) ??
|
|
29
|
+
toStringOrNull(record.user?.id) ??
|
|
30
|
+
toStringOrNull(fallbackUserId)
|
|
31
|
+
|
|
32
|
+
export function getAnalyticsEventId(data: unknown): AnalyticsEvent | null {
|
|
33
|
+
if (!data || typeof data !== 'object') {
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
const eventId = (data as AnalyticsLogData).eventId
|
|
37
|
+
return analyticsEvents.has(eventId as AnalyticsEvent)
|
|
38
|
+
? (eventId as AnalyticsEvent)
|
|
39
|
+
: null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function toTrackableAnalyticsPayload({
|
|
43
|
+
data,
|
|
44
|
+
level,
|
|
45
|
+
msg,
|
|
46
|
+
fallbackUserId,
|
|
47
|
+
}: {
|
|
48
|
+
data: unknown
|
|
49
|
+
level: string
|
|
50
|
+
msg: string
|
|
51
|
+
fallbackUserId?: string
|
|
52
|
+
}): TrackableAnalyticsPayload | null {
|
|
53
|
+
if (!data || typeof data !== 'object') {
|
|
54
|
+
return null
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const record = data as AnalyticsLogData
|
|
58
|
+
const eventId = getAnalyticsEventId(record)
|
|
59
|
+
if (!eventId) {
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const userId = getUserId(record, fallbackUserId)
|
|
64
|
+
|
|
65
|
+
if (!userId) {
|
|
66
|
+
return null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
event: eventId,
|
|
71
|
+
userId,
|
|
72
|
+
properties: {
|
|
73
|
+
...record,
|
|
74
|
+
level,
|
|
75
|
+
msg,
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import { AnalyticsEvent } from '../constants/analytics-events'
|
|
2
|
+
|
|
3
|
+
const DEFAULT_SAMPLED_RATE = 0.01
|
|
4
|
+
|
|
5
|
+
const SAMPLED_EVENT_RATES: Partial<Record<AnalyticsEvent, number>> = {
|
|
6
|
+
[AnalyticsEvent.AGENT_STEP]: DEFAULT_SAMPLED_RATE,
|
|
7
|
+
[AnalyticsEvent.CLI_LOG]: DEFAULT_SAMPLED_RATE,
|
|
8
|
+
[AnalyticsEvent.FEEDBACK_BUTTON_HOVERED]: DEFAULT_SAMPLED_RATE,
|
|
9
|
+
[AnalyticsEvent.FOLLOWUP_CLICKED]: DEFAULT_SAMPLED_RATE,
|
|
10
|
+
[AnalyticsEvent.CLI_INLINE_AD_SLOT_ELIGIBLE]: DEFAULT_SAMPLED_RATE,
|
|
11
|
+
[AnalyticsEvent.SLASH_COMMAND_USED]: DEFAULT_SAMPLED_RATE,
|
|
12
|
+
[AnalyticsEvent.SLASH_MENU_ACTIVATED]: DEFAULT_SAMPLED_RATE,
|
|
13
|
+
[AnalyticsEvent.TOOL_USE]: DEFAULT_SAMPLED_RATE,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const ALWAYS_TRACK_EVENTS = new Set<AnalyticsEvent>([
|
|
17
|
+
// DAU is measured from MESSAGE_SENT, so it must never be sampled.
|
|
18
|
+
AnalyticsEvent.MESSAGE_SENT,
|
|
19
|
+
// Engaged-time is summed from event counts, so it must never be sampled.
|
|
20
|
+
AnalyticsEvent.PRODUCT_ACTIVE_MINUTE,
|
|
21
|
+
AnalyticsEvent.APP_LAUNCHED,
|
|
22
|
+
AnalyticsEvent.CHANGE_DIRECTORY,
|
|
23
|
+
AnalyticsEvent.FINGERPRINT_GENERATED,
|
|
24
|
+
AnalyticsEvent.INVALID_COMMAND,
|
|
25
|
+
AnalyticsEvent.KNOWLEDGE_FILE_UPDATED,
|
|
26
|
+
AnalyticsEvent.LOGIN,
|
|
27
|
+
AnalyticsEvent.LOGIN_STARTED,
|
|
28
|
+
AnalyticsEvent.LOGIN_FAILED,
|
|
29
|
+
AnalyticsEvent.LOGIN_TIMEOUT,
|
|
30
|
+
AnalyticsEvent.LOGIN_ABORTED,
|
|
31
|
+
// Desktop surface events are low-volume; keep them whole so the app's launch /
|
|
32
|
+
// login / activity funnels aren't decimated by the 1% default sample.
|
|
33
|
+
AnalyticsEvent.DESKTOP_APP_LAUNCHED,
|
|
34
|
+
// Both halves of the sign-in funnel, or its conversion rate is a ratio of two
|
|
35
|
+
// differently-sampled numbers.
|
|
36
|
+
AnalyticsEvent.DESKTOP_LOGIN_STARTED,
|
|
37
|
+
AnalyticsEvent.DESKTOP_LOGIN,
|
|
38
|
+
// Rare, and the only evidence a sign-in failed at all — a sampled one is a
|
|
39
|
+
// support ticket with nothing behind it.
|
|
40
|
+
AnalyticsEvent.DESKTOP_LOGIN_FAILED,
|
|
41
|
+
AnalyticsEvent.DESKTOP_LOGOUT,
|
|
42
|
+
AnalyticsEvent.DESKTOP_THREAD_CREATED,
|
|
43
|
+
AnalyticsEvent.DESKTOP_PROJECT_OPENED,
|
|
44
|
+
AnalyticsEvent.DESKTOP_TURN_COMPLETED,
|
|
45
|
+
// Low-volume recovery funnel. Sampling any stage independently would make
|
|
46
|
+
// creation-to-success and repeated-failure rates impossible to measure.
|
|
47
|
+
AnalyticsEvent.DESKTOP_FAILED_TURN_RECOVERY,
|
|
48
|
+
// Rare reliability signal — every stalled turn must be counted, never sampled.
|
|
49
|
+
AnalyticsEvent.DESKTOP_TURN_STALLED,
|
|
50
|
+
// Its counterpart (an explained silence). Same reasoning: rare, and only
|
|
51
|
+
// useful if every one is counted.
|
|
52
|
+
AnalyticsEvent.DESKTOP_TURN_BACKGROUND_WAIT,
|
|
53
|
+
// Feature adoption is measured as UNIQUE USERS per feature. At desktop's
|
|
54
|
+
// ~1-2k DAU a 1% sample would leave a feature used by 2% of users with
|
|
55
|
+
// roughly zero sampled users — the number is unrecoverable from a sample, so
|
|
56
|
+
// this one is never sampled. Volume is controlled at the emit site instead
|
|
57
|
+
// (intent-only actions + per-session dedupe), not by throwing away users.
|
|
58
|
+
AnalyticsEvent.DESKTOP_FEATURE_USED,
|
|
59
|
+
AnalyticsEvent.DESKTOP_HARNESS_CHANGED,
|
|
60
|
+
AnalyticsEvent.DESKTOP_MODEL_CHANGED,
|
|
61
|
+
AnalyticsEvent.DESKTOP_SKILL_RUN,
|
|
62
|
+
AnalyticsEvent.DESKTOP_CODEX_RESOLUTION,
|
|
63
|
+
// Rare operational signal. Sampling would make per-version failure rates
|
|
64
|
+
// misleading precisely when a Windows-only regression affects few installs.
|
|
65
|
+
AnalyticsEvent.TERMINAL_BROKER_SPAWN_FAILED,
|
|
66
|
+
AnalyticsEvent.TERMINAL_WATCHDOG_FAILED,
|
|
67
|
+
AnalyticsEvent.TERMINAL_COMMAND_COMPLETED,
|
|
68
|
+
AnalyticsEvent.UPDATE_ANVIL_FAILED,
|
|
69
|
+
AnalyticsEvent.USER_INPUT,
|
|
70
|
+
AnalyticsEvent.USER_INPUT_COMPLETE,
|
|
71
|
+
])
|
|
72
|
+
|
|
73
|
+
type AnalyticsProperties = Record<string, unknown> | undefined
|
|
74
|
+
|
|
75
|
+
function getStringProperty(
|
|
76
|
+
properties: AnalyticsProperties,
|
|
77
|
+
key: string,
|
|
78
|
+
): string | undefined {
|
|
79
|
+
const value = properties?.[key]
|
|
80
|
+
return typeof value === 'string' && value.trim() ? value : undefined
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getPropertyUserId(
|
|
84
|
+
properties: AnalyticsProperties,
|
|
85
|
+
): string | undefined {
|
|
86
|
+
const direct =
|
|
87
|
+
getStringProperty(properties, 'userId') ??
|
|
88
|
+
getStringProperty(properties, 'user_id') ??
|
|
89
|
+
getStringProperty(properties, 'distinct_id')
|
|
90
|
+
if (direct) {
|
|
91
|
+
return direct
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const user = properties?.user
|
|
95
|
+
if (user && typeof user === 'object') {
|
|
96
|
+
const id = (user as { id?: unknown }).id
|
|
97
|
+
return typeof id === 'string' && id.trim() ? id : undefined
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return undefined
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function splitEnvList(value: string | undefined): Set<string> {
|
|
104
|
+
return new Set(
|
|
105
|
+
(value ?? '')
|
|
106
|
+
.split(',')
|
|
107
|
+
.map((item) => item.trim())
|
|
108
|
+
.filter(Boolean),
|
|
109
|
+
)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function isTruthyEnv(value: string | undefined): boolean {
|
|
113
|
+
return value === '1' || value === 'true' || value === 'yes'
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function isFullTelemetryEnabled(params: {
|
|
117
|
+
distinctId?: string
|
|
118
|
+
properties?: AnalyticsProperties
|
|
119
|
+
}): boolean {
|
|
120
|
+
if (isTruthyEnv(process.env.ANVIL_FULL_TELEMETRY)) {
|
|
121
|
+
return true
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const ids = splitEnvList(
|
|
125
|
+
process.env.ANVIL_FULL_TELEMETRY_IDS ??
|
|
126
|
+
process.env.ANVIL_FULL_TELEMETRY_USER_IDS,
|
|
127
|
+
)
|
|
128
|
+
if (ids.size === 0) {
|
|
129
|
+
return false
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const candidates = [
|
|
133
|
+
params.distinctId,
|
|
134
|
+
getPropertyUserId(params.properties),
|
|
135
|
+
getStringProperty(params.properties, 'userEmail'),
|
|
136
|
+
getStringProperty(params.properties, 'email'),
|
|
137
|
+
].filter(
|
|
138
|
+
(value): value is string => typeof value === 'string' && value.length > 0,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
return candidates.some((candidate) => ids.has(candidate))
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getEventSampleRate(
|
|
145
|
+
event: AnalyticsEvent,
|
|
146
|
+
properties: AnalyticsProperties,
|
|
147
|
+
): number {
|
|
148
|
+
const level = getStringProperty(properties, 'level')?.toLowerCase()
|
|
149
|
+
if (
|
|
150
|
+
event === AnalyticsEvent.CLI_LOG &&
|
|
151
|
+
(level === 'error' || level === 'fatal')
|
|
152
|
+
) {
|
|
153
|
+
return 1
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (ALWAYS_TRACK_EVENTS.has(event)) {
|
|
157
|
+
return 1
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return SAMPLED_EVENT_RATES[event] ?? 1
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Deterministic sampling for high-volume logs/events: hashes a stable key
|
|
165
|
+
* (typically a userId) so the same key is always in or out of the sample and
|
|
166
|
+
* per-key funnels stay coherent. Callers should record the rate on sampled
|
|
167
|
+
* rows (e.g. `sampleRate: 0.02`) so counts can be re-inflated in queries.
|
|
168
|
+
*/
|
|
169
|
+
export function shouldSampleByKey(key: string, rate: number): boolean {
|
|
170
|
+
if (rate >= 1) return true
|
|
171
|
+
if (rate <= 0) return false
|
|
172
|
+
return hashString(key) / 0xffffffff < rate
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function hashString(input: string): number {
|
|
176
|
+
let hash = 2166136261
|
|
177
|
+
for (let i = 0; i < input.length; i++) {
|
|
178
|
+
hash ^= input.charCodeAt(i)
|
|
179
|
+
hash = Math.imul(hash, 16777619)
|
|
180
|
+
}
|
|
181
|
+
return hash >>> 0
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function getSamplingKey(params: {
|
|
185
|
+
event: AnalyticsEvent
|
|
186
|
+
distinctId?: string
|
|
187
|
+
properties?: AnalyticsProperties
|
|
188
|
+
}): string {
|
|
189
|
+
return (
|
|
190
|
+
params.distinctId ??
|
|
191
|
+
getPropertyUserId(params.properties) ??
|
|
192
|
+
getStringProperty(params.properties, 'clientSessionId') ??
|
|
193
|
+
getStringProperty(params.properties, 'userInputId') ??
|
|
194
|
+
params.event
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function shouldTrackAnalyticsEvent(params: {
|
|
199
|
+
event: AnalyticsEvent
|
|
200
|
+
distinctId?: string
|
|
201
|
+
properties?: AnalyticsProperties
|
|
202
|
+
}): boolean {
|
|
203
|
+
if (isFullTelemetryEnabled(params)) {
|
|
204
|
+
return true
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const rate = getEventSampleRate(params.event, params.properties)
|
|
208
|
+
if (rate >= 1) {
|
|
209
|
+
return true
|
|
210
|
+
}
|
|
211
|
+
if (rate <= 0) {
|
|
212
|
+
return false
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const bucket =
|
|
216
|
+
hashString(`${params.event}:${getSamplingKey(params)}`) / 0xffffffff
|
|
217
|
+
return bucket < rate
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function valueKind(value: unknown): string {
|
|
221
|
+
if (Array.isArray(value)) {
|
|
222
|
+
return 'array'
|
|
223
|
+
}
|
|
224
|
+
if (value === null) {
|
|
225
|
+
return 'null'
|
|
226
|
+
}
|
|
227
|
+
return typeof value
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function summarizeAnalyticsValue(
|
|
231
|
+
value: unknown,
|
|
232
|
+
): Record<string, unknown> {
|
|
233
|
+
if (value === null || value === undefined) {
|
|
234
|
+
return { kind: valueKind(value) }
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (typeof value === 'string') {
|
|
238
|
+
return { kind: 'string', length: value.length }
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (Array.isArray(value)) {
|
|
242
|
+
return { kind: 'array', length: value.length }
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (typeof value === 'object') {
|
|
246
|
+
const keys = Object.keys(value as Record<string, unknown>)
|
|
247
|
+
return {
|
|
248
|
+
kind: 'object',
|
|
249
|
+
keyCount: keys.length,
|
|
250
|
+
keys: keys.slice(0, 25),
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return { kind: valueKind(value) }
|
|
255
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One line answering "why these models?" for a user whose account resolved to
|
|
3
|
+
* the reduced catalog.
|
|
4
|
+
*
|
|
5
|
+
* Tone matters here: this is shown to users who, through no fault of their own,
|
|
6
|
+
* get the smaller model set. Frame it as model *availability* ("aren't
|
|
7
|
+
* available in BR yet"), never as restricted *access* ("limited mode",
|
|
8
|
+
* "blocked") — clear enough to answer the question for someone who goes
|
|
9
|
+
* looking, quiet enough to ignore for someone who doesn't. The VPN case is the
|
|
10
|
+
* one the user can act on, so it leads with the action.
|
|
11
|
+
*
|
|
12
|
+
* Shared by the CLI landing picker and the Desktop model menu so the two
|
|
13
|
+
* surfaces cannot drift — a user who reads it in one and asks support about the
|
|
14
|
+
* other should be told the same thing.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
AnvilIpPrivacySignal,
|
|
19
|
+
AnvilLimitedModeReason,
|
|
20
|
+
} from '../types/anvil-session'
|
|
21
|
+
|
|
22
|
+
const PRIVACY_SIGNAL_LABELS: Partial<Record<AnvilIpPrivacySignal, string>> = {
|
|
23
|
+
anonymous: 'anonymized network',
|
|
24
|
+
proxy: 'proxy',
|
|
25
|
+
relay: 'relay',
|
|
26
|
+
res_proxy: 'residential proxy',
|
|
27
|
+
tor: 'Tor',
|
|
28
|
+
vpn: 'VPN',
|
|
29
|
+
hosting: 'hosting network',
|
|
30
|
+
service: 'privacy service',
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function formatAnvilPrivacySignalList(
|
|
34
|
+
signals: readonly AnvilIpPrivacySignal[] | null | undefined,
|
|
35
|
+
): string {
|
|
36
|
+
const labels = Array.from(
|
|
37
|
+
new Set(
|
|
38
|
+
signals
|
|
39
|
+
?.map((signal) => PRIVACY_SIGNAL_LABELS[signal])
|
|
40
|
+
.filter((label): label is string => Boolean(label)) ?? [],
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
if (labels.length === 0) {
|
|
45
|
+
return 'VPN, Tor, proxy, relay, or anonymized network'
|
|
46
|
+
}
|
|
47
|
+
if (labels.length === 1) return labels[0]
|
|
48
|
+
if (labels.length === 2) return `${labels[0]} or ${labels[1]}`
|
|
49
|
+
return `${labels.slice(0, -1).join(', ')}, or ${labels[labels.length - 1]}`
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** "BR" → "Brazil". Falls back to the raw code when the runtime can't
|
|
53
|
+
* resolve it (malformed code, missing ICU data). */
|
|
54
|
+
export function formatAnvilCountryName(countryCode: string): string {
|
|
55
|
+
try {
|
|
56
|
+
return (
|
|
57
|
+
new Intl.DisplayNames(['en'], { type: 'region' }).of(countryCode) ??
|
|
58
|
+
countryCode
|
|
59
|
+
)
|
|
60
|
+
} catch {
|
|
61
|
+
return countryCode
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The one line to render next to the model list. Callers gate on the access
|
|
67
|
+
* tier: a full-access account has the whole catalog and needs no explanation.
|
|
68
|
+
*
|
|
69
|
+
* A missing/unknown reason still returns a line — the reduced catalog is
|
|
70
|
+
* visible either way, so saying nothing is the one option that leaves the
|
|
71
|
+
* question unanswered.
|
|
72
|
+
*/
|
|
73
|
+
export function getAnvilModelAvailabilityNotice(
|
|
74
|
+
reason: AnvilLimitedModeReason | null | undefined,
|
|
75
|
+
): string {
|
|
76
|
+
const generic = "Some models aren't available on this connection"
|
|
77
|
+
if (!reason) return generic
|
|
78
|
+
|
|
79
|
+
const countryCode =
|
|
80
|
+
reason.countryCode && reason.countryCode !== 'UNKNOWN'
|
|
81
|
+
? reason.countryCode
|
|
82
|
+
: null
|
|
83
|
+
|
|
84
|
+
switch (reason.countryBlockReason) {
|
|
85
|
+
case 'anonymous_network':
|
|
86
|
+
return `Using a ${formatAnvilPrivacySignalList(
|
|
87
|
+
reason.ipPrivacySignals,
|
|
88
|
+
)}? More models are available on a direct connection`
|
|
89
|
+
case 'country_not_allowed':
|
|
90
|
+
return `Some models aren't available in ${
|
|
91
|
+
countryCode ? formatAnvilCountryName(countryCode) : 'your region'
|
|
92
|
+
} yet`
|
|
93
|
+
case 'anonymized_or_unknown_country':
|
|
94
|
+
case 'missing_client_ip':
|
|
95
|
+
case 'unresolved_client_ip':
|
|
96
|
+
return "We couldn't confirm your region, so we're showing models available everywhere"
|
|
97
|
+
case 'ip_privacy_lookup_failed':
|
|
98
|
+
return "We couldn't finish a network check, so we're showing models available everywhere"
|
|
99
|
+
default:
|
|
100
|
+
return generic
|
|
101
|
+
}
|
|
102
|
+
}
|