@ai-setting/roy-agent-core 1.3.10 → 1.3.11
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/dist/config/index.js +1647 -0
- package/dist/index.js +12579 -89691
- package/package.json +19 -56
- package/src/config/config-component.test.ts +0 -627
- package/src/config/config-component.ts +0 -906
- package/src/config/config-parser.test.ts +0 -319
- package/src/config/config-parser.ts +0 -203
- package/src/config/decentralized-config.test.ts +0 -740
- package/src/config/env-key.ts +0 -210
- package/src/config/env-source.test.ts +0 -252
- package/src/config/env-source.ts +0 -301
- package/src/config/file-source.test.ts +0 -357
- package/src/config/file-source.ts +0 -421
- package/src/config/index.ts +0 -24
- package/src/config/protocol-resolver.test.ts +0 -217
- package/src/config/protocol-resolver.ts +0 -228
- package/src/env/agent/agent-component.abort.test.ts +0 -511
- package/src/env/agent/agent-component.record-session.test.ts +0 -349
- package/src/env/agent/agent-component.test.ts +0 -1389
- package/src/env/agent/agent-component.tool-error.test.ts +0 -327
- package/src/env/agent/agent-component.ts +0 -1711
- package/src/env/agent/agent-config-registration.test.ts +0 -226
- package/src/env/agent/agent-config-registration.ts +0 -46
- package/src/env/agent/agent-reminder-plugin.integration.test.ts +0 -243
- package/src/env/agent/index.ts +0 -10
- package/src/env/agent/summary-agent.parse-hint.test.ts +0 -360
- package/src/env/agent/summary-agent.ts +0 -508
- package/src/env/agent/types.ts +0 -536
- package/src/env/commands/commands-component.test.ts +0 -364
- package/src/env/commands/commands-component.ts +0 -604
- package/src/env/commands/commands-config-registration.test.ts +0 -198
- package/src/env/commands/commands-config-registration.ts +0 -38
- package/src/env/commands/index.ts +0 -21
- package/src/env/commands/parser.test.ts +0 -203
- package/src/env/commands/parser.ts +0 -115
- package/src/env/commands/types.ts +0 -184
- package/src/env/commands-prompt-integration.test.ts +0 -243
- package/src/env/component-env.test.ts +0 -119
- package/src/env/component.ts +0 -335
- package/src/env/constants.test.ts +0 -72
- package/src/env/constants.ts +0 -123
- package/src/env/debug/debug-component.test.ts +0 -114
- package/src/env/debug/debug-component.ts +0 -547
- package/src/env/debug/formatters/index.ts +0 -9
- package/src/env/debug/formatters/repl-formatter.test.ts +0 -139
- package/src/env/debug/formatters/repl-formatter.ts +0 -358
- package/src/env/debug/formatters/trace-formatter.test.ts +0 -119
- package/src/env/debug/formatters/trace-formatter.ts +0 -191
- package/src/env/debug/formatters/tree-formatter.test.ts +0 -107
- package/src/env/debug/formatters/tree-formatter.ts +0 -325
- package/src/env/debug/index.ts +0 -38
- package/src/env/debug/parser/regex-parser.test.ts +0 -201
- package/src/env/debug/parser/regex-parser.ts +0 -196
- package/src/env/debug/parser/span-builder.test.ts +0 -241
- package/src/env/debug/parser/span-builder.ts +0 -386
- package/src/env/debug/reader/log-reader.test.ts +0 -170
- package/src/env/debug/reader/log-reader.ts +0 -186
- package/src/env/debug/reader/span-db-reader.test.ts +0 -118
- package/src/env/debug/reader/span-db-reader.ts +0 -201
- package/src/env/debug/types.test.ts +0 -187
- package/src/env/debug/types.ts +0 -171
- package/src/env/environment-init.test.ts +0 -183
- package/src/env/environment-lifecycle.test.ts +0 -516
- package/src/env/environment-service.test.ts +0 -332
- package/src/env/environment.handle-query.test.ts +0 -96
- package/src/env/environment.test.ts +0 -232
- package/src/env/environment.ts +0 -708
- package/src/env/errors.test.ts +0 -165
- package/src/env/errors.ts +0 -157
- package/src/env/event-source/event-source-agent-handler.test.ts +0 -193
- package/src/env/event-source/event-source-agent-handler.ts +0 -111
- package/src/env/event-source/event-source-component.process-cleanup.test.ts +0 -236
- package/src/env/event-source/event-source-component.stop.test.ts +0 -346
- package/src/env/event-source/event-source-component.test.ts +0 -1207
- package/src/env/event-source/event-source-component.ts +0 -1379
- package/src/env/event-source/event-source-config-registration.test.ts +0 -242
- package/src/env/event-source/event-source-config-registration.ts +0 -37
- package/src/env/event-source/event-source-integration.test.ts +0 -320
- package/src/env/event-source/event-source-platform.test.ts +0 -630
- package/src/env/event-source/types.ts +0 -298
- package/src/env/hook/global-hook-manager.ts +0 -162
- package/src/env/hook/hook-manager.test.ts +0 -374
- package/src/env/hook/hook-manager.ts +0 -309
- package/src/env/hook/index.ts +0 -38
- package/src/env/hook/types.ts +0 -138
- package/src/env/index.ts +0 -144
- package/src/env/interface.ts +0 -203
- package/src/env/llm/hooks.test.ts +0 -293
- package/src/env/llm/hooks.ts +0 -316
- package/src/env/llm/index.ts +0 -61
- package/src/env/llm/invoke-threshold-check.test.ts +0 -88
- package/src/env/llm/invoke-timeout.test.ts +0 -54
- package/src/env/llm/invoke.test.ts +0 -71
- package/src/env/llm/invoke.ts +0 -1039
- package/src/env/llm/llm-config.test.ts +0 -523
- package/src/env/llm/llm.test.ts +0 -233
- package/src/env/llm/llm.ts +0 -568
- package/src/env/llm/provider.test.ts +0 -182
- package/src/env/llm/provider.ts +0 -108
- package/src/env/llm/transform.test.ts +0 -251
- package/src/env/llm/transform.ts +0 -286
- package/src/env/llm/types.test.ts +0 -580
- package/src/env/llm/types.ts +0 -424
- package/src/env/log-trace/decorator-otel.test.ts +0 -182
- package/src/env/log-trace/decorator.ts +0 -230
- package/src/env/log-trace/index.ts +0 -79
- package/src/env/log-trace/log-trace-component.test.ts +0 -242
- package/src/env/log-trace/log-trace-component.ts +0 -497
- package/src/env/log-trace/log-trace-config-registration.test.ts +0 -348
- package/src/env/log-trace/log-trace-config-registration.ts +0 -45
- package/src/env/log-trace/logger.test.ts +0 -149
- package/src/env/log-trace/logger.ts +0 -522
- package/src/env/log-trace/opentelemetry/cli-propagation.test.ts +0 -147
- package/src/env/log-trace/opentelemetry/cli-propagation.ts +0 -194
- package/src/env/log-trace/opentelemetry/integration.test.ts +0 -668
- package/src/env/log-trace/opentelemetry/mod.ts +0 -25
- package/src/env/log-trace/opentelemetry/propagation-env.test.ts +0 -181
- package/src/env/log-trace/opentelemetry/propagation-env.ts +0 -136
- package/src/env/log-trace/opentelemetry/propagation.test.ts +0 -259
- package/src/env/log-trace/opentelemetry/propagation.ts +0 -215
- package/src/env/log-trace/opentelemetry/tracer-provider-context.test.ts +0 -166
- package/src/env/log-trace/opentelemetry/tracer-provider.test.ts +0 -379
- package/src/env/log-trace/opentelemetry/tracer-provider.ts +0 -612
- package/src/env/log-trace/span-storage.test.ts +0 -145
- package/src/env/log-trace/span-storage.ts +0 -230
- package/src/env/log-trace/trace-context.test.ts +0 -187
- package/src/env/log-trace/trace-context.ts +0 -162
- package/src/env/log-trace/types.test.ts +0 -63
- package/src/env/log-trace/types.ts +0 -172
- package/src/env/mcp/README.md +0 -244
- package/src/env/mcp/__integration__/mcp-component.integration.test.ts +0 -373
- package/src/env/mcp/config.test.ts +0 -74
- package/src/env/mcp/config.ts +0 -116
- package/src/env/mcp/index.ts +0 -41
- package/src/env/mcp/loader.test.ts +0 -161
- package/src/env/mcp/loader.ts +0 -209
- package/src/env/mcp/mcp-component.test.ts +0 -111
- package/src/env/mcp/mcp-component.ts +0 -358
- package/src/env/mcp/mcp-config-registration.test.ts +0 -304
- package/src/env/mcp/mcp-config-registration.ts +0 -50
- package/src/env/mcp/scanner.test.ts +0 -170
- package/src/env/mcp/scanner.ts +0 -246
- package/src/env/mcp/tool/adapter.test.ts +0 -520
- package/src/env/mcp/tool/adapter.ts +0 -521
- package/src/env/mcp/tool/index.ts +0 -5
- package/src/env/mcp/types.test.ts +0 -171
- package/src/env/mcp/types.ts +0 -79
- package/src/env/memory/README.md +0 -177
- package/src/env/memory/built-in/index.ts +0 -59
- package/src/env/memory/built-in/recall-memory.ts +0 -103
- package/src/env/memory/built-in/record-memory.ts +0 -148
- package/src/env/memory/index.ts +0 -20
- package/src/env/memory/memory-component.test.ts +0 -239
- package/src/env/memory/memory-component.ts +0 -503
- package/src/env/memory/memory-config-registration.test.ts +0 -67
- package/src/env/memory/memory-config-registration.ts +0 -48
- package/src/env/memory/memory-config.ts +0 -45
- package/src/env/memory/memory-file.test.ts +0 -268
- package/src/env/memory/plugin/index.ts +0 -48
- package/src/env/memory/plugin/memory-agent.test.ts +0 -249
- package/src/env/memory/plugin/memory-agent.ts +0 -365
- package/src/env/memory/plugin/memory-manager.ts +0 -198
- package/src/env/memory/plugin/memory-plugin-agent.test.ts +0 -145
- package/src/env/memory/plugin/memory-plugin.ts +0 -210
- package/src/env/memory/plugin/plugin-simplified.test.ts +0 -51
- package/src/env/memory/plugin/recall-memory.test.ts +0 -106
- package/src/env/memory/plugin/recall-memory.ts +0 -53
- package/src/env/memory/plugin/types.ts +0 -101
- package/src/env/memory/tools/memory-agent-tools.ts +0 -228
- package/src/env/memory/types.ts +0 -85
- package/src/env/paths.ts +0 -118
- package/src/env/prompt/index.ts +0 -18
- package/src/env/prompt/memory-prompts.test.ts +0 -91
- package/src/env/prompt/prompt-component.test.ts +0 -491
- package/src/env/prompt/prompt-component.ts +0 -619
- package/src/env/prompt/prompt-config-registration.test.ts +0 -213
- package/src/env/prompt/prompt-config-registration.ts +0 -39
- package/src/env/prompt/prompts-index.ts +0 -504
- package/src/env/prompt/renderer.ts +0 -67
- package/src/env/prompt/types.ts +0 -136
- package/src/env/session/hooks.ts +0 -18
- package/src/env/session/index.ts +0 -37
- package/src/env/session/search-query-parser.test.ts +0 -425
- package/src/env/session/search-query-parser.ts +0 -171
- package/src/env/session/session-checkpoint.test.ts +0 -523
- package/src/env/session/session-component.extract-recent-messages.test.ts +0 -209
- package/src/env/session/session-component.test.ts +0 -132
- package/src/env/session/session-component.ts +0 -1249
- package/src/env/session/session-config-registration.test.ts +0 -138
- package/src/env/session/session-config-registration.ts +0 -52
- package/src/env/session/session-message-converter.test.ts +0 -763
- package/src/env/session/session-message-converter.ts +0 -415
- package/src/env/session/session-message-e2e.test.ts +0 -448
- package/src/env/session/session-search.test.ts +0 -391
- package/src/env/session/session-store.test.ts +0 -362
- package/src/env/session/session-store.ts +0 -141
- package/src/env/session/storage/index.ts +0 -6
- package/src/env/session/storage/memory.ts +0 -502
- package/src/env/session/storage/sqlite.ts +0 -794
- package/src/env/session/types.ts +0 -742
- package/src/env/skill/config.ts +0 -39
- package/src/env/skill/index.ts +0 -6
- package/src/env/skill/parser.test.ts +0 -116
- package/src/env/skill/parser.ts +0 -77
- package/src/env/skill/scanner.test.ts +0 -211
- package/src/env/skill/scanner.ts +0 -119
- package/src/env/skill/skill-component.test.ts +0 -234
- package/src/env/skill/skill-component.ts +0 -352
- package/src/env/skill/skill-config-registration.test.ts +0 -60
- package/src/env/skill/skill-config-registration.ts +0 -43
- package/src/env/skill/tool/index.ts +0 -1
- package/src/env/skill/tool/skill-tool.test.ts +0 -100
- package/src/env/skill/tool/skill-tool.ts +0 -72
- package/src/env/skill/types.ts +0 -64
- package/src/env/task/delegate/delegate-tool.test.ts +0 -498
- package/src/env/task/delegate/delegate-tool.ts +0 -1014
- package/src/env/task/delegate/index.ts +0 -18
- package/src/env/task/delegate/stop-tool.test.ts +0 -140
- package/src/env/task/delegate/stop-tool.ts +0 -119
- package/src/env/task/delegate/task-events.test.ts +0 -178
- package/src/env/task/delegate/task-events.ts +0 -143
- package/src/env/task/hooks/contexts.test.ts +0 -92
- package/src/env/task/hooks/contexts.ts +0 -192
- package/src/env/task/hooks/index.ts +0 -23
- package/src/env/task/hooks/task-hook-points.test.ts +0 -32
- package/src/env/task/hooks/task-hook-points.ts +0 -54
- package/src/env/task/index.ts +0 -7
- package/src/env/task/plugins/index.ts +0 -13
- package/src/env/task/plugins/task-plugin.test.ts +0 -74
- package/src/env/task/plugins/task-plugin.ts +0 -89
- package/src/env/task/plugins/task-tag-plugin.test.ts +0 -377
- package/src/env/task/plugins/task-tag-plugin.ts +0 -319
- package/src/env/task/plugins/task-workflow-extractor.integration.test.ts +0 -226
- package/src/env/task/plugins/workflow-extractor-agent.test.ts +0 -107
- package/src/env/task/plugins/workflow-extractor-agent.ts +0 -225
- package/src/env/task/storage/index.ts +0 -6
- package/src/env/task/storage/sqlite-task-store.test.ts +0 -283
- package/src/env/task/storage/sqlite-task-store.ts +0 -903
- package/src/env/task/storage/task-search.test.ts +0 -291
- package/src/env/task/tag-service.test.ts +0 -198
- package/src/env/task/tag-service.ts +0 -264
- package/src/env/task/task-component.test.ts +0 -193
- package/src/env/task/task-component.ts +0 -658
- package/src/env/task/task-config-registration.test.ts +0 -57
- package/src/env/task/task-config-registration.ts +0 -37
- package/src/env/task/task-types.test.ts +0 -137
- package/src/env/task/tools/complete-tool.ts +0 -44
- package/src/env/task/tools/create-tool.ts +0 -49
- package/src/env/task/tools/delete-tool.ts +0 -43
- package/src/env/task/tools/get-tool.ts +0 -59
- package/src/env/task/tools/index.ts +0 -10
- package/src/env/task/tools/list-tool.ts +0 -40
- package/src/env/task/tools/operation/create-tool.ts +0 -48
- package/src/env/task/tools/operation/delete-tool.ts +0 -43
- package/src/env/task/tools/operation/get-tool.ts +0 -43
- package/src/env/task/tools/operation/index.ts +0 -9
- package/src/env/task/tools/operation/list-tool.ts +0 -40
- package/src/env/task/tools/operation/operation-tools.test.ts +0 -274
- package/src/env/task/tools/operation/operation-types.ts +0 -75
- package/src/env/task/tools/operation/update-tool.ts +0 -47
- package/src/env/task/tools/task-tools.test.ts +0 -203
- package/src/env/task/tools/task-types.test.ts +0 -75
- package/src/env/task/tools/task-types.ts +0 -68
- package/src/env/task/tools/update-tool.ts +0 -70
- package/src/env/task/types.ts +0 -160
- package/src/env/tool/built-in/bash.ts +0 -201
- package/src/env/tool/built-in/echo.ts +0 -29
- package/src/env/tool/built-in/edit-file.test.ts +0 -136
- package/src/env/tool/built-in/edit-file.ts +0 -92
- package/src/env/tool/built-in/glob.test.ts +0 -94
- package/src/env/tool/built-in/glob.ts +0 -65
- package/src/env/tool/built-in/grep.test.ts +0 -122
- package/src/env/tool/built-in/grep.ts +0 -108
- package/src/env/tool/built-in/index.ts +0 -44
- package/src/env/tool/built-in/read-file.test.ts +0 -84
- package/src/env/tool/built-in/read-file.ts +0 -75
- package/src/env/tool/built-in/write-file.test.ts +0 -119
- package/src/env/tool/built-in/write-file.ts +0 -68
- package/src/env/tool/index.ts +0 -24
- package/src/env/tool/registry.test.ts +0 -257
- package/src/env/tool/registry.ts +0 -167
- package/src/env/tool/tool-component.test.ts +0 -559
- package/src/env/tool/tool-component.ts +0 -563
- package/src/env/tool/tool-config-registration.test.ts +0 -249
- package/src/env/tool/tool-config-registration.ts +0 -46
- package/src/env/tool/types.ts +0 -267
- package/src/env/tool/validator.test.ts +0 -143
- package/src/env/tool/validator.ts +0 -44
- package/src/env/types.ts +0 -180
- package/src/env/workflow/ask-user-tool-registration.test.ts +0 -216
- package/src/env/workflow/complex-workflow.integration.test.ts +0 -1900
- package/src/env/workflow/decorators/decorator-node.ts +0 -229
- package/src/env/workflow/decorators/decorator.test.ts +0 -196
- package/src/env/workflow/decorators/edge.ts +0 -82
- package/src/env/workflow/decorators/index.ts +0 -31
- package/src/env/workflow/decorators/node-as.ts +0 -98
- package/src/env/workflow/decorators/workflow.ts +0 -54
- package/src/env/workflow/engine/dag-manager.test.ts +0 -570
- package/src/env/workflow/engine/dag-manager.ts +0 -594
- package/src/env/workflow/engine/engine.ts +0 -1422
- package/src/env/workflow/engine/event-bus.test.ts +0 -359
- package/src/env/workflow/engine/event-bus.ts +0 -156
- package/src/env/workflow/engine/executor-agent-session.test.ts +0 -84
- package/src/env/workflow/engine/executor.test.ts +0 -619
- package/src/env/workflow/engine/executor.ts +0 -593
- package/src/env/workflow/engine/index.ts +0 -24
- package/src/env/workflow/engine/node-registry.test.ts +0 -560
- package/src/env/workflow/engine/node-registry.ts +0 -289
- package/src/env/workflow/engine/resume-removed.test.ts +0 -22
- package/src/env/workflow/engine/scheduler.test.ts +0 -715
- package/src/env/workflow/engine/scheduler.ts +0 -318
- package/src/env/workflow/engine/workflow-engine.test.ts +0 -815
- package/src/env/workflow/extractor/workflow-converter.ts +0 -306
- package/src/env/workflow/fixtures.ts +0 -380
- package/src/env/workflow/index.ts +0 -38
- package/src/env/workflow/integration/run-resume-unified.test.ts +0 -186
- package/src/env/workflow/integration/service-integration.test.ts +0 -267
- package/src/env/workflow/metadata/keys.ts +0 -12
- package/src/env/workflow/nodes/agent-component-adapter.test.ts +0 -318
- package/src/env/workflow/nodes/agent-component-adapter.ts +0 -448
- package/src/env/workflow/nodes/agent-node.test.ts +0 -371
- package/src/env/workflow/nodes/agent-node.ts +0 -598
- package/src/env/workflow/nodes/ask-user-node.ts +0 -113
- package/src/env/workflow/nodes/condition-node.ts +0 -200
- package/src/env/workflow/nodes/index.ts +0 -9
- package/src/env/workflow/nodes/merge-node.ts +0 -141
- package/src/env/workflow/nodes/skill-node.test.ts +0 -253
- package/src/env/workflow/nodes/skill-node.ts +0 -393
- package/src/env/workflow/nodes/tool-node.test.ts +0 -251
- package/src/env/workflow/nodes/tool-node.ts +0 -493
- package/src/env/workflow/nodes/workflow-llm-history.test.ts +0 -455
- package/src/env/workflow/nodes/workflow-node.test.ts +0 -315
- package/src/env/workflow/nodes/workflow-node.ts +0 -311
- package/src/env/workflow/service/index.ts +0 -27
- package/src/env/workflow/service/registry.test.ts +0 -133
- package/src/env/workflow/service/registry.ts +0 -71
- package/src/env/workflow/service/workflow-service.test.ts +0 -310
- package/src/env/workflow/service/workflow-service.ts +0 -393
- package/src/env/workflow/storage/index.ts +0 -28
- package/src/env/workflow/storage/mock-repositories.ts +0 -385
- package/src/env/workflow/storage/sqlite.test.ts +0 -179
- package/src/env/workflow/storage/sqlite.ts +0 -163
- package/src/env/workflow/storage/workflow-repo.test.ts +0 -780
- package/src/env/workflow/storage/workflow-repo.ts +0 -342
- package/src/env/workflow/tools/ask-user-tool.ts +0 -82
- package/src/env/workflow/tools/index.ts +0 -26
- package/src/env/workflow/tools/run-workflow.test.ts +0 -352
- package/src/env/workflow/tools/run-workflow.ts +0 -214
- package/src/env/workflow/types/context.ts +0 -18
- package/src/env/workflow/types/decorators-types.ts +0 -198
- package/src/env/workflow/types/event.test.ts +0 -515
- package/src/env/workflow/types/event.ts +0 -193
- package/src/env/workflow/types/index.ts +0 -49
- package/src/env/workflow/types/run.test.ts +0 -437
- package/src/env/workflow/types/run.ts +0 -173
- package/src/env/workflow/types/workflow-hil.ts +0 -114
- package/src/env/workflow/types/workflow-message.test.ts +0 -138
- package/src/env/workflow/types/workflow-message.ts +0 -196
- package/src/env/workflow/types/workflow-session.test.ts +0 -95
- package/src/env/workflow/types/workflow-session.ts +0 -59
- package/src/env/workflow/types/workflow.test.ts +0 -495
- package/src/env/workflow/types/workflow.ts +0 -195
- package/src/env/workflow/types_compat.ts +0 -51
- package/src/env/workflow/utils/create-workflow.ts +0 -47
- package/src/env/workflow/utils/execution-state.ts +0 -245
- package/src/env/workflow/utils/index.ts +0 -18
- package/src/env/workflow/utils/node-registry-helper.ts +0 -58
- package/src/env/workflow/utils/recovery-validator.test.ts +0 -460
- package/src/env/workflow/utils/recovery-validator.ts +0 -377
- package/src/env/workflow/utils/session-parser.test.ts +0 -111
- package/src/env/workflow/utils/session-parser.ts +0 -94
- package/src/env/workflow/utils/session-recovery.test.ts +0 -334
- package/src/env/workflow/utils/session-recovery.ts +0 -188
- package/src/env/workflow/utils/template-resolver.test.ts +0 -258
- package/src/env/workflow/utils/template-resolver.ts +0 -436
- package/src/env/workflow/utils/validation-rules.ts +0 -149
- package/src/env/workflow/workflow-component.ts +0 -544
- package/src/index.ts +0 -422
- package/src/utils/id.ts +0 -21
|
@@ -1,200 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview ConditionNode - Workflow condition node
|
|
3
|
-
*
|
|
4
|
-
* Evaluates a condition and decides whether to proceed or skip.
|
|
5
|
-
*
|
|
6
|
-
* Input can contain template strings like {{nodeId.output.path}} that will be
|
|
7
|
-
* resolved from previousOutputs.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { Node, NodeDefinition, NodeExecutionContext, NodeExecutionResult } from '../types';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* ConditionNode evaluates a condition and returns the result.
|
|
14
|
-
*
|
|
15
|
-
* The condition can be:
|
|
16
|
-
* - A boolean value
|
|
17
|
-
* - A template expression that evaluates to a boolean
|
|
18
|
-
* - A template reference to a previous node's output
|
|
19
|
-
*
|
|
20
|
-
* Usage in workflow:
|
|
21
|
-
* ```yaml
|
|
22
|
-
* nodes:
|
|
23
|
-
* - id: check-tests-pass
|
|
24
|
-
* type: condition
|
|
25
|
-
* config:
|
|
26
|
-
* condition: "{{run-unit-tests.success}}"
|
|
27
|
-
* depends_on:
|
|
28
|
-
* - run-unit-tests
|
|
29
|
-
* ```
|
|
30
|
-
*/
|
|
31
|
-
export class ConditionNode implements Node {
|
|
32
|
-
readonly type = 'condition';
|
|
33
|
-
readonly id: string;
|
|
34
|
-
|
|
35
|
-
constructor(
|
|
36
|
-
private definition: NodeDefinition,
|
|
37
|
-
) {
|
|
38
|
-
this.id = definition.id;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
async execute(context: NodeExecutionContext): Promise<NodeExecutionResult> {
|
|
42
|
-
const startTime = Date.now();
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
// Get condition from config
|
|
46
|
-
const conditionConfig = this.definition.config?.condition;
|
|
47
|
-
|
|
48
|
-
if (conditionConfig === undefined) {
|
|
49
|
-
// No condition specified, default to true (pass through)
|
|
50
|
-
return {
|
|
51
|
-
output: { success: true, condition: true },
|
|
52
|
-
error: undefined,
|
|
53
|
-
durationMs: Date.now() - startTime,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Resolve template references in the condition
|
|
58
|
-
const resolvedCondition = this.resolveCondition(conditionConfig, context);
|
|
59
|
-
|
|
60
|
-
// Evaluate the condition
|
|
61
|
-
const result = this.evaluateCondition(resolvedCondition);
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
output: { success: result, condition: resolvedCondition },
|
|
65
|
-
error: undefined,
|
|
66
|
-
durationMs: Date.now() - startTime,
|
|
67
|
-
};
|
|
68
|
-
} catch (error) {
|
|
69
|
-
return {
|
|
70
|
-
output: undefined,
|
|
71
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
72
|
-
durationMs: Date.now() - startTime,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Resolve condition value, handling template references.
|
|
79
|
-
*/
|
|
80
|
-
private resolveCondition(
|
|
81
|
-
condition: unknown,
|
|
82
|
-
context: NodeExecutionContext
|
|
83
|
-
): unknown {
|
|
84
|
-
if (typeof condition === 'string') {
|
|
85
|
-
// Check if this is a template reference
|
|
86
|
-
const templateMatch = condition.match(/^\{\{([^}]+)\}\}$/);
|
|
87
|
-
if (templateMatch) {
|
|
88
|
-
const path = templateMatch[1].trim();
|
|
89
|
-
return this.resolveTemplate(path, context);
|
|
90
|
-
}
|
|
91
|
-
// Check if it's a literal boolean or other literal
|
|
92
|
-
if (condition === 'true') return true;
|
|
93
|
-
if (condition === 'false') return false;
|
|
94
|
-
return condition;
|
|
95
|
-
}
|
|
96
|
-
return condition;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Resolve a template path to get a value from previous outputs or workflow input.
|
|
101
|
-
*/
|
|
102
|
-
private resolveTemplate(path: string, context: NodeExecutionContext): unknown {
|
|
103
|
-
const trimmed = path.trim();
|
|
104
|
-
|
|
105
|
-
// Pattern 1: input.key
|
|
106
|
-
if (trimmed.startsWith('input.')) {
|
|
107
|
-
const key = trimmed.slice(6);
|
|
108
|
-
return (context.input as Record<string, unknown>)?.[key];
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Pattern 2: nodes.nodeId or nodes.nodeId.path
|
|
112
|
-
if (trimmed.startsWith('nodes.')) {
|
|
113
|
-
const rest = trimmed.slice(6);
|
|
114
|
-
const segments = rest.split('.');
|
|
115
|
-
const nodeId = segments[0];
|
|
116
|
-
|
|
117
|
-
// 尝试规范化匹配(hyphen <-> underscore)
|
|
118
|
-
let nodeOutput = context.previousOutputs.get(nodeId);
|
|
119
|
-
if (nodeOutput === undefined) {
|
|
120
|
-
const normalizedUnderscore = nodeId.replace(/-/g, '_');
|
|
121
|
-
const normalizedHyphen = nodeId.replace(/_/g, '-');
|
|
122
|
-
if (normalizedUnderscore !== nodeId) {
|
|
123
|
-
nodeOutput = context.previousOutputs.get(normalizedUnderscore);
|
|
124
|
-
}
|
|
125
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
126
|
-
nodeOutput = context.previousOutputs.get(normalizedHyphen);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
if (nodeOutput === undefined) return undefined;
|
|
130
|
-
|
|
131
|
-
// Navigate path
|
|
132
|
-
let value: unknown = nodeOutput;
|
|
133
|
-
for (const segment of segments.slice(1)) {
|
|
134
|
-
if (value && typeof value === 'object') {
|
|
135
|
-
value = (value as Record<string, unknown>)[segment];
|
|
136
|
-
} else {
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
return value;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Pattern 3: Bare nodeId or nodeId.path
|
|
144
|
-
const segments = trimmed.split('.');
|
|
145
|
-
const nodeId = segments[0];
|
|
146
|
-
|
|
147
|
-
// 尝试规范化匹配(hyphen <-> underscore)
|
|
148
|
-
let nodeOutput = context.previousOutputs.get(nodeId);
|
|
149
|
-
if (nodeOutput === undefined) {
|
|
150
|
-
const normalizedUnderscore = nodeId.replace(/-/g, '_');
|
|
151
|
-
const normalizedHyphen = nodeId.replace(/_/g, '-');
|
|
152
|
-
if (normalizedUnderscore !== nodeId) {
|
|
153
|
-
nodeOutput = context.previousOutputs.get(normalizedUnderscore);
|
|
154
|
-
}
|
|
155
|
-
if (nodeOutput === undefined && normalizedHyphen !== nodeId) {
|
|
156
|
-
nodeOutput = context.previousOutputs.get(normalizedHyphen);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
if (nodeOutput === undefined) return undefined;
|
|
160
|
-
|
|
161
|
-
// Navigate path
|
|
162
|
-
let value: unknown = nodeOutput;
|
|
163
|
-
for (const segment of segments.slice(1)) {
|
|
164
|
-
if (value && typeof value === 'object') {
|
|
165
|
-
value = (value as Record<string, unknown>)[segment];
|
|
166
|
-
} else {
|
|
167
|
-
return undefined;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return value;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/**
|
|
174
|
-
* Evaluate a resolved condition value.
|
|
175
|
-
*/
|
|
176
|
-
private evaluateCondition(value: unknown): boolean {
|
|
177
|
-
if (typeof value === 'boolean') {
|
|
178
|
-
return value;
|
|
179
|
-
}
|
|
180
|
-
if (typeof value === 'string') {
|
|
181
|
-
return value.toLowerCase() === 'true' || value === '1';
|
|
182
|
-
}
|
|
183
|
-
if (typeof value === 'number') {
|
|
184
|
-
return value !== 0;
|
|
185
|
-
}
|
|
186
|
-
if (value === null || value === undefined) {
|
|
187
|
-
return false;
|
|
188
|
-
}
|
|
189
|
-
// For objects, check if it has a 'success' property
|
|
190
|
-
if (typeof value === 'object') {
|
|
191
|
-
const obj = value as Record<string, unknown>;
|
|
192
|
-
if ('success' in obj) {
|
|
193
|
-
return Boolean(obj.success);
|
|
194
|
-
}
|
|
195
|
-
// Non-empty object is truthy
|
|
196
|
-
return Object.keys(obj).length > 0;
|
|
197
|
-
}
|
|
198
|
-
return Boolean(value);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
// Node implementations
|
|
2
|
-
export { ToolNode } from './tool-node';
|
|
3
|
-
export type { ToolRegistry, Tool } from './tool-node';
|
|
4
|
-
|
|
5
|
-
export { SkillNode } from './skill-node';
|
|
6
|
-
export type { SkillRegistry, Skill } from './skill-node';
|
|
7
|
-
|
|
8
|
-
export { WorkflowNode } from './workflow-node';
|
|
9
|
-
export type { WorkflowRunner, WorkflowRunResult } from './workflow-node';
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview MergeNode - Workflow merge/join node
|
|
3
|
-
*
|
|
4
|
-
* A merge node waits for all dependencies to complete and collects their outputs.
|
|
5
|
-
*
|
|
6
|
-
* Input can contain template strings like {{nodeId.output.path}} that will be
|
|
7
|
-
* resolved from previousOutputs.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { Node, NodeDefinition, NodeExecutionContext, NodeExecutionResult } from '../types';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* MergeNode collects outputs from all dependent nodes and optionally merges them.
|
|
14
|
-
*
|
|
15
|
-
* The merge strategy can be:
|
|
16
|
-
* - "collect": Collect all outputs into an array
|
|
17
|
-
* - "first": Return the first completed output
|
|
18
|
-
* - "last": Return the last completed output
|
|
19
|
-
* - "merge": Deep merge all outputs into a single object
|
|
20
|
-
*
|
|
21
|
-
* Usage in workflow:
|
|
22
|
-
* ```yaml
|
|
23
|
-
* nodes:
|
|
24
|
-
* - id: final
|
|
25
|
-
* type: merge
|
|
26
|
-
* config:
|
|
27
|
-
* strategy: collect
|
|
28
|
-
* depends_on:
|
|
29
|
-
* - log-workflow-complete
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export class MergeNode implements Node {
|
|
33
|
-
readonly type = 'merge';
|
|
34
|
-
readonly id: string;
|
|
35
|
-
|
|
36
|
-
constructor(
|
|
37
|
-
private definition: NodeDefinition,
|
|
38
|
-
) {
|
|
39
|
-
this.id = definition.id;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async execute(context: NodeExecutionContext): Promise<NodeExecutionResult> {
|
|
43
|
-
const startTime = Date.now();
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
// Get merge strategy from config (default: collect)
|
|
47
|
-
const strategy = (this.definition.config?.strategy as string) || 'collect';
|
|
48
|
-
|
|
49
|
-
// Get dependency outputs
|
|
50
|
-
const deps = this.definition.depends_on || [];
|
|
51
|
-
const outputs: Record<string, unknown> = {};
|
|
52
|
-
|
|
53
|
-
for (const depId of deps) {
|
|
54
|
-
// 尝试规范化匹配(hyphen <-> underscore)
|
|
55
|
-
let output = context.previousOutputs.get(depId);
|
|
56
|
-
if (output === undefined) {
|
|
57
|
-
const normalizedUnderscore = depId.replace(/-/g, '_');
|
|
58
|
-
const normalizedHyphen = depId.replace(/_/g, '-');
|
|
59
|
-
if (normalizedUnderscore !== depId) {
|
|
60
|
-
output = context.previousOutputs.get(normalizedUnderscore);
|
|
61
|
-
}
|
|
62
|
-
if (output === undefined && normalizedHyphen !== depId) {
|
|
63
|
-
output = context.previousOutputs.get(normalizedHyphen);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
if (output !== undefined) {
|
|
67
|
-
outputs[depId] = output;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Apply merge strategy
|
|
72
|
-
let result: unknown;
|
|
73
|
-
|
|
74
|
-
switch (strategy) {
|
|
75
|
-
case 'collect':
|
|
76
|
-
// Return all outputs as a map
|
|
77
|
-
result = outputs;
|
|
78
|
-
break;
|
|
79
|
-
|
|
80
|
-
case 'first':
|
|
81
|
-
// Return the first output
|
|
82
|
-
const firstKey = Object.keys(outputs)[0];
|
|
83
|
-
result = firstKey ? outputs[firstKey] : undefined;
|
|
84
|
-
break;
|
|
85
|
-
|
|
86
|
-
case 'last':
|
|
87
|
-
// Return the last output
|
|
88
|
-
const lastKey = Object.keys(outputs).pop();
|
|
89
|
-
result = lastKey ? outputs[lastKey] : undefined;
|
|
90
|
-
break;
|
|
91
|
-
|
|
92
|
-
case 'merge':
|
|
93
|
-
// Deep merge all outputs
|
|
94
|
-
result = this.deepMerge(Object.values(outputs));
|
|
95
|
-
break;
|
|
96
|
-
|
|
97
|
-
default:
|
|
98
|
-
result = outputs;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
output: {
|
|
103
|
-
strategy,
|
|
104
|
-
results: result,
|
|
105
|
-
count: Object.keys(outputs).length,
|
|
106
|
-
},
|
|
107
|
-
error: undefined,
|
|
108
|
-
durationMs: Date.now() - startTime,
|
|
109
|
-
};
|
|
110
|
-
} catch (error) {
|
|
111
|
-
return {
|
|
112
|
-
output: undefined,
|
|
113
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
114
|
-
durationMs: Date.now() - startTime,
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Deep merge multiple objects into a single object.
|
|
121
|
-
*/
|
|
122
|
-
private deepMerge(objects: unknown[]): Record<string, unknown> {
|
|
123
|
-
const result: Record<string, unknown> = {};
|
|
124
|
-
|
|
125
|
-
for (const obj of objects) {
|
|
126
|
-
if (obj && typeof obj === 'object' && !Array.isArray(obj)) {
|
|
127
|
-
for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {
|
|
128
|
-
if (result[key] && typeof result[key] === 'object' && !Array.isArray(result[key]) &&
|
|
129
|
-
value && typeof value === 'object' && !Array.isArray(value)) {
|
|
130
|
-
// Recursively merge nested objects
|
|
131
|
-
result[key] = this.deepMerge([result[key], value]);
|
|
132
|
-
} else {
|
|
133
|
-
result[key] = value;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return result;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, jest } from 'vitest';
|
|
2
|
-
import { SkillNode, SkillRegistry, Skill } from './skill-node';
|
|
3
|
-
import type { NodeDefinition, NodeExecutionContext } from '../types';
|
|
4
|
-
import type { EventBus } from '../engine/event-bus';
|
|
5
|
-
|
|
6
|
-
// Mock EventBus
|
|
7
|
-
const mockEventBus = {
|
|
8
|
-
emit: jest.fn(),
|
|
9
|
-
on: jest.fn(),
|
|
10
|
-
off: jest.fn(),
|
|
11
|
-
} as Partial<EventBus> as EventBus;
|
|
12
|
-
|
|
13
|
-
// Mock SkillRegistry
|
|
14
|
-
const mockRegistry = {
|
|
15
|
-
getSkill: jest.fn<(name: string) => Skill | undefined>(),
|
|
16
|
-
hasSkill: jest.fn<(name: string) => boolean>(),
|
|
17
|
-
} as {
|
|
18
|
-
getSkill: ReturnType<typeof jest.fn>;
|
|
19
|
-
hasSkill: ReturnType<typeof jest.fn>;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// Mock Skill
|
|
23
|
-
const mockSkill = {
|
|
24
|
-
name: 'test-skill',
|
|
25
|
-
invoke: jest.fn<(input: any, context: any) => Promise<any>>(),
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
describe('SkillNode', () => {
|
|
29
|
-
let skillNode: SkillNode;
|
|
30
|
-
let nodeDefinition: NodeDefinition;
|
|
31
|
-
let executionContext: NodeExecutionContext;
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
jest.clearAllMocks();
|
|
35
|
-
|
|
36
|
-
nodeDefinition = {
|
|
37
|
-
id: 'node-1',
|
|
38
|
-
type: 'skill',
|
|
39
|
-
name: 'Test Skill Node',
|
|
40
|
-
config: {
|
|
41
|
-
skill: 'test-skill',
|
|
42
|
-
input: { message: 'hello' },
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
executionContext = {
|
|
47
|
-
runId: 'run-1',
|
|
48
|
-
workflowName: 'test-workflow',
|
|
49
|
-
nodeId: 'node-1',
|
|
50
|
-
input: {},
|
|
51
|
-
previousOutputs: new Map(),
|
|
52
|
-
config: nodeDefinition.config,
|
|
53
|
-
debug: false,
|
|
54
|
-
eventBus: mockEventBus,
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
mockRegistry.getSkill = jest.fn().mockReturnValue(mockSkill);
|
|
58
|
-
mockRegistry.hasSkill = jest.fn().mockReturnValue(true);
|
|
59
|
-
mockSkill.invoke = jest.fn().mockResolvedValue({ result: 'success' });
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('constructor', () => {
|
|
63
|
-
it('should create a SkillNode with correct type', () => {
|
|
64
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
65
|
-
expect(skillNode.type).toBe('skill');
|
|
66
|
-
expect(skillNode.id).toBe('node-1');
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
describe('execute', () => {
|
|
71
|
-
it('should invoke skill successfully', async () => {
|
|
72
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
73
|
-
|
|
74
|
-
const result = await skillNode.execute(executionContext);
|
|
75
|
-
|
|
76
|
-
expect(result.output).toEqual({ result: 'success' });
|
|
77
|
-
expect(result.error).toBeUndefined();
|
|
78
|
-
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
79
|
-
expect(mockRegistry.getSkill).toHaveBeenCalledWith('test-skill');
|
|
80
|
-
expect(mockSkill.invoke).toHaveBeenCalled();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should return error when skill not found', async () => {
|
|
84
|
-
mockRegistry.getSkill = jest.fn().mockReturnValue(undefined);
|
|
85
|
-
mockRegistry.hasSkill = jest.fn().mockReturnValue(false);
|
|
86
|
-
|
|
87
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
88
|
-
|
|
89
|
-
const result = await skillNode.execute(executionContext);
|
|
90
|
-
|
|
91
|
-
expect(result.output).toBeUndefined();
|
|
92
|
-
expect(result.error).toBeDefined();
|
|
93
|
-
expect(result.error.message).toContain('Skill not found: test-skill');
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
it('should pass input to skill', async () => {
|
|
97
|
-
const customInput = { param1: 'value1', param2: 123 };
|
|
98
|
-
nodeDefinition.config.input = customInput;
|
|
99
|
-
executionContext.config = nodeDefinition.config;
|
|
100
|
-
|
|
101
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
102
|
-
|
|
103
|
-
await skillNode.execute(executionContext);
|
|
104
|
-
|
|
105
|
-
expect(mockSkill.invoke).toHaveBeenCalledWith(customInput, expect.any(Object));
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
it('should handle skill invocation errors', async () => {
|
|
109
|
-
const error = new Error('Skill invocation failed');
|
|
110
|
-
mockSkill.invoke = jest.fn().mockRejectedValue(error);
|
|
111
|
-
|
|
112
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
113
|
-
|
|
114
|
-
const result = await skillNode.execute(executionContext);
|
|
115
|
-
|
|
116
|
-
expect(result.output).toBeUndefined();
|
|
117
|
-
expect(result.error).toBeDefined();
|
|
118
|
-
expect(result.error.message).toBe('Skill invocation failed');
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should resolve template references from previous outputs', async () => {
|
|
122
|
-
// Set up previous outputs
|
|
123
|
-
executionContext.previousOutputs.set('node-0', {
|
|
124
|
-
output: { value: 'from-node-0' }
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Input contains template reference
|
|
128
|
-
nodeDefinition.config.input = {
|
|
129
|
-
message: '{{node-0.output.value}}',
|
|
130
|
-
};
|
|
131
|
-
executionContext.config = nodeDefinition.config;
|
|
132
|
-
|
|
133
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
134
|
-
|
|
135
|
-
const result = await skillNode.execute(executionContext);
|
|
136
|
-
|
|
137
|
-
expect(result.output).toEqual({ result: 'success' });
|
|
138
|
-
expect(mockSkill.invoke).toHaveBeenCalledWith({
|
|
139
|
-
message: 'from-node-0',
|
|
140
|
-
}, expect.any(Object));
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
it('should resolve nested template references', async () => {
|
|
144
|
-
executionContext.previousOutputs.set('data-node', {
|
|
145
|
-
nested: {
|
|
146
|
-
deep: {
|
|
147
|
-
value: 'nested-value',
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
nodeDefinition.config.input = {
|
|
153
|
-
message: '{{data-node.nested.deep.value}}',
|
|
154
|
-
};
|
|
155
|
-
executionContext.config = nodeDefinition.config;
|
|
156
|
-
|
|
157
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
158
|
-
|
|
159
|
-
await skillNode.execute(executionContext);
|
|
160
|
-
|
|
161
|
-
expect(mockSkill.invoke).toHaveBeenCalledWith({
|
|
162
|
-
message: 'nested-value',
|
|
163
|
-
}, expect.any(Object));
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it('should handle unresolved template references gracefully', async () => {
|
|
167
|
-
// Template references non-existent node
|
|
168
|
-
nodeDefinition.config.input = {
|
|
169
|
-
message: '{{non-existent.output.value}}',
|
|
170
|
-
};
|
|
171
|
-
executionContext.config = nodeDefinition.config;
|
|
172
|
-
|
|
173
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
174
|
-
|
|
175
|
-
const result = await skillNode.execute(executionContext);
|
|
176
|
-
|
|
177
|
-
// Should still execute with unresolved template
|
|
178
|
-
expect(mockSkill.invoke).toHaveBeenCalledWith({
|
|
179
|
-
message: '{{non-existent.output.value}}',
|
|
180
|
-
}, expect.any(Object));
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
it('should record execution duration', async () => {
|
|
184
|
-
mockSkill.invoke = jest.fn().mockImplementation(async () => {
|
|
185
|
-
await new Promise(resolve => setTimeout(resolve, 10));
|
|
186
|
-
return { result: 'success' };
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
190
|
-
|
|
191
|
-
const result = await skillNode.execute(executionContext);
|
|
192
|
-
|
|
193
|
-
expect(result.durationMs).toBeGreaterThanOrEqual(0);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
it('should use skill name from config.skill', async () => {
|
|
197
|
-
nodeDefinition.config.skill = 'custom-skill';
|
|
198
|
-
executionContext.config = nodeDefinition.config;
|
|
199
|
-
|
|
200
|
-
const customSkill = {
|
|
201
|
-
name: 'custom-skill',
|
|
202
|
-
invoke: jest.fn().mockResolvedValue({ custom: true }),
|
|
203
|
-
};
|
|
204
|
-
mockRegistry.getSkill = jest.fn().mockReturnValue(customSkill);
|
|
205
|
-
|
|
206
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
207
|
-
|
|
208
|
-
await skillNode.execute(executionContext);
|
|
209
|
-
|
|
210
|
-
expect(mockRegistry.getSkill).toHaveBeenCalledWith('custom-skill');
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('should throw error when skill config is missing', async () => {
|
|
214
|
-
nodeDefinition.config = {}; // No skill specified
|
|
215
|
-
executionContext.config = nodeDefinition.config;
|
|
216
|
-
|
|
217
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
218
|
-
|
|
219
|
-
const result = await skillNode.execute(executionContext);
|
|
220
|
-
|
|
221
|
-
expect(result.error).toBeDefined();
|
|
222
|
-
expect(result.error.message).toContain('Skill name is required');
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
it('should pass context to skill invoke', async () => {
|
|
226
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
227
|
-
|
|
228
|
-
await skillNode.execute(executionContext);
|
|
229
|
-
|
|
230
|
-
// Verify context is passed with relevant info
|
|
231
|
-
expect(mockSkill.invoke).toHaveBeenCalledWith(
|
|
232
|
-
{ message: 'hello' },
|
|
233
|
-
expect.objectContaining({
|
|
234
|
-
runId: 'run-1',
|
|
235
|
-
workflowName: 'test-workflow',
|
|
236
|
-
nodeId: 'node-1',
|
|
237
|
-
})
|
|
238
|
-
);
|
|
239
|
-
});
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
describe('SkillRegistry interface', () => {
|
|
243
|
-
it('should check skill existence with hasSkill', async () => {
|
|
244
|
-
mockRegistry.hasSkill = jest.fn().mockReturnValue(true);
|
|
245
|
-
|
|
246
|
-
skillNode = new SkillNode(nodeDefinition, mockRegistry);
|
|
247
|
-
|
|
248
|
-
// This is tested implicitly - if hasSkill returns false,
|
|
249
|
-
// getSkill should also return undefined
|
|
250
|
-
expect(mockRegistry.hasSkill('test-skill')).toBe(true);
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
});
|