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,125 @@
|
|
|
1
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
2
|
+
import { EmptyResponseError, classifyGenError, llmTimeoutMs, decideEmptyOrTimeoutAction, isInsufficientCreditError } from "./failure-policy.js";
|
|
3
|
+
export class AnthropicProvider {
|
|
4
|
+
client;
|
|
5
|
+
model;
|
|
6
|
+
fallbackModel;
|
|
7
|
+
constructor(apiKey) {
|
|
8
|
+
this.client = apiKey ? new Anthropic({ apiKey }) : null;
|
|
9
|
+
this.model = process.env.AI_MODEL ?? "claude-opus-4-6";
|
|
10
|
+
const fb = process.env.NODEDEX_FALLBACK_MODEL ?? "";
|
|
11
|
+
this.fallbackModel = fb && fb !== this.model ? fb : null;
|
|
12
|
+
}
|
|
13
|
+
isAvailable() { return this.client !== null; }
|
|
14
|
+
getName() { return "anthropic"; }
|
|
15
|
+
async generateStructured(systemPrompt, userInput, schema, options) {
|
|
16
|
+
if (!this.client)
|
|
17
|
+
return { result: null, rateLimited: false };
|
|
18
|
+
const modelsToTry = options?.modelOverride
|
|
19
|
+
? [options.modelOverride]
|
|
20
|
+
: this.fallbackModel ? [this.model, this.fallbackModel] : [this.model];
|
|
21
|
+
const attempts = [];
|
|
22
|
+
for (let i = 0; i < modelsToTry.length; i++) {
|
|
23
|
+
const modelName = modelsToTry[i];
|
|
24
|
+
const isFallback = i > 0;
|
|
25
|
+
let emptyRetried = false;
|
|
26
|
+
while (true) {
|
|
27
|
+
try {
|
|
28
|
+
const response = await this.client.messages.create({
|
|
29
|
+
model: modelName,
|
|
30
|
+
max_tokens: options?.maxOutputTokens ?? 8192,
|
|
31
|
+
system: systemPrompt,
|
|
32
|
+
messages: [{ role: "user", content: userInput }],
|
|
33
|
+
tools: [{
|
|
34
|
+
name: "save_result",
|
|
35
|
+
description: "Save the structured extraction result",
|
|
36
|
+
input_schema: schema,
|
|
37
|
+
}],
|
|
38
|
+
tool_choice: { type: "tool", name: "save_result" },
|
|
39
|
+
}, { timeout: llmTimeoutMs() });
|
|
40
|
+
const toolUse = response.content.find((c) => c.type === "tool_use");
|
|
41
|
+
// No tool_use block = the model produced no structured content = EMPTY/hung
|
|
42
|
+
// (see ./failure-policy). Raise it so the catch retries/escalates rather than
|
|
43
|
+
// failing the pass outright (the old behavior — no retry, no fallback).
|
|
44
|
+
if (!toolUse)
|
|
45
|
+
throw new EmptyResponseError(modelName);
|
|
46
|
+
if (isFallback)
|
|
47
|
+
console.log(`[anthropic] escalated to fallback model ${modelName}`);
|
|
48
|
+
attempts.push({ model: modelName, outcome: "ok" });
|
|
49
|
+
return {
|
|
50
|
+
result: toolUse.input,
|
|
51
|
+
rateLimited: false,
|
|
52
|
+
usage: { input: response.usage.input_tokens, thinking: 0, output: response.usage.output_tokens },
|
|
53
|
+
model: modelName,
|
|
54
|
+
attempts,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
// Out-of-credit (402) — surface DEFINITIVELY (see openai.ts): the reflect queue
|
|
59
|
+
// pauses-the-spend + requeues instead of swallowing it into a generic null.
|
|
60
|
+
if (isInsufficientCreditError(e)) {
|
|
61
|
+
attempts.push({ model: modelName, outcome: "error" });
|
|
62
|
+
console.error(`[anthropic] ${modelName} insufficient credit (status=${e?.status ?? "?"}) — credit exhausted; not retrying/escalating (account unfunded)`);
|
|
63
|
+
return { result: null, rateLimited: false, creditExhausted: true, model: modelName, attempts };
|
|
64
|
+
}
|
|
65
|
+
const kind = classifyGenError(e);
|
|
66
|
+
const rateLimited = kind === "rate_limited";
|
|
67
|
+
const hasNextModel = i + 1 < modelsToTry.length;
|
|
68
|
+
// EMPTY/TIMEOUT → shared escalate-first policy (./failure-policy): a fallback model
|
|
69
|
+
// is the likeliest recovery for an input-specific empty (and skips the slow same-
|
|
70
|
+
// model draw); only a single-key setup retries the SAME model once.
|
|
71
|
+
if (kind === "empty" || kind === "timeout") {
|
|
72
|
+
const action = decideEmptyOrTimeoutAction({ kind, hasNextModel, emptyRetried });
|
|
73
|
+
attempts.push({ model: modelName, outcome: kind === "timeout" ? "timeout" : "empty" });
|
|
74
|
+
if (action === "escalate") {
|
|
75
|
+
console.log(`[anthropic] ${modelName} ${kind} — escalating to fallback ${modelsToTry[i + 1]}`);
|
|
76
|
+
break; // exit while; outer for tries the next model
|
|
77
|
+
}
|
|
78
|
+
if (action === "retry_same") {
|
|
79
|
+
console.warn(`[anthropic] ${modelName} returned no structured content — no fallback; retrying same model once`);
|
|
80
|
+
emptyRetried = true;
|
|
81
|
+
continue; // retry same model
|
|
82
|
+
}
|
|
83
|
+
if (kind === "timeout") {
|
|
84
|
+
console.error(`[anthropic] generateStructured TIMEOUT (${modelName}): ${llmTimeoutMs()}ms — pipeline continues`);
|
|
85
|
+
}
|
|
86
|
+
return { result: null, rateLimited: false, model: modelName, attempts };
|
|
87
|
+
}
|
|
88
|
+
// RATE-LIMIT / other → escalate to the next model if one remains, else degrade.
|
|
89
|
+
// (No same-model bump: anthropic returns structured tool input directly, not
|
|
90
|
+
// parsed JSON, so there is no truncation-retry rung.)
|
|
91
|
+
attempts.push({ model: modelName, outcome: rateLimited ? "rate_limited" : "error" });
|
|
92
|
+
if (rateLimited && hasNextModel) {
|
|
93
|
+
console.log(`[anthropic] ${modelName} rate-limited — escalating to fallback ${modelsToTry[i + 1]}`);
|
|
94
|
+
break; // exit while; outer for tries the next model
|
|
95
|
+
}
|
|
96
|
+
if (!rateLimited) {
|
|
97
|
+
console.error(`[anthropic] generateStructured error (${modelName}): status=${e?.status} msg=${String(e?.message ?? e).slice(0, 200)}`);
|
|
98
|
+
}
|
|
99
|
+
return { result: null, rateLimited, model: modelName, attempts };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { result: null, rateLimited: true, attempts };
|
|
104
|
+
}
|
|
105
|
+
async generate(prompt) {
|
|
106
|
+
if (!this.client)
|
|
107
|
+
return null;
|
|
108
|
+
try {
|
|
109
|
+
const response = await this.client.messages.create({
|
|
110
|
+
model: this.model,
|
|
111
|
+
max_tokens: 2048,
|
|
112
|
+
messages: [{ role: "user", content: prompt }],
|
|
113
|
+
});
|
|
114
|
+
const textBlock = response.content.find((c) => c.type === "text");
|
|
115
|
+
return textBlock?.text ?? null;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
async ping() {
|
|
122
|
+
return (await this.generate("Say OK")) !== null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=anthropic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/engine/providers/anthropic.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,YAAY,EAAE,0BAA0B,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAEhJ,MAAM,OAAO,iBAAiB;IACpB,MAAM,CAAmB;IACzB,KAAK,CAAS;IACd,aAAa,CAAgB;IAErC,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,iBAAiB,CAAC;QACvD,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE,CAAC;QACpD,IAAI,CAAC,aAAa,GAAG,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,CAAC;IAED,WAAW,KAAc,OAAO,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC;IACvD,OAAO,KAAa,OAAO,WAAW,CAAC,CAAC,CAAC;IAEzC,KAAK,CAAC,kBAAkB,CACtB,YAAoB,EACpB,SAAiB,EACjB,MAAc,EACd,OAAuF;QAEvF,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAC9D,MAAM,WAAW,GAAG,OAAO,EAAE,aAAa;YACxC,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC;YACzB,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEzE,MAAM,QAAQ,GAA+C,EAAE,CAAC;QAChE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5C,MAAM,SAAS,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC;YACzB,IAAI,YAAY,GAAG,KAAK,CAAC;YACzB,OAAO,IAAI,EAAE,CAAC;gBACb,IAAI,CAAC;oBACJ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;wBACjD,KAAK,EAAE,SAAS;wBAChB,UAAU,EAAE,OAAO,EAAE,eAAe,IAAI,IAAI;wBAC5C,MAAM,EAAE,YAAY;wBACpB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;wBAChD,KAAK,EAAE,CAAC;gCACN,IAAI,EAAE,aAAa;gCACnB,WAAW,EAAE,uCAAuC;gCACpD,YAAY,EAAE,MAAwC;6BACvD,CAAC;wBACF,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE;qBACnD,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;oBAChC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CACnC,CAAC,CAAC,EAA+B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAC1D,CAAC;oBACF,4EAA4E;oBAC5E,8EAA8E;oBAC9E,wEAAwE;oBACxE,IAAI,CAAC,OAAO;wBAAE,MAAM,IAAI,kBAAkB,CAAC,SAAS,CAAC,CAAC;oBAEtD,IAAI,UAAU;wBAAE,OAAO,CAAC,GAAG,CAAC,2CAA2C,SAAS,EAAE,CAAC,CAAC;oBACpF,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;oBACnD,OAAO;wBACL,MAAM,EAAE,OAAO,CAAC,KAAU;wBAC1B,WAAW,EAAE,KAAK;wBAClB,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa,EAAE;wBAChG,KAAK,EAAE,SAAS;wBAChB,QAAQ;qBACT,CAAC;gBACH,CAAC;gBAAC,OAAO,CAAM,EAAE,CAAC;oBACjB,gFAAgF;oBAChF,4EAA4E;oBAC5E,IAAI,yBAAyB,CAAC,CAAC,CAAC,EAAE,CAAC;wBACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;wBACtD,OAAO,CAAC,KAAK,CAAC,eAAe,SAAS,gCAAgC,CAAC,EAAE,MAAM,IAAI,GAAG,kEAAkE,CAAC,CAAC;wBAC1J,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;oBACjG,CAAC;oBACD,MAAM,IAAI,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;oBACjC,MAAM,WAAW,GAAG,IAAI,KAAK,cAAc,CAAC;oBAC5C,MAAM,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC;oBAEhD,oFAAoF;oBACpF,kFAAkF;oBAClF,oEAAoE;oBACpE,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;wBAC3C,MAAM,MAAM,GAAG,0BAA0B,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC;wBAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;wBACvF,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;4BAC1B,OAAO,CAAC,GAAG,CAAC,eAAe,SAAS,IAAI,IAAI,6BAA6B,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;4BAC/F,MAAM,CAAC,6CAA6C;wBACtD,CAAC;wBACD,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;4BAC5B,OAAO,CAAC,IAAI,CAAC,eAAe,SAAS,yEAAyE,CAAC,CAAC;4BAChH,YAAY,GAAG,IAAI,CAAC;4BACpB,SAAS,CAAC,mBAAmB;wBAC/B,CAAC;wBACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;4BACvB,OAAO,CAAC,KAAK,CAAC,2CAA2C,SAAS,MAAM,YAAY,EAAE,yBAAyB,CAAC,CAAC;wBACnH,CAAC;wBACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;oBAC1E,CAAC;oBAED,gFAAgF;oBAChF,6EAA6E;oBAC7E,sDAAsD;oBACtD,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;oBACrF,IAAI,WAAW,IAAI,YAAY,EAAE,CAAC;wBAChC,OAAO,CAAC,GAAG,CAAC,eAAe,SAAS,0CAA0C,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC;wBACpG,MAAM,CAAC,6CAA6C;oBACtD,CAAC;oBACD,IAAI,CAAC,WAAW,EAAE,CAAC;wBACjB,OAAO,CAAC,KAAK,CAAC,yCAAyC,SAAS,aAAa,CAAC,EAAE,MAAM,QAAQ,MAAM,CAAC,CAAC,EAAE,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;oBACzI,CAAC;oBACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;gBAClE,CAAC;YACF,CAAC;QACH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACvD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,MAAc;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACjD,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,UAAU,EAAE,IAAI;gBAChB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC,CAAC;YACH,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CACrC,CAAC,CAAC,EAA4B,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CACnD,CAAC;YACF,OAAO,SAAS,EAAE,IAAI,IAAI,IAAI,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACR,OAAO,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,KAAK,IAAI,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/** Empty/hung response: the model returned NO content (text="" / 0 tokens, often
|
|
2
|
+
* after a long hang). DISTINCT from truncation — there is no partial classification,
|
|
3
|
+
* so a max_tokens bump is a no-op and escalating to a fallback model is SAFE (the
|
|
4
|
+
* determinism trap does not apply when there was no classification at all). */
|
|
5
|
+
export declare class EmptyResponseError extends Error {
|
|
6
|
+
readonly model: string;
|
|
7
|
+
constructor(model: string);
|
|
8
|
+
}
|
|
9
|
+
/** True when an extracted completion body has no usable content. */
|
|
10
|
+
export declare function isEmptyResult(text: string | null | undefined): boolean;
|
|
11
|
+
/** Bound an LLM call so a hung provider can't stall the pipeline indefinitely.
|
|
12
|
+
* Promise.race — the underlying request continues in the background on timeout but
|
|
13
|
+
* the pipeline unblocks. Providers whose SDK has a native per-request timeout
|
|
14
|
+
* (openai, anthropic) use that instead; gemini's SDK does not, so it wraps with this.
|
|
15
|
+
* (debt-4 Stage A, promoted from gemini.ts so the bound is shared.) */
|
|
16
|
+
export declare function withTimeout<T>(p: Promise<T>, ms: number, label: string): Promise<T>;
|
|
17
|
+
/** The shared call-timeout bound (ms). 180s is generous: a healthy Pass 3 (~60-80s)
|
|
18
|
+
* and Pass 2c (~100-150s) fit; it caps the worst case (~3min) AND the ~200s empty-
|
|
19
|
+
* hang we observed (Run 12, 2026-06-06). Configurable via NODEDEX_LLM_TIMEOUT_MS;
|
|
20
|
+
* <=0 disables the bound. */
|
|
21
|
+
export declare function llmTimeoutMs(): number;
|
|
22
|
+
export type GenFailureKind = "empty" | "timeout" | "rate_limited" | "truncated" | "mechanism_or_other";
|
|
23
|
+
/** Classify a generateStructured() failure so every provider's retry policy branches
|
|
24
|
+
* identically. Order matters: the explicit EmptyResponseError must win over the
|
|
25
|
+
* SyntaxError that an empty body would otherwise produce. */
|
|
26
|
+
export declare function classifyGenError(e: unknown): GenFailureKind;
|
|
27
|
+
/** Out-of-credit / billing failure — DISTINCT from a transient rate-limit. The account
|
|
28
|
+
* can't pay for the call (HTTP 402, or an "insufficient credit/funds/balance/quota" body),
|
|
29
|
+
* so retrying the same model OR escalating to a fallback is pointless — every model on the
|
|
30
|
+
* account is equally unfunded. The pipeline treats this as a PAUSE-the-spend trigger
|
|
31
|
+
* (preserve + requeue the turn, auto-resume on top-up), NOT a per-turn failure that counts
|
|
32
|
+
* toward the drop cap. Accepts an Error, an OpenRouter/OpenAI SDK error ({status,code,message}),
|
|
33
|
+
* or a plain reason string (so the reflect queue can classify a swallowed-null reason too).
|
|
34
|
+
* Checked separately from classifyGenError so a billing-out never masquerades as a
|
|
35
|
+
* rate-limit (which would wastefully escalate to an equally-unfunded fallback model). */
|
|
36
|
+
export declare function isInsufficientCreditError(e: unknown): boolean;
|
|
37
|
+
export type RetryAction = "escalate" | "retry_same" | "degrade";
|
|
38
|
+
/** Decide what to do with an EMPTY or TIMEOUT failure, given the retry state. This is
|
|
39
|
+
* the "escalate-first-when-a-fallback-exists" policy (2026-06-06, Run 14 finding):
|
|
40
|
+
* - escalate : a fallback model remains → try it. For an empty, a DIFFERENT model is
|
|
41
|
+
* the likeliest recovery (the empty tends to be input-specific to one
|
|
42
|
+
* model) and it skips the slow same-model draw; for a timeout, don't pay
|
|
43
|
+
* the bound twice on the same model.
|
|
44
|
+
* - retry_same : NO fallback remains AND this is an un-retried empty → give the SAME
|
|
45
|
+
* model one more independent draw. This is a single-key user's ONLY
|
|
46
|
+
* recovery path (empties are probabilistic — a 2nd draw sometimes wins).
|
|
47
|
+
* - degrade : nothing left to try (no fallback + already retried, or a timeout with
|
|
48
|
+
* no fallback — we never re-pay a timeout on the same model).
|
|
49
|
+
* Neither empty nor timeout ever bumps max_tokens (no partial output to grow) and both
|
|
50
|
+
* are SAFE to escalate (no determinism trap — there was no classification to contradict). */
|
|
51
|
+
export declare function decideEmptyOrTimeoutAction(opts: {
|
|
52
|
+
kind: "empty" | "timeout";
|
|
53
|
+
hasNextModel: boolean;
|
|
54
|
+
emptyRetried: boolean;
|
|
55
|
+
}): RetryAction;
|
|
56
|
+
//# sourceMappingURL=failure-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure-policy.d.ts","sourceRoot":"","sources":["../../../src/engine/providers/failure-policy.ts"],"names":[],"mappings":"AAoBA;;;gFAGgF;AAChF,qBAAa,kBAAmB,SAAQ,KAAK;aACf,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;CAI1C;AAED,oEAAoE;AACpE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEtE;AAED;;;;wEAIwE;AACxE,wBAAgB,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAOnF;AAED;;;8BAG8B;AAC9B,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,GAAG,WAAW,GAAG,oBAAoB,CAAC;AAEvG;;8DAE8D;AAC9D,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,cAAc,CAa3D;AAED;;;;;;;;0FAQ0F;AAC1F,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAY7D;AAED,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;AAEhE;;;;;;;;;;;;8FAY8F;AAC9F,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;CACvB,GAAG,WAAW,CAId"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// ── Shared LLM-call failure policy (2026-06-06) ──────────────────────────────────
|
|
2
|
+
// The three providers (openai/gemini/anthropic) differ only in SDK CALL MECHANICS.
|
|
3
|
+
// "What to do when a call empties / hangs / truncates / rate-limits" is the SAME
|
|
4
|
+
// policy and must hold on EVERY real-world provider path — a developer may run
|
|
5
|
+
// Nodedex on any provider with their own key, not just our OpenRouter setup. This
|
|
6
|
+
// module owns the provider-agnostic pieces (failure classification, empty-detection,
|
|
7
|
+
// the call timeout); each provider maps its SDK errors into classifyGenError() and
|
|
8
|
+
// applies the one canonical retry policy:
|
|
9
|
+
//
|
|
10
|
+
// empty → retry SAME model once (transient glitch; the only recovery a
|
|
11
|
+
// single-key user has) → escalate to fallback model if configured
|
|
12
|
+
// → else degrade. Never bump max_tokens (no output to grow).
|
|
13
|
+
// timeout → escalate to fallback model → else degrade. No same-model retry
|
|
14
|
+
// (the call already paid the full timeout; don't pay it twice).
|
|
15
|
+
// rate_limited → escalate to fallback model → else degrade (capacity problem).
|
|
16
|
+
// truncated → retry SAME model once with a bigger budget → else degrade. NEVER
|
|
17
|
+
// swap models (a different model yields a different classification =
|
|
18
|
+
// the determinism trap).
|
|
19
|
+
// mechanism_or_other → provider-specific (openai: one prompt-JSON retry; others degrade).
|
|
20
|
+
/** Empty/hung response: the model returned NO content (text="" / 0 tokens, often
|
|
21
|
+
* after a long hang). DISTINCT from truncation — there is no partial classification,
|
|
22
|
+
* so a max_tokens bump is a no-op and escalating to a fallback model is SAFE (the
|
|
23
|
+
* determinism trap does not apply when there was no classification at all). */
|
|
24
|
+
export class EmptyResponseError extends Error {
|
|
25
|
+
model;
|
|
26
|
+
constructor(model) {
|
|
27
|
+
super(`empty/hung response from ${model}`);
|
|
28
|
+
this.model = model;
|
|
29
|
+
this.name = "EmptyResponseError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** True when an extracted completion body has no usable content. */
|
|
33
|
+
export function isEmptyResult(text) {
|
|
34
|
+
return (text ?? "").trim() === "";
|
|
35
|
+
}
|
|
36
|
+
/** Bound an LLM call so a hung provider can't stall the pipeline indefinitely.
|
|
37
|
+
* Promise.race — the underlying request continues in the background on timeout but
|
|
38
|
+
* the pipeline unblocks. Providers whose SDK has a native per-request timeout
|
|
39
|
+
* (openai, anthropic) use that instead; gemini's SDK does not, so it wraps with this.
|
|
40
|
+
* (debt-4 Stage A, promoted from gemini.ts so the bound is shared.) */
|
|
41
|
+
export function withTimeout(p, ms, label) {
|
|
42
|
+
return Promise.race([
|
|
43
|
+
p,
|
|
44
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error(`${label} timeout after ${ms}ms`)), ms)),
|
|
45
|
+
]);
|
|
46
|
+
}
|
|
47
|
+
/** The shared call-timeout bound (ms). 180s is generous: a healthy Pass 3 (~60-80s)
|
|
48
|
+
* and Pass 2c (~100-150s) fit; it caps the worst case (~3min) AND the ~200s empty-
|
|
49
|
+
* hang we observed (Run 12, 2026-06-06). Configurable via NODEDEX_LLM_TIMEOUT_MS;
|
|
50
|
+
* <=0 disables the bound. */
|
|
51
|
+
export function llmTimeoutMs() {
|
|
52
|
+
const n = Number(process.env.NODEDEX_LLM_TIMEOUT_MS ?? "180000");
|
|
53
|
+
return Number.isFinite(n) ? n : 180000;
|
|
54
|
+
}
|
|
55
|
+
/** Classify a generateStructured() failure so every provider's retry policy branches
|
|
56
|
+
* identically. Order matters: the explicit EmptyResponseError must win over the
|
|
57
|
+
* SyntaxError that an empty body would otherwise produce. */
|
|
58
|
+
export function classifyGenError(e) {
|
|
59
|
+
if (e instanceof EmptyResponseError)
|
|
60
|
+
return "empty";
|
|
61
|
+
const msg = String(e?.message ?? "");
|
|
62
|
+
const status = e?.status;
|
|
63
|
+
// Capacity / rate-limit: 429, 503 (overloaded), 529 (Anthropic overloaded), quota.
|
|
64
|
+
if (status === 429 || status === 503 || status === 529 ||
|
|
65
|
+
/\b429\b|\b503\b|\b529\b|quota|RESOURCE_EXHAUSTED|high demand/i.test(msg))
|
|
66
|
+
return "rate_limited";
|
|
67
|
+
const name = String(e?.name ?? "");
|
|
68
|
+
// Timeout: openai/anthropic SDK throw APIConnectionTimeoutError; withTimeout() throws "... timeout after Nms".
|
|
69
|
+
if (name === "APIConnectionTimeoutError" || /timeout after|timed?\s?out|timeout/i.test(msg))
|
|
70
|
+
return "timeout";
|
|
71
|
+
// Truncation: JSON.parse threw on a NON-empty body (cut mid-structure at max_tokens).
|
|
72
|
+
if (e instanceof SyntaxError || msg.includes("Unterminated") || msg.includes("position"))
|
|
73
|
+
return "truncated";
|
|
74
|
+
return "mechanism_or_other";
|
|
75
|
+
}
|
|
76
|
+
/** Out-of-credit / billing failure — DISTINCT from a transient rate-limit. The account
|
|
77
|
+
* can't pay for the call (HTTP 402, or an "insufficient credit/funds/balance/quota" body),
|
|
78
|
+
* so retrying the same model OR escalating to a fallback is pointless — every model on the
|
|
79
|
+
* account is equally unfunded. The pipeline treats this as a PAUSE-the-spend trigger
|
|
80
|
+
* (preserve + requeue the turn, auto-resume on top-up), NOT a per-turn failure that counts
|
|
81
|
+
* toward the drop cap. Accepts an Error, an OpenRouter/OpenAI SDK error ({status,code,message}),
|
|
82
|
+
* or a plain reason string (so the reflect queue can classify a swallowed-null reason too).
|
|
83
|
+
* Checked separately from classifyGenError so a billing-out never masquerades as a
|
|
84
|
+
* rate-limit (which would wastefully escalate to an equally-unfunded fallback model). */
|
|
85
|
+
export function isInsufficientCreditError(e) {
|
|
86
|
+
if (e == null)
|
|
87
|
+
return false;
|
|
88
|
+
const status = e?.status ?? e?.code;
|
|
89
|
+
if (status === 402 || status === "402")
|
|
90
|
+
return true;
|
|
91
|
+
const msg = typeof e === "string" ? e : String(e?.message ?? "");
|
|
92
|
+
// 402 / "insufficient credit" = account out of funds. ALSO treat a provider SPEND-CAP as the
|
|
93
|
+
// same class so it routes through the pause-spend + TUI alert + auto-resume path instead of a
|
|
94
|
+
// silent generic-failure fail-clean: OpenRouter returns 403 "Key limit exceeded (total limit)"
|
|
95
|
+
// when a key's spend ceiling is hit. Deliberately NOT a transient 429 rate-limit (that backs
|
|
96
|
+
// off + retries — pausing-till-topup would be wrong) and NOT a bare 403 (auth/permission) —
|
|
97
|
+
// only the limit-exceeded TEXT, which "rate limit exceeded" does not match.
|
|
98
|
+
return /\b402\b|payment required|insufficient[\s_-]*(credit|fund|balance|quota)|negative\s+(credit|balance)|requires?\s+(more|additional)\s+credit|out of credit|add (more )?credit|key\s+limit\s+exceeded|\btotal\s+limit\b|credit\s+limit\b/i.test(msg);
|
|
99
|
+
}
|
|
100
|
+
/** Decide what to do with an EMPTY or TIMEOUT failure, given the retry state. This is
|
|
101
|
+
* the "escalate-first-when-a-fallback-exists" policy (2026-06-06, Run 14 finding):
|
|
102
|
+
* - escalate : a fallback model remains → try it. For an empty, a DIFFERENT model is
|
|
103
|
+
* the likeliest recovery (the empty tends to be input-specific to one
|
|
104
|
+
* model) and it skips the slow same-model draw; for a timeout, don't pay
|
|
105
|
+
* the bound twice on the same model.
|
|
106
|
+
* - retry_same : NO fallback remains AND this is an un-retried empty → give the SAME
|
|
107
|
+
* model one more independent draw. This is a single-key user's ONLY
|
|
108
|
+
* recovery path (empties are probabilistic — a 2nd draw sometimes wins).
|
|
109
|
+
* - degrade : nothing left to try (no fallback + already retried, or a timeout with
|
|
110
|
+
* no fallback — we never re-pay a timeout on the same model).
|
|
111
|
+
* Neither empty nor timeout ever bumps max_tokens (no partial output to grow) and both
|
|
112
|
+
* are SAFE to escalate (no determinism trap — there was no classification to contradict). */
|
|
113
|
+
export function decideEmptyOrTimeoutAction(opts) {
|
|
114
|
+
if (opts.hasNextModel)
|
|
115
|
+
return "escalate";
|
|
116
|
+
if (opts.kind === "empty" && !opts.emptyRetried)
|
|
117
|
+
return "retry_same";
|
|
118
|
+
return "degrade";
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=failure-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"failure-policy.js","sourceRoot":"","sources":["../../../src/engine/providers/failure-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { LLMProvider, EmbeddingProvider, GenerateResult } from "../ai-provider.js";
|
|
2
|
+
export declare class GeminiProvider implements LLMProvider {
|
|
3
|
+
private genAI;
|
|
4
|
+
constructor(apiKey: string);
|
|
5
|
+
isAvailable(): boolean;
|
|
6
|
+
getName(): string;
|
|
7
|
+
generateStructured<T>(systemPrompt: string, userInput: string, schema: object, options?: {
|
|
8
|
+
thinkingBudget?: number;
|
|
9
|
+
maxOutputTokens?: number;
|
|
10
|
+
modelOverride?: string;
|
|
11
|
+
}): Promise<GenerateResult<T>>;
|
|
12
|
+
generate(prompt: string): Promise<string | null>;
|
|
13
|
+
ping(): Promise<boolean>;
|
|
14
|
+
}
|
|
15
|
+
export declare class GeminiEmbeddingProvider implements EmbeddingProvider {
|
|
16
|
+
private genAI;
|
|
17
|
+
private readonly embModel;
|
|
18
|
+
constructor(apiKey: string);
|
|
19
|
+
isAvailable(): boolean;
|
|
20
|
+
embed(text: string): Promise<number[] | null>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=gemini.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../../src/engine/providers/gemini.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAkBxF,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,KAAK,CAA4B;gBAE7B,MAAM,EAAE,MAAM;IAI1B,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;IAmIvB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgBhD,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;CAG/B;AAED,qBAAa,uBAAwB,YAAW,iBAAiB;IAC/D,OAAO,CAAC,KAAK,CAA4B;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiE;gBAE9E,MAAM,EAAE,MAAM;IAI1B,WAAW,IAAI,OAAO;IAEhB,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC;CAiBpD"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
2
|
+
import { EmptyResponseError, classifyGenError, isEmptyResult, withTimeout, llmTimeoutMs, decideEmptyOrTimeoutAction, isInsufficientCreditError } from "./failure-policy.js";
|
|
3
|
+
// Default + fallback model resolved LIVE from env per call. A const frozen at
|
|
4
|
+
// MODULE LOAD would ignore a web-UI / config-endpoint model change until a full
|
|
5
|
+
// restart (resetProviders can't refresh a module-level const) — so these are
|
|
6
|
+
// functions read at call time.
|
|
7
|
+
function primaryModel() {
|
|
8
|
+
return process.env.AI_MODEL ?? process.env.NODEDEX_PRIMARY_MODEL ?? "gemini-2.5-flash";
|
|
9
|
+
}
|
|
10
|
+
function fallbackModel() {
|
|
11
|
+
return process.env.NODEDEX_FALLBACK_MODEL ?? "gemini-2.5-pro";
|
|
12
|
+
}
|
|
13
|
+
// Failure handling (timeout bound, empty-detection, failure classification) is now
|
|
14
|
+
// shared across all providers — see ./failure-policy.ts. The 180s call bound
|
|
15
|
+
// (debt-4 Stage A) lives there as llmTimeoutMs() / withTimeout().
|
|
16
|
+
export class GeminiProvider {
|
|
17
|
+
genAI;
|
|
18
|
+
constructor(apiKey) {
|
|
19
|
+
this.genAI = apiKey ? new GoogleGenerativeAI(apiKey) : null;
|
|
20
|
+
}
|
|
21
|
+
isAvailable() { return this.genAI !== null; }
|
|
22
|
+
getName() { return "gemini"; }
|
|
23
|
+
async generateStructured(systemPrompt, userInput, schema, options) {
|
|
24
|
+
if (!this.genAI)
|
|
25
|
+
return { result: null, rateLimited: false };
|
|
26
|
+
const primary = primaryModel(), fallback = fallbackModel();
|
|
27
|
+
const modelsToTry = options?.modelOverride
|
|
28
|
+
? [options.modelOverride]
|
|
29
|
+
: primary === fallback ? [primary] : [primary, fallback];
|
|
30
|
+
const attempts = [];
|
|
31
|
+
for (let i = 0; i < modelsToTry.length; i++) {
|
|
32
|
+
const modelName = modelsToTry[i];
|
|
33
|
+
const isFallback = i > 0;
|
|
34
|
+
// gemini-2.5-pro requires non-zero thinking budget
|
|
35
|
+
const budget = isFallback
|
|
36
|
+
? Math.max(512, options?.thinkingBudget ?? 0)
|
|
37
|
+
: (options?.thinkingBudget ?? 0);
|
|
38
|
+
const genConfig = {
|
|
39
|
+
thinkingConfig: { thinkingBudget: budget },
|
|
40
|
+
responseMimeType: "application/json",
|
|
41
|
+
responseSchema: schema,
|
|
42
|
+
};
|
|
43
|
+
if (options?.maxOutputTokens)
|
|
44
|
+
genConfig.maxOutputTokens = options.maxOutputTokens;
|
|
45
|
+
// Deterministic extraction → default temperature 0 (cuts run-to-run variance).
|
|
46
|
+
// Gemini thinking models accept temperature. Configurable via NODEDEX_REFLECT_TEMPERATURE.
|
|
47
|
+
{
|
|
48
|
+
const tEnv = process.env.NODEDEX_REFLECT_TEMPERATURE;
|
|
49
|
+
genConfig.temperature = tEnv !== undefined && tEnv !== "" && Number.isFinite(Number(tEnv)) ? Number(tEnv) : 0;
|
|
50
|
+
}
|
|
51
|
+
const model = this.genAI.getGenerativeModel({
|
|
52
|
+
model: modelName,
|
|
53
|
+
systemInstruction: systemPrompt,
|
|
54
|
+
generationConfig: genConfig,
|
|
55
|
+
});
|
|
56
|
+
let emptyRetried = false;
|
|
57
|
+
while (true) {
|
|
58
|
+
try {
|
|
59
|
+
const response = await withTimeout(model.generateContent(userInput), llmTimeoutMs(), `generateStructured(${modelName})`);
|
|
60
|
+
const usageMeta = response.response.usageMetadata ?? {};
|
|
61
|
+
// Extract non-thinking output parts (pass3 reads thinking separately)
|
|
62
|
+
const parts = response.response.candidates?.[0]?.content?.parts ?? [];
|
|
63
|
+
const rawText = (parts.length > 0
|
|
64
|
+
? parts.filter((p) => !p.thought).map((p) => p.text ?? "").join("")
|
|
65
|
+
: response.response.text()).trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
|
|
66
|
+
const thinking = parts
|
|
67
|
+
.filter((p) => p.thought === true)
|
|
68
|
+
.map((p) => p.text ?? "")
|
|
69
|
+
.join("\n")
|
|
70
|
+
.trim();
|
|
71
|
+
// EMPTY/HUNG guard BEFORE JSON.parse — a distinct failure (see ./failure-policy):
|
|
72
|
+
// JSON.parse("") would look like truncation; raise it explicitly so the catch
|
|
73
|
+
// retries/escalates instead of mislabeling it.
|
|
74
|
+
if (isEmptyResult(rawText))
|
|
75
|
+
throw new EmptyResponseError(modelName);
|
|
76
|
+
const result = JSON.parse(rawText);
|
|
77
|
+
attempts.push({ model: modelName, outcome: "ok" });
|
|
78
|
+
return {
|
|
79
|
+
result,
|
|
80
|
+
rateLimited: false,
|
|
81
|
+
thinking,
|
|
82
|
+
usage: {
|
|
83
|
+
input: usageMeta.promptTokenCount ?? 0,
|
|
84
|
+
thinking: usageMeta.thoughtsTokenCount ?? 0,
|
|
85
|
+
output: usageMeta.candidatesTokenCount ?? 0,
|
|
86
|
+
},
|
|
87
|
+
model: modelName,
|
|
88
|
+
attempts,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
// Out-of-credit (402) — surface DEFINITIVELY (see openai.ts): the reflect queue
|
|
93
|
+
// pauses-the-spend + requeues instead of swallowing it into a generic null.
|
|
94
|
+
if (isInsufficientCreditError(e)) {
|
|
95
|
+
attempts.push({ model: modelName, outcome: "error" });
|
|
96
|
+
console.error(`[gemini] ${modelName} insufficient credit (status=${e?.status ?? "?"}) — credit exhausted; not retrying/escalating (account unfunded)`);
|
|
97
|
+
return { result: null, rateLimited: false, creditExhausted: true, model: modelName, attempts };
|
|
98
|
+
}
|
|
99
|
+
const kind = classifyGenError(e);
|
|
100
|
+
const rateLimited = kind === "rate_limited";
|
|
101
|
+
const hasNextModel = i + 1 < modelsToTry.length;
|
|
102
|
+
// EMPTY/TIMEOUT → shared escalate-first policy (./failure-policy): a fallback
|
|
103
|
+
// model is the likeliest recovery for an input-specific empty (and skips the slow
|
|
104
|
+
// same-model draw); only a single-key setup retries the SAME model once.
|
|
105
|
+
if (kind === "empty" || kind === "timeout") {
|
|
106
|
+
const action = decideEmptyOrTimeoutAction({ kind, hasNextModel, emptyRetried });
|
|
107
|
+
attempts.push({ model: modelName, outcome: kind === "timeout" ? "timeout" : "empty" });
|
|
108
|
+
if (action === "escalate") {
|
|
109
|
+
console.warn(`[gemini] ${modelName} ${kind} — escalating to fallback`);
|
|
110
|
+
break; // exit while; outer for tries the next model
|
|
111
|
+
}
|
|
112
|
+
if (action === "retry_same") {
|
|
113
|
+
console.warn(`[gemini] ${modelName} returned EMPTY/hung response — no fallback; retrying same model once`);
|
|
114
|
+
emptyRetried = true;
|
|
115
|
+
continue; // retry same model
|
|
116
|
+
}
|
|
117
|
+
if (kind === "timeout") {
|
|
118
|
+
console.error(`[gemini] generateStructured TIMEOUT (${modelName}): ${llmTimeoutMs()}ms — pipeline continues, request may still be running at provider`);
|
|
119
|
+
}
|
|
120
|
+
return { result: null, rateLimited: false, model: modelName, attempts };
|
|
121
|
+
}
|
|
122
|
+
// RATE-LIMIT / TRUNCATED → escalate to the next model if one remains, else degrade.
|
|
123
|
+
// (Truncation→fallback preserves gemini's long-standing behavior; openai's stricter
|
|
124
|
+
// same-model-only truncation policy is left provider-specific to keep this tight.)
|
|
125
|
+
attempts.push({ model: modelName, outcome: kind === "truncated" ? "truncated" :
|
|
126
|
+
rateLimited ? "rate_limited" : "error" });
|
|
127
|
+
if ((kind === "truncated" || rateLimited) && hasNextModel) {
|
|
128
|
+
console.warn(`[gemini] ${modelName} ${kind} — escalating to fallback`);
|
|
129
|
+
break; // exit while; outer for tries the next model
|
|
130
|
+
}
|
|
131
|
+
if (!rateLimited) {
|
|
132
|
+
console.error(`[gemini] generateStructured error (${modelName}): ${String(e?.message ?? e).slice(0, 300)}`);
|
|
133
|
+
}
|
|
134
|
+
return { result: null, rateLimited, model: modelName, attempts };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return { result: null, rateLimited: true, attempts };
|
|
139
|
+
}
|
|
140
|
+
async generate(prompt) {
|
|
141
|
+
if (!this.genAI)
|
|
142
|
+
return null;
|
|
143
|
+
try {
|
|
144
|
+
const primary = primaryModel();
|
|
145
|
+
const model = this.genAI.getGenerativeModel({ model: primary });
|
|
146
|
+
const result = await withTimeout(model.generateContent(prompt), llmTimeoutMs(), `generate(${primary})`);
|
|
147
|
+
return result.response.text().trim();
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
async ping() {
|
|
154
|
+
return (await this.generate("Say OK")) !== null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export class GeminiEmbeddingProvider {
|
|
158
|
+
genAI;
|
|
159
|
+
embModel = process.env.NODEDEX_EMBEDDING_MODEL ?? "gemini-embedding-001";
|
|
160
|
+
constructor(apiKey) {
|
|
161
|
+
this.genAI = apiKey ? new GoogleGenerativeAI(apiKey) : null;
|
|
162
|
+
}
|
|
163
|
+
isAvailable() { return this.genAI !== null; }
|
|
164
|
+
async embed(text) {
|
|
165
|
+
if (!this.genAI)
|
|
166
|
+
return null;
|
|
167
|
+
try {
|
|
168
|
+
const model = this.genAI.getGenerativeModel({ model: this.embModel });
|
|
169
|
+
// Provider-level timeout: belt-and-suspenders with EmbeddingEngine.embed
|
|
170
|
+
// wrapper (which also times out at 30s + records stats). This catches
|
|
171
|
+
// direct provider calls if they ever happen without the engine.
|
|
172
|
+
const result = await withTimeout(model.embedContent(text), 30_000, `embed(${this.embModel})`);
|
|
173
|
+
return result.embedding.values;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../../src/engine/providers/gemini.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LLMProvider, EmbeddingProvider } from "../ai-provider.js";
|
|
2
|
+
/** Returns the singleton LLM provider (lazy-initialized from env vars). */
|
|
3
|
+
export declare function getLLMProvider(): LLMProvider;
|
|
4
|
+
/** Returns the singleton embedding provider (lazy-initialized from env vars). */
|
|
5
|
+
export declare function getEmbeddingProvider(): EmbeddingProvider;
|
|
6
|
+
/** Reset singletons — used in tests after env var changes. */
|
|
7
|
+
export declare function resetProviders(): void;
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAUxE,2EAA2E;AAC3E,wBAAgB,cAAc,IAAI,WAAW,CAoB5C;AAED,iFAAiF;AACjF,wBAAgB,oBAAoB,IAAI,iBAAiB,CAiCxD;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,IAAI,IAAI,CAGrC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { GeminiProvider, GeminiEmbeddingProvider } from "./gemini.js";
|
|
2
|
+
import { OpenAIProvider, OpenAIEmbeddingProvider } from "./openai.js";
|
|
3
|
+
import { AnthropicProvider } from "./anthropic.js";
|
|
4
|
+
import { LocalEmbeddingProvider } from "./local.js";
|
|
5
|
+
import { wrapWithUsageLedger } from "./usage-ledger.js";
|
|
6
|
+
let _llm = null;
|
|
7
|
+
let _embeddings = null;
|
|
8
|
+
/** Returns the singleton LLM provider (lazy-initialized from env vars). */
|
|
9
|
+
export function getLLMProvider() {
|
|
10
|
+
if (_llm)
|
|
11
|
+
return _llm;
|
|
12
|
+
const name = (process.env.AI_PROVIDER ?? "gemini").toLowerCase();
|
|
13
|
+
if (name === "openai" || name === "openai-compatible") {
|
|
14
|
+
_llm = new OpenAIProvider(process.env.OPENAI_API_KEY ?? "", process.env.OPENAI_BASE_URL);
|
|
15
|
+
}
|
|
16
|
+
else if (name === "anthropic") {
|
|
17
|
+
_llm = new AnthropicProvider(process.env.ANTHROPIC_API_KEY ?? "");
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
_llm = new GeminiProvider(process.env.GEMINI_API_KEY ?? "");
|
|
21
|
+
}
|
|
22
|
+
// Meter every structured key call at the single seam — wrap once so the cached
|
|
23
|
+
// provider (and all callers) route generateStructured() through the usage ledger.
|
|
24
|
+
_llm = wrapWithUsageLedger(_llm);
|
|
25
|
+
return _llm;
|
|
26
|
+
}
|
|
27
|
+
/** Returns the singleton embedding provider (lazy-initialized from env vars). */
|
|
28
|
+
export function getEmbeddingProvider() {
|
|
29
|
+
if (_embeddings)
|
|
30
|
+
return _embeddings;
|
|
31
|
+
// Embeddings default to LOCAL (bundled bge-small, offline, $0, no key) when
|
|
32
|
+
// EMBEDDING_PROVIDER is unset — the shipped release default. A fresh install gets
|
|
33
|
+
// working semantic search with zero setup; set EMBEDDING_PROVIDER=gemini|openai|
|
|
34
|
+
// anthropic for hosted embeddings. (Decoupled from AI_PROVIDER on purpose: a chat
|
|
35
|
+
// model like owl/openai-compatible is a poor embedder.)
|
|
36
|
+
const embName = (process.env.EMBEDDING_PROVIDER ?? "local").toLowerCase();
|
|
37
|
+
if (embName === "local") {
|
|
38
|
+
// Local, free, offline embeddings (transformers.js) — no API/quota.
|
|
39
|
+
_embeddings = new LocalEmbeddingProvider();
|
|
40
|
+
}
|
|
41
|
+
else if (embName === "openai" || embName === "openai-compatible") {
|
|
42
|
+
_embeddings = new OpenAIEmbeddingProvider(process.env.OPENAI_API_KEY ?? "", process.env.OPENAI_BASE_URL);
|
|
43
|
+
}
|
|
44
|
+
else if (embName === "anthropic") {
|
|
45
|
+
// Anthropic has no embeddings API — cascade to Gemini, then OpenAI
|
|
46
|
+
if (process.env.GEMINI_API_KEY) {
|
|
47
|
+
_embeddings = new GeminiEmbeddingProvider(process.env.GEMINI_API_KEY);
|
|
48
|
+
}
|
|
49
|
+
else if (process.env.OPENAI_API_KEY) {
|
|
50
|
+
_embeddings = new OpenAIEmbeddingProvider(process.env.OPENAI_API_KEY);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
_embeddings = { embed: async () => null, isAvailable: () => false };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
// gemini (default)
|
|
58
|
+
_embeddings = new GeminiEmbeddingProvider(process.env.GEMINI_API_KEY ?? "");
|
|
59
|
+
}
|
|
60
|
+
return _embeddings;
|
|
61
|
+
}
|
|
62
|
+
/** Reset singletons — used in tests after env var changes. */
|
|
63
|
+
export function resetProviders() {
|
|
64
|
+
_llm = null;
|
|
65
|
+
_embeddings = null;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=index.js.map
|