nodedex 0.1.0
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/adapters/claude-code-watcher.mjs +336 -0
- package/adapters/hermes-statedb-watcher.mjs +234 -0
- package/adapters/nodedex-capture-core.mjs +129 -0
- package/adapters/nodedex-capture.mjs +169 -0
- package/dist/agent-protocol.d.ts +7 -0
- package/dist/agent-protocol.d.ts.map +1 -0
- package/dist/agent-protocol.js +38 -0
- package/dist/agent-protocol.js.map +1 -0
- package/dist/api-server.d.ts +5 -0
- package/dist/api-server.d.ts.map +1 -0
- package/dist/api-server.js +351 -0
- package/dist/api-server.js.map +1 -0
- package/dist/boot-env.d.ts +2 -0
- package/dist/boot-env.d.ts.map +1 -0
- package/dist/boot-env.js +12 -0
- package/dist/boot-env.js.map +1 -0
- package/dist/engine/__tests__/search-core.test.d.ts +2 -0
- package/dist/engine/__tests__/search-core.test.d.ts.map +1 -0
- package/dist/engine/__tests__/search-core.test.js +139 -0
- package/dist/engine/__tests__/search-core.test.js.map +1 -0
- package/dist/engine/ai-provider.d.ts +45 -0
- package/dist/engine/ai-provider.d.ts.map +1 -0
- package/dist/engine/ai-provider.js +5 -0
- package/dist/engine/ai-provider.js.map +1 -0
- package/dist/engine/embeddings.d.ts +51 -0
- package/dist/engine/embeddings.d.ts.map +1 -0
- package/dist/engine/embeddings.js +89 -0
- package/dist/engine/embeddings.js.map +1 -0
- package/dist/engine/providers/__tests__/failure-policy.test.d.ts +2 -0
- package/dist/engine/providers/__tests__/failure-policy.test.d.ts.map +1 -0
- package/dist/engine/providers/__tests__/failure-policy.test.js +134 -0
- package/dist/engine/providers/__tests__/failure-policy.test.js.map +1 -0
- package/dist/engine/providers/__tests__/model-caps.test.d.ts +2 -0
- package/dist/engine/providers/__tests__/model-caps.test.d.ts.map +1 -0
- package/dist/engine/providers/__tests__/model-caps.test.js +38 -0
- package/dist/engine/providers/__tests__/model-caps.test.js.map +1 -0
- package/dist/engine/providers/__tests__/openai-structured.test.d.ts +2 -0
- package/dist/engine/providers/__tests__/openai-structured.test.d.ts.map +1 -0
- package/dist/engine/providers/__tests__/openai-structured.test.js +73 -0
- package/dist/engine/providers/__tests__/openai-structured.test.js.map +1 -0
- package/dist/engine/providers/__tests__/usage-ledger.test.d.ts +2 -0
- package/dist/engine/providers/__tests__/usage-ledger.test.d.ts.map +1 -0
- package/dist/engine/providers/__tests__/usage-ledger.test.js +108 -0
- package/dist/engine/providers/__tests__/usage-ledger.test.js.map +1 -0
- package/dist/engine/providers/anthropic.d.ts +17 -0
- package/dist/engine/providers/anthropic.d.ts.map +1 -0
- package/dist/engine/providers/anthropic.js +125 -0
- package/dist/engine/providers/anthropic.js.map +1 -0
- package/dist/engine/providers/failure-policy.d.ts +56 -0
- package/dist/engine/providers/failure-policy.d.ts.map +1 -0
- package/dist/engine/providers/failure-policy.js +120 -0
- package/dist/engine/providers/failure-policy.js.map +1 -0
- package/dist/engine/providers/gemini.d.ts +22 -0
- package/dist/engine/providers/gemini.d.ts.map +1 -0
- package/dist/engine/providers/gemini.js +180 -0
- package/dist/engine/providers/gemini.js.map +1 -0
- package/dist/engine/providers/index.d.ts +8 -0
- package/dist/engine/providers/index.d.ts.map +1 -0
- package/dist/engine/providers/index.js +67 -0
- package/dist/engine/providers/index.js.map +1 -0
- package/dist/engine/providers/local.d.ts +12 -0
- package/dist/engine/providers/local.d.ts.map +1 -0
- package/dist/engine/providers/local.js +46 -0
- package/dist/engine/providers/local.js.map +1 -0
- package/dist/engine/providers/model-caps.d.ts +6 -0
- package/dist/engine/providers/model-caps.d.ts.map +1 -0
- package/dist/engine/providers/model-caps.js +49 -0
- package/dist/engine/providers/model-caps.js.map +1 -0
- package/dist/engine/providers/openai.d.ts +30 -0
- package/dist/engine/providers/openai.d.ts.map +1 -0
- package/dist/engine/providers/openai.js +309 -0
- package/dist/engine/providers/openai.js.map +1 -0
- package/dist/engine/providers/usage-ledger.d.ts +69 -0
- package/dist/engine/providers/usage-ledger.d.ts.map +1 -0
- package/dist/engine/providers/usage-ledger.js +209 -0
- package/dist/engine/providers/usage-ledger.js.map +1 -0
- package/dist/engine/search-core.d.ts +40 -0
- package/dist/engine/search-core.d.ts.map +1 -0
- package/dist/engine/search-core.js +109 -0
- package/dist/engine/search-core.js.map +1 -0
- package/dist/engine/vector-math.d.ts +5 -0
- package/dist/engine/vector-math.d.ts.map +1 -0
- package/dist/engine/vector-math.js +25 -0
- package/dist/engine/vector-math.js.map +1 -0
- package/dist/home-env.d.ts +26 -0
- package/dist/home-env.d.ts.map +1 -0
- package/dist/home-env.js +87 -0
- package/dist/home-env.js.map +1 -0
- package/dist/mcp-server.d.ts +13 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +79 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/middleware/auth.d.ts +23 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +104 -0
- package/dist/middleware/auth.js.map +1 -0
- package/dist/middleware/auto-recall.d.ts +7 -0
- package/dist/middleware/auto-recall.d.ts.map +1 -0
- package/dist/middleware/auto-recall.js +257 -0
- package/dist/middleware/auto-recall.js.map +1 -0
- package/dist/middleware/auto-reflect.d.ts +4 -0
- package/dist/middleware/auto-reflect.d.ts.map +1 -0
- package/dist/middleware/auto-reflect.js +5 -0
- package/dist/middleware/auto-reflect.js.map +1 -0
- package/dist/middleware/reflect/apply-flag-verdict.d.ts +27 -0
- package/dist/middleware/reflect/apply-flag-verdict.d.ts.map +1 -0
- package/dist/middleware/reflect/apply-flag-verdict.js +57 -0
- package/dist/middleware/reflect/apply-flag-verdict.js.map +1 -0
- package/dist/middleware/reflect/arc-entity-resolve.d.ts +29 -0
- package/dist/middleware/reflect/arc-entity-resolve.d.ts.map +1 -0
- package/dist/middleware/reflect/arc-entity-resolve.js +356 -0
- package/dist/middleware/reflect/arc-entity-resolve.js.map +1 -0
- package/dist/middleware/reflect/arc-inactivity-timer.d.ts +47 -0
- package/dist/middleware/reflect/arc-inactivity-timer.d.ts.map +1 -0
- package/dist/middleware/reflect/arc-inactivity-timer.js +175 -0
- package/dist/middleware/reflect/arc-inactivity-timer.js.map +1 -0
- package/dist/middleware/reflect/arc-pipeline.d.ts +33 -0
- package/dist/middleware/reflect/arc-pipeline.d.ts.map +1 -0
- package/dist/middleware/reflect/arc-pipeline.js +498 -0
- package/dist/middleware/reflect/arc-pipeline.js.map +1 -0
- package/dist/middleware/reflect/comprehend-pergroup.d.ts +100 -0
- package/dist/middleware/reflect/comprehend-pergroup.d.ts.map +1 -0
- package/dist/middleware/reflect/comprehend-pergroup.js +610 -0
- package/dist/middleware/reflect/comprehend-pergroup.js.map +1 -0
- package/dist/middleware/reflect/comprehend.d.ts +237 -0
- package/dist/middleware/reflect/comprehend.d.ts.map +1 -0
- package/dist/middleware/reflect/comprehend.js +706 -0
- package/dist/middleware/reflect/comprehend.js.map +1 -0
- package/dist/middleware/reflect/config.d.ts +34 -0
- package/dist/middleware/reflect/config.d.ts.map +1 -0
- package/dist/middleware/reflect/config.js +131 -0
- package/dist/middleware/reflect/config.js.map +1 -0
- package/dist/middleware/reflect/context.d.ts +138 -0
- package/dist/middleware/reflect/context.d.ts.map +1 -0
- package/dist/middleware/reflect/context.js +619 -0
- package/dist/middleware/reflect/context.js.map +1 -0
- package/dist/middleware/reflect/cost-breakdown.d.ts +69 -0
- package/dist/middleware/reflect/cost-breakdown.d.ts.map +1 -0
- package/dist/middleware/reflect/cost-breakdown.js +63 -0
- package/dist/middleware/reflect/cost-breakdown.js.map +1 -0
- package/dist/middleware/reflect/cost-guard.d.ts +102 -0
- package/dist/middleware/reflect/cost-guard.d.ts.map +1 -0
- package/dist/middleware/reflect/cost-guard.js +243 -0
- package/dist/middleware/reflect/cost-guard.js.map +1 -0
- package/dist/middleware/reflect/cost-pricing.d.ts +54 -0
- package/dist/middleware/reflect/cost-pricing.d.ts.map +1 -0
- package/dist/middleware/reflect/cost-pricing.js +148 -0
- package/dist/middleware/reflect/cost-pricing.js.map +1 -0
- package/dist/middleware/reflect/cross-group-link.d.ts +61 -0
- package/dist/middleware/reflect/cross-group-link.d.ts.map +1 -0
- package/dist/middleware/reflect/cross-group-link.js +212 -0
- package/dist/middleware/reflect/cross-group-link.js.map +1 -0
- package/dist/middleware/reflect/dedup-by-source-and-value.d.ts +70 -0
- package/dist/middleware/reflect/dedup-by-source-and-value.d.ts.map +1 -0
- package/dist/middleware/reflect/dedup-by-source-and-value.js +0 -0
- package/dist/middleware/reflect/dedup-by-source-and-value.js.map +1 -0
- package/dist/middleware/reflect/describe-roots.d.ts +58 -0
- package/dist/middleware/reflect/describe-roots.d.ts.map +1 -0
- package/dist/middleware/reflect/describe-roots.js +266 -0
- package/dist/middleware/reflect/describe-roots.js.map +1 -0
- package/dist/middleware/reflect/flag-reviewer-startup.d.ts +16 -0
- package/dist/middleware/reflect/flag-reviewer-startup.d.ts.map +1 -0
- package/dist/middleware/reflect/flag-reviewer-startup.js +107 -0
- package/dist/middleware/reflect/flag-reviewer-startup.js.map +1 -0
- package/dist/middleware/reflect/flag-reviewer.d.ts +69 -0
- package/dist/middleware/reflect/flag-reviewer.d.ts.map +1 -0
- package/dist/middleware/reflect/flag-reviewer.js +520 -0
- package/dist/middleware/reflect/flag-reviewer.js.map +1 -0
- package/dist/middleware/reflect/inline-dedup.d.ts +26 -0
- package/dist/middleware/reflect/inline-dedup.d.ts.map +1 -0
- package/dist/middleware/reflect/inline-dedup.js +131 -0
- package/dist/middleware/reflect/inline-dedup.js.map +1 -0
- package/dist/middleware/reflect/justify-decisions.d.ts +37 -0
- package/dist/middleware/reflect/justify-decisions.d.ts.map +1 -0
- package/dist/middleware/reflect/justify-decisions.js +159 -0
- package/dist/middleware/reflect/justify-decisions.js.map +1 -0
- package/dist/middleware/reflect/nl-accept.d.ts +35 -0
- package/dist/middleware/reflect/nl-accept.d.ts.map +1 -0
- package/dist/middleware/reflect/nl-accept.js +167 -0
- package/dist/middleware/reflect/nl-accept.js.map +1 -0
- package/dist/middleware/reflect/pass0.d.ts +20 -0
- package/dist/middleware/reflect/pass0.d.ts.map +1 -0
- package/dist/middleware/reflect/pass0.js +423 -0
- package/dist/middleware/reflect/pass0.js.map +1 -0
- package/dist/middleware/reflect/pass1.d.ts +17 -0
- package/dist/middleware/reflect/pass1.d.ts.map +1 -0
- package/dist/middleware/reflect/pass1.js +241 -0
- package/dist/middleware/reflect/pass1.js.map +1 -0
- package/dist/middleware/reflect/pass2-quarantine.d.ts +129 -0
- package/dist/middleware/reflect/pass2-quarantine.d.ts.map +1 -0
- package/dist/middleware/reflect/pass2-quarantine.js +272 -0
- package/dist/middleware/reflect/pass2-quarantine.js.map +1 -0
- package/dist/middleware/reflect/pass2-seams.d.ts +205 -0
- package/dist/middleware/reflect/pass2-seams.d.ts.map +1 -0
- package/dist/middleware/reflect/pass2-seams.js +279 -0
- package/dist/middleware/reflect/pass2-seams.js.map +1 -0
- package/dist/middleware/reflect/pass2-split-orchestrator.d.ts +37 -0
- package/dist/middleware/reflect/pass2-split-orchestrator.d.ts.map +1 -0
- package/dist/middleware/reflect/pass2-split-orchestrator.js +531 -0
- package/dist/middleware/reflect/pass2-split-orchestrator.js.map +1 -0
- package/dist/middleware/reflect/pass2.d.ts +17 -0
- package/dist/middleware/reflect/pass2.d.ts.map +1 -0
- package/dist/middleware/reflect/pass2.js +324 -0
- package/dist/middleware/reflect/pass2.js.map +1 -0
- package/dist/middleware/reflect/pass2a.d.ts +141 -0
- package/dist/middleware/reflect/pass2a.d.ts.map +1 -0
- package/dist/middleware/reflect/pass2a.js +404 -0
- package/dist/middleware/reflect/pass2a.js.map +1 -0
- package/dist/middleware/reflect/pass2b.d.ts +108 -0
- package/dist/middleware/reflect/pass2b.d.ts.map +1 -0
- package/dist/middleware/reflect/pass2b.js +480 -0
- package/dist/middleware/reflect/pass2b.js.map +1 -0
- package/dist/middleware/reflect/pass2c.d.ts +113 -0
- package/dist/middleware/reflect/pass2c.d.ts.map +1 -0
- package/dist/middleware/reflect/pass2c.js +360 -0
- package/dist/middleware/reflect/pass2c.js.map +1 -0
- package/dist/middleware/reflect/pass3-batch.d.ts +62 -0
- package/dist/middleware/reflect/pass3-batch.d.ts.map +1 -0
- package/dist/middleware/reflect/pass3-batch.js +139 -0
- package/dist/middleware/reflect/pass3-batch.js.map +1 -0
- package/dist/middleware/reflect/pass3.d.ts +23 -0
- package/dist/middleware/reflect/pass3.d.ts.map +1 -0
- package/dist/middleware/reflect/pass3.js +371 -0
- package/dist/middleware/reflect/pass3.js.map +1 -0
- package/dist/middleware/reflect/pass4-slice.d.ts +25 -0
- package/dist/middleware/reflect/pass4-slice.d.ts.map +1 -0
- package/dist/middleware/reflect/pass4-slice.js +315 -0
- package/dist/middleware/reflect/pass4-slice.js.map +1 -0
- package/dist/middleware/reflect/pass4.d.ts +30 -0
- package/dist/middleware/reflect/pass4.d.ts.map +1 -0
- package/dist/middleware/reflect/pass4.js +193 -0
- package/dist/middleware/reflect/pass4.js.map +1 -0
- package/dist/middleware/reflect/pass5.d.ts +22 -0
- package/dist/middleware/reflect/pass5.d.ts.map +1 -0
- package/dist/middleware/reflect/pass5.js +178 -0
- package/dist/middleware/reflect/pass5.js.map +1 -0
- package/dist/middleware/reflect/pass_judge.d.ts +44 -0
- package/dist/middleware/reflect/pass_judge.d.ts.map +1 -0
- package/dist/middleware/reflect/pass_judge.js +263 -0
- package/dist/middleware/reflect/pass_judge.js.map +1 -0
- package/dist/middleware/reflect/pipeline-flags.d.ts +140 -0
- package/dist/middleware/reflect/pipeline-flags.d.ts.map +1 -0
- package/dist/middleware/reflect/pipeline-flags.js +314 -0
- package/dist/middleware/reflect/pipeline-flags.js.map +1 -0
- package/dist/middleware/reflect/pipeline.d.ts +237 -0
- package/dist/middleware/reflect/pipeline.d.ts.map +1 -0
- package/dist/middleware/reflect/pipeline.js +3114 -0
- package/dist/middleware/reflect/pipeline.js.map +1 -0
- package/dist/middleware/reflect/promptOverride.d.ts +14 -0
- package/dist/middleware/reflect/promptOverride.d.ts.map +1 -0
- package/dist/middleware/reflect/promptOverride.js +28 -0
- package/dist/middleware/reflect/promptOverride.js.map +1 -0
- package/dist/middleware/reflect/provenance-check.d.ts +48 -0
- package/dist/middleware/reflect/provenance-check.d.ts.map +1 -0
- package/dist/middleware/reflect/provenance-check.js +180 -0
- package/dist/middleware/reflect/provenance-check.js.map +1 -0
- package/dist/middleware/reflect/provenance-reviewer.d.ts +52 -0
- package/dist/middleware/reflect/provenance-reviewer.d.ts.map +1 -0
- package/dist/middleware/reflect/provenance-reviewer.js +253 -0
- package/dist/middleware/reflect/provenance-reviewer.js.map +1 -0
- package/dist/middleware/reflect/prune-collapsed-types.d.ts +11 -0
- package/dist/middleware/reflect/prune-collapsed-types.d.ts.map +1 -0
- package/dist/middleware/reflect/prune-collapsed-types.js +32 -0
- package/dist/middleware/reflect/prune-collapsed-types.js.map +1 -0
- package/dist/middleware/reflect/recognize-root.d.ts +75 -0
- package/dist/middleware/reflect/recognize-root.d.ts.map +1 -0
- package/dist/middleware/reflect/recognize-root.js +204 -0
- package/dist/middleware/reflect/recognize-root.js.map +1 -0
- package/dist/middleware/reflect/render-agent-flag.d.ts +25 -0
- package/dist/middleware/reflect/render-agent-flag.d.ts.map +1 -0
- package/dist/middleware/reflect/render-agent-flag.js +39 -0
- package/dist/middleware/reflect/render-agent-flag.js.map +1 -0
- package/dist/middleware/reflect/retrieve-graph-slice.d.ts +54 -0
- package/dist/middleware/reflect/retrieve-graph-slice.d.ts.map +1 -0
- package/dist/middleware/reflect/retrieve-graph-slice.js +173 -0
- package/dist/middleware/reflect/retrieve-graph-slice.js.map +1 -0
- package/dist/middleware/reflect/root-relatedness.d.ts +31 -0
- package/dist/middleware/reflect/root-relatedness.d.ts.map +1 -0
- package/dist/middleware/reflect/root-relatedness.js +92 -0
- package/dist/middleware/reflect/root-relatedness.js.map +1 -0
- package/dist/middleware/reflect/schema-heal.d.ts +22 -0
- package/dist/middleware/reflect/schema-heal.d.ts.map +1 -0
- package/dist/middleware/reflect/schema-heal.js +119 -0
- package/dist/middleware/reflect/schema-heal.js.map +1 -0
- package/dist/middleware/reflect/schema-validator.d.ts +85 -0
- package/dist/middleware/reflect/schema-validator.d.ts.map +1 -0
- package/dist/middleware/reflect/schema-validator.js +196 -0
- package/dist/middleware/reflect/schema-validator.js.map +1 -0
- package/dist/middleware/reflect/stage-audit-graph.d.ts +115 -0
- package/dist/middleware/reflect/stage-audit-graph.d.ts.map +1 -0
- package/dist/middleware/reflect/stage-audit-graph.js +563 -0
- package/dist/middleware/reflect/stage-audit-graph.js.map +1 -0
- package/dist/middleware/reflect/stage-d-resolve-graph.d.ts +87 -0
- package/dist/middleware/reflect/stage-d-resolve-graph.d.ts.map +1 -0
- package/dist/middleware/reflect/stage-d-resolve-graph.js +256 -0
- package/dist/middleware/reflect/stage-d-resolve-graph.js.map +1 -0
- package/dist/middleware/reflect/synthesizeFromSceneCard.d.ts +15 -0
- package/dist/middleware/reflect/synthesizeFromSceneCard.d.ts.map +1 -0
- package/dist/middleware/reflect/synthesizeFromSceneCard.js +91 -0
- package/dist/middleware/reflect/synthesizeFromSceneCard.js.map +1 -0
- package/dist/middleware/reflect/types.d.ts +261 -0
- package/dist/middleware/reflect/types.d.ts.map +1 -0
- package/dist/middleware/reflect/types.js +3 -0
- package/dist/middleware/reflect/types.js.map +1 -0
- package/dist/middleware/reflect/v2-integrate.d.ts +120 -0
- package/dist/middleware/reflect/v2-integrate.d.ts.map +1 -0
- package/dist/middleware/reflect/v2-integrate.js +388 -0
- package/dist/middleware/reflect/v2-integrate.js.map +1 -0
- package/dist/middleware/reflect/v2-judge.d.ts +44 -0
- package/dist/middleware/reflect/v2-judge.d.ts.map +1 -0
- package/dist/middleware/reflect/v2-judge.js +191 -0
- package/dist/middleware/reflect/v2-judge.js.map +1 -0
- package/dist/relation-sets.d.ts +2 -0
- package/dist/relation-sets.d.ts.map +1 -0
- package/dist/relation-sets.js +35 -0
- package/dist/relation-sets.js.map +1 -0
- package/dist/routes/__tests__/flags.test.d.ts +2 -0
- package/dist/routes/__tests__/flags.test.d.ts.map +1 -0
- package/dist/routes/__tests__/flags.test.js +257 -0
- package/dist/routes/__tests__/flags.test.js.map +1 -0
- package/dist/routes/__tests__/models-catalog.test.d.ts +2 -0
- package/dist/routes/__tests__/models-catalog.test.d.ts.map +1 -0
- package/dist/routes/__tests__/models-catalog.test.js +130 -0
- package/dist/routes/__tests__/models-catalog.test.js.map +1 -0
- package/dist/routes/__tests__/reflect-pause-drain.test.d.ts +2 -0
- package/dist/routes/__tests__/reflect-pause-drain.test.d.ts.map +1 -0
- package/dist/routes/__tests__/reflect-pause-drain.test.js +38 -0
- package/dist/routes/__tests__/reflect-pause-drain.test.js.map +1 -0
- package/dist/routes/__tests__/spend-pause-drain.test.d.ts +2 -0
- package/dist/routes/__tests__/spend-pause-drain.test.d.ts.map +1 -0
- package/dist/routes/__tests__/spend-pause-drain.test.js +38 -0
- package/dist/routes/__tests__/spend-pause-drain.test.js.map +1 -0
- package/dist/routes/admin.d.ts +49 -0
- package/dist/routes/admin.d.ts.map +1 -0
- package/dist/routes/admin.js +471 -0
- package/dist/routes/admin.js.map +1 -0
- package/dist/routes/blocks.d.ts +4 -0
- package/dist/routes/blocks.d.ts.map +1 -0
- package/dist/routes/blocks.js +893 -0
- package/dist/routes/blocks.js.map +1 -0
- package/dist/routes/chat-proxy.d.ts +5 -0
- package/dist/routes/chat-proxy.d.ts.map +1 -0
- package/dist/routes/chat-proxy.js +225 -0
- package/dist/routes/chat-proxy.js.map +1 -0
- package/dist/routes/conversations.d.ts +4 -0
- package/dist/routes/conversations.d.ts.map +1 -0
- package/dist/routes/conversations.js +139 -0
- package/dist/routes/conversations.js.map +1 -0
- package/dist/routes/flags.d.ts +4 -0
- package/dist/routes/flags.d.ts.map +1 -0
- package/dist/routes/flags.js +151 -0
- package/dist/routes/flags.js.map +1 -0
- package/dist/routes/inject.d.ts +4 -0
- package/dist/routes/inject.d.ts.map +1 -0
- package/dist/routes/inject.js +183 -0
- package/dist/routes/inject.js.map +1 -0
- package/dist/routes/mcp-http.d.ts +5 -0
- package/dist/routes/mcp-http.d.ts.map +1 -0
- package/dist/routes/mcp-http.js +94 -0
- package/dist/routes/mcp-http.js.map +1 -0
- package/dist/routes/quarantine.d.ts +4 -0
- package/dist/routes/quarantine.d.ts.map +1 -0
- package/dist/routes/quarantine.js +66 -0
- package/dist/routes/quarantine.js.map +1 -0
- package/dist/routes/recall.d.ts +5 -0
- package/dist/routes/recall.d.ts.map +1 -0
- package/dist/routes/recall.js +573 -0
- package/dist/routes/recall.js.map +1 -0
- package/dist/routes/reflect.d.ts +5 -0
- package/dist/routes/reflect.d.ts.map +1 -0
- package/dist/routes/reflect.js +231 -0
- package/dist/routes/reflect.js.map +1 -0
- package/dist/routes/session.d.ts +4 -0
- package/dist/routes/session.d.ts.map +1 -0
- package/dist/routes/session.js +418 -0
- package/dist/routes/session.js.map +1 -0
- package/dist/routes/state.d.ts +116 -0
- package/dist/routes/state.d.ts.map +1 -0
- package/dist/routes/state.js +621 -0
- package/dist/routes/state.js.map +1 -0
- package/dist/routes/usage.d.ts +3 -0
- package/dist/routes/usage.d.ts.map +1 -0
- package/dist/routes/usage.js +141 -0
- package/dist/routes/usage.js.map +1 -0
- package/dist/routes/workspace.d.ts +5 -0
- package/dist/routes/workspace.d.ts.map +1 -0
- package/dist/routes/workspace.js +435 -0
- package/dist/routes/workspace.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +298 -0
- package/dist/server.js.map +1 -0
- package/dist/store/__tests__/backup.test.d.ts +2 -0
- package/dist/store/__tests__/backup.test.d.ts.map +1 -0
- package/dist/store/__tests__/backup.test.js +53 -0
- package/dist/store/__tests__/backup.test.js.map +1 -0
- package/dist/store/__tests__/quality.test.d.ts +2 -0
- package/dist/store/__tests__/quality.test.d.ts.map +1 -0
- package/dist/store/__tests__/quality.test.js +75 -0
- package/dist/store/__tests__/quality.test.js.map +1 -0
- package/dist/store/backup.d.ts +14 -0
- package/dist/store/backup.d.ts.map +1 -0
- package/dist/store/backup.js +95 -0
- package/dist/store/backup.js.map +1 -0
- package/dist/store/database.d.ts +407 -0
- package/dist/store/database.d.ts.map +1 -0
- package/dist/store/database.js +2004 -0
- package/dist/store/database.js.map +1 -0
- package/dist/store/quality.d.ts +25 -0
- package/dist/store/quality.d.ts.map +1 -0
- package/dist/store/quality.js +48 -0
- package/dist/store/quality.js.map +1 -0
- package/dist/tools/__tests__/assemble-block-chains.test.d.ts +2 -0
- package/dist/tools/__tests__/assemble-block-chains.test.d.ts.map +1 -0
- package/dist/tools/__tests__/assemble-block-chains.test.js +118 -0
- package/dist/tools/__tests__/assemble-block-chains.test.js.map +1 -0
- package/dist/tools/__tests__/filter-roots-by-concepts.test.d.ts +2 -0
- package/dist/tools/__tests__/filter-roots-by-concepts.test.d.ts.map +1 -0
- package/dist/tools/__tests__/filter-roots-by-concepts.test.js +68 -0
- package/dist/tools/__tests__/filter-roots-by-concepts.test.js.map +1 -0
- package/dist/tools/__tests__/flag-surface.test.d.ts +2 -0
- package/dist/tools/__tests__/flag-surface.test.d.ts.map +1 -0
- package/dist/tools/__tests__/flag-surface.test.js +130 -0
- package/dist/tools/__tests__/flag-surface.test.js.map +1 -0
- package/dist/tools/core.d.ts +5 -0
- package/dist/tools/core.d.ts.map +1 -0
- package/dist/tools/core.js +962 -0
- package/dist/tools/core.js.map +1 -0
- package/dist/tools/derive.d.ts +5 -0
- package/dist/tools/derive.d.ts.map +1 -0
- package/dist/tools/derive.js +182 -0
- package/dist/tools/derive.js.map +1 -0
- package/dist/tools/flag-surface.d.ts +26 -0
- package/dist/tools/flag-surface.d.ts.map +1 -0
- package/dist/tools/flag-surface.js +59 -0
- package/dist/tools/flag-surface.js.map +1 -0
- package/dist/tools/helpers.d.ts +99 -0
- package/dist/tools/helpers.d.ts.map +1 -0
- package/dist/tools/helpers.js +243 -0
- package/dist/tools/helpers.js.map +1 -0
- package/dist/tools/projects.d.ts +5 -0
- package/dist/tools/projects.d.ts.map +1 -0
- package/dist/tools/projects.js +175 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/system.d.ts +5 -0
- package/dist/tools/system.d.ts.map +1 -0
- package/dist/tools/system.js +1361 -0
- package/dist/tools/system.js.map +1 -0
- package/dist/tools/tasks.d.ts +5 -0
- package/dist/tools/tasks.d.ts.map +1 -0
- package/dist/tools/tasks.js +289 -0
- package/dist/tools/tasks.js.map +1 -0
- package/package.json +69 -0
- package/scripts/nodedex-entry.mjs +396 -0
- package/tui-dist/App.js +185 -0
- package/tui-dist/api.js +197 -0
- package/tui-dist/cli.js +53 -0
- package/tui-dist/components.js +63 -0
- package/tui-dist/config.js +242 -0
- package/tui-dist/connect-snippets.js +98 -0
- package/tui-dist/feed.js +51 -0
- package/tui-dist/health.js +465 -0
- package/tui-dist/hooks.js +23 -0
- package/tui-dist/memory.js +220 -0
- package/tui-dist/onboarding.js +498 -0
- package/tui-dist/review.js +193 -0
- package/tui-dist/servers.js +556 -0
- package/tui-dist/smoke.js +15 -0
- package/tui-dist/theme.js +106 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical text for a STORED block's embedding vector (Tier 2 cleanup, 2026-06-15).
|
|
3
|
+
*
|
|
4
|
+
* ONE recipe so every stored vector is built the same way. Vectors compared
|
|
5
|
+
* stored-vs-stored (semantic dedup, Stage-D resolve, Pass-4 semantic-delta) MUST
|
|
6
|
+
* share a recipe or the cosine is noise — before this, ~5 call sites embedded the
|
|
7
|
+
* same population of blocks with different recipes (essence+concepts vs
|
|
8
|
+
* label+essence+concepts vs label+essence+type+unique vs a neighbor-context header).
|
|
9
|
+
*
|
|
10
|
+
* Recipe = essence + concepts — pure semantic CONTENT. The essence carries the
|
|
11
|
+
* meaning, concepts the named entities. Deliberately EXCLUDES:
|
|
12
|
+
* - label — a slug whose project prefix repeats across the project → would cluster
|
|
13
|
+
* by project, not meaning.
|
|
14
|
+
* - type — a category word → would cluster by category, not content.
|
|
15
|
+
* - unique{} — identity is confirmed DOWNSTREAM by the structured unique{} compare;
|
|
16
|
+
* the embedding is the recall net, not the identity key.
|
|
17
|
+
* `concepts` is read from the first-class blocks.concepts column (authoritative since
|
|
18
|
+
* the 2026 migration out of content JSON), tolerating both the array form (pre-save
|
|
19
|
+
* pass output) and the JSON-string form (a stored block).
|
|
20
|
+
*
|
|
21
|
+
* Query embeds (user message, search query, in-pass dedup) stay free-form — vs a
|
|
22
|
+
* query, heterogeneity is inherent to semantic search. This canonicalizes the STORED
|
|
23
|
+
* side only.
|
|
24
|
+
*/
|
|
25
|
+
export declare function blockEmbeddingText(input: {
|
|
26
|
+
essence?: string | null;
|
|
27
|
+
concepts?: string[] | string | null;
|
|
28
|
+
}): string;
|
|
29
|
+
export declare class EmbeddingEngine {
|
|
30
|
+
private provider;
|
|
31
|
+
constructor();
|
|
32
|
+
isAvailable(): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Embed a single text. Instrumented per debt-4 Stage A:
|
|
35
|
+
* - records wall-time + call count + input chars to embeddingStats
|
|
36
|
+
* so the turn-log can surface the previously-hidden embedding tax
|
|
37
|
+
* - bounds wall-time with EMBEDDING_TIMEOUT_MS so provider hangs
|
|
38
|
+
* don't stall the pipeline
|
|
39
|
+
*
|
|
40
|
+
* On timeout: returns null (matches existing error semantics — most call
|
|
41
|
+
* sites already do .catch(() => null) since embeddings are non-critical).
|
|
42
|
+
*/
|
|
43
|
+
embed(text: string): Promise<number[] | null>;
|
|
44
|
+
/** Embed a STORED block through the canonical recipe (essence + concepts).
|
|
45
|
+
* `concepts` accepts the first-class column's JSON-string form or an array. */
|
|
46
|
+
embedForBlock(block: {
|
|
47
|
+
essence: string;
|
|
48
|
+
concepts?: string[] | string | null;
|
|
49
|
+
}): Promise<number[] | null>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=embeddings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../../src/engine/embeddings.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE;IACxC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC;CACrC,GAAG,MAAM,CAQT;AAGD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAoB;;IAMpC,WAAW,IAAI,OAAO;IAItB;;;;;;;;;OASG;IACG,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;IAanD;oFACgF;IAC1E,aAAa,CAAC,KAAK,EAAE;QACzB,OAAO,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC;KACrC,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { getEmbeddingProvider } from "./providers/index.js";
|
|
2
|
+
import { withTimeout } from "./providers/failure-policy.js";
|
|
3
|
+
import { embeddingStats } from "../middleware/reflect/context.js";
|
|
4
|
+
// debt-4 Stage A — bound embedding calls so a hung provider can't stall the
|
|
5
|
+
// pipeline indefinitely. 30s is generous (typical embed call 100-500ms);
|
|
6
|
+
// caps the worst case without rejecting healthy calls. Promise.race based —
|
|
7
|
+
// the underlying request continues in background on timeout but the pipeline
|
|
8
|
+
// unblocks. A future SDK-level AbortController would also CANCEL the request,
|
|
9
|
+
// but Promise.race is enough for the bounded-time goal here.
|
|
10
|
+
const EMBEDDING_TIMEOUT_MS = 30_000;
|
|
11
|
+
/**
|
|
12
|
+
* Canonical text for a STORED block's embedding vector (Tier 2 cleanup, 2026-06-15).
|
|
13
|
+
*
|
|
14
|
+
* ONE recipe so every stored vector is built the same way. Vectors compared
|
|
15
|
+
* stored-vs-stored (semantic dedup, Stage-D resolve, Pass-4 semantic-delta) MUST
|
|
16
|
+
* share a recipe or the cosine is noise — before this, ~5 call sites embedded the
|
|
17
|
+
* same population of blocks with different recipes (essence+concepts vs
|
|
18
|
+
* label+essence+concepts vs label+essence+type+unique vs a neighbor-context header).
|
|
19
|
+
*
|
|
20
|
+
* Recipe = essence + concepts — pure semantic CONTENT. The essence carries the
|
|
21
|
+
* meaning, concepts the named entities. Deliberately EXCLUDES:
|
|
22
|
+
* - label — a slug whose project prefix repeats across the project → would cluster
|
|
23
|
+
* by project, not meaning.
|
|
24
|
+
* - type — a category word → would cluster by category, not content.
|
|
25
|
+
* - unique{} — identity is confirmed DOWNSTREAM by the structured unique{} compare;
|
|
26
|
+
* the embedding is the recall net, not the identity key.
|
|
27
|
+
* `concepts` is read from the first-class blocks.concepts column (authoritative since
|
|
28
|
+
* the 2026 migration out of content JSON), tolerating both the array form (pre-save
|
|
29
|
+
* pass output) and the JSON-string form (a stored block).
|
|
30
|
+
*
|
|
31
|
+
* Query embeds (user message, search query, in-pass dedup) stay free-form — vs a
|
|
32
|
+
* query, heterogeneity is inherent to semantic search. This canonicalizes the STORED
|
|
33
|
+
* side only.
|
|
34
|
+
*/
|
|
35
|
+
export function blockEmbeddingText(input) {
|
|
36
|
+
let concepts = [];
|
|
37
|
+
if (Array.isArray(input.concepts)) {
|
|
38
|
+
concepts = input.concepts;
|
|
39
|
+
}
|
|
40
|
+
else if (typeof input.concepts === "string") {
|
|
41
|
+
try {
|
|
42
|
+
concepts = JSON.parse(input.concepts || "[]");
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
concepts = [];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return [input.essence, ...concepts].filter(Boolean).join(" ");
|
|
49
|
+
}
|
|
50
|
+
// ─── Embedding Engine ─────────────────────────────────────────────────────────
|
|
51
|
+
export class EmbeddingEngine {
|
|
52
|
+
provider;
|
|
53
|
+
constructor() {
|
|
54
|
+
this.provider = getEmbeddingProvider();
|
|
55
|
+
}
|
|
56
|
+
isAvailable() {
|
|
57
|
+
return this.provider.isAvailable();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Embed a single text. Instrumented per debt-4 Stage A:
|
|
61
|
+
* - records wall-time + call count + input chars to embeddingStats
|
|
62
|
+
* so the turn-log can surface the previously-hidden embedding tax
|
|
63
|
+
* - bounds wall-time with EMBEDDING_TIMEOUT_MS so provider hangs
|
|
64
|
+
* don't stall the pipeline
|
|
65
|
+
*
|
|
66
|
+
* On timeout: returns null (matches existing error semantics — most call
|
|
67
|
+
* sites already do .catch(() => null) since embeddings are non-critical).
|
|
68
|
+
*/
|
|
69
|
+
async embed(text) {
|
|
70
|
+
const t0 = Date.now();
|
|
71
|
+
embeddingStats.calls++;
|
|
72
|
+
embeddingStats.input_chars += (text ?? "").length;
|
|
73
|
+
try {
|
|
74
|
+
return await withTimeout(this.provider.embed(text), EMBEDDING_TIMEOUT_MS, "embed");
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
embeddingStats.ms_total += Date.now() - t0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** Embed a STORED block through the canonical recipe (essence + concepts).
|
|
84
|
+
* `concepts` accepts the first-class column's JSON-string form or an array. */
|
|
85
|
+
async embedForBlock(block) {
|
|
86
|
+
return this.embed(blockEmbeddingText({ essence: block.essence, concepts: block.concepts }));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=embeddings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../../src/engine/embeddings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAE5D,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAElE,4EAA4E;AAC5E,yEAAyE;AACzE,4EAA4E;AAC5E,6EAA6E;AAC7E,8EAA8E;AAC9E,6DAA6D;AAC7D,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAGlC;IACC,IAAI,QAAQ,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC5B,CAAC;SAAM,IAAI,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9C,IAAI,CAAC;YAAC,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,IAAI,IAAI,CAAC,CAAC;QAAC,CAAC;QAAC,MAAM,CAAC;YAAC,QAAQ,GAAG,EAAE,CAAC;QAAC,CAAC;IACjF,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAChE,CAAC;AAED,iFAAiF;AACjF,MAAM,OAAO,eAAe;IAClB,QAAQ,CAAoB;IAEpC;QACE,IAAI,CAAC,QAAQ,GAAG,oBAAoB,EAAE,CAAC;IACzC,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,cAAc,CAAC,KAAK,EAAE,CAAC;QACvB,cAAc,CAAC,WAAW,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QAClD,IAAI,CAAC;YACH,OAAO,MAAM,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,oBAAoB,EAAE,OAAO,CAAC,CAAC;QACrF,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,cAAc,CAAC,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;QAC7C,CAAC;IACH,CAAC;IAED;oFACgF;IAChF,KAAK,CAAC,aAAa,CAAC,KAGnB;QACC,OAAO,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC9F,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure-policy.test.d.ts","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/failure-policy.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// Unit tests for the shared provider failure-policy (classification, empty-detection,
|
|
2
|
+
// timeout). This is the provider-agnostic policy all three providers consume so the
|
|
3
|
+
// retry behavior is identical on every real-world provider path.
|
|
4
|
+
import { test, describe, afterEach } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { EmptyResponseError, classifyGenError, isEmptyResult, withTimeout, llmTimeoutMs, decideEmptyOrTimeoutAction, isInsufficientCreditError, } from "../failure-policy.js";
|
|
7
|
+
describe("classifyGenError (provider-agnostic failure routing)", () => {
|
|
8
|
+
test("EmptyResponseError → empty (wins over the SyntaxError an empty body would throw)", () => {
|
|
9
|
+
assert.equal(classifyGenError(new EmptyResponseError("any/model")), "empty");
|
|
10
|
+
});
|
|
11
|
+
test("429 / 503 / 529 / quota / RESOURCE_EXHAUSTED → rate_limited", () => {
|
|
12
|
+
assert.equal(classifyGenError({ status: 429 }), "rate_limited");
|
|
13
|
+
assert.equal(classifyGenError({ status: 503 }), "rate_limited");
|
|
14
|
+
assert.equal(classifyGenError({ status: 529 }), "rate_limited"); // Anthropic overloaded
|
|
15
|
+
assert.equal(classifyGenError(new Error("RESOURCE_EXHAUSTED: quota")), "rate_limited");
|
|
16
|
+
assert.equal(classifyGenError(new Error("model is experiencing high demand")), "rate_limited");
|
|
17
|
+
});
|
|
18
|
+
test("APIConnectionTimeoutError / withTimeout message → timeout", () => {
|
|
19
|
+
const e = new Error("Request timed out.");
|
|
20
|
+
e.name = "APIConnectionTimeoutError";
|
|
21
|
+
assert.equal(classifyGenError(e), "timeout");
|
|
22
|
+
assert.equal(classifyGenError(new Error("generateStructured(x) timeout after 180000ms")), "timeout");
|
|
23
|
+
});
|
|
24
|
+
test("SyntaxError on a non-empty body → truncated (the determinism-trap case)", () => {
|
|
25
|
+
let parseErr;
|
|
26
|
+
try {
|
|
27
|
+
JSON.parse('{"a":1');
|
|
28
|
+
}
|
|
29
|
+
catch (pe) {
|
|
30
|
+
parseErr = pe;
|
|
31
|
+
}
|
|
32
|
+
assert.equal(classifyGenError(parseErr), "truncated");
|
|
33
|
+
assert.equal(classifyGenError(new Error("Unterminated string in JSON")), "truncated");
|
|
34
|
+
});
|
|
35
|
+
test("a 400/other provider error → mechanism_or_other (prompt-JSON floor / degrade)", () => {
|
|
36
|
+
assert.equal(classifyGenError({ status: 400, message: "Bad Request" }), "mechanism_or_other");
|
|
37
|
+
assert.equal(classifyGenError(new Error("something unexpected")), "mechanism_or_other");
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
describe("isInsufficientCreditError (out-of-credit, distinct from rate-limit)", () => {
|
|
41
|
+
test("HTTP 402 (status or code, number or string) → true", () => {
|
|
42
|
+
assert.equal(isInsufficientCreditError({ status: 402 }), true);
|
|
43
|
+
assert.equal(isInsufficientCreditError({ code: 402 }), true);
|
|
44
|
+
assert.equal(isInsufficientCreditError({ status: "402" }), true);
|
|
45
|
+
});
|
|
46
|
+
test("OpenRouter / OpenAI billing message bodies → true", () => {
|
|
47
|
+
assert.equal(isInsufficientCreditError(new Error("402 Insufficient credits. Add more to continue.")), true);
|
|
48
|
+
assert.equal(isInsufficientCreditError(new Error("Payment Required")), true);
|
|
49
|
+
assert.equal(isInsufficientCreditError(new Error("You exceeded your current quota — insufficient_quota")), true);
|
|
50
|
+
assert.equal(isInsufficientCreditError("insufficient_credit"), true); // the swallowed-null reason string
|
|
51
|
+
assert.equal(isInsufficientCreditError(new Error("negative credit balance")), true);
|
|
52
|
+
});
|
|
53
|
+
test("provider SPEND-CAP (OpenRouter 403 'Key limit exceeded') → true (same class as 402 → pause+alert)", () => {
|
|
54
|
+
assert.equal(isInsufficientCreditError(new Error("403 Key limit exceeded (total limit).")), true);
|
|
55
|
+
assert.equal(isInsufficientCreditError({ status: 403, message: "Key limit exceeded (total limit)" }), true);
|
|
56
|
+
assert.equal(isInsufficientCreditError(new Error("Your credit limit has been reached")), true);
|
|
57
|
+
});
|
|
58
|
+
test("a transient rate-limit is NOT credit-out (must not pause-the-spend on a 429)", () => {
|
|
59
|
+
assert.equal(isInsufficientCreditError({ status: 429 }), false);
|
|
60
|
+
assert.equal(isInsufficientCreditError(new Error("RESOURCE_EXHAUSTED: rate limit")), false);
|
|
61
|
+
assert.equal(isInsufficientCreditError(new Error("429 Rate limit exceeded")), false); // 'limit exceeded' but a RATE limit, not a spend-cap
|
|
62
|
+
assert.equal(isInsufficientCreditError(new Error("503 Service Unavailable")), false);
|
|
63
|
+
});
|
|
64
|
+
test("null / generic errors → false", () => {
|
|
65
|
+
assert.equal(isInsufficientCreditError(null), false);
|
|
66
|
+
assert.equal(isInsufficientCreditError(undefined), false);
|
|
67
|
+
assert.equal(isInsufficientCreditError(new Error("comprehend_failed")), false);
|
|
68
|
+
assert.equal(isInsufficientCreditError({ status: 400, message: "Bad Request" }), false);
|
|
69
|
+
assert.equal(isInsufficientCreditError({ status: 403, message: "Forbidden" }), false); // bare 403 (auth) ≠ spend-cap
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
describe("isEmptyResult", () => {
|
|
73
|
+
test("empty / whitespace / null / undefined → true", () => {
|
|
74
|
+
assert.equal(isEmptyResult(""), true);
|
|
75
|
+
assert.equal(isEmptyResult(" \n\t "), true);
|
|
76
|
+
assert.equal(isEmptyResult(null), true);
|
|
77
|
+
assert.equal(isEmptyResult(undefined), true);
|
|
78
|
+
});
|
|
79
|
+
test("any real content → false", () => {
|
|
80
|
+
assert.equal(isEmptyResult("{}"), false);
|
|
81
|
+
assert.equal(isEmptyResult(' {"a":1} '), false);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
describe("llmTimeoutMs", () => {
|
|
85
|
+
const saved = process.env.NODEDEX_LLM_TIMEOUT_MS;
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
if (saved === undefined)
|
|
88
|
+
delete process.env.NODEDEX_LLM_TIMEOUT_MS;
|
|
89
|
+
else
|
|
90
|
+
process.env.NODEDEX_LLM_TIMEOUT_MS = saved;
|
|
91
|
+
});
|
|
92
|
+
test("defaults to 180000 when unset", () => {
|
|
93
|
+
delete process.env.NODEDEX_LLM_TIMEOUT_MS;
|
|
94
|
+
assert.equal(llmTimeoutMs(), 180000);
|
|
95
|
+
});
|
|
96
|
+
test("honors the env override (incl. 0 = disabled)", () => {
|
|
97
|
+
process.env.NODEDEX_LLM_TIMEOUT_MS = "5000";
|
|
98
|
+
assert.equal(llmTimeoutMs(), 5000);
|
|
99
|
+
process.env.NODEDEX_LLM_TIMEOUT_MS = "0";
|
|
100
|
+
assert.equal(llmTimeoutMs(), 0);
|
|
101
|
+
});
|
|
102
|
+
test("falls back to 180000 on a non-numeric value", () => {
|
|
103
|
+
process.env.NODEDEX_LLM_TIMEOUT_MS = "not-a-number";
|
|
104
|
+
assert.equal(llmTimeoutMs(), 180000);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
describe("decideEmptyOrTimeoutAction (escalate-first-when-fallback policy)", () => {
|
|
108
|
+
test("empty WITH a fallback model → escalate (skip the slow same-model draw)", () => {
|
|
109
|
+
assert.equal(decideEmptyOrTimeoutAction({ kind: "empty", hasNextModel: true, emptyRetried: false }), "escalate");
|
|
110
|
+
});
|
|
111
|
+
test("empty with NO fallback, not yet retried → retry_same (single-key user's only recovery)", () => {
|
|
112
|
+
assert.equal(decideEmptyOrTimeoutAction({ kind: "empty", hasNextModel: false, emptyRetried: false }), "retry_same");
|
|
113
|
+
});
|
|
114
|
+
test("empty with NO fallback, already retried → degrade", () => {
|
|
115
|
+
assert.equal(decideEmptyOrTimeoutAction({ kind: "empty", hasNextModel: false, emptyRetried: true }), "degrade");
|
|
116
|
+
});
|
|
117
|
+
test("timeout WITH a fallback → escalate", () => {
|
|
118
|
+
assert.equal(decideEmptyOrTimeoutAction({ kind: "timeout", hasNextModel: true, emptyRetried: false }), "escalate");
|
|
119
|
+
});
|
|
120
|
+
test("timeout with NO fallback → degrade (never re-pay the timeout on the same model)", () => {
|
|
121
|
+
assert.equal(decideEmptyOrTimeoutAction({ kind: "timeout", hasNextModel: false, emptyRetried: false }), "degrade");
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe("withTimeout", () => {
|
|
125
|
+
test("resolves a fast promise before the bound", async () => {
|
|
126
|
+
const v = await withTimeout(Promise.resolve(42), 1000, "fast");
|
|
127
|
+
assert.equal(v, 42);
|
|
128
|
+
});
|
|
129
|
+
test("rejects with a 'timeout after' message when the bound fires first", async () => {
|
|
130
|
+
const slow = new Promise((res) => setTimeout(() => res("late"), 50));
|
|
131
|
+
await assert.rejects(withTimeout(slow, 5, "slow"), /timeout after 5ms/);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=failure-policy.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure-policy.test.js","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/failure-policy.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-caps.test.d.ts","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/model-caps.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* model-caps — per-model output ceiling resolution.
|
|
3
|
+
*
|
|
4
|
+
* Gates the token budget on every LLM call: the request (maxOut + thinking) must stay
|
|
5
|
+
* under the model's hard output cap or the provider returns a broken response that
|
|
6
|
+
* masquerades as a truncation (2026-06-16 Pass 3 glitch). This pins the resolution
|
|
7
|
+
* order: NODEDEX_MODEL_CAPS override → KNOWN_CAPS → conservative default.
|
|
8
|
+
*/
|
|
9
|
+
import { test, describe, afterEach } from "node:test";
|
|
10
|
+
import assert from "node:assert/strict";
|
|
11
|
+
import { modelOutputCeiling, DEFAULT_CEILING } from "../model-caps.js";
|
|
12
|
+
describe("modelOutputCeiling", () => {
|
|
13
|
+
afterEach(() => { delete process.env.NODEDEX_MODEL_CAPS; });
|
|
14
|
+
test("known prefixed model → its real cap", () => {
|
|
15
|
+
assert.equal(modelOutputCeiling("google/gemini-2.5-flash"), 65535);
|
|
16
|
+
assert.equal(modelOutputCeiling("openai/gpt-4o"), 16384);
|
|
17
|
+
});
|
|
18
|
+
test("known bare model id (AI_MODEL without vendor prefix) → its cap", () => {
|
|
19
|
+
assert.equal(modelOutputCeiling("gemini-2.5-flash"), 65535);
|
|
20
|
+
assert.equal(modelOutputCeiling("gpt-4o"), 16384);
|
|
21
|
+
});
|
|
22
|
+
test("unknown or missing model → conservative default", () => {
|
|
23
|
+
assert.equal(modelOutputCeiling("some/never-seen-model"), DEFAULT_CEILING);
|
|
24
|
+
assert.equal(modelOutputCeiling(undefined), DEFAULT_CEILING);
|
|
25
|
+
});
|
|
26
|
+
test("NODEDEX_MODEL_CAPS override wins over the known map (web-UI live cap)", () => {
|
|
27
|
+
process.env.NODEDEX_MODEL_CAPS = JSON.stringify({ "google/gemini-2.5-flash": 12345, "vendor/new": 200000 });
|
|
28
|
+
assert.equal(modelOutputCeiling("google/gemini-2.5-flash"), 12345); // override beats KNOWN_CAPS
|
|
29
|
+
assert.equal(modelOutputCeiling("vendor/new"), 200000); // override supplies an unknown
|
|
30
|
+
assert.equal(modelOutputCeiling("openai/gpt-4o"), 16384); // untouched models keep known cap
|
|
31
|
+
});
|
|
32
|
+
test("malformed NODEDEX_MODEL_CAPS is ignored (falls back to known/default)", () => {
|
|
33
|
+
process.env.NODEDEX_MODEL_CAPS = "{not json";
|
|
34
|
+
assert.equal(modelOutputCeiling("google/gemini-2.5-flash"), 65535);
|
|
35
|
+
assert.equal(modelOutputCeiling("x/y"), DEFAULT_CEILING);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=model-caps.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-caps.test.js","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/model-caps.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEvE,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,SAAS,CAAC,GAAG,EAAE,GAAG,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5D,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,EAAE,KAAK,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gEAAgE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5D,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iDAAiD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,uBAAuB,CAAC,EAAE,eAAe,CAAC,CAAC;QAC3E,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,SAAS,CAAC,EAAE,eAAe,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,uEAAuE,EAAE,GAAG,EAAE;QACjF,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,yBAAyB,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5G,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,4BAA4B;QAChG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC,CAAC,CAAa,+BAA+B;QACnG,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,CAAC,CAAW,kCAAkC;IACxG,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,uEAAuE,EAAE,GAAG,EAAE;QACjF,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,WAAW,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,yBAAyB,CAAC,EAAE,KAAK,CAAC,CAAC;QACnE,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,EAAE,eAAe,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-structured.test.d.ts","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/openai-structured.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Unit tests for the structured-output portability helpers (openai.ts).
|
|
2
|
+
// The mechanism-selection + prompt-JSON fallback make the pipeline model-portable
|
|
3
|
+
// (Anthropic→tool-use, default→response_format, unknown/400→prompt-JSON floor).
|
|
4
|
+
import { test, describe } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { primaryMechanism, stripJsonFences, classifyGenError, EmptyResponseError } from "../openai.js";
|
|
7
|
+
describe("primaryMechanism (mechanism-by-model)", () => {
|
|
8
|
+
test("Anthropic models → tool_use (they reject response_format)", () => {
|
|
9
|
+
assert.equal(primaryMechanism("anthropic/claude-haiku-4.5"), "tool_use");
|
|
10
|
+
assert.equal(primaryMechanism("anthropic/claude-opus-4.1"), "tool_use");
|
|
11
|
+
assert.equal(primaryMechanism("claude-3-5-sonnet"), "tool_use");
|
|
12
|
+
});
|
|
13
|
+
test("OpenAI / Gemini / others → response_format (the default, unchanged path)", () => {
|
|
14
|
+
assert.equal(primaryMechanism("google/gemini-2.5-flash"), "response_format");
|
|
15
|
+
assert.equal(primaryMechanism("openai/gpt-4o"), "response_format");
|
|
16
|
+
assert.equal(primaryMechanism("gpt-4o"), "response_format");
|
|
17
|
+
assert.equal(primaryMechanism("x-ai/grok-2"), "response_format");
|
|
18
|
+
assert.equal(primaryMechanism("deepseek/deepseek-chat"), "response_format");
|
|
19
|
+
});
|
|
20
|
+
test("empty/garbage → response_format (safe default)", () => {
|
|
21
|
+
assert.equal(primaryMechanism(""), "response_format");
|
|
22
|
+
assert.equal(primaryMechanism(undefined), "response_format");
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
describe("stripJsonFences (prompt-JSON robustness)", () => {
|
|
26
|
+
test("strips ```json fences", () => {
|
|
27
|
+
assert.equal(stripJsonFences('```json\n{"a":1}\n```'), '{"a":1}');
|
|
28
|
+
});
|
|
29
|
+
test("strips bare ``` fences", () => {
|
|
30
|
+
assert.equal(stripJsonFences('```\n{"a":1}\n```'), '{"a":1}');
|
|
31
|
+
});
|
|
32
|
+
test("leaves un-fenced JSON untouched", () => {
|
|
33
|
+
assert.equal(stripJsonFences('{"a":1}'), '{"a":1}');
|
|
34
|
+
});
|
|
35
|
+
test("trims surrounding whitespace", () => {
|
|
36
|
+
assert.equal(stripJsonFences(' {"a":1} '), '{"a":1}');
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
describe("classifyGenError (failure-mode routing)", () => {
|
|
40
|
+
test("EmptyResponseError → empty (escalates to fallback model, not a bump)", () => {
|
|
41
|
+
assert.equal(classifyGenError(new EmptyResponseError("google/gemini-2.5-flash")), "empty");
|
|
42
|
+
});
|
|
43
|
+
test("empty is NOT misclassified as truncated (the Run-12 bug)", () => {
|
|
44
|
+
// The old code let JSON.parse('') throw a SyntaxError → 'truncated'. The
|
|
45
|
+
// explicit EmptyResponseError must win so empties escalate instead of bumping.
|
|
46
|
+
assert.notEqual(classifyGenError(new EmptyResponseError("x")), "truncated");
|
|
47
|
+
});
|
|
48
|
+
test("429 → rate_limited (by status or message)", () => {
|
|
49
|
+
assert.equal(classifyGenError({ status: 429 }), "rate_limited");
|
|
50
|
+
assert.equal(classifyGenError(new Error("Request failed: 429 Too Many Requests")), "rate_limited");
|
|
51
|
+
});
|
|
52
|
+
test("APIConnectionTimeoutError / 'timed out' → timeout", () => {
|
|
53
|
+
const e = new Error("Request timed out.");
|
|
54
|
+
e.name = "APIConnectionTimeoutError";
|
|
55
|
+
assert.equal(classifyGenError(e), "timeout");
|
|
56
|
+
assert.equal(classifyGenError(new Error("the request timed out")), "timeout");
|
|
57
|
+
});
|
|
58
|
+
test("SyntaxError on a non-empty body → truncated (the determinism-trap case)", () => {
|
|
59
|
+
let parseErr;
|
|
60
|
+
try {
|
|
61
|
+
JSON.parse('{"a":1');
|
|
62
|
+
}
|
|
63
|
+
catch (pe) {
|
|
64
|
+
parseErr = pe;
|
|
65
|
+
}
|
|
66
|
+
assert.equal(classifyGenError(parseErr), "truncated");
|
|
67
|
+
assert.equal(classifyGenError(new Error("Unterminated string in JSON")), "truncated");
|
|
68
|
+
});
|
|
69
|
+
test("a 400/other provider error → mechanism_or_other (prompt-JSON floor)", () => {
|
|
70
|
+
assert.equal(classifyGenError({ status: 400, message: "Bad Request" }), "mechanism_or_other");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=openai-structured.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-structured.test.js","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/openai-structured.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-ledger.test.d.ts","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/usage-ledger.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { describe, it, beforeEach, afterEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { existsSync, rmSync, mkdtempSync } from "fs";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import { wrapWithUsageLedger, getUsageSummary } from "../usage-ledger.js";
|
|
7
|
+
/** Minimal fake provider. `model: null` simulates the no-API-key early return. */
|
|
8
|
+
function fakeProvider(usage, model = "gemini-2.5-flash") {
|
|
9
|
+
return {
|
|
10
|
+
getName: () => "test",
|
|
11
|
+
isAvailable: () => true,
|
|
12
|
+
ping: async () => true,
|
|
13
|
+
generate: async () => "ok",
|
|
14
|
+
async generateStructured() {
|
|
15
|
+
const res = { result: {}, rateLimited: false, usage };
|
|
16
|
+
if (model !== null)
|
|
17
|
+
res.model = model;
|
|
18
|
+
return res;
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
describe("usage-ledger", () => {
|
|
23
|
+
let dir;
|
|
24
|
+
let ledger;
|
|
25
|
+
const savedEnabled = process.env.NODEDEX_USAGE_LEDGER;
|
|
26
|
+
beforeEach(() => {
|
|
27
|
+
dir = mkdtempSync(path.join(tmpdir(), "nodedex-usage-"));
|
|
28
|
+
ledger = path.join(dir, "api-usage.jsonl");
|
|
29
|
+
process.env.NODEDEX_USAGE_LEDGER_PATH = ledger;
|
|
30
|
+
delete process.env.NODEDEX_USAGE_LEDGER; // default on
|
|
31
|
+
});
|
|
32
|
+
afterEach(() => {
|
|
33
|
+
delete process.env.NODEDEX_USAGE_LEDGER_PATH;
|
|
34
|
+
if (savedEnabled === undefined)
|
|
35
|
+
delete process.env.NODEDEX_USAGE_LEDGER;
|
|
36
|
+
else
|
|
37
|
+
process.env.NODEDEX_USAGE_LEDGER = savedEnabled;
|
|
38
|
+
try {
|
|
39
|
+
rmSync(dir, { recursive: true, force: true });
|
|
40
|
+
}
|
|
41
|
+
catch { /* ignore */ }
|
|
42
|
+
});
|
|
43
|
+
it("records a priced call with computed (estimated) cost", async () => {
|
|
44
|
+
const p = wrapWithUsageLedger(fakeProvider({ input: 1000, output: 2000, thinking: 500 }));
|
|
45
|
+
const r = await p.generateStructured("sys", "user", {});
|
|
46
|
+
assert.equal(r.rateLimited, false); // result passes through untouched
|
|
47
|
+
const s = getUsageSummary();
|
|
48
|
+
assert.equal(s.total.calls, 1);
|
|
49
|
+
assert.equal(s.total.input, 1000);
|
|
50
|
+
assert.equal(s.total.output, 2000);
|
|
51
|
+
assert.equal(s.total.thinking, 500);
|
|
52
|
+
// gemini-2.5-flash: (1000*0.30 + 2000*2.50 + 500*2.50) / 1e6 (thinking billed as output)
|
|
53
|
+
const expected = (1000 * 0.3 + 2000 * 2.5 + 500 * 2.5) / 1_000_000;
|
|
54
|
+
assert.ok(Math.abs(s.total.cost_usd - expected) < 1e-9, `cost ${s.total.cost_usd} ~ ${expected}`);
|
|
55
|
+
assert.equal(s.cost_sources.estimated, 1);
|
|
56
|
+
assert.equal(s.recent[0].cost_source, "estimated");
|
|
57
|
+
assert.ok(s.since && s.latest);
|
|
58
|
+
assert.equal(s.by_model["gemini-2.5-flash"].calls, 1);
|
|
59
|
+
});
|
|
60
|
+
it("uses the provider's ACTUAL cost when present (openrouter_actual, not the estimate)", async () => {
|
|
61
|
+
// costUsd deliberately != the table estimate → must win.
|
|
62
|
+
const p = wrapWithUsageLedger(fakeProvider({ input: 1000, output: 2000, thinking: 0, costUsd: 0.123 }));
|
|
63
|
+
await p.generateStructured("s", "u", {});
|
|
64
|
+
const s = getUsageSummary();
|
|
65
|
+
assert.equal(s.total.cost_usd, 0.123);
|
|
66
|
+
assert.equal(s.cost_sources.openrouter_actual, 1);
|
|
67
|
+
assert.equal(s.cost_sources.estimated, 0);
|
|
68
|
+
assert.equal(s.recent[0].cost_source, "openrouter_actual");
|
|
69
|
+
});
|
|
70
|
+
it("accumulates across calls and breaks down by model", async () => {
|
|
71
|
+
const flash = wrapWithUsageLedger(fakeProvider({ input: 100, output: 100, thinking: 0 }, "gemini-2.5-flash"));
|
|
72
|
+
const pro = wrapWithUsageLedger(fakeProvider({ input: 200, output: 200, thinking: 0 }, "gemini-2.5-pro"));
|
|
73
|
+
await flash.generateStructured("s", "u", {});
|
|
74
|
+
await flash.generateStructured("s", "u", {});
|
|
75
|
+
await pro.generateStructured("s", "u", {});
|
|
76
|
+
const s = getUsageSummary();
|
|
77
|
+
assert.equal(s.total.calls, 3);
|
|
78
|
+
assert.equal(s.by_model["gemini-2.5-flash"].calls, 2);
|
|
79
|
+
assert.equal(s.by_model["gemini-2.5-pro"].calls, 1);
|
|
80
|
+
assert.equal(s.total.input, 400);
|
|
81
|
+
});
|
|
82
|
+
it("marks an unpriced model as unknown (cost null, never fabricated)", async () => {
|
|
83
|
+
const p = wrapWithUsageLedger(fakeProvider({ input: 10, output: 10, thinking: 0 }, "some/unknown-model"));
|
|
84
|
+
await p.generateStructured("s", "u", {});
|
|
85
|
+
const s = getUsageSummary();
|
|
86
|
+
assert.equal(s.total.calls, 1);
|
|
87
|
+
assert.equal(s.total.unpriced_calls, 1);
|
|
88
|
+
assert.equal(s.total.cost_usd, 0); // unknown excluded from the $ total, not counted as 0-cost
|
|
89
|
+
assert.equal(s.cost_sources.unknown, 1);
|
|
90
|
+
});
|
|
91
|
+
it("writes nothing when disabled", async () => {
|
|
92
|
+
process.env.NODEDEX_USAGE_LEDGER = "off";
|
|
93
|
+
const p = wrapWithUsageLedger(fakeProvider({ input: 10, output: 10, thinking: 0 }));
|
|
94
|
+
const r = await p.generateStructured("s", "u", {});
|
|
95
|
+
assert.equal(r.rateLimited, false); // generation still works
|
|
96
|
+
assert.equal(existsSync(ledger), false);
|
|
97
|
+
const s = getUsageSummary();
|
|
98
|
+
assert.equal(s.enabled, false);
|
|
99
|
+
assert.equal(s.total.calls, 0);
|
|
100
|
+
});
|
|
101
|
+
it("does NOT record a no-API-key call (no model set)", async () => {
|
|
102
|
+
const p = wrapWithUsageLedger(fakeProvider(undefined, null)); // model null → not a real key call
|
|
103
|
+
await p.generateStructured("s", "u", {});
|
|
104
|
+
const s = getUsageSummary();
|
|
105
|
+
assert.equal(s.total.calls, 0);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=usage-ledger.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-ledger.test.js","sourceRoot":"","sources":["../../../../src/engine/providers/__tests__/usage-ledger.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LLMProvider, GenerateResult } from "../ai-provider.js";
|
|
2
|
+
export declare class AnthropicProvider implements LLMProvider {
|
|
3
|
+
private client;
|
|
4
|
+
private model;
|
|
5
|
+
private fallbackModel;
|
|
6
|
+
constructor(apiKey: string);
|
|
7
|
+
isAvailable(): boolean;
|
|
8
|
+
getName(): string;
|
|
9
|
+
generateStructured<T>(systemPrompt: string, userInput: string, schema: object, options?: {
|
|
10
|
+
thinkingBudget?: number;
|
|
11
|
+
maxOutputTokens?: number;
|
|
12
|
+
modelOverride?: string;
|
|
13
|
+
}): Promise<GenerateResult<T>>;
|
|
14
|
+
generate(prompt: string): Promise<string | null>;
|
|
15
|
+
ping(): Promise<boolean>;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=anthropic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../src/engine/providers/anthropic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGrE,qBAAa,iBAAkB,YAAW,WAAW;IACnD,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,aAAa,CAAgB;gBAEzB,MAAM,EAAE,MAAM;IAO1B,WAAW,IAAI,OAAO;IACtB,OAAO,IAAI,MAAM;IAEX,kBAAkB,CAAC,CAAC,EACxB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,cAAc,CAAC,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,MAAM,CAAA;KAAE,GACtF,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC;IA6FvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAiBhD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAG/B"}
|