mixdog 0.7.1
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/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +20 -0
- package/.gitattributes +34 -0
- package/.mcp.json +14 -0
- package/ARCHITECTURE.md +77 -0
- package/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +45 -0
- package/DATA-FLOW.md +79 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/SECURITY.md +138 -0
- package/UNINSTALL.md +112 -0
- package/agents/maintenance.md +5 -0
- package/agents/memory-classification.md +30 -0
- package/agents/scheduler-task.md +18 -0
- package/agents/webhook-handler.md +27 -0
- package/agents/worker.md +24 -0
- package/bin/bridge +133 -0
- package/bin/statusline-launcher.mjs +78 -0
- package/bin/statusline-lib.mjs +550 -0
- package/bin/statusline.mjs +607 -0
- package/bun.lock +802 -0
- package/commands/config.md +16 -0
- package/commands/doctor.md +13 -0
- package/commands/setup.md +17 -0
- package/defaults/cycle3-review-prompt.md +90 -0
- package/defaults/hidden-roles.json +65 -0
- package/defaults/memory-chunk-prompt.md +63 -0
- package/defaults/memory-promote-prompt.md +135 -0
- package/defaults/mixdog-config.template.json +27 -0
- package/defaults/user-workflow.json +8 -0
- package/defaults/user-workflow.md +12 -0
- package/hooks/hooks.json +73 -0
- package/hooks/lib/active-instance.cjs +77 -0
- package/hooks/lib/permission-evaluator.cjs +411 -0
- package/hooks/lib/permission-route.cjs +63 -0
- package/hooks/lib/permission-rules.cjs +170 -0
- package/hooks/lib/settings-loader.cjs +116 -0
- package/hooks/post-tool-use.cjs +84 -0
- package/hooks/pre-mcp-sandbox.cjs +158 -0
- package/hooks/pre-tool-subagent.cjs +253 -0
- package/hooks/session-start.cjs +1372 -0
- package/hooks/turn-timer.cjs +82 -0
- package/lib/claude-md-writer.cjs +386 -0
- package/lib/config-cjs.cjs +61 -0
- package/lib/hook-pipe-path.cjs +10 -0
- package/lib/keychain-cjs.cjs +263 -0
- package/lib/plugin-paths.cjs +61 -0
- package/lib/rules-builder.cjs +241 -0
- package/lib/text-utils.cjs +61 -0
- package/native/README.md +117 -0
- package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
- package/package.json +107 -0
- package/prompts/code-review.txt +16 -0
- package/prompts/security-audit.txt +17 -0
- package/rules/bridge/00-common.md +39 -0
- package/rules/bridge/20-skip-protocol.md +18 -0
- package/rules/bridge/30-explorer.md +33 -0
- package/rules/bridge/40-cycle1-agent.md +52 -0
- package/rules/bridge/41-cycle2-agent.md +62 -0
- package/rules/bridge/42-cycle3-agent.md +44 -0
- package/rules/lead/00-tool-lead.md +61 -0
- package/rules/lead/01-general.md +23 -0
- package/rules/lead/02-channels.md +49 -0
- package/rules/lead/03-team.md +27 -0
- package/rules/lead/04-workflow.md +20 -0
- package/rules/shared/00-language.md +14 -0
- package/rules/shared/01-tool.md +138 -0
- package/scripts/bootstrap.mjs +184 -0
- package/scripts/bridge-unify-smoke.mjs +308 -0
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/builtin-utils-smoke.mjs +392 -0
- package/scripts/check-json.mjs +45 -0
- package/scripts/check-syntax-changed.mjs +102 -0
- package/scripts/check-syntax.mjs +58 -0
- package/scripts/code-graph-batch.test.mjs +33 -0
- package/scripts/config-preserve-smoke.mjs +180 -0
- package/scripts/doctor.mjs +484 -0
- package/scripts/edit-normalize-fuzz.mjs +130 -0
- package/scripts/edit-normalize-smoke.mjs +401 -0
- package/scripts/edit-operation-smoke.mjs +369 -0
- package/scripts/edit2-smoke.mjs +63 -0
- package/scripts/fuzzy-e2e.mjs +28 -0
- package/scripts/fuzzy-smoke.mjs +26 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/guard-smoke.mjs +66 -0
- package/scripts/hidden-role-schema-smoke.mjs +162 -0
- package/scripts/hook-routing-smoke.mjs +29 -0
- package/scripts/inject-input.ps1 +204 -0
- package/scripts/io-complex-smoke.mjs +667 -0
- package/scripts/io-explore-bench.mjs +424 -0
- package/scripts/io-guardrails-smoke.mjs +205 -0
- package/scripts/io-mini-bench-baseline.json +11 -0
- package/scripts/io-mini-bench.mjs +216 -0
- package/scripts/io-route-harness.mjs +933 -0
- package/scripts/io-telemetry-report.mjs +691 -0
- package/scripts/mutation-bench.mjs +564 -0
- package/scripts/mutation-io-smoke.mjs +1081 -0
- package/scripts/native-patch-bridge-smoke.mjs +288 -0
- package/scripts/native-patch-smoke.mjs +304 -0
- package/scripts/patch-interior-context-smoke.mjs +49 -0
- package/scripts/patch-newline-utf8-smoke.mjs +157 -0
- package/scripts/perf-hook-smoke.mjs +71 -0
- package/scripts/permission-eval-smoke.mjs +426 -0
- package/scripts/prep-patch.mjs +53 -0
- package/scripts/prep-shim.mjs +96 -0
- package/scripts/provider-cache-smoke.mjs +687 -0
- package/scripts/report-runtime-health.mjs +132 -0
- package/scripts/run-mcp.mjs +1547 -0
- package/scripts/salvage-v4a-shatter.test.mjs +58 -0
- package/scripts/scoped-cache-io-smoke.mjs +103 -0
- package/scripts/shell-policy-round3-smoke.mjs +46 -0
- package/scripts/smoke-runtime-negative.ps1 +100 -0
- package/scripts/smoke-runtime-negative.sh +95 -0
- package/scripts/stall-policy-smoke.mjs +50 -0
- package/scripts/start-memory-worker.mjs +23 -0
- package/scripts/statusline-launcher-smoke.mjs +82 -0
- package/scripts/stress-atomic-write.mjs +1028 -0
- package/scripts/test-config-rmw-restore.mjs +122 -0
- package/scripts/test-fault-inject.mjs +164 -0
- package/scripts/test-large-file.mjs +174 -0
- package/scripts/tool-edge-smoke.mjs +209 -0
- package/scripts/uninstall.mjs +201 -0
- package/scripts/webhook-selfheal-smoke.mjs +29 -0
- package/scripts/write-overwrite-guard-smoke.mjs +56 -0
- package/server-main.mjs +3055 -0
- package/server.mjs +468 -0
- package/setup/config-merge.mjs +254 -0
- package/setup/install.mjs +120 -0
- package/setup/launch-core.mjs +507 -0
- package/setup/launch.mjs +101 -0
- package/setup/setup-server.mjs +3206 -0
- package/setup/setup.html +3693 -0
- package/skills/retro-skill-proposer/SKILL.md +92 -0
- package/skills/schedule-add/SKILL.md +77 -0
- package/skills/setup/SKILL.md +346 -0
- package/skills/webhook-add/SKILL.md +81 -0
- package/src/agent/bridge-stall-watchdog.mjs +337 -0
- package/src/agent/index.mjs +2138 -0
- package/src/agent/orchestrator/activity-bus.mjs +38 -0
- package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +1010 -0
- package/src/agent/orchestrator/bridge-retry.mjs +220 -0
- package/src/agent/orchestrator/bridge-trace.mjs +583 -0
- package/src/agent/orchestrator/cache-mtime.mjs +58 -0
- package/src/agent/orchestrator/config.mjs +358 -0
- package/src/agent/orchestrator/context/collect.mjs +651 -0
- package/src/agent/orchestrator/dispatch-persist.mjs +549 -0
- package/src/agent/orchestrator/drain-registry.mjs +50 -0
- package/src/agent/orchestrator/explore-validator.mjs +8 -0
- package/src/agent/orchestrator/internal-roles.mjs +118 -0
- package/src/agent/orchestrator/internal-tools.mjs +88 -0
- package/src/agent/orchestrator/jobs.mjs +116 -0
- package/src/agent/orchestrator/mcp/client.mjs +364 -0
- package/src/agent/orchestrator/providers/anthropic-betas.mjs +21 -0
- package/src/agent/orchestrator/providers/anthropic-oauth.mjs +1745 -0
- package/src/agent/orchestrator/providers/anthropic.mjs +437 -0
- package/src/agent/orchestrator/providers/gemini.mjs +1175 -0
- package/src/agent/orchestrator/providers/grok-oauth.mjs +782 -0
- package/src/agent/orchestrator/providers/model-catalog.mjs +241 -0
- package/src/agent/orchestrator/providers/openai-compat.mjs +1467 -0
- package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +1890 -0
- package/src/agent/orchestrator/providers/openai-oauth.mjs +1307 -0
- package/src/agent/orchestrator/providers/openai-ws.mjs +104 -0
- package/src/agent/orchestrator/providers/registry.mjs +192 -0
- package/src/agent/orchestrator/providers/retry-classifier.mjs +325 -0
- package/src/agent/orchestrator/session/abort-lookup.mjs +13 -0
- package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
- package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
- package/src/agent/orchestrator/session/cache/read-cache.mjs +319 -0
- package/src/agent/orchestrator/session/cache/scoped-cache-outcome.mjs +11 -0
- package/src/agent/orchestrator/session/cache/scoped-cache.mjs +361 -0
- package/src/agent/orchestrator/session/cache/util.mjs +49 -0
- package/src/agent/orchestrator/session/loop.mjs +1478 -0
- package/src/agent/orchestrator/session/manager.mjs +1975 -0
- package/src/agent/orchestrator/session/read-dedup.mjs +6 -0
- package/src/agent/orchestrator/session/result-classification.mjs +65 -0
- package/src/agent/orchestrator/session/save-session-worker.mjs +18 -0
- package/src/agent/orchestrator/session/store.mjs +624 -0
- package/src/agent/orchestrator/session/stream-watchdog.mjs +130 -0
- package/src/agent/orchestrator/session/tool-result-offload.mjs +166 -0
- package/src/agent/orchestrator/session/trim.mjs +491 -0
- package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +115 -0
- package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +327 -0
- package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +150 -0
- package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +228 -0
- package/src/agent/orchestrator/smart-bridge/index.mjs +215 -0
- package/src/agent/orchestrator/smart-bridge/profiles.mjs +37 -0
- package/src/agent/orchestrator/smart-bridge/registry.mjs +348 -0
- package/src/agent/orchestrator/smart-bridge/session-builder.mjs +116 -0
- package/src/agent/orchestrator/stall-policy.mjs +195 -0
- package/src/agent/orchestrator/tool-loop-guard.mjs +75 -0
- package/src/agent/orchestrator/tools/bash-policy-scan.mjs +77 -0
- package/src/agent/orchestrator/tools/bash-session.mjs +721 -0
- package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
- package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/atomic-write.mjs +236 -0
- package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +480 -0
- package/src/agent/orchestrator/tools/builtin/binary-file.mjs +76 -0
- package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +256 -0
- package/src/agent/orchestrator/tools/builtin/cache-layers.mjs +386 -0
- package/src/agent/orchestrator/tools/builtin/cwd-utils.mjs +37 -0
- package/src/agent/orchestrator/tools/builtin/device-paths.mjs +154 -0
- package/src/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +292 -0
- package/src/agent/orchestrator/tools/builtin/diff-utils.mjs +109 -0
- package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +58 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +240 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +74 -0
- package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +242 -0
- package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +211 -0
- package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +1364 -0
- package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +126 -0
- package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +141 -0
- package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +194 -0
- package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +60 -0
- package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +168 -0
- package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fs-reachability.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +99 -0
- package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +170 -0
- package/src/agent/orchestrator/tools/builtin/grep-formatting.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/hash-utils.mjs +6 -0
- package/src/agent/orchestrator/tools/builtin/list-formatting.mjs +7 -0
- package/src/agent/orchestrator/tools/builtin/list-tool.mjs +593 -0
- package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +89 -0
- package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +300 -0
- package/src/agent/orchestrator/tools/builtin/open-config-tool.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +152 -0
- package/src/agent/orchestrator/tools/builtin/path-locks.mjs +35 -0
- package/src/agent/orchestrator/tools/builtin/path-utils.mjs +201 -0
- package/src/agent/orchestrator/tools/builtin/read-args.mjs +103 -0
- package/src/agent/orchestrator/tools/builtin/read-batch.mjs +172 -0
- package/src/agent/orchestrator/tools/builtin/read-constants.mjs +40 -0
- package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
- package/src/agent/orchestrator/tools/builtin/read-image-resize.mjs +189 -0
- package/src/agent/orchestrator/tools/builtin/read-image.mjs +88 -0
- package/src/agent/orchestrator/tools/builtin/read-lines.mjs +12 -0
- package/src/agent/orchestrator/tools/builtin/read-mode-tool.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/read-open.mjs +190 -0
- package/src/agent/orchestrator/tools/builtin/read-range-index.mjs +271 -0
- package/src/agent/orchestrator/tools/builtin/read-ranges.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +728 -0
- package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/read-special-files.mjs +268 -0
- package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
- package/src/agent/orchestrator/tools/builtin/read-tool.mjs +530 -0
- package/src/agent/orchestrator/tools/builtin/read-windows.mjs +107 -0
- package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +196 -0
- package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +422 -0
- package/src/agent/orchestrator/tools/builtin/search-builders.mjs +158 -0
- package/src/agent/orchestrator/tools/builtin/search-tool.mjs +869 -0
- package/src/agent/orchestrator/tools/builtin/shell-analysis.mjs +653 -0
- package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +936 -0
- package/src/agent/orchestrator/tools/builtin/shell-output.mjs +36 -0
- package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +214 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +143 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +206 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-validation.mjs +98 -0
- package/src/agent/orchestrator/tools/builtin/text-stats.mjs +69 -0
- package/src/agent/orchestrator/tools/builtin/windows-roots.mjs +23 -0
- package/src/agent/orchestrator/tools/builtin/write-tool.mjs +401 -0
- package/src/agent/orchestrator/tools/builtin.mjs +500 -0
- package/src/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +39 -0
- package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
- package/src/agent/orchestrator/tools/code-graph.mjs +4095 -0
- package/src/agent/orchestrator/tools/cwd-tool.mjs +298 -0
- package/src/agent/orchestrator/tools/destructive-warning.mjs +323 -0
- package/src/agent/orchestrator/tools/edit-normalize.mjs +603 -0
- package/src/agent/orchestrator/tools/env-scrub.mjs +100 -0
- package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +144 -0
- package/src/agent/orchestrator/tools/graph-manifest.json +26 -0
- package/src/agent/orchestrator/tools/host-input.mjs +204 -0
- package/src/agent/orchestrator/tools/mutation-content-cache.mjs +67 -0
- package/src/agent/orchestrator/tools/mutation-planner.mjs +75 -0
- package/src/agent/orchestrator/tools/next-call-utils.mjs +48 -0
- package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +133 -0
- package/src/agent/orchestrator/tools/patch-manifest.json +26 -0
- package/src/agent/orchestrator/tools/patch-tool-defs.mjs +20 -0
- package/src/agent/orchestrator/tools/patch.mjs +2754 -0
- package/src/agent/orchestrator/tools/progress-message.mjs +118 -0
- package/src/agent/orchestrator/tools/result-compression.mjs +279 -0
- package/src/agent/orchestrator/tools/shell-command.mjs +865 -0
- package/src/agent/orchestrator/tools/shell-exec-policy.mjs +89 -0
- package/src/agent/orchestrator/tools/shell-policy-danger-target.mjs +27 -0
- package/src/agent/orchestrator/tools/shell-policy-imports.mjs +7 -0
- package/src/agent/orchestrator/tools/shell-policy.mjs +345 -0
- package/src/agent/orchestrator/tools/shell-snapshot.mjs +313 -0
- package/src/agent/orchestrator/workflow-store.mjs +93 -0
- package/src/agent/tool-defs.mjs +103 -0
- package/src/channels/backends/discord.mjs +784 -0
- package/src/channels/data/voice-runtime-manifest.json +138 -0
- package/src/channels/index.mjs +3229 -0
- package/src/channels/lib/cli-worker-host.mjs +12 -0
- package/src/channels/lib/config-lock.mjs +13 -0
- package/src/channels/lib/config.mjs +292 -0
- package/src/channels/lib/drop-trace.mjs +71 -0
- package/src/channels/lib/event-pipeline.mjs +81 -0
- package/src/channels/lib/event-queue.mjs +345 -0
- package/src/channels/lib/executor.mjs +168 -0
- package/src/channels/lib/format.mjs +188 -0
- package/src/channels/lib/holidays.mjs +138 -0
- package/src/channels/lib/hook-pipe-server.mjs +802 -0
- package/src/channels/lib/interaction-workflows.mjs +184 -0
- package/src/channels/lib/memory-client.mjs +149 -0
- package/src/channels/lib/output-forwarder.mjs +765 -0
- package/src/channels/lib/runtime-paths.mjs +479 -0
- package/src/channels/lib/scheduler.mjs +723 -0
- package/src/channels/lib/session-control.mjs +36 -0
- package/src/channels/lib/session-discovery.mjs +103 -0
- package/src/channels/lib/settings.mjs +11 -0
- package/src/channels/lib/state-file.mjs +68 -0
- package/src/channels/lib/status-snapshot.mjs +219 -0
- package/src/channels/lib/tool-format.mjs +140 -0
- package/src/channels/lib/transcript-discovery.mjs +195 -0
- package/src/channels/lib/voice-runtime-fetcher.mjs +734 -0
- package/src/channels/lib/webhook.mjs +1179 -0
- package/src/channels/lib/whisper-server.mjs +477 -0
- package/src/channels/tool-defs.mjs +170 -0
- package/src/daemon/host.mjs +118 -0
- package/src/daemon/mcp-transport.mjs +47 -0
- package/src/daemon/session.mjs +100 -0
- package/src/daemon/thin-client.mjs +71 -0
- package/src/daemon/transport.mjs +163 -0
- package/src/memory/data/runtime-manifest.json +40 -0
- package/src/memory/index.mjs +3305 -0
- package/src/memory/lib/agent-ipc.mjs +93 -0
- package/src/memory/lib/bridge-trace-queries.mjs +120 -0
- package/src/memory/lib/core-memory-store.mjs +330 -0
- package/src/memory/lib/embedding-provider.mjs +269 -0
- package/src/memory/lib/embedding-worker.mjs +323 -0
- package/src/memory/lib/llm-worker-host.mjs +17 -0
- package/src/memory/lib/memory-cycle.mjs +11 -0
- package/src/memory/lib/memory-cycle1.mjs +641 -0
- package/src/memory/lib/memory-cycle2.mjs +1284 -0
- package/src/memory/lib/memory-cycle3.mjs +540 -0
- package/src/memory/lib/memory-embed.mjs +299 -0
- package/src/memory/lib/memory-extraction.mjs +5 -0
- package/src/memory/lib/memory-maintenance-store.mjs +32 -0
- package/src/memory/lib/memory-ops-policy.mjs +190 -0
- package/src/memory/lib/memory-recall-id-patch.mjs +15 -0
- package/src/memory/lib/memory-recall-read-query.mjs +7 -0
- package/src/memory/lib/memory-recall-scope-filter.mjs +63 -0
- package/src/memory/lib/memory-recall-store.mjs +621 -0
- package/src/memory/lib/memory-retrievers.mjs +112 -0
- package/src/memory/lib/memory-score.mjs +71 -0
- package/src/memory/lib/memory-text-utils.mjs +58 -0
- package/src/memory/lib/memory.mjs +412 -0
- package/src/memory/lib/model-profile.mjs +85 -0
- package/src/memory/lib/pg/adapter.mjs +308 -0
- package/src/memory/lib/pg/process.mjs +360 -0
- package/src/memory/lib/pg/supervisor.mjs +396 -0
- package/src/memory/lib/project-id-resolver.mjs +86 -0
- package/src/memory/lib/runtime-fetcher.mjs +442 -0
- package/src/memory/lib/trace-store.mjs +728 -0
- package/src/memory/tool-defs.mjs +79 -0
- package/src/search/index.mjs +1173 -0
- package/src/search/lib/backends/anthropic-oauth.mjs +98 -0
- package/src/search/lib/backends/exa.mjs +50 -0
- package/src/search/lib/backends/firecrawl.mjs +61 -0
- package/src/search/lib/backends/gemini-api.mjs +83 -0
- package/src/search/lib/backends/grok-oauth.mjs +86 -0
- package/src/search/lib/backends/index.mjs +150 -0
- package/src/search/lib/backends/openai-api.mjs +144 -0
- package/src/search/lib/backends/openai-oauth.mjs +98 -0
- package/src/search/lib/backends/openai-web-search.mjs +76 -0
- package/src/search/lib/backends/tavily.mjs +55 -0
- package/src/search/lib/backends/xai-api.mjs +113 -0
- package/src/search/lib/cache.mjs +131 -0
- package/src/search/lib/config.mjs +192 -0
- package/src/search/lib/formatter.mjs +115 -0
- package/src/search/lib/provider-usage.mjs +67 -0
- package/src/search/lib/providers.mjs +47 -0
- package/src/search/lib/search-intent.mjs +109 -0
- package/src/search/lib/setup-handler.mjs +261 -0
- package/src/search/lib/state.mjs +201 -0
- package/src/search/lib/web-tools.mjs +1207 -0
- package/src/search/tool-defs.mjs +83 -0
- package/src/setup/defender-exclusion.mjs +183 -0
- package/src/shared/abort-controller.mjs +15 -0
- package/src/shared/atomic-file.mjs +420 -0
- package/src/shared/config.mjs +350 -0
- package/src/shared/daemon-recycle.mjs +108 -0
- package/src/shared/disable-claude-builtins.mjs +88 -0
- package/src/shared/err-text.mjs +12 -0
- package/src/shared/llm/cost.mjs +66 -0
- package/src/shared/llm/http-agent.mjs +123 -0
- package/src/shared/llm/index.mjs +41 -0
- package/src/shared/llm/pid-cleanup.mjs +27 -0
- package/src/shared/llm/usage-log.mjs +47 -0
- package/src/shared/plugin-paths.mjs +58 -0
- package/src/shared/schedules-store.mjs +70 -0
- package/src/shared/seed.mjs +119 -0
- package/src/shared/user-cwd.mjs +213 -0
- package/src/shared/user-data-guard.mjs +238 -0
- package/src/status/aggregator.mjs +584 -0
- package/src/status/server.mjs +413 -0
- package/tools.json +1653 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Bridge — Internal LLM Helper (session-based).
|
|
3
|
+
*
|
|
4
|
+
* Every one-shot LLM dispatch from internal callers (memory-cycle,
|
|
5
|
+
* scheduler, webhook) now flows through the SAME session pipeline as the
|
|
6
|
+
* MCP `bridge` tool. No more parallel `provider.send()` helper — one code
|
|
7
|
+
* path = one message shape = one usage log = "bridge single path".
|
|
8
|
+
*
|
|
9
|
+
* The returned function uses the existing caller signature, so call sites
|
|
10
|
+
* do not need changes:
|
|
11
|
+
*
|
|
12
|
+
* const llm = makeBridgeLlm({ role: 'maintenance', preset: 'haiku' });
|
|
13
|
+
* const text = await llm({ prompt });
|
|
14
|
+
*
|
|
15
|
+
* Internally it:
|
|
16
|
+
* 1. Resolves the preset (explicit arg > opts.preset > user-workflow.json[role])
|
|
17
|
+
* 2. Creates or reuses a session via the session manager
|
|
18
|
+
* 3. Applies stateless-reset for stateless profiles so the prefix handle
|
|
19
|
+
* stays warm while per-dispatch transcripts never leak
|
|
20
|
+
* 4. Calls `askSession` → provider.send() → usage logged via
|
|
21
|
+
* `session/manager.mjs` (mode='active')
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { readFileSync } from 'fs';
|
|
25
|
+
import { join } from 'path';
|
|
26
|
+
import { loadConfig } from '../config.mjs';
|
|
27
|
+
import { resolveRuntimeSpec } from '../config.mjs';
|
|
28
|
+
import { getHiddenRole, resolveBridgeSessionPermission } from '../internal-roles.mjs';
|
|
29
|
+
import { DEFAULT_PLUGIN, DEFAULT_MARKETPLACE } from '../../../shared/plugin-paths.mjs';
|
|
30
|
+
import { prepareBridgeSession } from './session-builder.mjs';
|
|
31
|
+
import {
|
|
32
|
+
askSession,
|
|
33
|
+
updateSessionStatus,
|
|
34
|
+
closeSession,
|
|
35
|
+
} from '../session/manager.mjs';
|
|
36
|
+
|
|
37
|
+
// Cap bridge role synthesis to ~3000 tokens (~12 KB at the 4 B/tok
|
|
38
|
+
// working average). Pool B explore/recall/search answers occasionally land
|
|
39
|
+
// 8-10k-token walls that then ride in the Lead context for the rest of the
|
|
40
|
+
// turn; the cap keeps those outliers bounded without touching the 95%+ of
|
|
41
|
+
// answers already under the threshold.
|
|
42
|
+
const BRIEF_CAP_BYTES = 12 * 1024;
|
|
43
|
+
function applyBriefCap(text) {
|
|
44
|
+
if (typeof text !== 'string') return text;
|
|
45
|
+
if (text.length <= BRIEF_CAP_BYTES) return text;
|
|
46
|
+
const head = text.slice(0, BRIEF_CAP_BYTES);
|
|
47
|
+
const approxTokens = Math.round(text.length / 4);
|
|
48
|
+
return `${head}\n\n... [TRUNCATED — full answer was ~${approxTokens} tokens / ${Math.round(text.length / 1024)} KB. Re-run with brief:false for the complete synthesis]`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function pluginRoot() {
|
|
52
|
+
return process.env.CLAUDE_PLUGIN_ROOT
|
|
53
|
+
|| join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'plugins', 'marketplaces', DEFAULT_MARKETPLACE, 'external_plugins', DEFAULT_PLUGIN);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Unified-shard policy — most bridge sessions (Pool B + Pool C) share the
|
|
57
|
+
// same tool schema so BP_1 is bit-identical across roles and one provider-side
|
|
58
|
+
// cache shard serves every caller. Per-role behaviour is steered by:
|
|
59
|
+
// 1. rules/bridge/*.md concatenated into BP2 roleCatalog (via
|
|
60
|
+
// loadScopedRoleCatalog — every bridge session carries the full
|
|
61
|
+
// hidden-role catalog so the shard stays bit-identical across roles)
|
|
62
|
+
// 2. call-time guards (loop.mjs write-block + ai-wrapped-dispatch
|
|
63
|
+
// recursion break)
|
|
64
|
+
// Hidden-role exceptions are declarative: defaults/hidden-roles.json may set
|
|
65
|
+
// toolSchemaProfile when first-turn routing quality is worth a separate tool
|
|
66
|
+
// prefix. Keep "unified" as the default; new profiles must justify the cache
|
|
67
|
+
// shard split.
|
|
68
|
+
// See manager.mjs resolveSessionTools for the single source of truth;
|
|
69
|
+
// bridge visibility is declared via annotations.bridgeHidden on each tool def.
|
|
70
|
+
const HIDDEN_ROLE_TOOL_SCHEMA_PROFILES = Object.freeze({
|
|
71
|
+
unified: null,
|
|
72
|
+
'llm-only': Object.freeze([]),
|
|
73
|
+
'filesystem-read': Object.freeze([
|
|
74
|
+
'code_graph',
|
|
75
|
+
'glob',
|
|
76
|
+
'list',
|
|
77
|
+
'grep',
|
|
78
|
+
'read',
|
|
79
|
+
]),
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
export function resolveHiddenRoleSchemaAllowedTools(hidden) {
|
|
83
|
+
if (!hidden) return null;
|
|
84
|
+
if (Array.isArray(hidden.schemaAllowedTools)) {
|
|
85
|
+
return hidden.schemaAllowedTools.map((name) => String(name || '').trim()).filter(Boolean);
|
|
86
|
+
}
|
|
87
|
+
const profile = String(hidden.toolSchemaProfile || 'unified').trim() || 'unified';
|
|
88
|
+
if (Object.prototype.hasOwnProperty.call(HIDDEN_ROLE_TOOL_SCHEMA_PROFILES, profile)) {
|
|
89
|
+
return HIDDEN_ROLE_TOOL_SCHEMA_PROFILES[profile];
|
|
90
|
+
}
|
|
91
|
+
process.stderr.write(`[bridge-llm] unknown hidden-role toolSchemaProfile="${profile}" role="${hidden.name || 'unknown'}"; using unified schema\n`);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function buildUnifiedHeader({ permission, role }) {
|
|
96
|
+
const lines = [];
|
|
97
|
+
if (permission) lines.push(`Permission: ${permission}`);
|
|
98
|
+
if (role) lines.push(`Role: ${role}`);
|
|
99
|
+
if (lines.length === 0) return '';
|
|
100
|
+
lines.push('');
|
|
101
|
+
lines.push('---');
|
|
102
|
+
lines.push('');
|
|
103
|
+
return lines.join('\n');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Resolve a preset name from (preset arg | opts.preset | hidden-role | user-workflow).
|
|
108
|
+
*
|
|
109
|
+
* Hidden roles (explorer, cycle1/cycle2, scheduler-task, etc.) are
|
|
110
|
+
* plugin-managed and take precedence over user-workflow.json — users cannot
|
|
111
|
+
* override them by redefining the same name.
|
|
112
|
+
*/
|
|
113
|
+
export function resolvePresetName({ preset, optsPreset, role, config: cfgIn = null }) {
|
|
114
|
+
if (preset) return preset;
|
|
115
|
+
if (optsPreset) return optsPreset;
|
|
116
|
+
if (!role) return null;
|
|
117
|
+
// Hidden roles resolve their maintenance preset by SLOT. Every slot carries
|
|
118
|
+
// a concrete default in DEFAULT_MAINTENANCE, so `maint[slot]` resolves
|
|
119
|
+
// directly; the Setup panel can still tune each slot independently.
|
|
120
|
+
// (explorer.slot = 'explore', cycle1-agent.slot = 'cycle1', …)
|
|
121
|
+
const hidden = getHiddenRole(role);
|
|
122
|
+
if (hidden) {
|
|
123
|
+
try {
|
|
124
|
+
const config = cfgIn || loadConfig();
|
|
125
|
+
const maint = config?.maintenance || {};
|
|
126
|
+
return maint[hidden.slot] || null;
|
|
127
|
+
} catch { return null; }
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const pluginData = process.env.CLAUDE_PLUGIN_DATA;
|
|
131
|
+
if (!pluginData) return null;
|
|
132
|
+
const wf = JSON.parse(readFileSync(join(pluginData, 'user-workflow.json'), 'utf8'));
|
|
133
|
+
if (!Array.isArray(wf.roles)) return null;
|
|
134
|
+
const entry = wf.roles.find((r) => r.name === role);
|
|
135
|
+
return entry ? entry.preset : null;
|
|
136
|
+
} catch {
|
|
137
|
+
return null;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Build a bridge-backed LLM callback.
|
|
143
|
+
*
|
|
144
|
+
* @param {object} opts
|
|
145
|
+
* @param {string} opts.role — REQUIRED; canonical role name (worker, cycle1-agent, scheduler-task, ...)
|
|
146
|
+
* @param {string} [opts.taskType] — optional internal classification stamped on the session
|
|
147
|
+
* @param {string} [opts.preset] — explicit preset override (bypasses role → preset lookup)
|
|
148
|
+
* @param {string} [opts.parentSessionId] — parent bridge session for trace aggregation
|
|
149
|
+
* @param {AbortSignal} [opts.parentSignal] — optional AbortSignal from the fan-out coordinator;
|
|
150
|
+
* when aborted the bridge role session's own controller is also aborted so the
|
|
151
|
+
* provider call tears down promptly (parent→child cascade).
|
|
152
|
+
* @returns {(args: { prompt, preset?, sourceName? }) => Promise<string>}
|
|
153
|
+
*/
|
|
154
|
+
export function makeBridgeLlm(opts = {}) {
|
|
155
|
+
if (!opts.role || typeof opts.role !== 'string') {
|
|
156
|
+
throw new Error('[bridge-llm] opts.role is required');
|
|
157
|
+
}
|
|
158
|
+
const role = opts.role;
|
|
159
|
+
|
|
160
|
+
return async function bridgeLlm({ prompt, preset: presetArg, sourceName: sourceNameArg, parentSignal: callParentSignal, idleTimeoutMs: callIdleTimeoutMs }) {
|
|
161
|
+
if (typeof prompt !== 'string' || !prompt) {
|
|
162
|
+
throw new Error(`[bridge-llm] prompt required for role "${role}"`);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const config = opts.config || loadConfig();
|
|
166
|
+
const presetName = resolvePresetName({
|
|
167
|
+
preset: presetArg,
|
|
168
|
+
optsPreset: opts.preset,
|
|
169
|
+
role,
|
|
170
|
+
config,
|
|
171
|
+
});
|
|
172
|
+
if (!presetName) {
|
|
173
|
+
throw new Error(
|
|
174
|
+
`[bridge-llm] preset unresolved for role "${role}" `
|
|
175
|
+
+ `(preset="${presetArg || opts.preset || ''}")`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const preset = config.presets?.find((p) => p.id === presetName || p.name === presetName);
|
|
180
|
+
if (!preset) {
|
|
181
|
+
throw new Error(`[bridge-llm] preset "${presetName}" not found in mixdog-config.json`);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const runtimeSpec = resolveRuntimeSpec(preset, {
|
|
185
|
+
lane: 'bridge',
|
|
186
|
+
agentId: role,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
// Callers (e.g. aiWrapped explore dispatch) may pass an explicit
|
|
190
|
+
// `cwd` to scope the agent's filesystem view. Absolute path expected
|
|
191
|
+
// (aiWrapped already expands `~` and resolves relatives). When unset
|
|
192
|
+
// we pass `null` through instead of falling back to `process.cwd()`
|
|
193
|
+
// — the MCP server's launch dir is not deterministic across callers,
|
|
194
|
+
// and the downstream skill-discovery path tolerates null. Combined
|
|
195
|
+
// with the frozen bridge skill meta-tools (collect.mjs) this keeps
|
|
196
|
+
// every caller on the same provider cache shard.
|
|
197
|
+
const cwd = (typeof opts.cwd === 'string' && opts.cwd) ? opts.cwd : null;
|
|
198
|
+
|
|
199
|
+
// Unified dispatch: Pool B/C share bit-identical tools + system prompt
|
|
200
|
+
// unless a hidden role declares a narrow toolSchemaProfile. Per-role
|
|
201
|
+
// differentiation rides in the user-message header (permission + role
|
|
202
|
+
// line) plus an optional short Pool C snippet. The read-only contract
|
|
203
|
+
// is still enforced at call time via loop.mjs's READ_BLOCKED_TOOLS
|
|
204
|
+
// guard; schema profiles are a routing-efficiency layer, not safety.
|
|
205
|
+
const hidden = getHiddenRole(role);
|
|
206
|
+
const isPoolC = Boolean(hidden);
|
|
207
|
+
// Permission: read-declared hidden roles are locked in
|
|
208
|
+
// resolveBridgeSessionPermission (prepareBridgeSession applies the same).
|
|
209
|
+
const permission = resolveBridgeSessionPermission(
|
|
210
|
+
role,
|
|
211
|
+
opts.permission ?? (isPoolC ? (hidden?.permission || 'read') : null),
|
|
212
|
+
);
|
|
213
|
+
// Pool C hidden-role instructions live in BP2 roleCatalog (loaded
|
|
214
|
+
// by loadScopedRoleCatalog from rules/bridge/*.md) — the Tier 3
|
|
215
|
+
// reminder is suppressed so the shard stays bit-identical across
|
|
216
|
+
// every bridge role.
|
|
217
|
+
//
|
|
218
|
+
// User message = pure query. Permission / role ride in BP3
|
|
219
|
+
// sessionMarker (composeSystemPrompt) — only the query varies per
|
|
220
|
+
// call, so provider cache reuses the shared prefix.
|
|
221
|
+
//
|
|
222
|
+
// Stateless ephemeral session — created fresh per call, never
|
|
223
|
+
// pooled or resumed. Cache prefix matching happens at the provider
|
|
224
|
+
// layer (account-level), not the session level.
|
|
225
|
+
const finalPrompt = prompt;
|
|
226
|
+
const { session } = prepareBridgeSession({
|
|
227
|
+
role,
|
|
228
|
+
presetName,
|
|
229
|
+
preset,
|
|
230
|
+
runtimeSpec,
|
|
231
|
+
permission,
|
|
232
|
+
cwd,
|
|
233
|
+
sourceType: opts.sourceType,
|
|
234
|
+
sourceName: sourceNameArg || opts.sourceName,
|
|
235
|
+
parentSessionId: opts.parentSessionId || null,
|
|
236
|
+
clientHostPid: opts.clientHostPid,
|
|
237
|
+
skipRoleReminder: isPoolC,
|
|
238
|
+
schemaAllowedTools: resolveHiddenRoleSchemaAllowedTools(hidden),
|
|
239
|
+
taskType: opts.taskType,
|
|
240
|
+
maxLoopIterations: opts.maxLoopIterations,
|
|
241
|
+
});
|
|
242
|
+
// Diagnostic — dump the actual tool names exposed to this LLM call,
|
|
243
|
+
// visible from the worker log instead of being hidden behind a
|
|
244
|
+
// count-only "tools=N" line.
|
|
245
|
+
try {
|
|
246
|
+
const _toolNames = (session.tools || []).map((t) => t?.name).filter(Boolean);
|
|
247
|
+
process.stderr.write(`[bridge-llm] role=${role} tool-list (${_toolNames.length}): ${_toolNames.join(',')}\n`);
|
|
248
|
+
} catch { /* best-effort diagnostic */ }
|
|
249
|
+
|
|
250
|
+
await updateSessionStatus(session.id, 'running');
|
|
251
|
+
// Parent→child abort cascade: when opts.parentSignal (factory) or
|
|
252
|
+
// callParentSignal (per-call) fires, abort the sub-session's own
|
|
253
|
+
// controller so the provider call tears down promptly. Best-effort:
|
|
254
|
+
// if the session/manager import is unavailable we fall back silently.
|
|
255
|
+
const _managerMod = await import('../session/manager.mjs').catch(() => null);
|
|
256
|
+
const _linkSignal = _managerMod?.linkParentSignalToSession;
|
|
257
|
+
const _getLastProgressAt = _managerMod?.getSessionLastProgressAt;
|
|
258
|
+
if (_linkSignal) {
|
|
259
|
+
if (opts.parentSignal instanceof AbortSignal) {
|
|
260
|
+
try { _linkSignal(session.id, opts.parentSignal); } catch { /* ignore */ }
|
|
261
|
+
}
|
|
262
|
+
if (callParentSignal instanceof AbortSignal) {
|
|
263
|
+
try { _linkSignal(session.id, callParentSignal); } catch { /* ignore */ }
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Idle-progress watchdog. A "session that's actually doing work"
|
|
267
|
+
// refreshes one of three runtime fields every chunk/tool-call.
|
|
268
|
+
// If none of those advance for `idleMs`, we treat the provider call
|
|
269
|
+
// as stuck (network black-hole, nested-spawn deadlock, etc.) and
|
|
270
|
+
// abort the sub-session controller. Routine long runs — multi-tool
|
|
271
|
+
// chains, slow streams — stay untouched because at least one of
|
|
272
|
+
// the three fields keeps ticking. `0` or negative disables the
|
|
273
|
+
// watchdog entirely; default is 120s.
|
|
274
|
+
const _idleMs = Number.isFinite(callIdleTimeoutMs)
|
|
275
|
+
? callIdleTimeoutMs
|
|
276
|
+
: (Number.isFinite(opts.idleTimeoutMs) ? opts.idleTimeoutMs : 120_000);
|
|
277
|
+
const _idleController = (_idleMs > 0 && _linkSignal) ? new AbortController() : null;
|
|
278
|
+
if (_idleController) {
|
|
279
|
+
try { _linkSignal(session.id, _idleController.signal); } catch { /* ignore */ }
|
|
280
|
+
}
|
|
281
|
+
const _idleTimer = (_idleController && typeof _getLastProgressAt === 'function')
|
|
282
|
+
? setInterval(() => {
|
|
283
|
+
const last = _getLastProgressAt(session.id);
|
|
284
|
+
if (!last) return; // ask hasn't started writing progress yet
|
|
285
|
+
if (Date.now() - last > _idleMs) {
|
|
286
|
+
try {
|
|
287
|
+
_idleController.abort(new Error(`idle timeout exceeded (${_idleMs}ms)`));
|
|
288
|
+
} catch { /* ignore */ }
|
|
289
|
+
}
|
|
290
|
+
}, 1000)
|
|
291
|
+
: null;
|
|
292
|
+
if (_idleTimer && typeof _idleTimer.unref === 'function') _idleTimer.unref();
|
|
293
|
+
let terminalStatus = 'idle';
|
|
294
|
+
process.stderr.write(`[bridge-llm] role=${role} preset=${presetName} model=${preset.model} provider=${preset.provider} session=${session.id}\n`);
|
|
295
|
+
const _bridgeT0 = Date.now();
|
|
296
|
+
try {
|
|
297
|
+
const result = await askSession(session.id, finalPrompt, null, null, cwd);
|
|
298
|
+
process.stderr.write(`[bridge-llm] role=${role} session=${session.id} elapsed=${Date.now() - _bridgeT0}ms\n`);
|
|
299
|
+
const raw = result?.content || '';
|
|
300
|
+
// Brief cap. Bridge role answers (explore/recall/search)
|
|
301
|
+
// occasionally balloon to 8-10k token walls that then ride in the
|
|
302
|
+
// parent Lead's context for the rest of the turn. A 3000-token
|
|
303
|
+
// (~12 KB) ceiling trims the long tail while leaving the vast
|
|
304
|
+
// majority of answers untouched. Opt-out via `brief:false` when
|
|
305
|
+
// the caller explicitly wants the full synthesis.
|
|
306
|
+
if (opts.brief === false) {
|
|
307
|
+
try { closeSession(session.id, 'ephemeral-done'); } catch { /* ignore */ }
|
|
308
|
+
return raw;
|
|
309
|
+
}
|
|
310
|
+
const out = applyBriefCap(raw);
|
|
311
|
+
try { closeSession(session.id, 'ephemeral-done'); } catch { /* ignore */ }
|
|
312
|
+
return out;
|
|
313
|
+
} catch (err) {
|
|
314
|
+
terminalStatus = 'error';
|
|
315
|
+
try { closeSession(session.id, 'ephemeral-error'); } catch { /* ignore */ }
|
|
316
|
+
throw err;
|
|
317
|
+
} finally {
|
|
318
|
+
if (_idleTimer) {
|
|
319
|
+
try { clearInterval(_idleTimer); } catch { /* ignore */ }
|
|
320
|
+
}
|
|
321
|
+
// Always flip out of 'running' before returning so the sweep never
|
|
322
|
+
// leaves a stateless Pool C session stuck in 'running' when the
|
|
323
|
+
// try/catch falls through in unexpected ways.
|
|
324
|
+
try { await updateSessionStatus(session.id, terminalStatus); } catch { /* ignore */ }
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Smart Bridge — Cache Observability
|
|
3
|
+
*
|
|
4
|
+
* Normalizes raw provider usage objects into a unified CacheObservation
|
|
5
|
+
* for cross-provider cache performance comparison.
|
|
6
|
+
*
|
|
7
|
+
* @typedef {Object} CacheObservation
|
|
8
|
+
* @property {string} provider — provider name
|
|
9
|
+
* @property {number} cache_hit_tokens — tokens read from cache
|
|
10
|
+
* @property {number} cache_write_tokens — tokens written to cache
|
|
11
|
+
* @property {string|null} cache_ttl_tier — '5m' | '1h' | null
|
|
12
|
+
* @property {number|null} cache_hit_ratio — 0.0–1.0, null if not computable
|
|
13
|
+
* @property {boolean} cache_observable — whether the provider reports cache metrics
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Normalize raw provider usage into a CacheObservation.
|
|
18
|
+
*
|
|
19
|
+
* @param {string} provider — one of the 10 supported providers
|
|
20
|
+
* @param {object} rawUsage — raw usage object from provider response
|
|
21
|
+
* @returns {CacheObservation}
|
|
22
|
+
*/
|
|
23
|
+
export function normalizeUsage(provider, rawUsage) {
|
|
24
|
+
if (!rawUsage) {
|
|
25
|
+
return _empty(provider, false);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
switch (provider) {
|
|
29
|
+
case 'anthropic':
|
|
30
|
+
case 'anthropic-oauth':
|
|
31
|
+
return _normalizeAnthropic(provider, rawUsage);
|
|
32
|
+
|
|
33
|
+
case 'openai':
|
|
34
|
+
case 'openai-oauth':
|
|
35
|
+
case 'xai':
|
|
36
|
+
case 'grok-oauth':
|
|
37
|
+
// xAI Responses usage mirrors OpenAI's shape:
|
|
38
|
+
// input_tokens_details.cached_tokens for prefix cache hits.
|
|
39
|
+
return _normalizeOpenai(provider, rawUsage);
|
|
40
|
+
|
|
41
|
+
case 'gemini':
|
|
42
|
+
return _normalizeGemini(provider, rawUsage);
|
|
43
|
+
|
|
44
|
+
case 'deepseek':
|
|
45
|
+
return _normalizeOpenai(provider, rawUsage);
|
|
46
|
+
|
|
47
|
+
case 'ollama':
|
|
48
|
+
case 'lmstudio':
|
|
49
|
+
return _empty(provider, false);
|
|
50
|
+
|
|
51
|
+
default:
|
|
52
|
+
return _empty(provider, false);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// --- Per-provider extractors ---
|
|
57
|
+
|
|
58
|
+
function _normalizeAnthropic(provider, u) {
|
|
59
|
+
const hit = _num(u.cache_read_input_tokens);
|
|
60
|
+
const write = _num(u.cache_creation_input_tokens);
|
|
61
|
+
const input = _num(u.input_tokens);
|
|
62
|
+
|
|
63
|
+
// TTL tier: pick from cache_creation breakdown
|
|
64
|
+
let ttlTier = null;
|
|
65
|
+
if (u.cache_creation) {
|
|
66
|
+
if (_num(u.cache_creation.ephemeral_1h_input_tokens) > 0) ttlTier = '1h';
|
|
67
|
+
else if (_num(u.cache_creation.ephemeral_5m_input_tokens) > 0) ttlTier = '5m';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const total = hit + input + write;
|
|
71
|
+
const ratio = total > 0 ? hit / total : null;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
provider,
|
|
75
|
+
cache_hit_tokens: hit,
|
|
76
|
+
cache_write_tokens: write,
|
|
77
|
+
cache_ttl_tier: ttlTier,
|
|
78
|
+
cache_hit_ratio: ratio,
|
|
79
|
+
cache_observable: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function _normalizeOpenai(provider, u) {
|
|
84
|
+
// OpenAI: cached_tokens in prompt_tokens_details or input_tokens_details
|
|
85
|
+
const hit = _num(u.prompt_tokens_details?.cached_tokens)
|
|
86
|
+
|| _num(u.input_tokens_details?.cached_tokens)
|
|
87
|
+
|| 0;
|
|
88
|
+
const input = _num(u.prompt_tokens) || _num(u.input_tokens) || 0;
|
|
89
|
+
const ratio = input > 0 ? hit / input : null;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
provider,
|
|
93
|
+
cache_hit_tokens: hit,
|
|
94
|
+
cache_write_tokens: 0,
|
|
95
|
+
cache_ttl_tier: null,
|
|
96
|
+
cache_hit_ratio: ratio,
|
|
97
|
+
cache_observable: true,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function _normalizeGemini(provider, u) {
|
|
102
|
+
// Gemini: provider-normalized usage may already include fallback-adjusted
|
|
103
|
+
// cachedTokens. Raw SDK/REST usage reports cachedContentTokenCount.
|
|
104
|
+
const meta = u.usageMetadata || u;
|
|
105
|
+
const hit = _num(meta.cachedTokens)
|
|
106
|
+
|| _num(meta.cached_tokens)
|
|
107
|
+
|| _num(meta.effectiveCachedTokens)
|
|
108
|
+
|| _num(meta.cachedContentTokenCount)
|
|
109
|
+
|| _num(meta.cachedFallbackTokens)
|
|
110
|
+
|| 0;
|
|
111
|
+
const observable = 'cachedTokens' in (meta || {})
|
|
112
|
+
|| 'cached_tokens' in (meta || {})
|
|
113
|
+
|| 'effectiveCachedTokens' in (meta || {})
|
|
114
|
+
|| 'cachedContentTokenCount' in (meta || {})
|
|
115
|
+
|| 'cachedFallbackTokens' in (meta || {});
|
|
116
|
+
const input = _num(meta.promptTokens)
|
|
117
|
+
|| _num(meta.inputTokens)
|
|
118
|
+
|| _num(meta.input_tokens)
|
|
119
|
+
|| _num(meta.promptTokenCount)
|
|
120
|
+
|| _num(meta.totalTokenCount)
|
|
121
|
+
|| 0;
|
|
122
|
+
const ratio = input > 0 ? hit / input : null;
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
provider,
|
|
126
|
+
cache_hit_tokens: hit,
|
|
127
|
+
cache_write_tokens: 0,
|
|
128
|
+
cache_ttl_tier: null,
|
|
129
|
+
cache_hit_ratio: ratio,
|
|
130
|
+
cache_observable: observable,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// --- Helpers ---
|
|
135
|
+
|
|
136
|
+
function _empty(provider, observable) {
|
|
137
|
+
return {
|
|
138
|
+
provider,
|
|
139
|
+
cache_hit_tokens: 0,
|
|
140
|
+
cache_write_tokens: 0,
|
|
141
|
+
cache_ttl_tier: null,
|
|
142
|
+
cache_hit_ratio: null,
|
|
143
|
+
cache_observable: observable,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function _num(v) {
|
|
148
|
+
const n = Number(v);
|
|
149
|
+
return Number.isFinite(n) ? n : 0;
|
|
150
|
+
}
|