@sprinterai/runtime 0.3.0 → 0.5.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/LICENSE +21 -0
- package/dist/adapters/a2a-adapter.d.ts +37 -9
- package/dist/adapters/a2a-adapter.d.ts.map +1 -1
- package/dist/adapters/a2a-adapter.js +132 -9
- package/dist/adapters/a2a-adapter.js.map +1 -1
- package/dist/adapters/a2a-adapter.test.d.ts +2 -0
- package/dist/adapters/a2a-adapter.test.d.ts.map +1 -0
- package/dist/adapters/a2a-adapter.test.js +295 -0
- package/dist/adapters/a2a-adapter.test.js.map +1 -0
- package/dist/adapters/http-agent-adapter.d.ts +19 -9
- package/dist/adapters/http-agent-adapter.d.ts.map +1 -1
- package/dist/adapters/http-agent-adapter.js +55 -9
- package/dist/adapters/http-agent-adapter.js.map +1 -1
- package/dist/adapters/http-agent-adapter.test.d.ts +2 -0
- package/dist/adapters/http-agent-adapter.test.d.ts.map +1 -0
- package/dist/adapters/http-agent-adapter.test.js +164 -0
- package/dist/adapters/http-agent-adapter.test.js.map +1 -0
- package/dist/adapters/index.d.ts +8 -8
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/mcp-adapter.d.ts +29 -9
- package/dist/adapters/mcp-adapter.d.ts.map +1 -1
- package/dist/adapters/mcp-adapter.js +43 -8
- package/dist/adapters/mcp-adapter.js.map +1 -1
- package/dist/adapters/mcp-adapter.test.d.ts +2 -0
- package/dist/adapters/mcp-adapter.test.d.ts.map +1 -0
- package/dist/adapters/mcp-adapter.test.js +118 -0
- package/dist/adapters/mcp-adapter.test.js.map +1 -0
- package/dist/adapters/openclaw-adapter.d.ts +34 -8
- package/dist/adapters/openclaw-adapter.d.ts.map +1 -1
- package/dist/adapters/openclaw-adapter.js +38 -8
- package/dist/adapters/openclaw-adapter.js.map +1 -1
- package/dist/adapters/openclaw-adapter.test.d.ts +2 -0
- package/dist/adapters/openclaw-adapter.test.d.ts.map +1 -0
- package/dist/adapters/openclaw-adapter.test.js +77 -0
- package/dist/adapters/openclaw-adapter.test.js.map +1 -0
- package/dist/agent/agent-registry.test.js +1 -1
- package/dist/agent/agent-resolver.d.ts +8 -2
- package/dist/agent/agent-resolver.d.ts.map +1 -1
- package/dist/agent/agent-resolver.js +7 -1
- package/dist/agent/agent-resolver.js.map +1 -1
- package/dist/agent/agent-resolver.test.js +21 -3
- package/dist/agent/agent-resolver.test.js.map +1 -1
- package/dist/agent/delegate.test.js +1 -1
- package/dist/agent/execute-agent.d.ts +32 -8
- package/dist/agent/execute-agent.d.ts.map +1 -1
- package/dist/agent/execute-agent.js +40 -3
- package/dist/agent/execute-agent.js.map +1 -1
- package/dist/agent/index.d.ts +9 -9
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +5 -5
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/prompt-builder.test.js +1 -1
- package/dist/approval/approval-manager.d.ts +19 -0
- package/dist/approval/approval-manager.d.ts.map +1 -0
- package/dist/approval/approval-manager.js +36 -0
- package/dist/approval/approval-manager.js.map +1 -0
- package/dist/approval/approval-manager.test.d.ts +2 -0
- package/dist/approval/approval-manager.test.d.ts.map +1 -0
- package/dist/approval/approval-manager.test.js +239 -0
- package/dist/approval/approval-manager.test.js.map +1 -0
- package/dist/approval/index.d.ts +3 -0
- package/dist/approval/index.d.ts.map +1 -0
- package/dist/approval/index.js +2 -0
- package/dist/approval/index.js.map +1 -0
- package/dist/chat/chat-handler.d.ts +14 -7
- package/dist/chat/chat-handler.d.ts.map +1 -1
- package/dist/chat/chat-handler.js +56 -11
- package/dist/chat/chat-handler.js.map +1 -1
- package/dist/chat/chat-handler.test.js +100 -11
- package/dist/chat/chat-handler.test.js.map +1 -1
- package/dist/chat/index.d.ts +3 -3
- package/dist/chat/index.js +2 -2
- package/dist/chat/message-utils.d.ts +15 -7
- package/dist/chat/message-utils.d.ts.map +1 -1
- package/dist/chat/message-utils.js +94 -22
- package/dist/chat/message-utils.js.map +1 -1
- package/dist/chat/message-utils.test.js +71 -1
- package/dist/chat/message-utils.test.js.map +1 -1
- package/dist/document/chunk-generator.d.ts +6 -0
- package/dist/document/chunk-generator.d.ts.map +1 -0
- package/dist/document/chunk-generator.js +107 -0
- package/dist/document/chunk-generator.js.map +1 -0
- package/dist/document/chunk-generator.test.d.ts +2 -0
- package/dist/document/chunk-generator.test.d.ts.map +1 -0
- package/dist/document/chunk-generator.test.js +166 -0
- package/dist/document/chunk-generator.test.js.map +1 -0
- package/dist/document/document-processor.d.ts +27 -0
- package/dist/document/document-processor.d.ts.map +1 -0
- package/dist/document/document-processor.js +44 -0
- package/dist/document/document-processor.js.map +1 -0
- package/dist/document/document-processor.test.d.ts +2 -0
- package/dist/document/document-processor.test.d.ts.map +1 -0
- package/dist/document/document-processor.test.js +197 -0
- package/dist/document/document-processor.test.js.map +1 -0
- package/dist/document/index.d.ts +5 -0
- package/dist/document/index.d.ts.map +1 -0
- package/dist/document/index.js +4 -0
- package/dist/document/index.js.map +1 -0
- package/dist/document/parsers/index.d.ts +2 -0
- package/dist/document/parsers/index.d.ts.map +1 -0
- package/dist/document/parsers/index.js +2 -0
- package/dist/document/parsers/index.js.map +1 -0
- package/dist/document/parsers/text-parser.d.ts +4 -0
- package/dist/document/parsers/text-parser.d.ts.map +1 -0
- package/dist/document/parsers/text-parser.js +23 -0
- package/dist/document/parsers/text-parser.js.map +1 -0
- package/dist/document/parsers/text-parser.test.d.ts +2 -0
- package/dist/document/parsers/text-parser.test.d.ts.map +1 -0
- package/dist/document/parsers/text-parser.test.js +64 -0
- package/dist/document/parsers/text-parser.test.js.map +1 -0
- package/dist/eval/eval-runner.test.js +2 -2
- package/dist/eval/index.d.ts +3 -3
- package/dist/eval/index.js +2 -2
- package/dist/eval/scorers.test.js +1 -1
- package/dist/events/event-bus.d.ts +12 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +77 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/events/event-bus.test.d.ts +2 -0
- package/dist/events/event-bus.test.d.ts.map +1 -0
- package/dist/events/event-bus.test.js +155 -0
- package/dist/events/event-bus.test.js.map +1 -0
- package/dist/events/index.d.ts +2 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +2 -0
- package/dist/events/index.js.map +1 -0
- package/dist/guardrail/guardrail-pipeline.test.js +1 -1
- package/dist/guardrail/index.d.ts +2 -2
- package/dist/guardrail/index.js +1 -1
- package/dist/index.d.ts +81 -45
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -27
- package/dist/index.js.map +1 -1
- package/dist/jobs/in-memory-job-queue.d.ts +20 -0
- package/dist/jobs/in-memory-job-queue.d.ts.map +1 -0
- package/dist/jobs/in-memory-job-queue.js +120 -0
- package/dist/jobs/in-memory-job-queue.js.map +1 -0
- package/dist/jobs/in-memory-job-queue.test.d.ts +2 -0
- package/dist/jobs/in-memory-job-queue.test.d.ts.map +1 -0
- package/dist/jobs/in-memory-job-queue.test.js +146 -0
- package/dist/jobs/in-memory-job-queue.test.js.map +1 -0
- package/dist/jobs/index.d.ts +4 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +3 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/jobs/job-runner.d.ts +42 -0
- package/dist/jobs/job-runner.d.ts.map +1 -0
- package/dist/jobs/job-runner.js +119 -0
- package/dist/jobs/job-runner.js.map +1 -0
- package/dist/jobs/job-runner.test.d.ts +2 -0
- package/dist/jobs/job-runner.test.d.ts.map +1 -0
- package/dist/jobs/job-runner.test.js +190 -0
- package/dist/jobs/job-runner.test.js.map +1 -0
- package/dist/memory/index.d.ts +3 -3
- package/dist/memory/index.js +2 -2
- package/dist/memory/memory-prompt.d.ts +1 -1
- package/dist/module/create-runtime.d.ts +21 -6
- package/dist/module/create-runtime.d.ts.map +1 -1
- package/dist/module/create-runtime.js +7 -7
- package/dist/module/create-runtime.js.map +1 -1
- package/dist/module/create-runtime.test.js +8 -8
- package/dist/module/index.d.ts +5 -4
- package/dist/module/index.d.ts.map +1 -1
- package/dist/module/index.js +3 -2
- package/dist/module/index.js.map +1 -1
- package/dist/module/map-supabase-stores.d.ts +33 -0
- package/dist/module/map-supabase-stores.d.ts.map +1 -0
- package/dist/module/map-supabase-stores.js +28 -0
- package/dist/module/map-supabase-stores.js.map +1 -0
- package/dist/module/module-loader.d.ts +9 -1
- package/dist/module/module-loader.d.ts.map +1 -1
- package/dist/module/module-loader.js +40 -1
- package/dist/module/module-loader.js.map +1 -1
- package/dist/module/module-loader.test.js +38 -1
- package/dist/module/module-loader.test.js.map +1 -1
- package/dist/notification/digest-scheduler.d.ts +18 -0
- package/dist/notification/digest-scheduler.d.ts.map +1 -0
- package/dist/notification/digest-scheduler.js +44 -0
- package/dist/notification/digest-scheduler.js.map +1 -0
- package/dist/notification/digest-scheduler.test.d.ts +2 -0
- package/dist/notification/digest-scheduler.test.d.ts.map +1 -0
- package/dist/notification/digest-scheduler.test.js +306 -0
- package/dist/notification/digest-scheduler.test.js.map +1 -0
- package/dist/notification/index.d.ts +5 -0
- package/dist/notification/index.d.ts.map +1 -0
- package/dist/notification/index.js +3 -0
- package/dist/notification/index.js.map +1 -0
- package/dist/notification/notification-engine.d.ts +20 -0
- package/dist/notification/notification-engine.d.ts.map +1 -0
- package/dist/notification/notification-engine.js +78 -0
- package/dist/notification/notification-engine.js.map +1 -0
- package/dist/notification/notification-engine.test.d.ts +2 -0
- package/dist/notification/notification-engine.test.d.ts.map +1 -0
- package/dist/notification/notification-engine.test.js +364 -0
- package/dist/notification/notification-engine.test.js.map +1 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +3 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/model-resolver.d.ts +93 -0
- package/dist/providers/model-resolver.d.ts.map +1 -0
- package/dist/providers/model-resolver.js +152 -0
- package/dist/providers/model-resolver.js.map +1 -0
- package/dist/providers/model-resolver.test.d.ts +2 -0
- package/dist/providers/model-resolver.test.d.ts.map +1 -0
- package/dist/providers/model-resolver.test.js +199 -0
- package/dist/providers/model-resolver.test.js.map +1 -0
- package/dist/providers/noop-providers.d.ts +6 -0
- package/dist/providers/noop-providers.d.ts.map +1 -0
- package/dist/providers/noop-providers.js +15 -0
- package/dist/providers/noop-providers.js.map +1 -0
- package/dist/providers/noop-providers.test.d.ts +2 -0
- package/dist/providers/noop-providers.test.d.ts.map +1 -0
- package/dist/providers/noop-providers.test.js +63 -0
- package/dist/providers/noop-providers.test.js.map +1 -0
- package/dist/providers/provider-interfaces.d.ts +65 -0
- package/dist/providers/provider-interfaces.d.ts.map +1 -0
- package/dist/providers/provider-interfaces.js +2 -0
- package/dist/providers/provider-interfaces.js.map +1 -0
- package/dist/realtime/index.d.ts +3 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +2 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/realtime-manager.d.ts +20 -0
- package/dist/realtime/realtime-manager.d.ts.map +1 -0
- package/dist/realtime/realtime-manager.js +110 -0
- package/dist/realtime/realtime-manager.js.map +1 -0
- package/dist/realtime/realtime-manager.test.d.ts +2 -0
- package/dist/realtime/realtime-manager.test.d.ts.map +1 -0
- package/dist/realtime/realtime-manager.test.js +273 -0
- package/dist/realtime/realtime-manager.test.js.map +1 -0
- package/dist/scoring/compute-score.test.js +1 -1
- package/dist/scoring/index.d.ts +2 -2
- package/dist/scoring/index.js +1 -1
- package/dist/search/cosine-similarity.d.ts +8 -0
- package/dist/search/cosine-similarity.d.ts.map +1 -0
- package/dist/search/cosine-similarity.js +28 -0
- package/dist/search/cosine-similarity.js.map +1 -0
- package/dist/search/cosine-similarity.test.d.ts +2 -0
- package/dist/search/cosine-similarity.test.d.ts.map +1 -0
- package/dist/search/cosine-similarity.test.js +49 -0
- package/dist/search/cosine-similarity.test.js.map +1 -0
- package/dist/search/hybrid-search.d.ts +47 -0
- package/dist/search/hybrid-search.d.ts.map +1 -0
- package/dist/search/hybrid-search.js +111 -0
- package/dist/search/hybrid-search.js.map +1 -0
- package/dist/search/hybrid-search.test.d.ts +2 -0
- package/dist/search/hybrid-search.test.d.ts.map +1 -0
- package/dist/search/hybrid-search.test.js +238 -0
- package/dist/search/hybrid-search.test.js.map +1 -0
- package/dist/search/in-memory-search.d.ts +17 -0
- package/dist/search/in-memory-search.d.ts.map +1 -0
- package/dist/search/in-memory-search.js +59 -0
- package/dist/search/in-memory-search.js.map +1 -0
- package/dist/search/in-memory-search.test.d.ts +2 -0
- package/dist/search/in-memory-search.test.d.ts.map +1 -0
- package/dist/search/in-memory-search.test.js +169 -0
- package/dist/search/in-memory-search.test.js.map +1 -0
- package/dist/search/index.d.ts +6 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +4 -0
- package/dist/search/index.js.map +1 -0
- package/dist/testing/in-memory-agent-store.d.ts +5 -1
- package/dist/testing/in-memory-agent-store.d.ts.map +1 -1
- package/dist/testing/in-memory-agent-store.js +19 -0
- package/dist/testing/in-memory-agent-store.js.map +1 -1
- package/dist/testing/in-memory-agent-store.test.js +1 -1
- package/dist/testing/in-memory-chat-store.d.ts.map +1 -1
- package/dist/testing/in-memory-chat-store.js +2 -1
- package/dist/testing/in-memory-chat-store.js.map +1 -1
- package/dist/testing/in-memory-entity-store.d.ts +5 -1
- package/dist/testing/in-memory-entity-store.d.ts.map +1 -1
- package/dist/testing/in-memory-entity-store.js +69 -4
- package/dist/testing/in-memory-entity-store.js.map +1 -1
- package/dist/testing/in-memory-entity-store.test.js +1 -1
- package/dist/testing/in-memory-memory-store.d.ts +3 -1
- package/dist/testing/in-memory-memory-store.d.ts.map +1 -1
- package/dist/testing/in-memory-memory-store.js +20 -0
- package/dist/testing/in-memory-memory-store.js.map +1 -1
- package/dist/testing/in-memory-tool-store.d.ts +13 -2
- package/dist/testing/in-memory-tool-store.d.ts.map +1 -1
- package/dist/testing/in-memory-tool-store.js +51 -0
- package/dist/testing/in-memory-tool-store.js.map +1 -1
- package/dist/testing/index.d.ts +7 -7
- package/dist/testing/index.js +7 -7
- package/dist/tool/ai-bridge.d.ts +1 -0
- package/dist/tool/ai-bridge.d.ts.map +1 -1
- package/dist/tool/ai-bridge.js +1 -0
- package/dist/tool/ai-bridge.js.map +1 -1
- package/dist/tool/ai-bridge.test.js +1 -1
- package/dist/tool/catalog.d.ts +19 -0
- package/dist/tool/catalog.d.ts.map +1 -0
- package/dist/tool/catalog.js +88 -0
- package/dist/tool/catalog.js.map +1 -0
- package/dist/tool/catalog.test.d.ts +2 -0
- package/dist/tool/catalog.test.d.ts.map +1 -0
- package/dist/tool/catalog.test.js +129 -0
- package/dist/tool/catalog.test.js.map +1 -0
- package/dist/tool/entity-tools-factory.test.js +2 -2
- package/dist/tool/execute-registered-tool.d.ts +17 -0
- package/dist/tool/execute-registered-tool.d.ts.map +1 -0
- package/dist/tool/execute-registered-tool.js +24 -0
- package/dist/tool/execute-registered-tool.js.map +1 -0
- package/dist/tool/execute-registered-tool.test.d.ts +2 -0
- package/dist/tool/execute-registered-tool.test.d.ts.map +1 -0
- package/dist/tool/execute-registered-tool.test.js +73 -0
- package/dist/tool/execute-registered-tool.test.js.map +1 -0
- package/dist/tool/index.d.ts +11 -7
- package/dist/tool/index.d.ts.map +1 -1
- package/dist/tool/index.js +7 -5
- package/dist/tool/index.js.map +1 -1
- package/dist/tool/resolve-tools.d.ts +3 -1
- package/dist/tool/resolve-tools.d.ts.map +1 -1
- package/dist/tool/resolve-tools.js +1 -1
- package/dist/tool/resolve-tools.js.map +1 -1
- package/dist/tool/resolve-tools.test.js +1 -1
- package/dist/tool/tool-executor.d.ts +3 -2
- package/dist/tool/tool-executor.d.ts.map +1 -1
- package/dist/tool/tool-executor.js +4 -2
- package/dist/tool/tool-executor.js.map +1 -1
- package/dist/tool/tool-executor.test.js +2 -2
- package/dist/tool/tool-registry.test.js +1 -1
- package/dist/tool/zod-to-json-schema.d.ts +7 -0
- package/dist/tool/zod-to-json-schema.d.ts.map +1 -0
- package/dist/tool/zod-to-json-schema.js +12 -0
- package/dist/tool/zod-to-json-schema.js.map +1 -0
- package/dist/tool/zod-to-json-schema.test.d.ts +2 -0
- package/dist/tool/zod-to-json-schema.test.d.ts.map +1 -0
- package/dist/tool/zod-to-json-schema.test.js +127 -0
- package/dist/tool/zod-to-json-schema.test.js.map +1 -0
- package/dist/webhook/index.d.ts +4 -0
- package/dist/webhook/index.d.ts.map +1 -0
- package/dist/webhook/index.js +3 -0
- package/dist/webhook/index.js.map +1 -0
- package/dist/webhook/webhook-delivery.d.ts +12 -0
- package/dist/webhook/webhook-delivery.d.ts.map +1 -0
- package/dist/webhook/webhook-delivery.js +102 -0
- package/dist/webhook/webhook-delivery.js.map +1 -0
- package/dist/webhook/webhook-delivery.test.d.ts +2 -0
- package/dist/webhook/webhook-delivery.test.d.ts.map +1 -0
- package/dist/webhook/webhook-delivery.test.js +284 -0
- package/dist/webhook/webhook-delivery.test.js.map +1 -0
- package/dist/webhook/webhook-signer.d.ts +14 -0
- package/dist/webhook/webhook-signer.d.ts.map +1 -0
- package/dist/webhook/webhook-signer.js +31 -0
- package/dist/webhook/webhook-signer.js.map +1 -0
- package/dist/webhook/webhook-signer.test.d.ts +2 -0
- package/dist/webhook/webhook-signer.test.d.ts.map +1 -0
- package/dist/webhook/webhook-signer.test.js +74 -0
- package/dist/webhook/webhook-signer.test.js.map +1 -0
- package/dist/workflow/compile.js +4 -1
- package/dist/workflow/compile.js.map +1 -1
- package/dist/workflow/compile.test.js +1 -1
- package/dist/workflow/evaluate-nodes.d.ts +24 -0
- package/dist/workflow/evaluate-nodes.d.ts.map +1 -0
- package/dist/workflow/evaluate-nodes.js +126 -0
- package/dist/workflow/evaluate-nodes.js.map +1 -0
- package/dist/workflow/evaluate-nodes.test.d.ts +2 -0
- package/dist/workflow/evaluate-nodes.test.d.ts.map +1 -0
- package/dist/workflow/evaluate-nodes.test.js +363 -0
- package/dist/workflow/evaluate-nodes.test.js.map +1 -0
- package/dist/workflow/index.d.ts +8 -3
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +4 -2
- package/dist/workflow/index.js.map +1 -1
- package/dist/workflow/node-executor.d.ts +40 -0
- package/dist/workflow/node-executor.d.ts.map +1 -0
- package/dist/workflow/node-executor.js +2 -0
- package/dist/workflow/node-executor.js.map +1 -0
- package/dist/workflow/node-executor.test.d.ts +2 -0
- package/dist/workflow/node-executor.test.d.ts.map +1 -0
- package/dist/workflow/node-executor.test.js +91 -0
- package/dist/workflow/node-executor.test.js.map +1 -0
- package/dist/workflow/status.test.js +1 -1
- package/dist/workflow/workflow-runner.d.ts +57 -0
- package/dist/workflow/workflow-runner.d.ts.map +1 -0
- package/dist/workflow/workflow-runner.js +263 -0
- package/dist/workflow/workflow-runner.js.map +1 -0
- package/dist/workflow/workflow-runner.test.d.ts +2 -0
- package/dist/workflow/workflow-runner.test.d.ts.map +1 -0
- package/dist/workflow/workflow-runner.test.js +657 -0
- package/dist/workflow/workflow-runner.test.js.map +1 -0
- package/package.json +19 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-signer.test.d.ts","sourceRoot":"","sources":["../../src/webhook/webhook-signer.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createHmac } from 'node:crypto';
|
|
2
|
+
import { describe, it, expect } from 'vitest';
|
|
3
|
+
import { signPayload, verifySignature } from './webhook-signer.js';
|
|
4
|
+
describe('webhook-signer', () => {
|
|
5
|
+
const secret = 'test-webhook-secret-key';
|
|
6
|
+
const payload = JSON.stringify({ event: 'entity.created', data: { id: '123' } });
|
|
7
|
+
describe('signPayload', () => {
|
|
8
|
+
it('produces a sha256-prefixed hex signature', () => {
|
|
9
|
+
const sig = signPayload(payload, secret);
|
|
10
|
+
expect(sig).toMatch(/^sha256=[0-9a-f]{64}$/);
|
|
11
|
+
});
|
|
12
|
+
it('matches manual HMAC-SHA256 computation', () => {
|
|
13
|
+
const sig = signPayload(payload, secret);
|
|
14
|
+
const expected = createHmac('sha256', secret).update(payload).digest('hex');
|
|
15
|
+
expect(sig).toBe(`sha256=${expected}`);
|
|
16
|
+
});
|
|
17
|
+
it('produces deterministic output for same input', () => {
|
|
18
|
+
const sig1 = signPayload(payload, secret);
|
|
19
|
+
const sig2 = signPayload(payload, secret);
|
|
20
|
+
expect(sig1).toBe(sig2);
|
|
21
|
+
});
|
|
22
|
+
it('produces different signatures for different payloads', () => {
|
|
23
|
+
const sig1 = signPayload('payload-a', secret);
|
|
24
|
+
const sig2 = signPayload('payload-b', secret);
|
|
25
|
+
expect(sig1).not.toBe(sig2);
|
|
26
|
+
});
|
|
27
|
+
it('produces different signatures for different secrets', () => {
|
|
28
|
+
const sig1 = signPayload(payload, 'secret-a');
|
|
29
|
+
const sig2 = signPayload(payload, 'secret-b');
|
|
30
|
+
expect(sig1).not.toBe(sig2);
|
|
31
|
+
});
|
|
32
|
+
it('handles empty payload', () => {
|
|
33
|
+
const sig = signPayload('', secret);
|
|
34
|
+
expect(sig).toMatch(/^sha256=[0-9a-f]{64}$/);
|
|
35
|
+
});
|
|
36
|
+
it('handles empty secret', () => {
|
|
37
|
+
const sig = signPayload(payload, '');
|
|
38
|
+
expect(sig).toMatch(/^sha256=[0-9a-f]{64}$/);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
describe('verifySignature', () => {
|
|
42
|
+
it('returns true for a valid signature', () => {
|
|
43
|
+
const sig = signPayload(payload, secret);
|
|
44
|
+
expect(verifySignature(payload, sig, secret)).toBe(true);
|
|
45
|
+
});
|
|
46
|
+
it('returns false for a wrong signature', () => {
|
|
47
|
+
expect(verifySignature(payload, 'sha256=0000000000000000000000000000000000000000000000000000000000000000', secret)).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
it('returns false for a completely malformed signature', () => {
|
|
50
|
+
expect(verifySignature(payload, 'not-a-real-signature', secret)).toBe(false);
|
|
51
|
+
});
|
|
52
|
+
it('returns false for wrong secret', () => {
|
|
53
|
+
const sig = signPayload(payload, secret);
|
|
54
|
+
expect(verifySignature(payload, sig, 'wrong-secret')).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
it('returns false for tampered payload', () => {
|
|
57
|
+
const sig = signPayload(payload, secret);
|
|
58
|
+
expect(verifySignature(payload + 'tampered', sig, secret)).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
it('returns false for empty signature', () => {
|
|
61
|
+
expect(verifySignature(payload, '', secret)).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
it('returns false for signature with wrong length', () => {
|
|
64
|
+
expect(verifySignature(payload, 'sha256=abc', secret)).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
it('is consistent across multiple verifications', () => {
|
|
67
|
+
const sig = signPayload(payload, secret);
|
|
68
|
+
for (let i = 0; i < 10; i++) {
|
|
69
|
+
expect(verifySignature(payload, sig, secret)).toBe(true);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=webhook-signer.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook-signer.test.js","sourceRoot":"","sources":["../../src/webhook/webhook-signer.test.ts"],"names":[],"mappings":"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"}
|
package/dist/workflow/compile.js
CHANGED
|
@@ -100,7 +100,10 @@ function sortFieldsByDependency(fields) {
|
|
|
100
100
|
if (!fieldSet.has(dep))
|
|
101
101
|
continue;
|
|
102
102
|
inDegree.set(name, (inDegree.get(name) ?? 0) + 1);
|
|
103
|
-
dependents.get(dep)
|
|
103
|
+
const depList = dependents.get(dep);
|
|
104
|
+
if (depList) {
|
|
105
|
+
depList.push(name);
|
|
106
|
+
}
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
109
|
const layers = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/workflow/compile.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/workflow/compile.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { compileEntityWorkflowDefinition, getWorkflowLayers } from './compile';
|
|
2
|
+
import { compileEntityWorkflowDefinition, getWorkflowLayers } from './compile.js';
|
|
3
3
|
function makeEntityType(fields) {
|
|
4
4
|
return {
|
|
5
5
|
id: 'et-1',
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { WorkflowNodeRunRecord, WorkflowNodeStatus } from '@sprinterai/core';
|
|
2
|
+
/** A status update to apply to a node run. */
|
|
3
|
+
export interface NodeStatusUpdate {
|
|
4
|
+
nodeRunId: string;
|
|
5
|
+
nodeKey: string;
|
|
6
|
+
previousStatus: WorkflowNodeStatus;
|
|
7
|
+
newStatus: WorkflowNodeStatus;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Evaluate node statuses based on entity content and dependency state.
|
|
11
|
+
*
|
|
12
|
+
* This implements the core scheduling logic:
|
|
13
|
+
* - `wait_human` nodes: completed if field populated, waiting_human if deps met, blocked otherwise
|
|
14
|
+
* - `agent_task` nodes: completed if field populated (unless force), pending if deps met, blocked otherwise
|
|
15
|
+
* - Terminal/in-progress nodes are not re-evaluated (unless force clears completed status)
|
|
16
|
+
*
|
|
17
|
+
* Uses multi-pass convergence: evaluates all nodes, applies changes to a virtual
|
|
18
|
+
* status map, and re-evaluates until no more changes occur. This ensures downstream
|
|
19
|
+
* nodes see their dependencies' new statuses within the same evaluation call.
|
|
20
|
+
*
|
|
21
|
+
* Returns only the nodes whose status changed from their original status.
|
|
22
|
+
*/
|
|
23
|
+
export declare function evaluateNodeStatuses(nodeRuns: WorkflowNodeRunRecord[], entityContent: Record<string, unknown>, force?: boolean): NodeStatusUpdate[];
|
|
24
|
+
//# sourceMappingURL=evaluate-nodes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate-nodes.d.ts","sourceRoot":"","sources":["../../src/workflow/evaluate-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAElF,8CAA8C;AAC9C,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,kBAAkB,CAAC;IACnC,SAAS,EAAE,kBAAkB,CAAC;CAC/B;AAoCD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,qBAAqB,EAAE,EACjC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACtC,KAAK,CAAC,EAAE,OAAO,GACd,gBAAgB,EAAE,CAgEpB"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-progress statuses that should not be re-evaluated.
|
|
3
|
+
* A running node stays running until the executor finishes.
|
|
4
|
+
*/
|
|
5
|
+
const IN_PROGRESS_STATUSES = new Set(['running']);
|
|
6
|
+
/**
|
|
7
|
+
* Check if a field has a non-empty value in entity content.
|
|
8
|
+
* null, undefined, empty string, and empty arrays are considered empty.
|
|
9
|
+
*/
|
|
10
|
+
function fieldHasValue(entityContent, fieldName) {
|
|
11
|
+
const value = entityContent[fieldName];
|
|
12
|
+
if (value === null || value === undefined || value === '')
|
|
13
|
+
return false;
|
|
14
|
+
if (Array.isArray(value) && value.length === 0)
|
|
15
|
+
return false;
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Check whether all dependencies of a node are satisfied (completed)
|
|
20
|
+
* using the resolved status map (which reflects in-progress evaluation).
|
|
21
|
+
*/
|
|
22
|
+
function areDependenciesSatisfied(node, resolvedStatuses) {
|
|
23
|
+
const deps = node.depends_on;
|
|
24
|
+
if (!deps || deps.length === 0)
|
|
25
|
+
return true;
|
|
26
|
+
return deps.every((depKey) => {
|
|
27
|
+
const depStatus = resolvedStatuses.get(depKey);
|
|
28
|
+
return depStatus === 'completed';
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Evaluate node statuses based on entity content and dependency state.
|
|
33
|
+
*
|
|
34
|
+
* This implements the core scheduling logic:
|
|
35
|
+
* - `wait_human` nodes: completed if field populated, waiting_human if deps met, blocked otherwise
|
|
36
|
+
* - `agent_task` nodes: completed if field populated (unless force), pending if deps met, blocked otherwise
|
|
37
|
+
* - Terminal/in-progress nodes are not re-evaluated (unless force clears completed status)
|
|
38
|
+
*
|
|
39
|
+
* Uses multi-pass convergence: evaluates all nodes, applies changes to a virtual
|
|
40
|
+
* status map, and re-evaluates until no more changes occur. This ensures downstream
|
|
41
|
+
* nodes see their dependencies' new statuses within the same evaluation call.
|
|
42
|
+
*
|
|
43
|
+
* Returns only the nodes whose status changed from their original status.
|
|
44
|
+
*/
|
|
45
|
+
export function evaluateNodeStatuses(nodeRuns, entityContent, force) {
|
|
46
|
+
if (nodeRuns.length === 0)
|
|
47
|
+
return [];
|
|
48
|
+
// Build lookup maps
|
|
49
|
+
const nodesByKey = new Map();
|
|
50
|
+
const originalStatuses = new Map();
|
|
51
|
+
const resolvedStatuses = new Map();
|
|
52
|
+
for (const node of nodeRuns) {
|
|
53
|
+
nodesByKey.set(node.node_key, node);
|
|
54
|
+
originalStatuses.set(node.node_key, node.status);
|
|
55
|
+
resolvedStatuses.set(node.node_key, node.status);
|
|
56
|
+
}
|
|
57
|
+
// Multi-pass: keep evaluating until no more changes
|
|
58
|
+
const maxPasses = nodeRuns.length + 1; // At most N passes for N-deep dependency chains
|
|
59
|
+
for (let pass = 0; pass < maxPasses; pass++) {
|
|
60
|
+
let changed = false;
|
|
61
|
+
for (const node of nodeRuns) {
|
|
62
|
+
const currentResolved = resolvedStatuses.get(node.node_key);
|
|
63
|
+
// Running nodes are never re-evaluated -- they're in-flight
|
|
64
|
+
if (IN_PROGRESS_STATUSES.has(currentResolved)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
// Failed/skipped nodes are terminal -- never re-evaluated
|
|
68
|
+
if (currentResolved === 'failed' || currentResolved === 'skipped') {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
// Completed nodes stay completed unless force is specified
|
|
72
|
+
if (currentResolved === 'completed' && !force) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const newStatus = evaluateSingleNode(node, entityContent, resolvedStatuses, force);
|
|
76
|
+
if (newStatus !== currentResolved) {
|
|
77
|
+
resolvedStatuses.set(node.node_key, newStatus);
|
|
78
|
+
changed = true;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!changed)
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
// Build updates: compare original vs resolved
|
|
85
|
+
const updates = [];
|
|
86
|
+
for (const node of nodeRuns) {
|
|
87
|
+
const original = originalStatuses.get(node.node_key);
|
|
88
|
+
const resolved = resolvedStatuses.get(node.node_key);
|
|
89
|
+
if (resolved !== original) {
|
|
90
|
+
updates.push({
|
|
91
|
+
nodeRunId: node.id,
|
|
92
|
+
nodeKey: node.node_key,
|
|
93
|
+
previousStatus: original,
|
|
94
|
+
newStatus: resolved,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return updates;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Evaluate the desired status for a single node.
|
|
102
|
+
*/
|
|
103
|
+
function evaluateSingleNode(node, entityContent, resolvedStatuses, force) {
|
|
104
|
+
const hasFieldValue = node.field_name ? fieldHasValue(entityContent, node.field_name) : false;
|
|
105
|
+
const depsSatisfied = areDependenciesSatisfied(node, resolvedStatuses);
|
|
106
|
+
if (node.node_type === 'wait_human') {
|
|
107
|
+
// Human-input nodes complete when the field is populated
|
|
108
|
+
if (hasFieldValue)
|
|
109
|
+
return 'completed';
|
|
110
|
+
// If deps are met, wait for human input
|
|
111
|
+
if (depsSatisfied)
|
|
112
|
+
return 'waiting_human';
|
|
113
|
+
// Otherwise blocked
|
|
114
|
+
return 'blocked';
|
|
115
|
+
}
|
|
116
|
+
// agent_task (and legacy types)
|
|
117
|
+
// If field already has a value and we're not forcing, mark completed
|
|
118
|
+
if (hasFieldValue && !force)
|
|
119
|
+
return 'completed';
|
|
120
|
+
// If deps are met, mark pending (ready to be claimed)
|
|
121
|
+
if (depsSatisfied)
|
|
122
|
+
return 'pending';
|
|
123
|
+
// Otherwise blocked
|
|
124
|
+
return 'blocked';
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=evaluate-nodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate-nodes.js","sourceRoot":"","sources":["../../src/workflow/evaluate-nodes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate-nodes.test.d.ts","sourceRoot":"","sources":["../../src/workflow/evaluate-nodes.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { evaluateNodeStatuses } from './evaluate-nodes.js';
|
|
3
|
+
function makeNodeRun(overrides) {
|
|
4
|
+
const { node_key, ...rest } = overrides;
|
|
5
|
+
return {
|
|
6
|
+
id: `nr-${node_key}`,
|
|
7
|
+
workflow_run_id: 'run-1',
|
|
8
|
+
entity_id: 'ent-1',
|
|
9
|
+
tenant_id: 'ten-1',
|
|
10
|
+
node_key,
|
|
11
|
+
node_type: 'agent_task',
|
|
12
|
+
label: node_key,
|
|
13
|
+
field_name: null,
|
|
14
|
+
block_id: null,
|
|
15
|
+
output_type: 'field',
|
|
16
|
+
status: 'pending',
|
|
17
|
+
assignee_type: 'agent',
|
|
18
|
+
assignee_agent_slug: null,
|
|
19
|
+
depends_on: null,
|
|
20
|
+
instructions: null,
|
|
21
|
+
metadata: null,
|
|
22
|
+
error_message: null,
|
|
23
|
+
claimed_by: null,
|
|
24
|
+
claimed_at: null,
|
|
25
|
+
attempt_count: 0,
|
|
26
|
+
started_at: null,
|
|
27
|
+
completed_at: null,
|
|
28
|
+
duration_ms: null,
|
|
29
|
+
created_at: new Date().toISOString(),
|
|
30
|
+
...rest,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
describe('evaluateNodeStatuses', () => {
|
|
34
|
+
describe('agent_task nodes', () => {
|
|
35
|
+
it('marks nodes pending when no deps and no existing value', () => {
|
|
36
|
+
const nodes = [
|
|
37
|
+
makeNodeRun({
|
|
38
|
+
node_key: 'agent_task:title',
|
|
39
|
+
field_name: 'title',
|
|
40
|
+
status: 'blocked',
|
|
41
|
+
}),
|
|
42
|
+
];
|
|
43
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
44
|
+
expect(updates).toHaveLength(1);
|
|
45
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
46
|
+
});
|
|
47
|
+
it('marks nodes completed when field already has value', () => {
|
|
48
|
+
const nodes = [
|
|
49
|
+
makeNodeRun({
|
|
50
|
+
node_key: 'agent_task:title',
|
|
51
|
+
field_name: 'title',
|
|
52
|
+
status: 'pending',
|
|
53
|
+
}),
|
|
54
|
+
];
|
|
55
|
+
const updates = evaluateNodeStatuses(nodes, { title: 'My Title' });
|
|
56
|
+
expect(updates).toHaveLength(1);
|
|
57
|
+
expect(updates[0].newStatus).toBe('completed');
|
|
58
|
+
});
|
|
59
|
+
it('keeps nodes blocked when deps not satisfied', () => {
|
|
60
|
+
const nodes = [
|
|
61
|
+
makeNodeRun({
|
|
62
|
+
node_key: 'agent_task:title',
|
|
63
|
+
field_name: 'title',
|
|
64
|
+
status: 'completed',
|
|
65
|
+
}),
|
|
66
|
+
makeNodeRun({
|
|
67
|
+
node_key: 'agent_task:summary',
|
|
68
|
+
field_name: 'summary',
|
|
69
|
+
status: 'blocked',
|
|
70
|
+
depends_on: ['agent_task:title'],
|
|
71
|
+
}),
|
|
72
|
+
];
|
|
73
|
+
// title dep is completed but summary field empty -> pending (deps satisfied)
|
|
74
|
+
const updates = evaluateNodeStatuses(nodes, { title: 'value' });
|
|
75
|
+
expect(updates).toHaveLength(1);
|
|
76
|
+
expect(updates[0].nodeKey).toBe('agent_task:summary');
|
|
77
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
78
|
+
});
|
|
79
|
+
it('stays blocked when dependency is not completed', () => {
|
|
80
|
+
const nodes = [
|
|
81
|
+
makeNodeRun({
|
|
82
|
+
node_key: 'agent_task:title',
|
|
83
|
+
field_name: 'title',
|
|
84
|
+
status: 'pending',
|
|
85
|
+
}),
|
|
86
|
+
makeNodeRun({
|
|
87
|
+
node_key: 'agent_task:summary',
|
|
88
|
+
field_name: 'summary',
|
|
89
|
+
status: 'blocked',
|
|
90
|
+
depends_on: ['agent_task:title'],
|
|
91
|
+
}),
|
|
92
|
+
];
|
|
93
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
94
|
+
// title stays pending (no change), summary stays blocked (no change)
|
|
95
|
+
expect(updates).toHaveLength(0);
|
|
96
|
+
});
|
|
97
|
+
it('does not re-evaluate running nodes', () => {
|
|
98
|
+
const nodes = [
|
|
99
|
+
makeNodeRun({
|
|
100
|
+
node_key: 'agent_task:title',
|
|
101
|
+
field_name: 'title',
|
|
102
|
+
status: 'running',
|
|
103
|
+
}),
|
|
104
|
+
];
|
|
105
|
+
const updates = evaluateNodeStatuses(nodes, { title: 'already populated' });
|
|
106
|
+
expect(updates).toHaveLength(0);
|
|
107
|
+
});
|
|
108
|
+
it('does not re-evaluate failed nodes', () => {
|
|
109
|
+
const nodes = [
|
|
110
|
+
makeNodeRun({
|
|
111
|
+
node_key: 'agent_task:title',
|
|
112
|
+
field_name: 'title',
|
|
113
|
+
status: 'failed',
|
|
114
|
+
}),
|
|
115
|
+
];
|
|
116
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
117
|
+
expect(updates).toHaveLength(0);
|
|
118
|
+
});
|
|
119
|
+
it('does not re-evaluate skipped nodes', () => {
|
|
120
|
+
const nodes = [
|
|
121
|
+
makeNodeRun({
|
|
122
|
+
node_key: 'agent_task:title',
|
|
123
|
+
field_name: 'title',
|
|
124
|
+
status: 'skipped',
|
|
125
|
+
}),
|
|
126
|
+
];
|
|
127
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
128
|
+
expect(updates).toHaveLength(0);
|
|
129
|
+
});
|
|
130
|
+
it('does not re-evaluate completed nodes without force', () => {
|
|
131
|
+
const nodes = [
|
|
132
|
+
makeNodeRun({
|
|
133
|
+
node_key: 'agent_task:title',
|
|
134
|
+
field_name: 'title',
|
|
135
|
+
status: 'completed',
|
|
136
|
+
}),
|
|
137
|
+
];
|
|
138
|
+
const updates = evaluateNodeStatuses(nodes, { title: 'value' });
|
|
139
|
+
expect(updates).toHaveLength(0);
|
|
140
|
+
});
|
|
141
|
+
it('force allows re-evaluating completed nodes to pending', () => {
|
|
142
|
+
const nodes = [
|
|
143
|
+
makeNodeRun({
|
|
144
|
+
node_key: 'agent_task:title',
|
|
145
|
+
field_name: 'title',
|
|
146
|
+
status: 'completed',
|
|
147
|
+
}),
|
|
148
|
+
];
|
|
149
|
+
// With force=true and field populated, the node should still become pending
|
|
150
|
+
// because force overrides the "field has value => completed" logic
|
|
151
|
+
const updates = evaluateNodeStatuses(nodes, { title: 'value' }, true);
|
|
152
|
+
// With force, field has value check is bypassed -> deps satisfied -> pending
|
|
153
|
+
expect(updates).toHaveLength(1);
|
|
154
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
155
|
+
});
|
|
156
|
+
it('force re-evaluates completed nodes to pending when field has value', () => {
|
|
157
|
+
const nodes = [
|
|
158
|
+
makeNodeRun({
|
|
159
|
+
node_key: 'agent_task:title',
|
|
160
|
+
field_name: 'title',
|
|
161
|
+
status: 'completed',
|
|
162
|
+
}),
|
|
163
|
+
];
|
|
164
|
+
const updates = evaluateNodeStatuses(nodes, {}, true);
|
|
165
|
+
expect(updates).toHaveLength(1);
|
|
166
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe('wait_human nodes', () => {
|
|
170
|
+
it('marks waiting_human when deps satisfied and no field value', () => {
|
|
171
|
+
const nodes = [
|
|
172
|
+
makeNodeRun({
|
|
173
|
+
node_key: 'wait_human:notes',
|
|
174
|
+
node_type: 'wait_human',
|
|
175
|
+
field_name: 'notes',
|
|
176
|
+
status: 'blocked',
|
|
177
|
+
}),
|
|
178
|
+
];
|
|
179
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
180
|
+
expect(updates).toHaveLength(1);
|
|
181
|
+
expect(updates[0].newStatus).toBe('waiting_human');
|
|
182
|
+
});
|
|
183
|
+
it('marks completed when field has value', () => {
|
|
184
|
+
const nodes = [
|
|
185
|
+
makeNodeRun({
|
|
186
|
+
node_key: 'wait_human:notes',
|
|
187
|
+
node_type: 'wait_human',
|
|
188
|
+
field_name: 'notes',
|
|
189
|
+
status: 'waiting_human',
|
|
190
|
+
}),
|
|
191
|
+
];
|
|
192
|
+
const updates = evaluateNodeStatuses(nodes, { notes: 'User provided notes' });
|
|
193
|
+
expect(updates).toHaveLength(1);
|
|
194
|
+
expect(updates[0].newStatus).toBe('completed');
|
|
195
|
+
});
|
|
196
|
+
it('stays blocked when deps not met', () => {
|
|
197
|
+
const nodes = [
|
|
198
|
+
makeNodeRun({
|
|
199
|
+
node_key: 'agent_task:title',
|
|
200
|
+
field_name: 'title',
|
|
201
|
+
status: 'pending',
|
|
202
|
+
}),
|
|
203
|
+
makeNodeRun({
|
|
204
|
+
node_key: 'wait_human:notes',
|
|
205
|
+
node_type: 'wait_human',
|
|
206
|
+
field_name: 'notes',
|
|
207
|
+
status: 'blocked',
|
|
208
|
+
depends_on: ['agent_task:title'],
|
|
209
|
+
}),
|
|
210
|
+
];
|
|
211
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
212
|
+
// notes stays blocked
|
|
213
|
+
expect(updates).toHaveLength(0);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
describe('empty field value detection', () => {
|
|
217
|
+
it('treats null as empty', () => {
|
|
218
|
+
const nodes = [
|
|
219
|
+
makeNodeRun({
|
|
220
|
+
node_key: 'agent_task:title',
|
|
221
|
+
field_name: 'title',
|
|
222
|
+
status: 'blocked',
|
|
223
|
+
}),
|
|
224
|
+
];
|
|
225
|
+
const updates = evaluateNodeStatuses(nodes, { title: null });
|
|
226
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
227
|
+
});
|
|
228
|
+
it('treats undefined as empty', () => {
|
|
229
|
+
const nodes = [
|
|
230
|
+
makeNodeRun({
|
|
231
|
+
node_key: 'agent_task:title',
|
|
232
|
+
field_name: 'title',
|
|
233
|
+
status: 'blocked',
|
|
234
|
+
}),
|
|
235
|
+
];
|
|
236
|
+
const updates = evaluateNodeStatuses(nodes, { title: undefined });
|
|
237
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
238
|
+
});
|
|
239
|
+
it('treats empty string as empty', () => {
|
|
240
|
+
const nodes = [
|
|
241
|
+
makeNodeRun({
|
|
242
|
+
node_key: 'agent_task:title',
|
|
243
|
+
field_name: 'title',
|
|
244
|
+
status: 'blocked',
|
|
245
|
+
}),
|
|
246
|
+
];
|
|
247
|
+
const updates = evaluateNodeStatuses(nodes, { title: '' });
|
|
248
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
249
|
+
});
|
|
250
|
+
it('treats empty array as empty', () => {
|
|
251
|
+
const nodes = [
|
|
252
|
+
makeNodeRun({
|
|
253
|
+
node_key: 'agent_task:tags',
|
|
254
|
+
field_name: 'tags',
|
|
255
|
+
status: 'blocked',
|
|
256
|
+
}),
|
|
257
|
+
];
|
|
258
|
+
const updates = evaluateNodeStatuses(nodes, { tags: [] });
|
|
259
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
260
|
+
});
|
|
261
|
+
it('treats non-empty array as populated', () => {
|
|
262
|
+
const nodes = [
|
|
263
|
+
makeNodeRun({
|
|
264
|
+
node_key: 'agent_task:tags',
|
|
265
|
+
field_name: 'tags',
|
|
266
|
+
status: 'pending',
|
|
267
|
+
}),
|
|
268
|
+
];
|
|
269
|
+
const updates = evaluateNodeStatuses(nodes, { tags: ['a'] });
|
|
270
|
+
expect(updates[0].newStatus).toBe('completed');
|
|
271
|
+
});
|
|
272
|
+
it('treats zero as populated', () => {
|
|
273
|
+
const nodes = [
|
|
274
|
+
makeNodeRun({
|
|
275
|
+
node_key: 'agent_task:count',
|
|
276
|
+
field_name: 'count',
|
|
277
|
+
status: 'pending',
|
|
278
|
+
}),
|
|
279
|
+
];
|
|
280
|
+
const updates = evaluateNodeStatuses(nodes, { count: 0 });
|
|
281
|
+
expect(updates[0].newStatus).toBe('completed');
|
|
282
|
+
});
|
|
283
|
+
it('treats false as populated', () => {
|
|
284
|
+
const nodes = [
|
|
285
|
+
makeNodeRun({
|
|
286
|
+
node_key: 'agent_task:active',
|
|
287
|
+
field_name: 'active',
|
|
288
|
+
status: 'pending',
|
|
289
|
+
}),
|
|
290
|
+
];
|
|
291
|
+
const updates = evaluateNodeStatuses(nodes, { active: false });
|
|
292
|
+
expect(updates[0].newStatus).toBe('completed');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
describe('complex dependency graphs', () => {
|
|
296
|
+
it('handles diamond dependencies (A -> B, A -> C, B+C -> D)', () => {
|
|
297
|
+
const nodes = [
|
|
298
|
+
makeNodeRun({
|
|
299
|
+
node_key: 'agent_task:a',
|
|
300
|
+
field_name: 'a',
|
|
301
|
+
status: 'completed',
|
|
302
|
+
}),
|
|
303
|
+
makeNodeRun({
|
|
304
|
+
node_key: 'agent_task:b',
|
|
305
|
+
field_name: 'b',
|
|
306
|
+
status: 'blocked',
|
|
307
|
+
depends_on: ['agent_task:a'],
|
|
308
|
+
}),
|
|
309
|
+
makeNodeRun({
|
|
310
|
+
node_key: 'agent_task:c',
|
|
311
|
+
field_name: 'c',
|
|
312
|
+
status: 'blocked',
|
|
313
|
+
depends_on: ['agent_task:a'],
|
|
314
|
+
}),
|
|
315
|
+
makeNodeRun({
|
|
316
|
+
node_key: 'agent_task:d',
|
|
317
|
+
field_name: 'd',
|
|
318
|
+
status: 'blocked',
|
|
319
|
+
depends_on: ['agent_task:b', 'agent_task:c'],
|
|
320
|
+
}),
|
|
321
|
+
];
|
|
322
|
+
const updates = evaluateNodeStatuses(nodes, { a: 'done' });
|
|
323
|
+
// b and c should become pending, d stays blocked
|
|
324
|
+
const updateMap = new Map(updates.map((u) => [u.nodeKey, u.newStatus]));
|
|
325
|
+
expect(updateMap.get('agent_task:b')).toBe('pending');
|
|
326
|
+
expect(updateMap.get('agent_task:c')).toBe('pending');
|
|
327
|
+
expect(updateMap.has('agent_task:d')).toBe(false); // stays blocked
|
|
328
|
+
});
|
|
329
|
+
it('handles nodes without field_name', () => {
|
|
330
|
+
const nodes = [
|
|
331
|
+
makeNodeRun({
|
|
332
|
+
node_key: 'agent_task:process',
|
|
333
|
+
field_name: null,
|
|
334
|
+
status: 'blocked',
|
|
335
|
+
output_type: 'none',
|
|
336
|
+
}),
|
|
337
|
+
];
|
|
338
|
+
// No field_name means hasFieldValue is false -> deps satisfied -> pending
|
|
339
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
340
|
+
expect(updates).toHaveLength(1);
|
|
341
|
+
expect(updates[0].newStatus).toBe('pending');
|
|
342
|
+
});
|
|
343
|
+
});
|
|
344
|
+
describe('no changes', () => {
|
|
345
|
+
it('returns empty array when no status changes needed', () => {
|
|
346
|
+
const nodes = [
|
|
347
|
+
makeNodeRun({
|
|
348
|
+
node_key: 'agent_task:title',
|
|
349
|
+
field_name: 'title',
|
|
350
|
+
status: 'pending',
|
|
351
|
+
}),
|
|
352
|
+
];
|
|
353
|
+
// pending with no deps and no field value -> stays pending
|
|
354
|
+
const updates = evaluateNodeStatuses(nodes, {});
|
|
355
|
+
expect(updates).toHaveLength(0);
|
|
356
|
+
});
|
|
357
|
+
it('returns empty for empty input', () => {
|
|
358
|
+
const updates = evaluateNodeStatuses([], {});
|
|
359
|
+
expect(updates).toHaveLength(0);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
});
|
|
363
|
+
//# sourceMappingURL=evaluate-nodes.test.js.map
|