@ai-setting/roy-agent-core 1.3.10 → 1.3.14
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,258 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach } from 'vitest';
|
|
2
|
-
import { TemplateResolver } from './template-resolver';
|
|
3
|
-
import type { NodeExecutionContext } from '../types';
|
|
4
|
-
|
|
5
|
-
describe('TemplateResolver', () => {
|
|
6
|
-
let resolver: TemplateResolver;
|
|
7
|
-
|
|
8
|
-
beforeEach(() => {
|
|
9
|
-
resolver = new TemplateResolver({
|
|
10
|
-
input: { query: 'weather', city: 'Beijing' },
|
|
11
|
-
previousOutputs: new Map([
|
|
12
|
-
['fetch', { data: { temp: 25, condition: 'sunny', items: [1, 2, 3] } }],
|
|
13
|
-
['process', { result: 'processed', score: 0.95 }],
|
|
14
|
-
['agent', { result: { summary: 'Great day!', metadata: { source: 'weather-api' } }, metadata: { tokens: 100 } }],
|
|
15
|
-
]),
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
describe('resolveString', () => {
|
|
20
|
-
test('should return primitive values unchanged', () => {
|
|
21
|
-
expect(resolver.resolveString('hello')).toBe('hello');
|
|
22
|
-
expect(resolver.resolveString('123')).toBe('123');
|
|
23
|
-
expect(resolver.resolveString('')).toBe('');
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
test('should resolve input references with prefix', () => {
|
|
27
|
-
expect(resolver.resolveString('Query: {{input.query}}')).toBe('Query: weather');
|
|
28
|
-
expect(resolver.resolveString('City: {{input.city}}')).toBe('City: Beijing');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test('should resolve nested input references', () => {
|
|
32
|
-
resolver = new TemplateResolver({
|
|
33
|
-
input: { user: { profile: { name: 'John' } } },
|
|
34
|
-
});
|
|
35
|
-
expect(resolver.resolveString('Name: {{input.user.profile.name}}')).toBe('Name: John');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test('should resolve node output with prefix', () => {
|
|
39
|
-
expect(resolver.resolveString('Condition: {{nodes.fetch}}')).toBe('Condition: {"data":{"temp":25,"condition":"sunny","items":[1,2,3]}}');
|
|
40
|
-
expect(resolver.resolveString('Temp: {{nodes.fetch.data.temp}}')).toBe('Temp: 25');
|
|
41
|
-
expect(resolver.resolveString('Condition: {{nodes.fetch.data.condition}}')).toBe('Condition: sunny');
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test('should resolve node output without prefix (backward compatibility)', () => {
|
|
45
|
-
expect(resolver.resolveString('Temp: {{fetch.data.temp}}')).toBe('Temp: 25');
|
|
46
|
-
expect(resolver.resolveString('Condition: {{fetch.data.condition}}')).toBe('Condition: sunny');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('should resolve agent node result', () => {
|
|
50
|
-
// Bare {{agent}} extracts the result field from AgentNode output format
|
|
51
|
-
expect(resolver.resolveString('Summary: {{agent}}')).toBe('Summary: {"summary":"Great day!","metadata":{"source":"weather-api"}}');
|
|
52
|
-
// Explicit {{agent.result}} also works
|
|
53
|
-
expect(resolver.resolveString('Summary: {{agent.result.summary}}')).toBe('Summary: Great day!');
|
|
54
|
-
// Can also access metadata directly
|
|
55
|
-
expect(resolver.resolveString('Tokens: {{agent.metadata.tokens}}')).toBe('Tokens: 100');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test('should resolve multiple templates in one string', () => {
|
|
59
|
-
expect(resolver.resolveString('Query: {{input.query}}, Condition: {{nodes.fetch.data.condition}}'))
|
|
60
|
-
.toBe('Query: weather, Condition: sunny');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test('should leave unresolved templates unchanged', () => {
|
|
64
|
-
expect(resolver.resolveString('Missing: {{nodes.nonexistent}}')).toBe('Missing: {{nodes.nonexistent}}');
|
|
65
|
-
expect(resolver.resolveString('Missing: {{nonexistent}}')).toBe('Missing: {{nonexistent}}');
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test('should handle empty template', () => {
|
|
69
|
-
expect(resolver.resolveString('Empty: {{}}')).toBe('Empty: {{}}');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('resolveValue', () => {
|
|
74
|
-
test('should resolve string values', () => {
|
|
75
|
-
expect(resolver.resolveValue('Temperature: {{nodes.fetch.data.temp}}°C'))
|
|
76
|
-
.toBe('Temperature: 25°C');
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test('should resolve object values', () => {
|
|
80
|
-
const result = resolver.resolveValue({
|
|
81
|
-
query: '{{input.query}}',
|
|
82
|
-
temp: '{{nodes.fetch.data.temp}}',
|
|
83
|
-
});
|
|
84
|
-
expect(result).toEqual({
|
|
85
|
-
query: 'weather',
|
|
86
|
-
temp: 25, // Pure template references preserve original types
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test('should resolve array values', () => {
|
|
91
|
-
const result = resolver.resolveValue([
|
|
92
|
-
'{{input.query}}',
|
|
93
|
-
'{{nodes.fetch.data.condition}}',
|
|
94
|
-
'static',
|
|
95
|
-
]);
|
|
96
|
-
expect(result).toEqual(['weather', 'sunny', 'static']);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
test('should resolve nested structures', () => {
|
|
100
|
-
const result = resolver.resolveValue({
|
|
101
|
-
level1: {
|
|
102
|
-
level2: '{{input.query}}',
|
|
103
|
-
items: ['{{input.city}}', '{{nodes.fetch.data.temp}}'],
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
expect(result).toEqual({
|
|
107
|
-
level1: {
|
|
108
|
-
level2: 'weather',
|
|
109
|
-
items: ['Beijing', 25], // Pure template references preserve original types
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
test('should handle null and undefined', () => {
|
|
115
|
-
expect(resolver.resolveValue(null)).toBe(null);
|
|
116
|
-
expect(resolver.resolveValue(undefined)).toBe(undefined);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
describe('containsTemplates', () => {
|
|
121
|
-
test('should detect templates in strings', () => {
|
|
122
|
-
expect(resolver.containsTemplates('{{input.query}}')).toBe(true);
|
|
123
|
-
expect(resolver.containsTemplates('Query: {{input.query}}')).toBe(true);
|
|
124
|
-
expect(resolver.containsTemplates('No templates')).toBe(false);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('should return false for non-strings', () => {
|
|
128
|
-
expect(resolver.containsTemplates(123 as any)).toBe(false);
|
|
129
|
-
expect(resolver.containsTemplates(null)).toBe(false);
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
describe('extractTemplates', () => {
|
|
134
|
-
test('should extract all template references', () => {
|
|
135
|
-
const templates = resolver.extractTemplates(
|
|
136
|
-
'Query: {{input.query}}, Temp: {{nodes.fetch.data.temp}}'
|
|
137
|
-
);
|
|
138
|
-
expect(templates).toEqual(['{{input.query}}', '{{nodes.fetch.data.temp}}']);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
test('should return empty array for strings without templates', () => {
|
|
142
|
-
expect(resolver.extractTemplates('No templates')).toEqual([]);
|
|
143
|
-
});
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
describe('fromContext', () => {
|
|
147
|
-
test('should create resolver from NodeExecutionContext', () => {
|
|
148
|
-
const context: NodeExecutionContext = {
|
|
149
|
-
runId: 'run_123',
|
|
150
|
-
workflowName: 'test-workflow',
|
|
151
|
-
nodeId: 'test-node',
|
|
152
|
-
input: { key: 'value' },
|
|
153
|
-
previousOutputs: new Map([['prev', { out: 'result' }]]),
|
|
154
|
-
config: {},
|
|
155
|
-
debug: false,
|
|
156
|
-
eventBus: {} as any,
|
|
157
|
-
nodeOutputs: new Map(),
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
const contextResolver = TemplateResolver.fromContext(context);
|
|
161
|
-
expect(contextResolver.resolveString('{{input.key}}')).toBe('value');
|
|
162
|
-
expect(contextResolver.resolveString('{{prev.out}}')).toBe('result');
|
|
163
|
-
});
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
describe('TemplateResolver Edge Cases', () => {
|
|
168
|
-
test('should handle complex nested paths', () => {
|
|
169
|
-
const resolver = new TemplateResolver({
|
|
170
|
-
previousOutputs: new Map([
|
|
171
|
-
['node', { a: { b: { c: { d: 'deep value' } } } }],
|
|
172
|
-
]),
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
expect(resolver.resolveString('{{node.a.b.c.d}}')).toBe('deep value');
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
test('should handle arrays in path', () => {
|
|
179
|
-
const resolver = new TemplateResolver({
|
|
180
|
-
previousOutputs: new Map([
|
|
181
|
-
['node', { items: [{ name: 'item1' }, { name: 'item2' }] }],
|
|
182
|
-
]),
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
expect(resolver.resolveString('{{node.items.0.name}}')).toBe('item1');
|
|
186
|
-
expect(resolver.resolveString('{{node.items.1.name}}')).toBe('item2');
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
test('should handle special characters in values', () => {
|
|
190
|
-
const resolver = new TemplateResolver({
|
|
191
|
-
previousOutputs: new Map([
|
|
192
|
-
['node', { special: 'value with "quotes" and \'apostrophes\'' }],
|
|
193
|
-
]),
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
expect(resolver.resolveString('{{node.special}}')).toBe('value with "quotes" and \'apostrophes\'');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
test('should handle numeric values', () => {
|
|
200
|
-
const resolver = new TemplateResolver({
|
|
201
|
-
previousOutputs: new Map([
|
|
202
|
-
['node', { count: 42, ratio: 0.5, negative: -10 }],
|
|
203
|
-
]),
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
expect(resolver.resolveString('Count: {{node.count}}')).toBe('Count: 42');
|
|
207
|
-
expect(resolver.resolveString('Ratio: {{node.ratio}}')).toBe('Ratio: 0.5');
|
|
208
|
-
expect(resolver.resolveString('Negative: {{node.negative}}')).toBe('Negative: -10');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
test('should handle boolean values', () => {
|
|
212
|
-
const resolver = new TemplateResolver({
|
|
213
|
-
previousOutputs: new Map([
|
|
214
|
-
['node', { active: true, deleted: false }],
|
|
215
|
-
]),
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
expect(resolver.resolveString('Active: {{node.active}}')).toBe('Active: true');
|
|
219
|
-
expect(resolver.resolveString('Deleted: {{node.deleted}}')).toBe('Deleted: false');
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
test('should handle empty previousOutputs map', () => {
|
|
223
|
-
const resolver = new TemplateResolver({
|
|
224
|
-
previousOutputs: new Map(),
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
expect(resolver.resolveString('{{node.output}}')).toBe('{{node.output}}');
|
|
228
|
-
expect(resolver.resolveString('Missing: {{nodes.nodeId}}')).toBe('Missing: {{nodes.nodeId}}');
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
test('should handle null values in chain', () => {
|
|
232
|
-
const resolver = new TemplateResolver({
|
|
233
|
-
previousOutputs: new Map([
|
|
234
|
-
['node', { a: null }],
|
|
235
|
-
]),
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
expect(resolver.resolveString('{{node.a.b}}')).toBe('{{node.a.b}}');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
test('should handle undefined intermediate values', () => {
|
|
242
|
-
const resolver = new TemplateResolver({
|
|
243
|
-
previousOutputs: new Map([
|
|
244
|
-
['node', { a: undefined }],
|
|
245
|
-
]),
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
expect(resolver.resolveString('{{node.a.b}}')).toBe('{{node.a.b}}');
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
test('should handle missing node', () => {
|
|
252
|
-
const resolver = new TemplateResolver({
|
|
253
|
-
previousOutputs: new Map(),
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
expect(resolver.resolveString('Value: {{missing.value}}')).toBe('Value: {{missing.value}}');
|
|
257
|
-
});
|
|
258
|
-
});
|
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview Template Resolver - Unified template resolution for workflow nodes
|
|
3
|
-
*
|
|
4
|
-
* This module provides a unified template resolution system for workflow nodes.
|
|
5
|
-
* Templates are in the format {{path}} where path can reference:
|
|
6
|
-
*
|
|
7
|
-
* - Input variables: {{input.key}} or {{input.key.nested}}
|
|
8
|
-
* - Node outputs: {{nodeId}} or {{nodeId.output}} or {{nodeId.output.path}}
|
|
9
|
-
* - With prefix: {{nodes.nodeId}} or {{nodes.nodeId.output.path}}
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* ```typescript
|
|
13
|
-
* const resolver = new TemplateResolver({
|
|
14
|
-
* input: { query: 'weather' },
|
|
15
|
-
* previousOutputs: new Map([
|
|
16
|
-
* ['fetch', { data: { temp: 25, condition: 'sunny' } }]
|
|
17
|
-
* ])
|
|
18
|
-
* });
|
|
19
|
-
*
|
|
20
|
-
* resolver.resolve('Weather in {{input.query}}: {{nodes.fetch.data.condition}}');
|
|
21
|
-
* // => 'Weather in weather: sunny'
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
import type { NodeExecutionContext } from '../types';
|
|
26
|
-
|
|
27
|
-
// ============================================================================
|
|
28
|
-
// Types
|
|
29
|
-
// ============================================================================
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Template resolution options
|
|
33
|
-
*/
|
|
34
|
-
export interface TemplateResolverOptions {
|
|
35
|
-
/** Input passed to the workflow/node */
|
|
36
|
-
input?: Record<string, unknown>;
|
|
37
|
-
/** Map of previous node outputs */
|
|
38
|
-
previousOutputs?: Map<string, unknown>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Result of template resolution
|
|
43
|
-
*/
|
|
44
|
-
export interface ResolvedValue {
|
|
45
|
-
/** Whether the value was resolved */
|
|
46
|
-
resolved: boolean;
|
|
47
|
-
/** The resolved value */
|
|
48
|
-
value: unknown;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ============================================================================
|
|
52
|
-
// TemplateResolver Class
|
|
53
|
-
// ============================================================================
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* TemplateResolver
|
|
57
|
-
*
|
|
58
|
-
* Resolves template strings that reference workflow inputs and node outputs.
|
|
59
|
-
*/
|
|
60
|
-
export class TemplateResolver {
|
|
61
|
-
private input: Record<string, unknown>;
|
|
62
|
-
private previousOutputs: Map<string, unknown>;
|
|
63
|
-
|
|
64
|
-
constructor(options: TemplateResolverOptions = {}) {
|
|
65
|
-
this.input = options.input ?? {};
|
|
66
|
-
this.previousOutputs = options.previousOutputs ?? new Map();
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Create a TemplateResolver from NodeExecutionContext
|
|
71
|
-
*
|
|
72
|
-
* @param context - Node execution context
|
|
73
|
-
* @returns TemplateResolver instance
|
|
74
|
-
*/
|
|
75
|
-
static fromContext(context: NodeExecutionContext): TemplateResolver {
|
|
76
|
-
return new TemplateResolver({
|
|
77
|
-
input: context.input as Record<string, unknown>,
|
|
78
|
-
previousOutputs: context.previousOutputs,
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Resolve template references in an input value.
|
|
84
|
-
*
|
|
85
|
-
* Handles:
|
|
86
|
-
* - Primitive values (returned as-is)
|
|
87
|
-
* - Objects (recursively resolved)
|
|
88
|
-
* - Arrays (recursively resolved)
|
|
89
|
-
* - Strings (template resolution)
|
|
90
|
-
*
|
|
91
|
-
* Key behavior for template strings:
|
|
92
|
-
* - If the string is a pure template reference (e.g., "{{nodes.fetch}}"),
|
|
93
|
-
* the resolved value is returned as-is (preserving objects/arrays)
|
|
94
|
-
* - If the string contains text + templates (e.g., "Hello {{name}}"),
|
|
95
|
-
* returns a string with interpolated values
|
|
96
|
-
*
|
|
97
|
-
* @param input - Input value that may contain template strings
|
|
98
|
-
* @returns Input with template references resolved
|
|
99
|
-
*/
|
|
100
|
-
resolveValue(input: unknown): unknown {
|
|
101
|
-
if (input === null || input === undefined) {
|
|
102
|
-
return input;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (typeof input === 'string') {
|
|
106
|
-
// Check if this is a pure template reference (no surrounding text)
|
|
107
|
-
const pureTemplate = this.extractPureTemplate(input);
|
|
108
|
-
if (pureTemplate) {
|
|
109
|
-
// Pure template reference - resolve and return value as-is (preserve objects/arrays)
|
|
110
|
-
return this.resolvePureTemplate(pureTemplate);
|
|
111
|
-
}
|
|
112
|
-
// Mixed text + templates - return resolved string
|
|
113
|
-
return this.resolveString(input);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (Array.isArray(input)) {
|
|
117
|
-
return input.map(item => this.resolveValue(item));
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (typeof input === 'object') {
|
|
121
|
-
const resolved: Record<string, unknown> = {};
|
|
122
|
-
for (const [key, value] of Object.entries(input)) {
|
|
123
|
-
resolved[key] = this.resolveValue(value);
|
|
124
|
-
}
|
|
125
|
-
return resolved;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Return primitive values as-is
|
|
129
|
-
return input;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Check if a string is a pure template reference (starts with {{ and ends with }})
|
|
134
|
-
* @param str - String to check
|
|
135
|
-
* @returns The template content if pure, null otherwise
|
|
136
|
-
*/
|
|
137
|
-
private extractPureTemplate(str: string): string | null {
|
|
138
|
-
const trimmed = str.trim();
|
|
139
|
-
if (trimmed.startsWith('{{') && trimmed.endsWith('}}') && trimmed.length > 4) {
|
|
140
|
-
// Extract content between {{ and }}
|
|
141
|
-
const content = trimmed.slice(2, -2).trim();
|
|
142
|
-
// Check there's no other text (except the template patterns themselves)
|
|
143
|
-
// This ensures we don't treat "Hello {{name}}" as pure template
|
|
144
|
-
if (!content.includes('{{') && !content.includes('}}')) {
|
|
145
|
-
return content;
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return null;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Resolve a pure template reference and return the value as-is.
|
|
153
|
-
* @param templateContent - Content between {{ and }}
|
|
154
|
-
* @returns The resolved value (may be object, array, or primitive)
|
|
155
|
-
*/
|
|
156
|
-
private resolvePureTemplate(templateContent: string): unknown {
|
|
157
|
-
// Try to resolve the template
|
|
158
|
-
const value = this.resolveTemplateContent(templateContent);
|
|
159
|
-
return value;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Resolve template content (the part inside {{ }}) and return the value.
|
|
164
|
-
* @param templateContent - The path to resolve (e.g., "input.key", "nodes.fetch.data")
|
|
165
|
-
* @returns The resolved value
|
|
166
|
-
*/
|
|
167
|
-
private resolveTemplateContent(templateContent: string): unknown {
|
|
168
|
-
const trimmed = templateContent.trim();
|
|
169
|
-
|
|
170
|
-
// Pattern 1: {{input.key}} or {{input.key.nested}}
|
|
171
|
-
if (trimmed.startsWith('input.')) {
|
|
172
|
-
return this.getNestedValue(this.input, trimmed.slice(6)); // "input." is 6 chars
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// Pattern 2: {{nodes.nodeId}} or {{nodes.nodeId.output}}
|
|
176
|
-
if (trimmed.startsWith('nodes.')) {
|
|
177
|
-
return this.resolveNodePath(trimmed.slice(6)); // "nodes." is 6 chars
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Pattern 3: Bare nodeId (backward compatibility)
|
|
181
|
-
// Skip reserved keywords
|
|
182
|
-
if (trimmed !== 'input' && trimmed !== 'nodes') {
|
|
183
|
-
const segments = trimmed.split('.');
|
|
184
|
-
const nodeId = segments[0];
|
|
185
|
-
const restPath = segments.slice(1).join('.') || undefined;
|
|
186
|
-
return this.resolveNodePath(`${nodeId}${restPath ? '.' + restPath : ''}`);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return undefined;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Resolve a single template string.
|
|
194
|
-
*
|
|
195
|
-
* Supports patterns:
|
|
196
|
-
* - {{input.key}} - Input variable
|
|
197
|
-
* - {{nodeId}} - Node's entire output
|
|
198
|
-
* - {{nodeId.output}} - Node's output property
|
|
199
|
-
* - {{nodeId.output.path}} - Node's nested output property
|
|
200
|
-
* - {{nodes.nodeId}} - Node's entire output (with prefix)
|
|
201
|
-
* - {{nodes.nodeId.output.path}} - Node's nested property (with prefix)
|
|
202
|
-
*
|
|
203
|
-
* @param template - Template string to resolve
|
|
204
|
-
* @returns Resolved string
|
|
205
|
-
*/
|
|
206
|
-
resolveString(template: string): string {
|
|
207
|
-
if (!template || typeof template !== 'string') {
|
|
208
|
-
return template;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
let resolved = template;
|
|
212
|
-
|
|
213
|
-
// Pattern 1: {{input.key}} or {{input.key.nested}}
|
|
214
|
-
resolved = resolved.replace(/\{\{input\.([^}]+)\}\}/g, (match, path) => {
|
|
215
|
-
const value = this.getNestedValue(this.input, path);
|
|
216
|
-
return this.stringify(value, match);
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Pattern 2: {{nodes.nodeId}} or {{nodes.nodeId.output.path}}
|
|
220
|
-
// Also handles {{nodes.nodeId.output}} format
|
|
221
|
-
resolved = resolved.replace(/\{\{nodes\.([^}]+)\}\}/g, (match, path) => {
|
|
222
|
-
const value = this.resolveNodePath(path);
|
|
223
|
-
return this.stringify(value, match);
|
|
224
|
-
});
|
|
225
|
-
|
|
226
|
-
// Pattern 3: {{nodeId}} or {{nodeId.output}} or {{nodeId.output.path}}
|
|
227
|
-
// This is for backward compatibility with SkillNode's bare nodeId format
|
|
228
|
-
// Only matches if not already matched by nodes. pattern
|
|
229
|
-
// We need to be careful not to match {{input.xxx}} patterns
|
|
230
|
-
// Supports node IDs with alphanumeric, underscore, hyphen characters
|
|
231
|
-
resolved = resolved.replace(/\{\{([a-zA-Z_][a-zA-Z0-9_-]*)(?:\.([^}]+))?\}\}/g, (match, nodeId, path) => {
|
|
232
|
-
// Skip if this looks like an input reference without the prefix
|
|
233
|
-
// This is a heuristic: 'input' as first segment is handled above
|
|
234
|
-
if (nodeId === 'input') {
|
|
235
|
-
return match;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Skip 'nodes' prefix (already handled above)
|
|
239
|
-
if (nodeId === 'nodes') {
|
|
240
|
-
return match;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const value = this.resolveNodePath(`${nodeId}${path ? '.' + path : ''}`);
|
|
244
|
-
return this.stringify(value, match);
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
return resolved;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Resolve a node output path.
|
|
252
|
-
*
|
|
253
|
-
* @param path - Path like "nodeId" or "nodeId.output" or "nodeId.output.path"
|
|
254
|
-
* @returns The resolved value or undefined
|
|
255
|
-
*/
|
|
256
|
-
private resolveNodePath(path: string): unknown {
|
|
257
|
-
const segments = path.split('.');
|
|
258
|
-
const nodeId = segments[0];
|
|
259
|
-
|
|
260
|
-
if (!nodeId) {
|
|
261
|
-
return undefined;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Get node output from previous outputs
|
|
265
|
-
// Try exact match first, then try normalized versions (hyphen <-> underscore)
|
|
266
|
-
let value = this.previousOutputs.get(nodeId);
|
|
267
|
-
|
|
268
|
-
if (value === undefined) {
|
|
269
|
-
// Try normalized versions for flexibility
|
|
270
|
-
// This handles cases where workflow defines node with underscore but template uses hyphen, or vice versa
|
|
271
|
-
const normalizedUnderscore = nodeId.replace(/-/g, '_');
|
|
272
|
-
const normalizedHyphen = nodeId.replace(/_/g, '-');
|
|
273
|
-
|
|
274
|
-
if (normalizedUnderscore !== nodeId) {
|
|
275
|
-
value = this.previousOutputs.get(normalizedUnderscore);
|
|
276
|
-
}
|
|
277
|
-
if (value === undefined && normalizedHyphen !== nodeId) {
|
|
278
|
-
value = this.previousOutputs.get(normalizedHyphen);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
if (value === undefined) {
|
|
283
|
-
return undefined;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// If no additional path (bare nodeId), handle AgentNode output format
|
|
287
|
-
if (segments.length === 1) {
|
|
288
|
-
// Special handling for AgentNode output format: { result, metadata }
|
|
289
|
-
// If output has this shape, extract the result
|
|
290
|
-
if (value && typeof value === 'object' && 'result' in value && !('nodes' in value)) {
|
|
291
|
-
value = (value as { result: unknown }).result;
|
|
292
|
-
}
|
|
293
|
-
return value;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Navigate nested path
|
|
297
|
-
// Special handling for AgentNode output format: { result, metadata }
|
|
298
|
-
// If path starts with 'result' or 'output', try to extract from wrapper
|
|
299
|
-
const secondSegment = segments[1];
|
|
300
|
-
if (secondSegment === 'result' || secondSegment === 'output') {
|
|
301
|
-
// Check if current value is an AgentNode-style wrapper
|
|
302
|
-
if (value && typeof value === 'object' && 'result' in value) {
|
|
303
|
-
value = (value as { result: unknown }).result;
|
|
304
|
-
|
|
305
|
-
if (segments.length === 2) {
|
|
306
|
-
// Path was {{nodeId.result}} - return the result directly
|
|
307
|
-
return value;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Skip the 'result' segment and continue navigating
|
|
311
|
-
for (let i = 2; i < segments.length; i++) {
|
|
312
|
-
if (value === null || value === undefined) {
|
|
313
|
-
return undefined;
|
|
314
|
-
}
|
|
315
|
-
value = (value as any)[segments[i]];
|
|
316
|
-
}
|
|
317
|
-
return value;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Standard nested path navigation
|
|
322
|
-
for (let i = 1; i < segments.length; i++) {
|
|
323
|
-
if (value === null || value === undefined) {
|
|
324
|
-
return undefined;
|
|
325
|
-
}
|
|
326
|
-
value = (value as any)[segments[i]];
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
return value;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Get a nested value from an object using dot notation.
|
|
334
|
-
*
|
|
335
|
-
* @param obj - Object to traverse
|
|
336
|
-
* @param path - Dot-separated path
|
|
337
|
-
* @returns The nested value or undefined
|
|
338
|
-
*/
|
|
339
|
-
private getNestedValue(obj: Record<string, unknown> | undefined, path: string): unknown {
|
|
340
|
-
if (!obj || !path) {
|
|
341
|
-
return undefined;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const segments = path.split('.');
|
|
345
|
-
let current: unknown = obj;
|
|
346
|
-
|
|
347
|
-
for (const segment of segments) {
|
|
348
|
-
if (current === null || current === undefined) {
|
|
349
|
-
return undefined;
|
|
350
|
-
}
|
|
351
|
-
if (typeof current !== 'object') {
|
|
352
|
-
return undefined;
|
|
353
|
-
}
|
|
354
|
-
current = (current as Record<string, unknown>)[segment];
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
return current;
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
/**
|
|
361
|
-
* Convert a value to string, or return the original template if value is undefined.
|
|
362
|
-
*/
|
|
363
|
-
private stringify(value: unknown, originalTemplate: string): string {
|
|
364
|
-
if (value === undefined) {
|
|
365
|
-
return originalTemplate;
|
|
366
|
-
}
|
|
367
|
-
if (typeof value === 'string') {
|
|
368
|
-
return value;
|
|
369
|
-
}
|
|
370
|
-
if (value === null) {
|
|
371
|
-
return 'null';
|
|
372
|
-
}
|
|
373
|
-
return JSON.stringify(value);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Check if a string contains template references.
|
|
378
|
-
*
|
|
379
|
-
* @param str - String to check
|
|
380
|
-
* @returns True if the string contains template references
|
|
381
|
-
*/
|
|
382
|
-
containsTemplates(str: string): boolean {
|
|
383
|
-
if (typeof str !== 'string') {
|
|
384
|
-
return false;
|
|
385
|
-
}
|
|
386
|
-
return /\{\{[^}]+\}\}/.test(str);
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Extract all template references from a string.
|
|
391
|
-
*
|
|
392
|
-
* @param str - String to extract from
|
|
393
|
-
* @returns Array of template references
|
|
394
|
-
*/
|
|
395
|
-
extractTemplates(str: string): string[] {
|
|
396
|
-
if (typeof str !== 'string') {
|
|
397
|
-
return [];
|
|
398
|
-
}
|
|
399
|
-
const matches = str.match(/\{\{[^}]+\}\}/g);
|
|
400
|
-
return matches ?? [];
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
// ============================================================================
|
|
405
|
-
// Convenience Functions
|
|
406
|
-
// ============================================================================
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Resolve template references in input using context.
|
|
410
|
-
*
|
|
411
|
-
* @param input - Input value with potential templates
|
|
412
|
-
* @param context - Node execution context
|
|
413
|
-
* @returns Resolved input
|
|
414
|
-
*/
|
|
415
|
-
export function resolveTemplates(
|
|
416
|
-
input: unknown,
|
|
417
|
-
context: NodeExecutionContext
|
|
418
|
-
): unknown {
|
|
419
|
-
const resolver = TemplateResolver.fromContext(context);
|
|
420
|
-
return resolver.resolveValue(input);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
/**
|
|
424
|
-
* Resolve a template string using context.
|
|
425
|
-
*
|
|
426
|
-
* @param template - Template string
|
|
427
|
-
* @param context - Node execution context
|
|
428
|
-
* @returns Resolved string
|
|
429
|
-
*/
|
|
430
|
-
export function resolveTemplateString(
|
|
431
|
-
template: string,
|
|
432
|
-
context: NodeExecutionContext
|
|
433
|
-
): string {
|
|
434
|
-
const resolver = TemplateResolver.fromContext(context);
|
|
435
|
-
return resolver.resolveString(template);
|
|
436
|
-
}
|