diff --git a/src/node.ts b/src/node.ts index 0e596324e..96b89b309 100644 --- a/src/node.ts +++ b/src/node.ts @@ -53,6 +53,7 @@ export class ComputedNode extends Node { public readonly graphId: string; public readonly isResult: boolean; public readonly params: NodeDataParams; // Agent-specific parameters + private readonly dynamicParams: Record; public readonly nestedGraph?: GraphData; public readonly retryLimit: number; public retryCount: number = 0; @@ -98,6 +99,18 @@ export class ComputedNode extends Node { assert(!!this.ifSource.nodeId, `Invalid data source ${data.if}`); this.pendings.add(this.ifSource.nodeId); } + const regex = /^\$\{([^{}]+)\}$/; + this.dynamicParams = Object.keys(this.params).reduce((tmp: Record, key) => { + const value = this.params[key]; + const match = typeof value === "string" ? value.match(regex) : null; + if (match) { + const dataSource = parseNodeName(match[1]); + tmp[key] = dataSource; + assert(!!dataSource.nodeId, `Invalid data source ${key}:${value}`); + this.pendings.add(dataSource.nodeId); + } + return tmp; + }, {}); this.log.initForComputedNode(this); } @@ -242,8 +255,16 @@ export class ComputedNode extends Node { try { const callback = this.agentFunction ?? this.graph.getCallback(this.agentId); const localLog: TransactionLog[] = []; + const params = Object.keys(this.dynamicParams).reduce( + (tmp, key) => { + const [result] = this.graph.resultsOf([this.dynamicParams[key]]); + tmp[key] = result; + return tmp; + }, + { ...this.params }, + ); const context: AgentFunctionContext = { - params: this.params, + params: params, inputs: previousResults, debugInfo: { nodeId: this.nodeId, diff --git a/tests/graphai/test_params.ts b/tests/graphai/test_params.ts new file mode 100644 index 000000000..f5c28bbc1 --- /dev/null +++ b/tests/graphai/test_params.ts @@ -0,0 +1,57 @@ +import { AgentFunction } from "@/graphai"; +import { graphDataTestRunner } from "~/utils/runner"; +import { defaultTestAgents } from "@/utils/test_agents"; + +import test from "node:test"; +import assert from "node:assert"; + +const testAgent: AgentFunction, any> = async ({ params }) => { + return params; +}; + +const graphData_literal = { + version: 0.2, + nodes: { + source1: { + value: { apple: "red" }, + }, + source2: { + value: { lemon: "yellow" }, + }, + delayed1: { + agent: "sleeperAgent", + inputs: ["source1"], + }, + delayed2: { + agent: "sleeperAgent", + params: { + duration: 100, + }, + inputs: ["source2"], + }, + test1: { + agent: "testAgent", + params: { + fruit: "${source1}", + color: "${source2.lemon}", + }, + isResult: true, + }, + test2: { + agent: "testAgent", + params: { + fruit: "${delayed1}", + color: "${delayed2.lemon}", + }, + isResult: true, + }, + }, +}; + +test("test params", async () => { + const result = await graphDataTestRunner(__filename, graphData_literal, { testAgent, ...defaultTestAgents }, () => {}, false); + assert.deepStrictEqual(result, { + test1: { fruit: { apple: "red" }, color: "yellow" }, + test2: { fruit: { apple: "red" }, color: "yellow" }, + }); +});