@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,426 @@
|
|
|
1
|
+
import { sumBy } from 'lodash'
|
|
2
|
+
|
|
3
|
+
export const truncateString = (str: string, maxLength: number) => {
|
|
4
|
+
if (str.length <= maxLength) {
|
|
5
|
+
return str
|
|
6
|
+
}
|
|
7
|
+
return str.slice(0, maxLength) + '...'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const truncateStringWithMessage = ({
|
|
11
|
+
str,
|
|
12
|
+
maxLength,
|
|
13
|
+
message = 'TRUNCATED DUE TO LENGTH',
|
|
14
|
+
remove = 'END',
|
|
15
|
+
}: {
|
|
16
|
+
str: string
|
|
17
|
+
maxLength: number
|
|
18
|
+
message?: string
|
|
19
|
+
remove?: 'END' | 'START' | 'MIDDLE'
|
|
20
|
+
}) => {
|
|
21
|
+
if (str.length <= maxLength) {
|
|
22
|
+
return str
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (remove === 'END') {
|
|
26
|
+
const suffix = `\n[${message}...]`
|
|
27
|
+
return str.slice(0, maxLength - suffix.length) + suffix
|
|
28
|
+
}
|
|
29
|
+
if (remove === 'START') {
|
|
30
|
+
const prefix = `[...${message}]\n`
|
|
31
|
+
return prefix + str.slice(str.length - maxLength + prefix.length)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const middle = `\n[...${message}...]\n`
|
|
35
|
+
const length = Math.floor((maxLength - middle.length) / 2)
|
|
36
|
+
return str.slice(0, length) + middle + str.slice(-length)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if a character is a whitespace character according
|
|
41
|
+
* to the XML spec (space, carriage return, line feed or tab)
|
|
42
|
+
*
|
|
43
|
+
* @param character Character to check
|
|
44
|
+
* @return Whether the character is whitespace or not
|
|
45
|
+
*/
|
|
46
|
+
export const isWhitespace = (character: string) => /\s/.test(character)
|
|
47
|
+
|
|
48
|
+
export const randBoolFromStr = (str: string) => {
|
|
49
|
+
return sumBy(str.split(''), (char) => char.charCodeAt(0)) % 2 === 0
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Irregular plurals that cannot be derived from rules
|
|
53
|
+
// Note: -sis → -ses words are handled by rule, not listed here
|
|
54
|
+
const IRREGULAR_PLURALS: Record<string, string> = {
|
|
55
|
+
// Common English irregulars
|
|
56
|
+
person: 'people',
|
|
57
|
+
child: 'children',
|
|
58
|
+
man: 'men',
|
|
59
|
+
woman: 'women',
|
|
60
|
+
mouse: 'mice', // computer mice
|
|
61
|
+
// Tech terms with -ex/-ix → -ices (no reliable rule)
|
|
62
|
+
index: 'indices',
|
|
63
|
+
vertex: 'vertices',
|
|
64
|
+
matrix: 'matrices',
|
|
65
|
+
appendix: 'appendices',
|
|
66
|
+
// Latin -um → -a (too many exceptions like forum→forums for a rule)
|
|
67
|
+
datum: 'data',
|
|
68
|
+
medium: 'media',
|
|
69
|
+
criterion: 'criteria',
|
|
70
|
+
phenomenon: 'phenomena',
|
|
71
|
+
// Latin -us → -i (too many exceptions like bus→buses for a rule)
|
|
72
|
+
stimulus: 'stimuli',
|
|
73
|
+
radius: 'radii',
|
|
74
|
+
focus: 'foci',
|
|
75
|
+
cactus: 'cacti',
|
|
76
|
+
nucleus: 'nuclei',
|
|
77
|
+
syllabus: 'syllabi',
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Words that stay the same in plural (only those not derivable from rules)
|
|
81
|
+
// Note: -ware words and -ics words are handled by rules, not listed here
|
|
82
|
+
const UNCHANGING_PLURALS = new Set([
|
|
83
|
+
// Uncountable/mass nouns in tech
|
|
84
|
+
'data', // already plural of datum, but often used as uncountable
|
|
85
|
+
'metadata',
|
|
86
|
+
'info',
|
|
87
|
+
'feedback',
|
|
88
|
+
'news',
|
|
89
|
+
// Words ending in -s that don't change
|
|
90
|
+
'series',
|
|
91
|
+
'species',
|
|
92
|
+
'chassis',
|
|
93
|
+
'corps',
|
|
94
|
+
'means',
|
|
95
|
+
])
|
|
96
|
+
|
|
97
|
+
// Words ending in -f that just add -s (exceptions to -f → -ves rule)
|
|
98
|
+
const F_EXCEPTIONS = new Set([
|
|
99
|
+
// Tech/common terms
|
|
100
|
+
'roof',
|
|
101
|
+
'proof', // proofs (mathematical proofs, design proofs)
|
|
102
|
+
'chief', // tech leads
|
|
103
|
+
'brief', // design briefs
|
|
104
|
+
'belief',
|
|
105
|
+
'cliff',
|
|
106
|
+
'staff',
|
|
107
|
+
'bluff',
|
|
108
|
+
'spoof',
|
|
109
|
+
'motif', // design motifs
|
|
110
|
+
'serif', // fonts
|
|
111
|
+
'tariff',
|
|
112
|
+
'plaintiff',
|
|
113
|
+
'sheriff',
|
|
114
|
+
'reef',
|
|
115
|
+
'chef',
|
|
116
|
+
'ref',
|
|
117
|
+
'gif', // GIFs
|
|
118
|
+
'pdf', // PDFs
|
|
119
|
+
])
|
|
120
|
+
|
|
121
|
+
// Words ending in -o that just add -s (exceptions to -o → -oes rule)
|
|
122
|
+
const O_EXCEPTIONS = new Set([
|
|
123
|
+
// Tech terms
|
|
124
|
+
'photo',
|
|
125
|
+
'video',
|
|
126
|
+
'audio',
|
|
127
|
+
'studio',
|
|
128
|
+
'logo',
|
|
129
|
+
'demo',
|
|
130
|
+
'memo',
|
|
131
|
+
'repo', // repositories
|
|
132
|
+
'info',
|
|
133
|
+
'typo',
|
|
134
|
+
'intro',
|
|
135
|
+
'outro',
|
|
136
|
+
'combo',
|
|
137
|
+
'promo',
|
|
138
|
+
'proto', // prototypes
|
|
139
|
+
'retro',
|
|
140
|
+
'macro',
|
|
141
|
+
'micro',
|
|
142
|
+
'nano',
|
|
143
|
+
'auto',
|
|
144
|
+
'euro',
|
|
145
|
+
'pro',
|
|
146
|
+
'disco',
|
|
147
|
+
'duo',
|
|
148
|
+
'trio',
|
|
149
|
+
'solo',
|
|
150
|
+
'piano',
|
|
151
|
+
'casino',
|
|
152
|
+
'ratio',
|
|
153
|
+
'portfolio',
|
|
154
|
+
'scenario',
|
|
155
|
+
'studio',
|
|
156
|
+
'folio',
|
|
157
|
+
'manifesto',
|
|
158
|
+
'motto',
|
|
159
|
+
'dynamo',
|
|
160
|
+
'limo',
|
|
161
|
+
'albino',
|
|
162
|
+
'espresso',
|
|
163
|
+
'fiasco',
|
|
164
|
+
'ghetto',
|
|
165
|
+
'grotto',
|
|
166
|
+
'inferno',
|
|
167
|
+
'jumbo',
|
|
168
|
+
'kimono',
|
|
169
|
+
'libido',
|
|
170
|
+
'lingo',
|
|
171
|
+
'memento',
|
|
172
|
+
'neutrino',
|
|
173
|
+
'placebo',
|
|
174
|
+
'silo', // data silos
|
|
175
|
+
'stiletto',
|
|
176
|
+
'tempo',
|
|
177
|
+
'torso',
|
|
178
|
+
'virtuoso',
|
|
179
|
+
'volcano',
|
|
180
|
+
'zero',
|
|
181
|
+
])
|
|
182
|
+
|
|
183
|
+
export const pluralize = (
|
|
184
|
+
count: number,
|
|
185
|
+
word: string,
|
|
186
|
+
{ includeCount = true }: { includeCount?: boolean } = {},
|
|
187
|
+
) => {
|
|
188
|
+
let pluralWord: string
|
|
189
|
+
const lowerWord = word.toLowerCase()
|
|
190
|
+
|
|
191
|
+
if (count === 1) {
|
|
192
|
+
pluralWord = word
|
|
193
|
+
} else if (word === word.toUpperCase() && word.length > 1) {
|
|
194
|
+
// Acronyms (API, SDK, URL, etc.) - just add 's'
|
|
195
|
+
pluralWord = word + 's'
|
|
196
|
+
} else if (IRREGULAR_PLURALS[lowerWord]) {
|
|
197
|
+
// Check irregular plurals first (truly irregular words)
|
|
198
|
+
pluralWord = IRREGULAR_PLURALS[lowerWord]
|
|
199
|
+
} else if (UNCHANGING_PLURALS.has(lowerWord)) {
|
|
200
|
+
// Specific words that don't change
|
|
201
|
+
pluralWord = word
|
|
202
|
+
} else if (lowerWord.endsWith('ware')) {
|
|
203
|
+
// Rule: -ware words stay unchanged (software, hardware, firmware, malware, etc.)
|
|
204
|
+
pluralWord = word
|
|
205
|
+
} else if (lowerWord.endsWith('ics')) {
|
|
206
|
+
// Rule: -ics words stay unchanged (analytics, graphics, physics, statistics, etc.)
|
|
207
|
+
pluralWord = word
|
|
208
|
+
} else if (lowerWord.endsWith('sis')) {
|
|
209
|
+
// Rule: -sis → -ses (analysis→analyses, basis→bases, crisis→crises, etc.)
|
|
210
|
+
pluralWord = word.slice(0, -2) + 'es'
|
|
211
|
+
} else if (lowerWord.endsWith('xis')) {
|
|
212
|
+
// Rule: -xis → -xes (axis→axes)
|
|
213
|
+
pluralWord = word.slice(0, -2) + 'es'
|
|
214
|
+
} else if (F_EXCEPTIONS.has(lowerWord)) {
|
|
215
|
+
// -f words that just add -s
|
|
216
|
+
pluralWord = word + 's'
|
|
217
|
+
} else if (word.endsWith('f')) {
|
|
218
|
+
// Handle words ending in -f → -ves
|
|
219
|
+
pluralWord = word.slice(0, -1) + 'ves'
|
|
220
|
+
} else if (word.endsWith('fe')) {
|
|
221
|
+
// Handle words ending in -fe → -ves
|
|
222
|
+
pluralWord = word.slice(0, -2) + 'ves'
|
|
223
|
+
} else if (word.endsWith('y') && !word.match(/[aeiou]y$/)) {
|
|
224
|
+
// Handle words ending in 'y' (unless preceded by a vowel)
|
|
225
|
+
pluralWord = word.slice(0, -1) + 'ies'
|
|
226
|
+
} else if (O_EXCEPTIONS.has(lowerWord)) {
|
|
227
|
+
// -o words that just add -s
|
|
228
|
+
pluralWord = word + 's'
|
|
229
|
+
} else if (word.match(/[cs]h$/) || word.match(/o$/)) {
|
|
230
|
+
// Handle words ending in sh, ch, o → add -es
|
|
231
|
+
pluralWord = word + 'es'
|
|
232
|
+
} else if (word.match(/[^z]z$/)) {
|
|
233
|
+
// Single z at end (not zz) → double the z and add -es (quiz → quizzes)
|
|
234
|
+
pluralWord = word + 'zes'
|
|
235
|
+
} else if (word.match(/[sxz]$/)) {
|
|
236
|
+
// Handle words ending in s, x, zz → add -es
|
|
237
|
+
pluralWord = word + 'es'
|
|
238
|
+
} else {
|
|
239
|
+
pluralWord = word + 's'
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return includeCount ? `${count} ${pluralWord}` : pluralWord
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Safely replaces all occurrences of a search string with a replacement string,
|
|
247
|
+
* escaping special replacement patterns (like $) in the replacement string.
|
|
248
|
+
*/
|
|
249
|
+
export const capitalize = (str: string): string => {
|
|
250
|
+
if (!str) return str
|
|
251
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Converts a snake_case string to Title Case
|
|
256
|
+
* Example: "add_subgoal" -> "Add Subgoal"
|
|
257
|
+
*/
|
|
258
|
+
export const snakeToTitleCase = (str: string): string => {
|
|
259
|
+
return str
|
|
260
|
+
.split('_')
|
|
261
|
+
.map((word) => capitalize(word))
|
|
262
|
+
.join(' ')
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Ensures a URL has the appropriate protocol (http:// or https://)
|
|
267
|
+
* Uses http:// for localhost and local IPs, https:// for all other domains
|
|
268
|
+
*/
|
|
269
|
+
export const ensureUrlProtocol = (url: string): string => {
|
|
270
|
+
if (
|
|
271
|
+
url.startsWith('http://') ||
|
|
272
|
+
url.startsWith('https://') ||
|
|
273
|
+
url.startsWith('file://')
|
|
274
|
+
) {
|
|
275
|
+
return url
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (url.startsWith('localhost') || url.match(/^127\.\d+\.\d+\.\d+/)) {
|
|
279
|
+
return `http://${url}`
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (url.startsWith('/')) {
|
|
283
|
+
return `file://${url}`
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return `https://${url}`
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export const safeReplace = (
|
|
290
|
+
content: string,
|
|
291
|
+
searchStr: string,
|
|
292
|
+
replaceStr: string,
|
|
293
|
+
): string => {
|
|
294
|
+
const escapedReplaceStr = replaceStr.replace(/\$/g, '$$$$')
|
|
295
|
+
return content.replace(searchStr, escapedReplaceStr)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Extracts a JSON field from a string, transforms it, and puts it back.
|
|
300
|
+
* Handles both array and object JSON values.
|
|
301
|
+
* @param content The string containing JSON-like content
|
|
302
|
+
* @param field The field name to find and transform
|
|
303
|
+
* @param transform Function to transform the parsed JSON value
|
|
304
|
+
* @param fallback String to use if parsing fails
|
|
305
|
+
* @returns The content string with the transformed JSON field
|
|
306
|
+
*/
|
|
307
|
+
export function transformJsonInString<T = unknown>(
|
|
308
|
+
content: string,
|
|
309
|
+
field: string,
|
|
310
|
+
transform: (json: T) => unknown,
|
|
311
|
+
fallback: string,
|
|
312
|
+
): string {
|
|
313
|
+
// Use a non-greedy match for objects/arrays to prevent over-matching
|
|
314
|
+
const pattern = new RegExp(`"${field}"\\s*:\\s*(\\{[^}]*?\\}|\\[[^\\]]*?\\])`)
|
|
315
|
+
const match = content.match(pattern)
|
|
316
|
+
|
|
317
|
+
if (!match) {
|
|
318
|
+
return content
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
try {
|
|
322
|
+
const json = JSON.parse(match[1])
|
|
323
|
+
const transformed = transform(json)
|
|
324
|
+
|
|
325
|
+
// Important: Only replace the exact matched portion to prevent duplicates
|
|
326
|
+
return content.replace(
|
|
327
|
+
match[0],
|
|
328
|
+
`"${field}":${JSON.stringify(transformed)}`,
|
|
329
|
+
)
|
|
330
|
+
} catch (error) {
|
|
331
|
+
// Only replace the exact matched portion even in error case
|
|
332
|
+
return content.replace(match[0], `"${field}":${fallback}`)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Generates a compact unique identifier by combining timestamp bits with random bits.
|
|
338
|
+
* Uses 40 bits of timestamp (enough for ~34 years) and 24 random bits for exactly 64 total bits.
|
|
339
|
+
* Encodes in base64url for compact, URL-safe strings (~11 chars).
|
|
340
|
+
* @param prefix Optional prefix to add to the ID
|
|
341
|
+
* @returns A unique string ID
|
|
342
|
+
* @example
|
|
343
|
+
* generateCompactId() // => "1a2b3c4d5e6"
|
|
344
|
+
* generateCompactId('msg-') // => "msg-1a2b3c4d5e6"
|
|
345
|
+
*/
|
|
346
|
+
export const generateCompactId = (prefix?: string): string => {
|
|
347
|
+
// Get the last 32 bits of the timestamp
|
|
348
|
+
const timestamp = (Date.now() & 0xffffffff) >>> 0
|
|
349
|
+
// Generate a 32-bit random number
|
|
350
|
+
const random = Math.floor(Math.random() * 0x100000000) >>> 0
|
|
351
|
+
|
|
352
|
+
// Combine them into a 64-bit representation as two 32-bit numbers
|
|
353
|
+
const high = timestamp
|
|
354
|
+
const low = random
|
|
355
|
+
|
|
356
|
+
// Convert to a hex string, pad if necessary, and combine
|
|
357
|
+
const highHex = high.toString(16).padStart(8, '0')
|
|
358
|
+
const lowHex = low.toString(16).padStart(8, '0')
|
|
359
|
+
|
|
360
|
+
const combinedHex = highHex + lowHex
|
|
361
|
+
|
|
362
|
+
// Convert hex to a Buffer and then to base64url
|
|
363
|
+
const bytes = Buffer.from(combinedHex, 'hex')
|
|
364
|
+
const str = bytes.toString('base64url').replace(/=/g, '')
|
|
365
|
+
|
|
366
|
+
return prefix ? `${prefix}${str}` : str
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Removes null characters from a string
|
|
371
|
+
*/
|
|
372
|
+
export const stripNullChars = (str: string): string => {
|
|
373
|
+
return str.replace(/\u0000/g, '')
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const ansiColorsRegex = /\x1B\[[0-9;]*m/g
|
|
377
|
+
export function stripColors(str: string): string {
|
|
378
|
+
return str.replace(ansiColorsRegex, '')
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
const ansiRegex = /\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~]|\][^\x1B]*\x1B\\?)/g
|
|
382
|
+
export function stripAnsi(str: string): string {
|
|
383
|
+
return str.replace(ansiRegex, '')
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export function includesMatch(
|
|
387
|
+
array: (string | RegExp)[],
|
|
388
|
+
value: string,
|
|
389
|
+
): boolean {
|
|
390
|
+
return array.some((p) => {
|
|
391
|
+
if (typeof p === 'string') {
|
|
392
|
+
return p === value
|
|
393
|
+
}
|
|
394
|
+
return p.test(value)
|
|
395
|
+
})
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Finds the longest substring that is **both** a suffix of `source`
|
|
400
|
+
* **and** a prefix of `next`.
|
|
401
|
+
* Useful when concatenating strings while avoiding duplicate overlap.
|
|
402
|
+
*
|
|
403
|
+
* @example
|
|
404
|
+
* ```ts
|
|
405
|
+
* suffixPrefixOverlap('foobar', 'barbaz'); // ➜ 'bar'
|
|
406
|
+
* suffixPrefixOverlap('abc', 'def'); // ➜ ''
|
|
407
|
+
* ```
|
|
408
|
+
*
|
|
409
|
+
* @param source The string whose **suffix** is inspected.
|
|
410
|
+
* @param next The string whose **prefix** is inspected.
|
|
411
|
+
* @returns The longest overlapping edge, or an empty string if none exists.
|
|
412
|
+
*/
|
|
413
|
+
export function suffixPrefixOverlap(source: string, next: string): string {
|
|
414
|
+
for (let len = next.length; len >= 0; len--) {
|
|
415
|
+
const prefix = next.slice(0, len)
|
|
416
|
+
if (source.endsWith(prefix)) {
|
|
417
|
+
return prefix
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return ''
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export const escapeString = (str: string) => {
|
|
425
|
+
return JSON.stringify(str).slice(1, -1)
|
|
426
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import os from 'os'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import { platform } from 'process'
|
|
5
|
+
|
|
6
|
+
import { getProcessEnv } from '../env-process'
|
|
7
|
+
|
|
8
|
+
import type { ProcessEnv } from '../types/contracts/env'
|
|
9
|
+
|
|
10
|
+
const CHROME_PATHS: Record<string, string[]> = {
|
|
11
|
+
darwin: [
|
|
12
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
13
|
+
'/Applications/Google Chrome Beta.app/Contents/MacOS/Google Chrome Beta',
|
|
14
|
+
'/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev',
|
|
15
|
+
'/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary',
|
|
16
|
+
'/Applications/Chromium.app/Contents/MacOS/Chromium',
|
|
17
|
+
],
|
|
18
|
+
linux: [
|
|
19
|
+
'/usr/bin/google-chrome',
|
|
20
|
+
'/usr/bin/google-chrome-stable',
|
|
21
|
+
'/usr/bin/google-chrome-beta',
|
|
22
|
+
'/usr/bin/google-chrome-unstable',
|
|
23
|
+
'/usr/bin/chromium',
|
|
24
|
+
'/usr/bin/chromium-browser',
|
|
25
|
+
'/snap/bin/chromium',
|
|
26
|
+
],
|
|
27
|
+
win32: [
|
|
28
|
+
'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe',
|
|
29
|
+
'C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe',
|
|
30
|
+
`${process.env.LOCALAPPDATA ?? ''}\\Google\\Chrome\\Application\\chrome.exe`,
|
|
31
|
+
],
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const findChromeExecutable = (): string | null => {
|
|
35
|
+
const paths = CHROME_PATHS[platform] ?? []
|
|
36
|
+
for (const p of paths) {
|
|
37
|
+
if (p && fs.existsSync(p)) return p
|
|
38
|
+
}
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export const getSystemInfo = (processEnv: ProcessEnv = getProcessEnv()) => {
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
platform,
|
|
46
|
+
shell: 'bash',
|
|
47
|
+
nodeVersion: process.version,
|
|
48
|
+
arch: process.arch,
|
|
49
|
+
homedir: os.homedir(),
|
|
50
|
+
cpus: os.cpus().length,
|
|
51
|
+
chromeAvailable: findChromeExecutable() !== null,
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared pieces of "summarize the user's first message into a tab/thread
|
|
3
|
+
* title": the prompts every surface sends, and the sanitizer that turns raw
|
|
4
|
+
* model output into something safe to draw in a one-line label.
|
|
5
|
+
*
|
|
6
|
+
* Kept dependency-free so the desktop server, the desktop renderer and the web
|
|
7
|
+
* API can all import it.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/** The model only needs the gist; truncate long first messages so the title
|
|
11
|
+
* call stays cheap and fast. */
|
|
12
|
+
export const THREAD_TITLE_INPUT_MAX_CHARS = 2000
|
|
13
|
+
|
|
14
|
+
/** Titles are drawn in a tab label — anything longer is cut off anyway. */
|
|
15
|
+
export const THREAD_TITLE_MAX_CHARS = 60
|
|
16
|
+
|
|
17
|
+
export const THREAD_TITLE_SYSTEM_PROMPT =
|
|
18
|
+
'You generate short, clean titles for chat conversations. You output only the title.'
|
|
19
|
+
|
|
20
|
+
export const THREAD_TITLE_INSTRUCTIONS_PROMPT = `Write a concise title (3-6 words) summarizing the topic of the user's message.
|
|
21
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
- Plain text only: no surrounding quotes, no trailing punctuation, no preamble or explanation.
|
|
24
|
+
- Write the title in the same language as the user's message.
|
|
25
|
+
- Capitalize it like a headline (when the language uses capitalization).
|
|
26
|
+
- Describe what the message is *about*, in general terms. Never copy sensitive personal data into the title — names, emails, phone numbers, addresses, API keys, passwords, or other secrets. Summarize the topic, not the private details.
|
|
27
|
+
- If the message is too vague to summarize, use its wording as the title instead of a generic placeholder.
|
|
28
|
+
|
|
29
|
+
Output only the title.`
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Cleans up the model's raw output into a single-line, quote-free, length-
|
|
33
|
+
* bounded title. Returns null when nothing usable is left, so the caller keeps
|
|
34
|
+
* whatever placeholder it already showed.
|
|
35
|
+
*/
|
|
36
|
+
export function sanitizeThreadTitle(raw: string): string | null {
|
|
37
|
+
let title = raw.replace(/\s+/g, ' ').trim()
|
|
38
|
+
// a "Title:" label the model sometimes prepends despite instructions
|
|
39
|
+
title = title.replace(/^title:\s*/i, '').trim()
|
|
40
|
+
// surrounding quotes, straight or smart
|
|
41
|
+
title = title.replace(/^["'“”‘’]+|["'“”‘’]+$/g, '').trim()
|
|
42
|
+
// trailing sentence punctuation
|
|
43
|
+
title = title.replace(/[.!?,;:]+$/g, '').trim()
|
|
44
|
+
if (!title) return null
|
|
45
|
+
return title.slice(0, THREAD_TITLE_MAX_CHARS)
|
|
46
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log-scale bucketing for time-to-first-token samples.
|
|
3
|
+
*
|
|
4
|
+
* The /latency dashboard reports p50/p95 TTFT over a 24h window, but percentiles
|
|
5
|
+
* are not additive: you cannot combine hourly p50s into a window p50. Storing a
|
|
6
|
+
* histogram per (hour, model) is what makes the rollup summable — counts add, so
|
|
7
|
+
* percentiles over any set of hours (and over any set of models) come from the
|
|
8
|
+
* merged distribution rather than from the raw `message` table.
|
|
9
|
+
*
|
|
10
|
+
* Buckets are geometric, so the error is a fixed *relative* one at every
|
|
11
|
+
* latency: a bucket spans BASE**i .. BASE**(i+1), and we report its geometric
|
|
12
|
+
* midpoint, so a reported value is within ±1.5% of the true sample. That matters
|
|
13
|
+
* more than absolute precision here — the page renders 1.9s and 3.0s, and models
|
|
14
|
+
* are ranked against each other, so a constant relative error preserves both the
|
|
15
|
+
* displayed figure and the ordering.
|
|
16
|
+
*
|
|
17
|
+
* These constants are baked into stored rows: `message_latency_bucket.bucket` is
|
|
18
|
+
* an index in this scheme. Changing BASE or BUCKET_COUNT silently reinterprets
|
|
19
|
+
* every existing row, so a change means re-rolling the retained window.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/** Ratio between consecutive bucket edges. 1.03 => ±1.5% reported error. */
|
|
23
|
+
export const TTFT_HISTOGRAM_BASE = 1.03
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Number of buckets. 1.03**512 is ~3.7e6 ms (~62 min), well past any TTFT a
|
|
27
|
+
* request can produce, so the top bucket only ever catches pathological rows.
|
|
28
|
+
*/
|
|
29
|
+
export const TTFT_HISTOGRAM_BUCKET_COUNT = 512
|
|
30
|
+
|
|
31
|
+
const LN_BASE = Math.log(TTFT_HISTOGRAM_BASE)
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Bucket index for a TTFT sample in milliseconds.
|
|
35
|
+
*
|
|
36
|
+
* Mirrors the SQL in scripts/rollup-anvil-latency.ts — keep the two in step.
|
|
37
|
+
* Sub-millisecond and zero samples land in bucket 0 rather than at -Infinity.
|
|
38
|
+
*/
|
|
39
|
+
export function ttftBucketIndex(ttftMs: number): number {
|
|
40
|
+
const index = Math.floor(Math.log(Math.max(ttftMs, 1)) / LN_BASE)
|
|
41
|
+
return Math.min(TTFT_HISTOGRAM_BUCKET_COUNT - 1, Math.max(0, index))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Representative latency for a bucket: the geometric midpoint, which is the
|
|
46
|
+
* value minimizing worst-case relative error across the bucket's span.
|
|
47
|
+
*/
|
|
48
|
+
export function ttftBucketMs(bucket: number): number {
|
|
49
|
+
return Math.round(Math.exp((bucket + 0.5) * LN_BASE))
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Percentile over a histogram given as [bucketIndex, count] pairs.
|
|
54
|
+
*
|
|
55
|
+
* Nearest-rank: the first bucket whose cumulative count reaches `quantile` of
|
|
56
|
+
* the total. Returns null for an empty histogram. Pairs need not be sorted.
|
|
57
|
+
*/
|
|
58
|
+
export function ttftPercentileFromHistogram(
|
|
59
|
+
buckets: Iterable<readonly [number, number]>,
|
|
60
|
+
quantile: number,
|
|
61
|
+
): number | null {
|
|
62
|
+
const sorted = [...buckets].sort((a, b) => a[0] - b[0])
|
|
63
|
+
const total = sorted.reduce((sum, [, count]) => sum + count, 0)
|
|
64
|
+
if (total === 0) return null
|
|
65
|
+
|
|
66
|
+
const target = total * quantile
|
|
67
|
+
let cumulative = 0
|
|
68
|
+
for (const [bucket, count] of sorted) {
|
|
69
|
+
cumulative += count
|
|
70
|
+
if (cumulative >= target) return ttftBucketMs(bucket)
|
|
71
|
+
}
|
|
72
|
+
return ttftBucketMs(sorted[sorted.length - 1][0])
|
|
73
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses XML content for a tool call into a structured object with only string values.
|
|
3
|
+
* Example input:
|
|
4
|
+
* <type>click</type>
|
|
5
|
+
* <selector>#button</selector>
|
|
6
|
+
* <timeout>5000</timeout>
|
|
7
|
+
*/
|
|
8
|
+
export function parseToolCallXml(xmlString: string): Record<string, string> {
|
|
9
|
+
if (!xmlString.trim()) return {}
|
|
10
|
+
|
|
11
|
+
const result: Record<string, string> = {}
|
|
12
|
+
const tagPattern = /<(\w+)>([\s\S]*?)<\/\1>/g
|
|
13
|
+
let match
|
|
14
|
+
|
|
15
|
+
while ((match = tagPattern.exec(xmlString)) !== null) {
|
|
16
|
+
const [, key, rawValue] = match
|
|
17
|
+
|
|
18
|
+
// Remove leading/trailing whitespace but preserve internal whitespace
|
|
19
|
+
const value = rawValue.replace(/^\s+|\s+$/g, '')
|
|
20
|
+
|
|
21
|
+
// Assign all values as strings
|
|
22
|
+
result[key] = value
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return result
|
|
26
|
+
}
|
|
27
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a closing XML tag for a single tool name
|
|
3
|
+
* @param toolName Single tool name to generate closing tag for
|
|
4
|
+
* @returns Closing XML tag string
|
|
5
|
+
*/
|
|
6
|
+
export function closeXml(toolName: string): string {
|
|
7
|
+
return `</${toolName}>`
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Generate stop sequences (closing XML tags) for a list of tool names
|
|
12
|
+
* @param toolNames Array of tool names to generate closing tags for
|
|
13
|
+
* @returns Array of closing XML tag strings
|
|
14
|
+
*/
|
|
15
|
+
export function getStopSequences(toolNames: readonly string[]): string[] {
|
|
16
|
+
return toolNames.map((toolName) => `</anvil_tool_${toolName}>`)
|
|
17
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import z from 'zod/v4'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert a Zod4 schema to JSON string representation.
|
|
5
|
+
*/
|
|
6
|
+
export function schemaToJsonStr(
|
|
7
|
+
schema: z.ZodTypeAny | undefined | Record<string, any>,
|
|
8
|
+
options?: Parameters<typeof z.toJSONSchema>[1],
|
|
9
|
+
): string {
|
|
10
|
+
if (!schema) return 'None'
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
// Handle Zod schemas
|
|
14
|
+
if (schema instanceof z.ZodType) {
|
|
15
|
+
const jsonSchema = z.toJSONSchema(schema, options)
|
|
16
|
+
delete jsonSchema['$schema']
|
|
17
|
+
return JSON.stringify(jsonSchema, null, 2)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Otherwise, pass on plain object
|
|
21
|
+
return JSON.stringify(schema, null, 2)
|
|
22
|
+
} catch (error) {
|
|
23
|
+
return 'None'
|
|
24
|
+
}
|
|
25
|
+
}
|