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,621 @@
|
|
|
1
|
+
// routes/state.ts — shared in-memory state + queue processor.
|
|
2
|
+
// All route modules import from here rather than from api-server.ts.
|
|
3
|
+
// Reference: api-server.v1.ts (lines 13-325)
|
|
4
|
+
import { v4 as uuidv4 } from "uuid";
|
|
5
|
+
import { runAutoReflect, reflectTokenStats } from "../middleware/auto-reflect.js";
|
|
6
|
+
import { runComprehendFrontHalf } from "../middleware/reflect/v2-integrate.js";
|
|
7
|
+
import { getLLMProvider } from "../engine/providers/index.js";
|
|
8
|
+
import { evaluateBudgetLive, writeSpendPauseFile, clearSpendPauseFile, creditExhausted, creditRecovered } from "../middleware/reflect/cost-guard.js";
|
|
9
|
+
import { isInsufficientCreditError } from "../engine/providers/failure-policy.js";
|
|
10
|
+
import { resolveRoutedFlagsFromText } from "../middleware/reflect/nl-accept.js";
|
|
11
|
+
import { arcAutoTurns } from "../middleware/reflect/config.js";
|
|
12
|
+
export function resolveStateLabel(agentId) {
|
|
13
|
+
return agentId ? `agent_session_state_${agentId}` : "agent_session_state";
|
|
14
|
+
}
|
|
15
|
+
export const reflectQueue = [];
|
|
16
|
+
export let reflectProcessing = false;
|
|
17
|
+
export let reflectFlushGeneration = 0; // incremented on every flush; each sleeping job checks its own snapshot
|
|
18
|
+
export let reflectPaused = false;
|
|
19
|
+
// SPEND pause — distinct from reflectPaused. reflectPaused stops CAPTURE (drops turns at
|
|
20
|
+
// /trigger) for benchmark/manual isolation; spendPaused stops only SPENDING (halts the
|
|
21
|
+
// drain) while CAPTURE KEEPS QUEUING, so a credit outage loses no turns. Set by the
|
|
22
|
+
// cost-breaker + the credit-out handler; cleared automatically when credit tops back up.
|
|
23
|
+
export let spendPaused = false;
|
|
24
|
+
export function setReflectProcessing(v) { reflectProcessing = v; }
|
|
25
|
+
export function setReflectFlushGeneration(v) { reflectFlushGeneration = v; }
|
|
26
|
+
export function setReflectPaused(v) { reflectPaused = v; }
|
|
27
|
+
export function setSpendPaused(v) { spendPaused = v; }
|
|
28
|
+
// Enqueue ONE captured turn for reflection — the SINGLE in-process path, shared by the
|
|
29
|
+
// HTTP trigger route (where hooks / the tee adapter POST in) and the chat proxy (which
|
|
30
|
+
// enqueues directly, no self-HTTP-call). Mechanics only — the CALLER owns pause policy
|
|
31
|
+
// (the proxy honors reflectPaused; the trigger route additionally bypasses it for
|
|
32
|
+
// benchmark runs) and the <50-char gate. Never throws: capture must never break its caller.
|
|
33
|
+
export function enqueueReflectTurn(db, embeddings, turn) {
|
|
34
|
+
const jobId = `rj_${uuidv4().slice(0, 12)}`;
|
|
35
|
+
try {
|
|
36
|
+
if (turn.agentId)
|
|
37
|
+
db.registerAgent(turn.agentId);
|
|
38
|
+
try {
|
|
39
|
+
db.insertReflectJob(jobId, turn.agentId || null, JSON.stringify({
|
|
40
|
+
agentResponse: turn.agentResponse,
|
|
41
|
+
userMessage: turn.userMessage || "",
|
|
42
|
+
loadedBlockIds: turn.loadedBlockIds || [],
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
catch { /* non-critical — the DB row is for status sync only */ }
|
|
46
|
+
reflectQueue.push({
|
|
47
|
+
agentResponse: turn.agentResponse,
|
|
48
|
+
agentThinking: turn.agentThinking || "",
|
|
49
|
+
userMessage: turn.userMessage || "",
|
|
50
|
+
loadedBlockIds: turn.loadedBlockIds || [],
|
|
51
|
+
agentId: turn.agentId,
|
|
52
|
+
turnNumber: turn.turnNumber,
|
|
53
|
+
turnName: turn.turnName,
|
|
54
|
+
dbId: jobId,
|
|
55
|
+
});
|
|
56
|
+
processReflectQueue(db, embeddings || undefined).catch((e) => console.error("[reflect] worker error:", e));
|
|
57
|
+
}
|
|
58
|
+
catch (e) {
|
|
59
|
+
console.error("[reflect] enqueue error:", e);
|
|
60
|
+
}
|
|
61
|
+
return { jobId, queueDepth: reflectQueue.length };
|
|
62
|
+
}
|
|
63
|
+
export const sessionEvents = [];
|
|
64
|
+
export let sessionEventCounter = 0;
|
|
65
|
+
export const SESSION_EVENT_MAX = 500; // cap at 500 events to avoid unbounded growth
|
|
66
|
+
export function incrementSessionEventCounter() { return ++sessionEventCounter; }
|
|
67
|
+
export const alertStore = [];
|
|
68
|
+
let alertCounter = 0;
|
|
69
|
+
const ALERT_STORE_MAX = 200;
|
|
70
|
+
const ALERT_COOLDOWN_MS = 5 * 60 * 1000; // 5-minute cooldown per condition
|
|
71
|
+
export const alertCooldowns = new Map(); // condition → last fired ms
|
|
72
|
+
/** Reset all session monitoring state (session events, alerts, counters) */
|
|
73
|
+
export function resetMonitoring() {
|
|
74
|
+
sessionEvents.length = 0;
|
|
75
|
+
sessionEventCounter = 0;
|
|
76
|
+
alertStore.length = 0;
|
|
77
|
+
alertCounter = 0;
|
|
78
|
+
alertCooldowns.clear();
|
|
79
|
+
}
|
|
80
|
+
export function fireAlert(condition, severity, message, context) {
|
|
81
|
+
const now = Date.now();
|
|
82
|
+
if ((alertCooldowns.get(condition) ?? 0) + ALERT_COOLDOWN_MS > now)
|
|
83
|
+
return;
|
|
84
|
+
alertCooldowns.set(condition, now);
|
|
85
|
+
const record = { id: ++alertCounter, timestamp: new Date().toISOString(), condition, severity, message, context };
|
|
86
|
+
if (alertStore.length < ALERT_STORE_MAX)
|
|
87
|
+
alertStore.push(record);
|
|
88
|
+
console.warn(`[ALERT:${severity.toUpperCase()}] ${condition}: ${message}`);
|
|
89
|
+
}
|
|
90
|
+
export function evaluateAlertsAfterReflect(evt) {
|
|
91
|
+
// Rate limit hit
|
|
92
|
+
if (evt.rate_limited) {
|
|
93
|
+
fireAlert("rate_limit", "warn", `Pass ${evt.rate_limit_pass ?? "?"} rate limited`, { pass: evt.rate_limit_pass });
|
|
94
|
+
}
|
|
95
|
+
// Processing lag
|
|
96
|
+
if (evt.processing_ms > 120_000) {
|
|
97
|
+
fireAlert("processing_lag_critical", "critical", `Reflect cycle took ${Math.round(evt.processing_ms / 1000)}s (threshold: 120s)`, { processing_ms: evt.processing_ms });
|
|
98
|
+
}
|
|
99
|
+
else if (evt.processing_ms > 60_000) {
|
|
100
|
+
fireAlert("processing_lag_warn", "warn", `Reflect cycle took ${Math.round(evt.processing_ms / 1000)}s (threshold: 60s)`, { processing_ms: evt.processing_ms });
|
|
101
|
+
}
|
|
102
|
+
// Queue backup
|
|
103
|
+
if (reflectQueue.length > 10) {
|
|
104
|
+
fireAlert("queue_backup_critical", "critical", `Queue depth ${reflectQueue.length} (threshold: 10)`, { queue_depth: reflectQueue.length });
|
|
105
|
+
}
|
|
106
|
+
else if (reflectQueue.length > 3) {
|
|
107
|
+
fireAlert("queue_backup_warn", "warn", `Queue depth ${reflectQueue.length} (threshold: 3)`, { queue_depth: reflectQueue.length });
|
|
108
|
+
}
|
|
109
|
+
// Quality drop — last 5 blocks avg < 3
|
|
110
|
+
const allCreatedSoFar = sessionEvents
|
|
111
|
+
.filter((e) => e.type === "reflect")
|
|
112
|
+
.flatMap(e => e.blocks_created);
|
|
113
|
+
const last5 = allCreatedSoFar.slice(-5);
|
|
114
|
+
if (last5.length >= 5) {
|
|
115
|
+
const avgQuality = last5.reduce((s, b) => s + b.quality, 0) / last5.length;
|
|
116
|
+
if (avgQuality < 3) {
|
|
117
|
+
fireAlert("quality_drop", "warn", `Avg quality of last 5 blocks: ${avgQuality.toFixed(1)} (threshold: 3.0)`, { avg_quality: avgQuality, blocks: last5.map(b => b.label) });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Block creation spike — this cycle > 2× session avg, min 10 blocks
|
|
121
|
+
const reflectEvtsSoFar = sessionEvents.filter((e) => e.type === "reflect");
|
|
122
|
+
if (reflectEvtsSoFar.length >= 3) {
|
|
123
|
+
const prevAvg = reflectEvtsSoFar.slice(0, -1).reduce((s, e) => s + e.blocks_created.length, 0) / (reflectEvtsSoFar.length - 1);
|
|
124
|
+
const thisCount = evt.blocks_created.length;
|
|
125
|
+
if (prevAvg > 0 && thisCount > prevAvg * 2 && thisCount >= 10) {
|
|
126
|
+
fireAlert("block_creation_spike", "warn", `${thisCount} blocks this cycle (2× avg of ${prevAvg.toFixed(1)})`, { this_cycle: thisCount, session_avg: prevAvg });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Block drought — 0 blocks for 3 consecutive cycles despite input tokens
|
|
130
|
+
const recentEvts = reflectEvtsSoFar.slice(-3);
|
|
131
|
+
if (recentEvts.length === 3 && recentEvts.every(e => e.blocks_created.length === 0 && e.tokens.pass1_input > 0)) {
|
|
132
|
+
fireAlert("block_drought", "warn", "0 blocks saved in last 3 reflect cycles despite input being processed", { cycles_checked: 3 });
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function evaluateAlertsAfterRecall(evt) {
|
|
136
|
+
// Recall pollution threshold scales with project count:
|
|
137
|
+
// Single-project workspace: 25% (cross-project recall is unexpected)
|
|
138
|
+
// Multi-project workspace: 60% (cross-project recall is expected and useful)
|
|
139
|
+
if (evt.total_injected >= 8) {
|
|
140
|
+
const pct = (evt.cross_project_count / evt.total_injected) * 100;
|
|
141
|
+
const threshold = evt.project_count <= 1 ? 25 : 60;
|
|
142
|
+
if (pct > threshold) {
|
|
143
|
+
fireAlert("recall_pollution", "warn", `${pct.toFixed(0)}% of recalled blocks are cross-project (threshold: ${threshold}%)`, { pollution_pct: pct, cross_project: evt.cross_project_count, total: evt.total_injected, query: evt.query, project_count: evt.project_count });
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// ─── Mining candidates (removed — never wired, zero API calls, zero value at 42/42)
|
|
148
|
+
// To restore: add MiningCandidate interface + miningStore here, POST/GET/PATCH
|
|
149
|
+
// /api/mining-candidates in workspace.ts, inject in session.ts GET /api/session,
|
|
150
|
+
// inject in context hook section "3. Mining candidates".
|
|
151
|
+
// ─── Credit-out: pause spending, REQUEUE the turn (never drop) ───────────────────
|
|
152
|
+
// The REACTIVE backstop. When an extraction fails, decide whether it failed because the
|
|
153
|
+
// account is out of credit; if so, pause SPENDING and requeue the turn UNCHANGED so it
|
|
154
|
+
// drains after a top-up. Detection: the DEFINITIVE 402 signal first (isInsufficientCredit
|
|
155
|
+
// on the failure / reason — no network), then a FORCE-REFRESHED balance probe as the net.
|
|
156
|
+
//
|
|
157
|
+
// The requeue is the SAME mechanism as the rate-limit path (unshift + retry_wait row) with
|
|
158
|
+
// ONE deliberate difference: it does NOT increment retryAttempts. A credit outage is a
|
|
159
|
+
// global condition, not this turn's fault — counting it toward the per-turn drop cap would
|
|
160
|
+
// wrongly discard turns during an outage. Pairing it with the spend-pause (instead of a
|
|
161
|
+
// backoff-retry that would just re-hit the 402) is what makes capture-keeps-queuing work.
|
|
162
|
+
async function pauseAndRequeueIfCreditOut(db, job, errOrReason) {
|
|
163
|
+
let remaining = null;
|
|
164
|
+
let out = isInsufficientCreditError(errOrReason);
|
|
165
|
+
if (!out) {
|
|
166
|
+
const c = await creditExhausted();
|
|
167
|
+
out = c.out;
|
|
168
|
+
remaining = c.remaining;
|
|
169
|
+
}
|
|
170
|
+
if (!out)
|
|
171
|
+
return false;
|
|
172
|
+
setSpendPaused(true);
|
|
173
|
+
const reason = `credit exhausted${remaining != null ? ` — remaining $${remaining.toFixed(2)}` : ""} (auto-resume on top-up)`;
|
|
174
|
+
writeSpendPauseFile(reason);
|
|
175
|
+
// Surface it in the monitoring feed (the TUI error terminal reads alertStore) — a
|
|
176
|
+
// timestamped record alongside the standing spend_paused flag. 5-min cooldown built in.
|
|
177
|
+
fireAlert("credit_exhausted", "critical", `Credit exhausted — extraction paused, ${reflectQueue.length + 1} turn(s) queued, auto-resume on top-up`, { remaining });
|
|
178
|
+
// Requeue UNCHANGED — same unshift + retry_wait mechanism as the rate-limit path, but
|
|
179
|
+
// NO attempt increment (a global outage, not this turn's fault → never drop it).
|
|
180
|
+
if (job.dbId)
|
|
181
|
+
db.updateReflectJob(job.dbId, { status: 'retry_wait', error: 'paused: credit exhausted' });
|
|
182
|
+
reflectQueue.unshift(job);
|
|
183
|
+
console.warn(`[reflect-queue] CREDIT EXHAUSTED — ${reason}. Spending paused, ${reflectQueue.length} job(s) preserved + still queuing. Auto-resumes when credit tops up.`);
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
// ─── Auto-resume: drain again once credit recovers ───────────────────────────────
|
|
187
|
+
// processReflectQueue BREAKS on spendPaused BEFORE the budget re-check, so a paused queue
|
|
188
|
+
// never re-evaluates itself — resume needs a SEPARATE timer. It only ever acts on an active
|
|
189
|
+
// spendPaused (never the capture reflect-pause), force-refreshes the balance, and on recovery
|
|
190
|
+
// clears the spend-pause (flag + its OWN file — never the user's/dogfood reflect-pause) and
|
|
191
|
+
// kicks the drain. Idempotent; unref'd so it never holds the process open (tests/CI safe).
|
|
192
|
+
/**
|
|
193
|
+
* One auto-resume check: if spend-paused AND credit has POSITIVELY recovered, lift the
|
|
194
|
+
* pause + drain. Returns true iff it resumed. Exported so the behavior is unit/live-testable
|
|
195
|
+
* without waiting on the 60s timer. Conservative — `creditRecovered` only confirms recovery
|
|
196
|
+
* on a readable balance above the floor, so an indeterminate balance keeps the pause.
|
|
197
|
+
*/
|
|
198
|
+
export async function creditAutoResumeTick(db, embeddings) {
|
|
199
|
+
if (!spendPaused)
|
|
200
|
+
return false;
|
|
201
|
+
let rec;
|
|
202
|
+
try {
|
|
203
|
+
rec = await creditRecovered();
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
if (!rec.recovered)
|
|
209
|
+
return false; // still out / unconfirmed — stay paused
|
|
210
|
+
setSpendPaused(false);
|
|
211
|
+
clearSpendPauseFile();
|
|
212
|
+
console.log(`[cost-breaker] credit recovered${rec.remaining != null ? ` (remaining $${rec.remaining.toFixed(2)})` : ""} — SPENDING RESUMED, draining ${reflectQueue.length} queued job(s)`);
|
|
213
|
+
processReflectQueue(db, embeddings).catch(e => console.error("[cost-breaker] resume drain error:", e));
|
|
214
|
+
// Arc turns aren't in the per-turn reflectQueue — they live as pass01_done conversation_turns,
|
|
215
|
+
// so the drain above can't reach an arc that credit-failed mid-extraction. Re-fire arc
|
|
216
|
+
// extraction for each agent whose arc failed (last_extract_error marker), re-using the SAME
|
|
217
|
+
// runArcExtraction over its full pending range → it re-consolidates ALL pass01_done turns (full
|
|
218
|
+
// arc context, not a fragment) and commits on success, or fail-cleans again if still out.
|
|
219
|
+
try {
|
|
220
|
+
const stuck = db.listAgentsWithFailedArc();
|
|
221
|
+
if (stuck.length) {
|
|
222
|
+
console.log(`[cost-breaker] re-extracting ${stuck.length} arc(s) that the spend-stop paused`);
|
|
223
|
+
void import("../middleware/reflect/arc-pipeline.js").then(({ runArcExtraction }) => {
|
|
224
|
+
for (const agentId of stuck) {
|
|
225
|
+
void runArcExtraction(db, { agent_id: agentId, trigger_source: "auto" })
|
|
226
|
+
.catch((e) => console.warn(`[cost-breaker] arc resume re-extract failed for ${agentId}: ${e?.message ?? e}`));
|
|
227
|
+
}
|
|
228
|
+
}).catch((e) => console.warn(`[cost-breaker] arc resume import failed: ${e?.message ?? e}`));
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (e) {
|
|
232
|
+
console.warn(`[cost-breaker] arc resume check failed: ${e?.message}`);
|
|
233
|
+
}
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
let autoResumeTimer = null;
|
|
237
|
+
export function startCreditAutoResume(db, embeddings, intervalMs = 60_000) {
|
|
238
|
+
if (autoResumeTimer)
|
|
239
|
+
return;
|
|
240
|
+
autoResumeTimer = setInterval(() => { creditAutoResumeTick(db, embeddings).catch(() => { }); }, intervalMs);
|
|
241
|
+
autoResumeTimer.unref?.();
|
|
242
|
+
}
|
|
243
|
+
export function stopCreditAutoResume() {
|
|
244
|
+
if (autoResumeTimer) {
|
|
245
|
+
clearInterval(autoResumeTimer);
|
|
246
|
+
autoResumeTimer = null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
// ─── Reflect queue processor ──────────────────────────────────────────────────
|
|
250
|
+
export async function processReflectQueue(db, embeddings) {
|
|
251
|
+
if (reflectProcessing)
|
|
252
|
+
return;
|
|
253
|
+
reflectProcessing = true;
|
|
254
|
+
try {
|
|
255
|
+
while (reflectQueue.length > 0) {
|
|
256
|
+
// Pause halts the drain. "Pause" means "stop spending" — and a paused
|
|
257
|
+
// server must never silently resume a recovered queue. Jobs stay queued
|
|
258
|
+
// (and persisted in DB); they drain on the next trigger after resume, or
|
|
259
|
+
// on a restart that boots unpaused. (Before this guard, pause only gated
|
|
260
|
+
// NEW enqueues at /trigger while the existing queue kept draining — the
|
|
261
|
+
// surprising behavior that burned credit on 2026-06-01.)
|
|
262
|
+
if (reflectPaused) {
|
|
263
|
+
console.log(`[reflect-queue] paused — halting drain (${reflectQueue.length} job(s) remain queued)`);
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
// SPEND pause — halts the drain (stop spending) but capture keeps queuing at
|
|
267
|
+
// /trigger, so a credit outage never loses turns. Auto-resumes on top-up.
|
|
268
|
+
if (spendPaused) {
|
|
269
|
+
console.log(`[reflect-queue] spend paused (credit/budget) — halting drain; capture still queuing (${reflectQueue.length} job(s) preserved, auto-resume on top-up)`);
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
// Cost breaker (production gap 2): trip BEFORE pulling a job, reusing the
|
|
273
|
+
// SPEND-pause lever. No-op + no I/O when no budget is configured (the default).
|
|
274
|
+
// Tripping persists the spend-pause file so a restart can't bypass the budget;
|
|
275
|
+
// the queue is preserved (fail-safe) and CAPTURE KEEPS QUEUING. The auto-resume
|
|
276
|
+
// timer drains it when the balance recovers. The designed protections (floor
|
|
277
|
+
// breach, balance-unknown) return a clean tripped verdict; an unexpected THROW
|
|
278
|
+
// here is a breaker BUG, and a guard must never break what it guards — so we fail
|
|
279
|
+
// OPEN on a throw (proceed), never silently halt reflection because the breaker
|
|
280
|
+
// itself errored.
|
|
281
|
+
let budget = null;
|
|
282
|
+
try {
|
|
283
|
+
budget = await evaluateBudgetLive();
|
|
284
|
+
}
|
|
285
|
+
catch (e) {
|
|
286
|
+
console.error("[cost-breaker] evaluation threw — proceeding WITHOUT tripping (breaker bug, not a budget breach):", e);
|
|
287
|
+
}
|
|
288
|
+
if (budget?.tripped) {
|
|
289
|
+
setSpendPaused(true);
|
|
290
|
+
writeSpendPauseFile(budget.reason ?? "cost breaker tripped");
|
|
291
|
+
console.warn(`[cost-breaker] TRIPPED — ${budget.reason}. SPENDING PAUSED (${reflectQueue.length} job(s) preserved + queued; capture continues). Auto-resumes when the balance recovers.`);
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
const job = reflectQueue.shift();
|
|
295
|
+
// Honour retry delay — put back and wait if not ready yet
|
|
296
|
+
if (job.retryAfter && Date.now() < job.retryAfter) {
|
|
297
|
+
const wait = job.retryAfter - Date.now();
|
|
298
|
+
console.log(`[reflect-queue] rate-limit retry in ${Math.round(wait / 1000)}s — pausing queue`);
|
|
299
|
+
reflectQueue.unshift(job);
|
|
300
|
+
// Snapshot generation at sleep entry — flush increments it, so any change means abandon
|
|
301
|
+
const myGeneration = reflectFlushGeneration;
|
|
302
|
+
const sleepUntil = Date.now() + Math.min(wait, 10000);
|
|
303
|
+
while (Date.now() < sleepUntil) {
|
|
304
|
+
await new Promise(r => setTimeout(r, 1000));
|
|
305
|
+
if (reflectFlushGeneration !== myGeneration)
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
if (reflectFlushGeneration !== myGeneration) {
|
|
309
|
+
reflectQueue.length = 0;
|
|
310
|
+
console.log("[reflect-queue] flush acknowledged — sleeping job abandoned");
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
// Mark job as actively processing in DB
|
|
316
|
+
if (job.dbId)
|
|
317
|
+
db.updateReflectJob(job.dbId, { status: 'processing' });
|
|
318
|
+
const recalledBlocks = job.loadedBlockIds
|
|
319
|
+
.map(id => db.getBlock(id))
|
|
320
|
+
.filter(Boolean)
|
|
321
|
+
.map((b) => ({ id: b.id, label: b.label, essence: b.essence || "", type: b.type }));
|
|
322
|
+
// FLAG-RESOLUTION (b): if this turn answered a question the system routed to the
|
|
323
|
+
// agent, apply it. Fire-and-forget + independent of extraction. Self-gated
|
|
324
|
+
// (NODEDEX_FLAG_NL_ACCEPT off → instant no-op) and work-gated (no LLM call unless
|
|
325
|
+
// a flag is actually pending), so this is $0 in the common case.
|
|
326
|
+
resolveRoutedFlagsFromText(db, getLLMProvider(), job.agentResponse)
|
|
327
|
+
.then(r => { if (r.addressed)
|
|
328
|
+
console.log(`[nl-accept] addressed=${r.addressed} merged=${r.merged} left=${r.left} split=${r.split} skipped=${r.skipped_low_conf} errors=${r.errors}`); })
|
|
329
|
+
.catch(e => console.warn(`[nl-accept] ${e?.message ?? e}`));
|
|
330
|
+
const jobStart = Date.now();
|
|
331
|
+
const statsBefore = {
|
|
332
|
+
p1in: reflectTokenStats.pass1.input,
|
|
333
|
+
p2in: reflectTokenStats.pass2.input, p2th: reflectTokenStats.pass2.thinking,
|
|
334
|
+
p3in: reflectTokenStats.pass3.input, p3th: reflectTokenStats.pass3.thinking,
|
|
335
|
+
};
|
|
336
|
+
try {
|
|
337
|
+
// Carry forward every completed pass when resuming, so Pass 0/1/2 reasoning
|
|
338
|
+
// ends up in the final turn log regardless of which pass triggered the retry.
|
|
339
|
+
let checkpoint = job.precomputedPass3PendingBlockIds
|
|
340
|
+
? {
|
|
341
|
+
resumeFrom: 'pass4',
|
|
342
|
+
pass0: job.precomputedPass0,
|
|
343
|
+
pass1Items: job.precomputedPass1?.items,
|
|
344
|
+
pass2Classified: job.precomputedPass2?.classified ?? [],
|
|
345
|
+
p3PendingBlockIds: job.precomputedPass3PendingBlockIds,
|
|
346
|
+
}
|
|
347
|
+
: job.precomputedPass2
|
|
348
|
+
? {
|
|
349
|
+
resumeFrom: 'pass3',
|
|
350
|
+
pass0: job.precomputedPass0,
|
|
351
|
+
pass1Items: job.precomputedPass1?.items,
|
|
352
|
+
pass2Classified: job.precomputedPass2.classified,
|
|
353
|
+
}
|
|
354
|
+
: job.precomputedPass1
|
|
355
|
+
? {
|
|
356
|
+
resumeFrom: 'pass2',
|
|
357
|
+
pass0: job.precomputedPass0,
|
|
358
|
+
pass1Items: job.precomputedPass1.items,
|
|
359
|
+
}
|
|
360
|
+
: undefined;
|
|
361
|
+
// ── PIPELINE v2 (per-turn) — gated on its OWN flag, NOT pipelineV2Enabled ─────
|
|
362
|
+
// v2 was arc/batch-only; this brings it to the LIVE per-turn path so a live agent
|
|
363
|
+
// gets v2's worth-gate SELECTOR + (with NODEDEX_V2_MERGE_DUPS) cross-group dedup.
|
|
364
|
+
// SEPARATE flag NODEDEX_V2_PER_TURN so it does NOT auto-fire on the arc-mode
|
|
365
|
+
// NODEDEX_PIPELINE_V2 flag a deployment may set for batch. Routes through
|
|
366
|
+
// runComprehendFrontHalf with holistic:true — a single turn fits ONE COMPREHEND
|
|
367
|
+
// call, so it does NOT use per-group SEGMENT (which exists only as the big-arc
|
|
368
|
+
// truncate fix and, on a single turn's overlapping threads, blind-parallel
|
|
369
|
+
// re-extracts shared claims → cross-group dups). Holistic prevents the dup at the
|
|
370
|
+
// source; the MERGE_DUPS pass then stays a harmless no-op here (arc-mode net).
|
|
371
|
+
// Transcript = USER/AGENT only (matches the arc path; thinking is captured to
|
|
372
|
+
// conversation_turns but not fed to COMPREHEND — it amplified over-seg in testing).
|
|
373
|
+
// Guards: !checkpoint (don't override a retry) · !job.turnNumber (arc mode keeps
|
|
374
|
+
// its Pass 0-1 defer, so this NEVER runs in arc mode). V2-ONLY (2026-06-20): a v2
|
|
375
|
+
// failure NO LONGER degrades to v1 — it REQUEUES (retry v2 with backoff) up to a
|
|
376
|
+
// cap, then fail-cleans (turn skipped, never v1, no silent corruption). This matches
|
|
377
|
+
// the arc path's v2-only fail-clean policy (arc-pipeline.ts §"V2-ONLY failure
|
|
378
|
+
// policy"). ⚠ OLD v1 PIPELINE — DO NOT TURN ON: the NODEDEX_V2_PER_TURN=0
|
|
379
|
+
// off-switch was REMOVED, so v2 per-turn is unconditional and the v1 path below
|
|
380
|
+
// (runAutoReflect with no checkpoint + no turnNumber) is intentionally unreachable.
|
|
381
|
+
let v2PerTurnAttempted = false;
|
|
382
|
+
let v2PerTurnReason = null;
|
|
383
|
+
if (!checkpoint && !job.turnNumber && job.agentResponse) {
|
|
384
|
+
v2PerTurnAttempted = true;
|
|
385
|
+
try {
|
|
386
|
+
const v2Transcript = `USER: ${job.userMessage ?? ""}\nAGENT: ${job.agentResponse}`;
|
|
387
|
+
// holistic by default (1 turn fits one call, no cross-group dup). Set
|
|
388
|
+
// NODEDEX_V2_PER_TURN_PERGROUP=1 to instead run per-group + merge on the
|
|
389
|
+
// per-turn path — under evaluation: per-group runs the cross-group LINKER
|
|
390
|
+
// (no-op on holistic's single group), which may wire based_on/supports that
|
|
391
|
+
// holistic leaves as islands. The wiring-vs-dup A/B decides the default.
|
|
392
|
+
const useHolistic = process.env.NODEDEX_V2_PER_TURN_PERGROUP !== "1";
|
|
393
|
+
const front = await runComprehendFrontHalf(db, getLLMProvider(), v2Transcript, { holistic: useHolistic });
|
|
394
|
+
if (front.checkpoint) {
|
|
395
|
+
checkpoint = front.checkpoint;
|
|
396
|
+
console.log(`[reflect-per-turn] PIPELINE v2: ${front.groups} group(s), ${front.blocks} block(s), ${front.merged ?? 0} merged`);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
v2PerTurnReason = front.reason ?? "unknown"; // "empty" (legit: nothing to save) | "comprehend_failed" | "seam1_invalid"
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch (e) {
|
|
403
|
+
v2PerTurnReason = `threw: ${e?.message ?? e}`;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
// V2-ONLY per-turn outcome — never fall through to v1.
|
|
407
|
+
// • checkpoint set → success → fall through to runAutoReflect (v2 back-half).
|
|
408
|
+
// • reason "empty" → legitimately no residue → clean 0-block, done (NOT a failure).
|
|
409
|
+
// • any other failure → REQUEUE (retry v2) up to the cap, then fail-clean.
|
|
410
|
+
if (v2PerTurnAttempted && !checkpoint) {
|
|
411
|
+
if (v2PerTurnReason === "empty") {
|
|
412
|
+
console.log(`[reflect-per-turn] v2: nothing worth saving (empty) — done, 0 blocks`);
|
|
413
|
+
if (job.dbId)
|
|
414
|
+
db.updateReflectJob(job.dbId, { status: 'done' });
|
|
415
|
+
}
|
|
416
|
+
else if (await pauseAndRequeueIfCreditOut(db, job, v2PerTurnReason)) {
|
|
417
|
+
// Out of credit — paused + requeued UNCHANGED (no retry-cap burn). The loop
|
|
418
|
+
// top sees spendPaused and halts the drain; capture keeps queuing.
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
const attempts = (job.retryAttempts ?? 0) + 1;
|
|
423
|
+
const maxRetries = Number(process.env.NODEDEX_V2_PER_TURN_MAX_RETRIES) || 3;
|
|
424
|
+
if (attempts <= maxRetries) {
|
|
425
|
+
const base = Math.min(15_000 * Math.pow(2, attempts - 1), 60_000);
|
|
426
|
+
const retryDelay = Math.round(base + Math.random() * base * 0.5);
|
|
427
|
+
console.warn(`[reflect-per-turn] v2 failed (${v2PerTurnReason}) — requeue ${attempts}/${maxRetries} in ${Math.round(retryDelay / 1000)}s (v2-only, NO v1)`);
|
|
428
|
+
const retryJob = { ...job, retryAfter: Date.now() + retryDelay, retryAttempts: attempts };
|
|
429
|
+
if (job.dbId)
|
|
430
|
+
db.updateReflectJob(job.dbId, { status: 'retry_wait', retry_after: retryJob.retryAfter, retry_attempts: attempts });
|
|
431
|
+
reflectQueue.unshift(retryJob);
|
|
432
|
+
}
|
|
433
|
+
else {
|
|
434
|
+
console.warn(`[reflect-per-turn] v2 failed after ${maxRetries} retries (${v2PerTurnReason}) — fail-clean, turn skipped (v2-only, NO v1)`);
|
|
435
|
+
if (job.dbId)
|
|
436
|
+
db.updateReflectJob(job.dbId, { status: 'dead', error: `v2 per-turn failed: ${v2PerTurnReason}`.slice(0, 200) });
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
continue; // skip runAutoReflect — the per-turn v2 path never falls to v1
|
|
440
|
+
}
|
|
441
|
+
const r = await runAutoReflect(db, job.agentResponse, job.loadedBlockIds, job.userMessage, job.agentThinking || undefined, embeddings || undefined, recalledBlocks, job.agentId, checkpoint,
|
|
442
|
+
// ── DEBT 5 Phase 2: thread turn identity into pipeline ──
|
|
443
|
+
// When NODEDEX_ARC_EXTRACTION=1 + agentId present + turnNumber present,
|
|
444
|
+
// pipeline persists Pass 0-1 to conversation_turns and defers Pass 2-5
|
|
445
|
+
// to arc-extract trigger. ReflectJob has carried turnNumber/turnName
|
|
446
|
+
// since the inventory pass; this completes the wire.
|
|
447
|
+
job.turnNumber, job.turnName);
|
|
448
|
+
if (r.saved > 0 || r.updated > 0)
|
|
449
|
+
console.log(`[reflect-queue] saved=${r.saved} updated=${r.updated} labels=${r.saved_labels.join(",")}`);
|
|
450
|
+
if (r.uncertain_count > 0)
|
|
451
|
+
console.log(`[reflect-queue] uncertain_refs=${r.uncertain_count} — stored for next turn`);
|
|
452
|
+
// ── Every-N arc auto-extract (safety net) ────────────────────────────────
|
|
453
|
+
// In arc mode this turn was just CAPTURED (pass01_done) but not yet extracted. If
|
|
454
|
+
// the agent doesn't fire workspace_extract_arc itself at a task boundary, auto-commit
|
|
455
|
+
// once N turns have accumulated (NODEDEX_ARC_AUTO_TURNS; 0/unset = off → inert). The
|
|
456
|
+
// guard `job.turnNumber !== undefined` means this NEVER runs in per-turn mode. Fire-
|
|
457
|
+
// and-forget so it never blocks the queue; runArcExtraction's own in-flight + rate
|
|
458
|
+
// guards stop double-firing. Dynamic import avoids a static arc-pipeline↔state cycle.
|
|
459
|
+
const autoN = arcAutoTurns();
|
|
460
|
+
if (autoN > 0 && job.agentId && job.turnNumber !== undefined) {
|
|
461
|
+
try {
|
|
462
|
+
const pending = db.getExtractionStatus(job.agentId).pending?.turns ?? 0;
|
|
463
|
+
if (pending >= autoN) {
|
|
464
|
+
const agentId = job.agentId;
|
|
465
|
+
void import("../middleware/reflect/arc-pipeline.js")
|
|
466
|
+
.then(({ runArcExtraction }) => runArcExtraction(db, { agent_id: agentId, trigger_source: "auto" }))
|
|
467
|
+
.then((res) => { if (res?.status === "extracted")
|
|
468
|
+
console.log(`[arc-auto] committed ${res.turns_consumed} turn(s) for ${agentId} (pending>=${autoN})`); })
|
|
469
|
+
.catch((e) => console.warn(`[arc-auto] ${e?.message ?? e}`));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
catch (e) {
|
|
473
|
+
console.warn(`[arc-auto] check failed: ${e?.message}`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
// ── Record session event ──────────────────────────────────────────────
|
|
477
|
+
const processing_ms = Date.now() - jobStart;
|
|
478
|
+
const rateLimited = !!r.checkpoint;
|
|
479
|
+
const rateLimitPass = r.checkpoint?.resumeFrom === 'pass1' ? 1 : r.checkpoint?.resumeFrom === 'pass2' ? 2 : r.checkpoint?.resumeFrom === 'pass3' ? 3 : undefined;
|
|
480
|
+
const p1in = reflectTokenStats.pass1.input - statsBefore.p1in;
|
|
481
|
+
const p2in = reflectTokenStats.pass2.input - statsBefore.p2in;
|
|
482
|
+
const p2th = reflectTokenStats.pass2.thinking - statsBefore.p2th;
|
|
483
|
+
const p3in = reflectTokenStats.pass3.input - statsBefore.p3in;
|
|
484
|
+
const p3th = reflectTokenStats.pass3.thinking - statsBefore.p3th;
|
|
485
|
+
const billedEquiv = p1in + p2in + (p2th * 23) + p3in + (p3th * 23);
|
|
486
|
+
if (sessionEvents.length < SESSION_EVENT_MAX) {
|
|
487
|
+
sessionEvents.push({
|
|
488
|
+
id: incrementSessionEventCounter(),
|
|
489
|
+
timestamp: new Date().toISOString(),
|
|
490
|
+
type: "reflect",
|
|
491
|
+
agent_id: job.agentId,
|
|
492
|
+
turn_number: job.turnNumber,
|
|
493
|
+
turn_name: job.turnName,
|
|
494
|
+
blocks_created: r.created_blocks,
|
|
495
|
+
blocks_updated: r.updated_blocks,
|
|
496
|
+
tokens: { pass1_input: p1in, pass2_input: p2in, pass2_thinking: p2th, pass3_input: p3in, pass3_thinking: p3th, billed_equiv: billedEquiv },
|
|
497
|
+
processing_ms,
|
|
498
|
+
rate_limited: rateLimited,
|
|
499
|
+
...(rateLimitPass ? { rate_limit_pass: rateLimitPass } : {}),
|
|
500
|
+
});
|
|
501
|
+
evaluateAlertsAfterReflect(sessionEvents[sessionEvents.length - 1]);
|
|
502
|
+
}
|
|
503
|
+
// Exponential backoff with full jitter — avoids thundering herd on Gemini 503s.
|
|
504
|
+
// Base: 15s. Doubles each attempt, caps at 60s. Jitter: random 0-50% of base delay.
|
|
505
|
+
// Jobs are never dropped — agent knowledge is permanent. Retries until Gemini is available.
|
|
506
|
+
// Survives server restarts via DB (retry_wait rows recovered on startup).
|
|
507
|
+
const attempts = (job.retryAttempts ?? 0) + 1;
|
|
508
|
+
{
|
|
509
|
+
const baseDelay = Math.min(15_000 * Math.pow(2, attempts - 1), 60_000);
|
|
510
|
+
const jitter = Math.random() * baseDelay * 0.5;
|
|
511
|
+
const retryDelay = Math.round(baseDelay + jitter);
|
|
512
|
+
const retryInSec = Math.round(retryDelay / 1000);
|
|
513
|
+
// Every retry preserves EVERY completed pass so the eventual turn log shows
|
|
514
|
+
// Pass 0/1/2/3 reasoning regardless of where the retry started.
|
|
515
|
+
const pass0Snapshot = r.checkpoint?.pass0 ?? job.precomputedPass0;
|
|
516
|
+
const pass1Snapshot = r.checkpoint?.pass1Items
|
|
517
|
+
? { items: r.checkpoint.pass1Items }
|
|
518
|
+
: job.precomputedPass1;
|
|
519
|
+
const pass2Snapshot = r.checkpoint?.pass2Classified
|
|
520
|
+
? { classified: r.checkpoint.pass2Classified }
|
|
521
|
+
: job.precomputedPass2;
|
|
522
|
+
if (r.checkpoint?.resumeFrom === 'pass1') {
|
|
523
|
+
console.log(`[reflect-queue] Pass 1 failed — re-queuing (attempt ${attempts}, retry in ${retryInSec}s)`);
|
|
524
|
+
const retryJob = {
|
|
525
|
+
...job,
|
|
526
|
+
precomputedPass0: pass0Snapshot,
|
|
527
|
+
precomputedPass1: undefined,
|
|
528
|
+
precomputedPass2: undefined,
|
|
529
|
+
precomputedPass3PendingBlockIds: undefined,
|
|
530
|
+
retryAfter: Date.now() + retryDelay,
|
|
531
|
+
retryAttempts: attempts,
|
|
532
|
+
};
|
|
533
|
+
if (job.dbId)
|
|
534
|
+
db.updateReflectJob(job.dbId, { status: 'retry_wait', retry_after: retryJob.retryAfter, retry_attempts: attempts, precomputed: JSON.stringify({ pass0: pass0Snapshot }) });
|
|
535
|
+
reflectQueue.unshift(retryJob);
|
|
536
|
+
}
|
|
537
|
+
else if (r.checkpoint?.resumeFrom === 'pass2') {
|
|
538
|
+
console.log(`[reflect-queue] Pass 2 failed — re-queuing with Pass 0+1 (attempt ${attempts}, retry in ${retryInSec}s)`);
|
|
539
|
+
const retryJob = {
|
|
540
|
+
...job,
|
|
541
|
+
precomputedPass0: pass0Snapshot,
|
|
542
|
+
precomputedPass1: pass1Snapshot,
|
|
543
|
+
precomputedPass2: undefined,
|
|
544
|
+
precomputedPass3PendingBlockIds: undefined,
|
|
545
|
+
retryAfter: Date.now() + retryDelay,
|
|
546
|
+
retryAttempts: attempts,
|
|
547
|
+
};
|
|
548
|
+
if (job.dbId)
|
|
549
|
+
db.updateReflectJob(job.dbId, { status: 'retry_wait', retry_after: retryJob.retryAfter, retry_attempts: attempts, precomputed: JSON.stringify({ pass0: pass0Snapshot, pass1: pass1Snapshot }) });
|
|
550
|
+
reflectQueue.unshift(retryJob);
|
|
551
|
+
}
|
|
552
|
+
else if (r.checkpoint?.resumeFrom === 'pass3') {
|
|
553
|
+
console.log(`[reflect-queue] Pass 3 failed — re-queuing with Pass 0+1+2 (attempt ${attempts}, retry in ${retryInSec}s)`);
|
|
554
|
+
const retryJob = {
|
|
555
|
+
...job,
|
|
556
|
+
precomputedPass0: pass0Snapshot,
|
|
557
|
+
precomputedPass1: pass1Snapshot,
|
|
558
|
+
precomputedPass2: pass2Snapshot,
|
|
559
|
+
precomputedPass3PendingBlockIds: undefined,
|
|
560
|
+
retryAfter: Date.now() + retryDelay,
|
|
561
|
+
retryAttempts: attempts,
|
|
562
|
+
};
|
|
563
|
+
if (job.dbId)
|
|
564
|
+
db.updateReflectJob(job.dbId, { status: 'retry_wait', retry_after: retryJob.retryAfter, retry_attempts: attempts, precomputed: JSON.stringify({ pass0: pass0Snapshot, pass1: pass1Snapshot, pass2: pass2Snapshot }) });
|
|
565
|
+
reflectQueue.unshift(retryJob);
|
|
566
|
+
}
|
|
567
|
+
else if (r.checkpoint?.resumeFrom === 'pass4') {
|
|
568
|
+
console.log(`[reflect-queue] Pass 4 failed — re-queuing with Pass 0+1+2+3 pending blocks (attempt ${attempts}, retry in ${retryInSec}s)`);
|
|
569
|
+
const retryJob = {
|
|
570
|
+
...job,
|
|
571
|
+
precomputedPass0: pass0Snapshot,
|
|
572
|
+
precomputedPass1: pass1Snapshot,
|
|
573
|
+
precomputedPass2: pass2Snapshot,
|
|
574
|
+
precomputedPass3PendingBlockIds: r.checkpoint.p3PendingBlockIds,
|
|
575
|
+
retryAfter: Date.now() + retryDelay,
|
|
576
|
+
retryAttempts: attempts,
|
|
577
|
+
};
|
|
578
|
+
if (job.dbId)
|
|
579
|
+
db.updateReflectJob(job.dbId, { status: 'retry_wait', retry_after: retryJob.retryAfter, retry_attempts: attempts, precomputed: JSON.stringify({ pass0: pass0Snapshot, pass1: pass1Snapshot, pass2: pass2Snapshot, p3PendingBlockIds: r.checkpoint.p3PendingBlockIds }) });
|
|
580
|
+
reflectQueue.unshift(retryJob);
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
// Job completed successfully
|
|
584
|
+
if (job.dbId)
|
|
585
|
+
db.updateReflectJob(job.dbId, { status: 'done' });
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
catch (e) {
|
|
590
|
+
// Out of credit → pause spending + requeue UNCHANGED (never drop, no cap burn).
|
|
591
|
+
// Checked BEFORE the 503/rate-limit branch so a 402 is never mistaken for capacity.
|
|
592
|
+
if (await pauseAndRequeueIfCreditOut(db, job, e)) {
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
const errStr = String(e);
|
|
596
|
+
const isBothModels503 = errStr.includes("503") || errStr.includes("Service Unavailable") ||
|
|
597
|
+
errStr.includes("high demand") || errStr.includes("429") || errStr.includes("RESOURCE_EXHAUSTED");
|
|
598
|
+
const attempts = (job.retryAttempts ?? 0) + 1;
|
|
599
|
+
if (isBothModels503) {
|
|
600
|
+
// Both primary and fallback returned 503 — park and retry later
|
|
601
|
+
const baseDelay = Math.min(15_000 * Math.pow(2, attempts - 1), 60_000);
|
|
602
|
+
const retryDelay = Math.round(baseDelay + Math.random() * baseDelay * 0.5);
|
|
603
|
+
console.warn(`[reflect-queue] both models 503 — retry ${attempts} in ${Math.round(retryDelay / 1000)}s`);
|
|
604
|
+
const retryJob = { ...job, retryAfter: Date.now() + retryDelay, retryAttempts: attempts };
|
|
605
|
+
if (job.dbId)
|
|
606
|
+
db.updateReflectJob(job.dbId, { status: 'retry_wait', retry_after: retryJob.retryAfter, retry_attempts: attempts });
|
|
607
|
+
reflectQueue.unshift(retryJob);
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
console.error("[reflect-queue] job error:", e);
|
|
611
|
+
if (job.dbId)
|
|
612
|
+
db.updateReflectJob(job.dbId, { status: 'dead', error: errStr.slice(0, 200) });
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
finally {
|
|
618
|
+
reflectProcessing = false;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
//# sourceMappingURL=state.js.map
|