@picoflow/ezgraph 0.0.16 → 0.0.17

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/README.md CHANGED
@@ -42,7 +42,7 @@ returns exactly one response:
42
42
  | ------------------------------- | -------------------------------------------------------------------------------------- |
43
43
  | `stay(feedback)` | Validation failed; continue collecting in the current node. |
44
44
  | `go(TargetNode)` | Enter another registered conversational node now. |
45
- | `go(Child1Node, Child2Node)` | Schedule multiple registered nodes concurrently; use an explicit join to continue. |
45
+ | `fanout(Child1Node, Child2Node)` | Schedule two or more registered nodes concurrently; use an explicit join to continue. |
46
46
  | `direct(content)` | Return exact code-owned content, such as a policy decision, price table, or ticket ID. |
47
47
  | `directTo(TargetNode, content)` | Return exact content and make the target the next user-turn node. |
48
48
  | `finish(content)` | Return exact final content and complete the conversation. |
@@ -328,7 +328,7 @@ class SupportNode extends LlmNode<SupportState> {
328
328
  }
329
329
  ```
330
330
 
331
- Recovery hooks may return fixed text or `direct()`, `directTo()`, `go()`, or
331
+ Recovery hooks may return fixed text or `direct()`, `directTo()`, `go()`, `fanout()`, or
332
332
  `finish()`. `stay()`, tool feedback, and cleanup remain tool-only.
333
333
  `onLlmError()` may also return `retryWithModel(ModelCatalog.model(...))` to
334
334
  select one temporary alternate model. The alternate stays active through tool
@@ -459,19 +459,23 @@ ordinary conversational handoffs; fixed worker edges remain ordinary LangGraph
459
459
  edges. Register `TerminateSessionNode` and connect it to `END` when a graph
460
460
  contains conversational nodes.
461
461
 
462
- For conditional fan-out, return `go(Child1Node, Child2Node)` from the successful
463
- tool handler, `onResponse()`, or deterministic `GraphNode.run()`. Save parent-owned
462
+ `go(TargetNode)` accepts exactly one target. For conditional fan-out, return
463
+ `fanout(Child1Node, Child2Node)` with two or more distinct registered targets
464
+ from the successful tool handler, `onResponse()`, or deterministic `GraphNode.run()`.
465
+ Save parent-owned
464
466
  data before returning. A multi-target builder has no `withState()` or
465
467
  `withMessage()` because there is no single destination for those effects;
466
468
  `withUsage()`, tool feedback, tool cleanup, and current-history messages still work.
467
- Single-target `go(TargetNode).withState(...)` remains unchanged.
469
+ `go(TargetNode).withState(...)` initializes that one target.
468
470
 
469
471
  Register the children as internal work (leave them out of `registerTurns()`, or
470
472
  use `workers()` in a fixed-entry graph), and declare a barrier for the next stage:
471
473
 
472
474
  ```ts
475
+ import { fanout } from "@picoflow/ezgraph";
476
+
473
477
  // In the parent, only after accepting and saving the input:
474
- return go(Child1Node, Child2Node);
478
+ return fanout(Child1Node, Child2Node);
475
479
 
476
480
  // In buildGraph(), after registering all nodes:
477
481
  graph.addEdge([Child1Node, Child2Node], NextConversationNode);
@@ -1 +1 @@
1
- var R=Object.defineProperty;var d=(r,e)=>R(r,"name",{value:e,configurable:!0});import"reflect-metadata";import{AIMessage as c,HumanMessage as T}from"@langchain/core/messages";import{Command as p,END as y,isCommand as u}from"@langchain/langgraph";import{GraphLlm as f}from"./graph-llm.config.js";import{GraphStateSupport as L}from"./graph-state-support.js";import{LlmRunner as O,DEFAULT_LLM_POLICY as I,DEFAULT_MAX_AGENT_ROUNDS as H,EmptyModelResponseError as k}from"./llm-runner.js";import{currentTurnSignal as x}from"./turn-context.js";import{combineGraphNodeUpdates as $}from"./node-outcome.js";import{parseJsonObjectResponse as N}from"./json-response.js";import{stableClassId as v}from"./stable-id.js";import{SessionLogWarning as b}from"./session-log.js";import{goTargetIds as A,isToolResponse as S,stay as M}from"./tool-response.js";import{invocationGraphState as G,hasNodeInvocation as P,invocationHistory as _,invocationNodeState as j,invocationUpdate as D,appendInvocationHistory as U,replaceInvocationNodeState as J,invocationContext as q,saveInvocationContext as F,replaceInvocationContext as W,saveInvocationNodeState as z,withNodeInvocation as X,invocationMode as Y,invocationPriorNode as B,invocationIsLocalOnly as K,assertInvocationWrite as g}from"./node-invocation.js";import{DecisionConfigurationError as Q,resolveDecisionOptions as V}from"./decision/decision-types.js";import{GRAPH_NODE_LOCAL_STATE as Ee}from"./node-outcome.js";const Z=Symbol("GRAPH_NODE_CLASS"),w=Symbol("graph-node-tool-handlers");function we(r){if(!r.trim())throw new Error("A tool handler requires a tool name.");return(e,t)=>{const o=Reflect.getOwnMetadata(w,e)??[];if(o.some(n=>n.toolName===r))throw new Error(`Tool '${r}' already has a handler.`);o.push({toolName:r,methodName:t}),Reflect.defineMetadata(w,o,e)}}d(we,"Tool");class E{static{d(this,"GraphNode")}llmGateway;runtime;static[Z]=!0;static id(){return this.name}name;id;constructor(e,t){this.llmGateway=e,this.runtime=t;const o=new.target;this.name=o.name,this.id=v(o,"graph node")}get graph(){return this.runtime}defineTool(){return[]}getLlmConfig(){return{}}route(e){throw new Error(`Graph node '${this.id}' does not define a branch route.`)}async handleTool(e,t,o){const n=this.toolHandler(t.name);if(!n)return this.rejectToolCall(t.name,`Unsupported tool '${t.name}'.`);const i=this.runtime.requireTool(n.toolName),a=oe(t.args);if(!a.ok)return this.rejectToolCall(n.toolName,a.error);const s=i.schema.safeParse(a.value);if(!s.success)return this.rejectToolCall(n.toolName,ne(s.error));const h=s.data,l=this[n.methodName];if(!l)throw new Error(`Tool '${n.toolName}' is decorated on missing method '${String(n.methodName)}'.`);const m=await l.call(this,h,o,e);if(S(m))return m;throw new Error(`Tool '${n.toolName}' on '${this.id}' must return a ToolResponse.`)}rejectToolCall(e,t){return b({tool_call:t,node:this.id,tool:e}),M(JSON.stringify({accepted:!1,error:t}))}usesChatModel(){return!0}onInvalidJsonResponse(e){throw e.error}onEmptyModelResponse(e){throw new k(e.reason)}invoke=d((e,t={})=>this.runtime.withInvocation(this.id,e,async()=>{const o=this.resolveNodeResponse(await this.run(e)),n=te(o),i=await this.resolveJsonResponse(e,n);if(this.runtime.stageNodeEntries(i.nodes),i.context!==void 0&&this.runtime.stageContext(i.context),this.usesChatModel()){const s=this.runtime.resolveLlmConfig(this.getLlmConfig()),h=ee(s,this.runtime.resolveLlmConfig()),l=(e.nodes??{})[this.id];(!h||l?.model!==void 0)&&this.runtime.saveNode(this.id,{model:h?void 0:f.modelMetadata(s)})}const a=$(i,this.runtime.stagedUpdate());if(this.runtime.isLocalOnlyInvocation()&&(u(o)||Object.keys(a).some(s=>s!=="nodes"&&s!=="tokens")||Object.keys(a.nodes??{}).some(s=>s!==this.id)))throw new Error(`Internal LLM node '${this.id}' may publish only its own node state and token usage.`);return this.validateNodeResult(a,u(o)),u(o)?new p({update:a,...o.goto===void 0?{}:{goto:o.goto},...o.graph===void 0?{}:{graph:o.graph},...o.resume===void 0?{}:{resume:o.resume}}):a},t,this.managesLlmExecution()),"invoke");managesLlmExecution(){return!1}validateNodeResult(e,t){}obtainTools(e={}){return this.toolHandlers().filter(({toolName:t})=>this.includeTool(t,e)).map(({toolName:t})=>this.runtime.requireTool(t)).sort((t,o)=>t.name==="terminate_session"?1:o.name==="terminate_session"?-1:0)}validateTools(e={}){this.obtainTools(e)}includeTool(e,t){return!0}llmConfig(){return this.runtime.resolveLlmConfig(this.getLlmConfig())}llmCallOptions(){return this.runtime.llmCallOptions()}async runLlm(e,t){const o=await this.runAgentLoop(e,t);if(!o.stopReason)return o;const n=await this.onEmptyModelResponse({state:e,conversation:o,reason:o.stopReason});return{...o,response:n}}llmLifecycle(){}runAgentLoop(e,t){const o=this.llmLifecycle();return new O(this.llmGateway).run({...o===void 0?{}:{lifecycle:o},systemPrompt:this.getPrompt(e),history:this.llmHistory(e),tools:this.obtainTools(),llmConfig:this.llmConfig(),executeTool:d(n=>this.handleTool(e,n,t),"executeTool"),maxAgentRounds:this.runtime.maxAgentRounds,emptyHistorySeed:this.runtime.llmPolicy.emptyHistorySeed,emptyResponseRecovery:this.runtime.llmPolicy.emptyResponseRecovery,callOptions:this.llmCallOptions()})}llmHistory(e){return this.history(e)}historySpace(){return this.runtime.historySpace(this.id)}history(e){return this.runtime.hasInvocation()?this.runtime.invocationHistory(this.historySpace()):e.histories[this.historySpace()]??[]}historyUpdate(e){return{histories:{[this.historySpace()]:e}}}respond(e){return{...this.runtime.respond(e),...this.historyUpdate([new c(e)])}}complete(e){return{...this.runtime.complete(e),...this.historyUpdate([new c(e)])}}resolveNodeResponse(e){if(!S(e))return e;if(e.targets!==void 0&&e.kind!=="go")throw new Error("Multiple targets are only supported by go().");if(e.kind==="stay")throw new Error(`Graph node '${this.id}' can only return stay() from a tool handler.`);if(e.cleanup)throw new Error(`Graph node '${this.id}' can only use withCleanup() from a tool handler.`);if(e.feedback!==void 0)throw new Error(`Graph node '${this.id}' can only use withToolFeedback() from a tool handler.`);if(e.messages&&this.graph.appendHistory(this.historySpace(),e.messages),e.kind==="go"||e.kind==="directTo"){const t=e.kind==="go"?A(e):void 0;if(t&&t.length>1)return new p({update:{response:"",inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:[...t]});if(!e.target)throw new Error(`Graph node '${this.id}' selected ${e.kind}() without a target.`);const o=t?.[0]??v(e.target,"graph node"),n=this.graph.historySpace(o);if(e.state&&this.graph.saveNodeState(e.target,e.state),e.message&&this.graph.appendHistory(n,[e.message]),e.kind==="directTo"){const i=C(this.id,e);return this.graph.appendHistory(n,[new c(i)]),new p({update:{currentNode:o,response:i,inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:y})}return new p({update:{currentNode:o,response:"",inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:o})}if(e.message)throw new Error(`Graph node '${this.id}' can only use withMessage() with go() or directTo().`);if(e.kind==="direct"){const t=C(this.id,e);return this.graph.appendHistory(this.historySpace(),[new c(t)]),new p({update:{currentNode:this.id,response:t,inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:y})}if(e.kind==="finish"){const t=C(this.id,e);return this.graph.appendHistory(this.historySpace(),[new c(t)]),new p({update:{...this.graph.complete(t),...e.usage===void 0?{}:{tokens:e.usage}},goto:y})}throw new Error(`Graph node '${this.id}' returned an unsupported response kind '${e.kind}'.`)}state(e){return this.runtime.hasInvocation()?this.runtime.nodeState(this.id):e.nodes[this.id]??{}}getState(){return this.runtime.nodeState(this.id)}saveState(e){this.runtime.saveNode(this.id,e)}save(e){return this.runtime.saveNode(this.id,e)}remove(...e){return this.runtime.removeNode(this.id,...e)}toolHandler(e){return this.toolHandlers().find(t=>t.toolName===e)}async resolveJsonResponse(e,t){if(!this.runtime.expectsJsonResponse()||t.completed!==!0)return t;try{return N(t.response??""),t}catch(o){const n=await this.onInvalidJsonResponse({state:e,update:t,response:t.response??"",error:o instanceof Error?o:new Error(String(o))});return(n.completed===!0||n.response)&&N(n.response??""),n}}toolHandlers(){let e=Object.getPrototypeOf(this);const t=[];for(;e&&e!==E.prototype;){const n=Reflect.getOwnMetadata(w,e)??[];t.push(...n),e=Object.getPrototypeOf(e)}const o=new Set;for(const n of t){if(o.has(n.toolName))throw new Error(`Graph node '${this.id}' has more than one handler for tool '${n.toolName}'.`);o.add(n.toolName)}return t}}function ee(r,e){return r.model===e.model&&JSON.stringify(f.parameters(r))===JSON.stringify(f.parameters(e))}d(ee,"sameLlmConfig");class Ce extends L{static{d(this,"GraphNodeRuntime")}defaultLlmConfig;historySpaces;responseMode;maxAgentRounds;llmPolicy;decisionOptions;decisionErrorHandler;llmLifecycle;assertContextChannel;tools=new Map;constructor(e,t,o={},n="chat",i=H,a=I,s={},h,l,m){super(e),this.defaultLlmConfig=t,this.historySpaces=o,this.responseMode=n,this.maxAgentRounds=i,this.llmPolicy=a,this.decisionOptions=s,this.decisionErrorHandler=h,this.llmLifecycle=l,this.assertContextChannel=m}llmCallOptions(){const{llmTimeoutMs:e}=this.llmPolicy,t=x();return{...e===void 0?{}:{timeoutMs:e},...t===void 0?{}:{signal:t}}}expectsJsonResponse(){return this.responseMode==="json"}historySpace(e){return e?this.historySpaces[e]??"default":"default"}resolveLlmConfig(e={}){return f.resolveConfig(this.defaultLlmConfig,e)}resolveDecisionOptions(e={}){return V(this.decisionOptions,e)}decisionProviderResolver;attachDecisionProviderResolver(e){this.decisionProviderResolver=e}resolveDecisionProvider(e){if(!this.decisionProviderResolver)throw new Q(`Decision provider '${e}' cannot be resolved before the graph is attached to an engine.`);return this.decisionProviderResolver(e)}async handleDecisionError(e){return await this.decisionErrorHandler?.(e)??null}registerTools(e,t){for(const o of t){const n=this.tools.get(o.name);if(n)throw new Error(`Tool '${o.name}' is defined by both '${n.owner}' and '${e}'.`);this.tools.set(o.name,{definition:o,owner:e})}}requireTool(e){const t=this.tools.get(e);if(!t)throw new Error(`Tool '${e}' is not defined in this graph.`);return t.definition}input(e){return this.latestInput({messages:e.histories[this.historySpace(e.currentNode)]??[]})}getConversation(e){const o=(this.hasInvocation()?this.invocationHistory(e):[]).filter(n=>T.isInstance(n)&&n.additional_kwargs?.ezgraphInternal!==!0).map(n=>typeof n.content=="string"?n.content:JSON.stringify(n.content));return{request:o.at(-1)??"",priorRequests:o.slice(-5,-1)}}respond(e){return this.hasInvocation()&&g(this),this.responseUpdate(e)}complete(e){return this.hasInvocation()&&g(this),this.endUpdate(e)}withInvocation(e,t,o,n={},i=!1){return X(this,e,t,o,n,i)}invocationMode(){return Y(this)}priorNode(){return B(this)}isLocalOnlyInvocation(){return K(this)}nodeState(e){return j(this,e)}hasInvocation(){return P(this)}graphState(){return G(this)}getContext(){return q(this)}saveContext(e){g(this),this.assertContextChannel?.(),F(this,e)}stageContext(e){g(this),this.assertContextChannel?.(),W(this,e)}appendHistory(e,t){U(this,e,t)}invocationHistory(e){return _(this,e)}stagedUpdate(){return D(this)}stageNodeEntries(e){for(const[t,o]of Object.entries(e??{}))!o||typeof o!="object"||Array.isArray(o)||J(this,t,o)}saveNode(e,t){return z(this,e,t),{nodes:{[e]:this.nodeState(e)}}}saveNodeState(e,t){this.saveNode(v(e,"graph node"),t)}removeNode(e,...t){return this.saveNode(e,Object.fromEntries(t.map(o=>[o,void 0])))}}function te(r){if(!u(r))return r;if(Array.isArray(r.update))throw new Error("GraphNode Command updates must be state objects.");return r.update??{}}d(te,"commandUpdate");function C(r,e){if(!e.response?.trim())throw new Error(`Graph node '${r}' selected ${e.kind}() without a response.`);return e.response}d(C,"requireNodeResponse");function oe(r){if(typeof r!="string")return{ok:!0,value:r};try{return{ok:!0,value:JSON.parse(r)}}catch(e){return{ok:!1,error:`Tool arguments were not valid JSON: ${e instanceof Error?e.message:String(e)}`}}}d(oe,"coerceToolArgs");function ne(r){return r.issues.map(e=>e.path.length>0?`${e.path.join(".")}: ${e.message}`:e.message).join("; ")}d(ne,"formatToolArgumentError");export{Z as GRAPH_NODE_CLASS,Ee as GRAPH_NODE_LOCAL_STATE,E as GraphNode,Ce as GraphNodeRuntime,we as Tool};
1
+ var R=Object.defineProperty;var d=(r,e)=>R(r,"name",{value:e,configurable:!0});import"reflect-metadata";import{AIMessage as c,HumanMessage as T}from"@langchain/core/messages";import{Command as p,END as y,isCommand as u}from"@langchain/langgraph";import{GraphLlm as f}from"./graph-llm.config.js";import{GraphStateSupport as L}from"./graph-state-support.js";import{LlmRunner as O,DEFAULT_LLM_POLICY as I,DEFAULT_MAX_AGENT_ROUNDS as H,EmptyModelResponseError as k}from"./llm-runner.js";import{currentTurnSignal as x}from"./turn-context.js";import{combineGraphNodeUpdates as $}from"./node-outcome.js";import{parseJsonObjectResponse as N}from"./json-response.js";import{stableClassId as v}from"./stable-id.js";import{SessionLogWarning as b}from"./session-log.js";import{goTargetIds as A,isToolResponse as S,stay as M}from"./tool-response.js";import{invocationGraphState as G,hasNodeInvocation as P,invocationHistory as _,invocationNodeState as j,invocationUpdate as D,appendInvocationHistory as U,replaceInvocationNodeState as J,invocationContext as q,saveInvocationContext as F,replaceInvocationContext as W,saveInvocationNodeState as z,withNodeInvocation as X,invocationMode as Y,invocationPriorNode as B,invocationIsLocalOnly as K,assertInvocationWrite as g}from"./node-invocation.js";import{DecisionConfigurationError as Q,resolveDecisionOptions as V}from"./decision/decision-types.js";import{GRAPH_NODE_LOCAL_STATE as Ee}from"./node-outcome.js";const Z=Symbol("GRAPH_NODE_CLASS"),w=Symbol("graph-node-tool-handlers");function we(r){if(!r.trim())throw new Error("A tool handler requires a tool name.");return(e,t)=>{const o=Reflect.getOwnMetadata(w,e)??[];if(o.some(n=>n.toolName===r))throw new Error(`Tool '${r}' already has a handler.`);o.push({toolName:r,methodName:t}),Reflect.defineMetadata(w,o,e)}}d(we,"Tool");class E{static{d(this,"GraphNode")}llmGateway;runtime;static[Z]=!0;static id(){return this.name}name;id;constructor(e,t){this.llmGateway=e,this.runtime=t;const o=new.target;this.name=o.name,this.id=v(o,"graph node")}get graph(){return this.runtime}defineTool(){return[]}getLlmConfig(){return{}}route(e){throw new Error(`Graph node '${this.id}' does not define a branch route.`)}async handleTool(e,t,o){const n=this.toolHandler(t.name);if(!n)return this.rejectToolCall(t.name,`Unsupported tool '${t.name}'.`);const i=this.runtime.requireTool(n.toolName),a=oe(t.args);if(!a.ok)return this.rejectToolCall(n.toolName,a.error);const s=i.schema.safeParse(a.value);if(!s.success)return this.rejectToolCall(n.toolName,ne(s.error));const h=s.data,l=this[n.methodName];if(!l)throw new Error(`Tool '${n.toolName}' is decorated on missing method '${String(n.methodName)}'.`);const m=await l.call(this,h,o,e);if(S(m))return m;throw new Error(`Tool '${n.toolName}' on '${this.id}' must return a ToolResponse.`)}rejectToolCall(e,t){return b({tool_call:t,node:this.id,tool:e}),M(JSON.stringify({accepted:!1,error:t}))}usesChatModel(){return!0}onInvalidJsonResponse(e){throw e.error}onEmptyModelResponse(e){throw new k(e.reason)}invoke=d((e,t={})=>this.runtime.withInvocation(this.id,e,async()=>{const o=this.resolveNodeResponse(await this.run(e)),n=te(o),i=await this.resolveJsonResponse(e,n);if(this.runtime.stageNodeEntries(i.nodes),i.context!==void 0&&this.runtime.stageContext(i.context),this.usesChatModel()){const s=this.runtime.resolveLlmConfig(this.getLlmConfig()),h=ee(s,this.runtime.resolveLlmConfig()),l=(e.nodes??{})[this.id];(!h||l?.model!==void 0)&&this.runtime.saveNode(this.id,{model:h?void 0:f.modelMetadata(s)})}const a=$(i,this.runtime.stagedUpdate());if(this.runtime.isLocalOnlyInvocation()&&(u(o)||Object.keys(a).some(s=>s!=="nodes"&&s!=="tokens")||Object.keys(a.nodes??{}).some(s=>s!==this.id)))throw new Error(`Internal LLM node '${this.id}' may publish only its own node state and token usage.`);return this.validateNodeResult(a,u(o)),u(o)?new p({update:a,...o.goto===void 0?{}:{goto:o.goto},...o.graph===void 0?{}:{graph:o.graph},...o.resume===void 0?{}:{resume:o.resume}}):a},t,this.managesLlmExecution()),"invoke");managesLlmExecution(){return!1}validateNodeResult(e,t){}obtainTools(e={}){return this.toolHandlers().filter(({toolName:t})=>this.includeTool(t,e)).map(({toolName:t})=>this.runtime.requireTool(t)).sort((t,o)=>t.name==="terminate_session"?1:o.name==="terminate_session"?-1:0)}validateTools(e={}){this.obtainTools(e)}includeTool(e,t){return!0}llmConfig(){return this.runtime.resolveLlmConfig(this.getLlmConfig())}llmCallOptions(){return this.runtime.llmCallOptions()}async runLlm(e,t){const o=await this.runAgentLoop(e,t);if(!o.stopReason)return o;const n=await this.onEmptyModelResponse({state:e,conversation:o,reason:o.stopReason});return{...o,response:n}}llmLifecycle(){}runAgentLoop(e,t){const o=this.llmLifecycle();return new O(this.llmGateway).run({...o===void 0?{}:{lifecycle:o},systemPrompt:this.getPrompt(e),history:this.llmHistory(e),tools:this.obtainTools(),llmConfig:this.llmConfig(),executeTool:d(n=>this.handleTool(e,n,t),"executeTool"),maxAgentRounds:this.runtime.maxAgentRounds,emptyHistorySeed:this.runtime.llmPolicy.emptyHistorySeed,emptyResponseRecovery:this.runtime.llmPolicy.emptyResponseRecovery,callOptions:this.llmCallOptions()})}llmHistory(e){return this.history(e)}historySpace(){return this.runtime.historySpace(this.id)}history(e){return this.runtime.hasInvocation()?this.runtime.invocationHistory(this.historySpace()):e.histories[this.historySpace()]??[]}historyUpdate(e){return{histories:{[this.historySpace()]:e}}}respond(e){return{...this.runtime.respond(e),...this.historyUpdate([new c(e)])}}complete(e){return{...this.runtime.complete(e),...this.historyUpdate([new c(e)])}}resolveNodeResponse(e){if(!S(e))return e;if(e.targets!==void 0&&e.kind!=="go")throw new Error("Multiple targets are only supported by fanout().");if(e.kind==="stay")throw new Error(`Graph node '${this.id}' can only return stay() from a tool handler.`);if(e.cleanup)throw new Error(`Graph node '${this.id}' can only use withCleanup() from a tool handler.`);if(e.feedback!==void 0)throw new Error(`Graph node '${this.id}' can only use withToolFeedback() from a tool handler.`);if(e.messages&&this.graph.appendHistory(this.historySpace(),e.messages),e.kind==="go"||e.kind==="directTo"){const t=e.kind==="go"?A(e):void 0;if(t&&t.length>1)return new p({update:{response:"",inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:[...t]});if(!e.target)throw new Error(`Graph node '${this.id}' selected ${e.kind}() without a target.`);const o=t?.[0]??v(e.target,"graph node"),n=this.graph.historySpace(o);if(e.state&&this.graph.saveNodeState(e.target,e.state),e.message&&this.graph.appendHistory(n,[e.message]),e.kind==="directTo"){const i=C(this.id,e);return this.graph.appendHistory(n,[new c(i)]),new p({update:{currentNode:o,response:i,inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:y})}return new p({update:{currentNode:o,response:"",inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:o})}if(e.message)throw new Error(`Graph node '${this.id}' can only use withMessage() with go() or directTo().`);if(e.kind==="direct"){const t=C(this.id,e);return this.graph.appendHistory(this.historySpace(),[new c(t)]),new p({update:{currentNode:this.id,response:t,inputConsumed:!0,completed:!1,...e.usage===void 0?{}:{tokens:e.usage}},goto:y})}if(e.kind==="finish"){const t=C(this.id,e);return this.graph.appendHistory(this.historySpace(),[new c(t)]),new p({update:{...this.graph.complete(t),...e.usage===void 0?{}:{tokens:e.usage}},goto:y})}throw new Error(`Graph node '${this.id}' returned an unsupported response kind '${e.kind}'.`)}state(e){return this.runtime.hasInvocation()?this.runtime.nodeState(this.id):e.nodes[this.id]??{}}getState(){return this.runtime.nodeState(this.id)}saveState(e){this.runtime.saveNode(this.id,e)}save(e){return this.runtime.saveNode(this.id,e)}remove(...e){return this.runtime.removeNode(this.id,...e)}toolHandler(e){return this.toolHandlers().find(t=>t.toolName===e)}async resolveJsonResponse(e,t){if(!this.runtime.expectsJsonResponse()||t.completed!==!0)return t;try{return N(t.response??""),t}catch(o){const n=await this.onInvalidJsonResponse({state:e,update:t,response:t.response??"",error:o instanceof Error?o:new Error(String(o))});return(n.completed===!0||n.response)&&N(n.response??""),n}}toolHandlers(){let e=Object.getPrototypeOf(this);const t=[];for(;e&&e!==E.prototype;){const n=Reflect.getOwnMetadata(w,e)??[];t.push(...n),e=Object.getPrototypeOf(e)}const o=new Set;for(const n of t){if(o.has(n.toolName))throw new Error(`Graph node '${this.id}' has more than one handler for tool '${n.toolName}'.`);o.add(n.toolName)}return t}}function ee(r,e){return r.model===e.model&&JSON.stringify(f.parameters(r))===JSON.stringify(f.parameters(e))}d(ee,"sameLlmConfig");class Ce extends L{static{d(this,"GraphNodeRuntime")}defaultLlmConfig;historySpaces;responseMode;maxAgentRounds;llmPolicy;decisionOptions;decisionErrorHandler;llmLifecycle;assertContextChannel;tools=new Map;constructor(e,t,o={},n="chat",i=H,a=I,s={},h,l,m){super(e),this.defaultLlmConfig=t,this.historySpaces=o,this.responseMode=n,this.maxAgentRounds=i,this.llmPolicy=a,this.decisionOptions=s,this.decisionErrorHandler=h,this.llmLifecycle=l,this.assertContextChannel=m}llmCallOptions(){const{llmTimeoutMs:e}=this.llmPolicy,t=x();return{...e===void 0?{}:{timeoutMs:e},...t===void 0?{}:{signal:t}}}expectsJsonResponse(){return this.responseMode==="json"}historySpace(e){return e?this.historySpaces[e]??"default":"default"}resolveLlmConfig(e={}){return f.resolveConfig(this.defaultLlmConfig,e)}resolveDecisionOptions(e={}){return V(this.decisionOptions,e)}decisionProviderResolver;attachDecisionProviderResolver(e){this.decisionProviderResolver=e}resolveDecisionProvider(e){if(!this.decisionProviderResolver)throw new Q(`Decision provider '${e}' cannot be resolved before the graph is attached to an engine.`);return this.decisionProviderResolver(e)}async handleDecisionError(e){return await this.decisionErrorHandler?.(e)??null}registerTools(e,t){for(const o of t){const n=this.tools.get(o.name);if(n)throw new Error(`Tool '${o.name}' is defined by both '${n.owner}' and '${e}'.`);this.tools.set(o.name,{definition:o,owner:e})}}requireTool(e){const t=this.tools.get(e);if(!t)throw new Error(`Tool '${e}' is not defined in this graph.`);return t.definition}input(e){return this.latestInput({messages:e.histories[this.historySpace(e.currentNode)]??[]})}getConversation(e){const o=(this.hasInvocation()?this.invocationHistory(e):[]).filter(n=>T.isInstance(n)&&n.additional_kwargs?.ezgraphInternal!==!0).map(n=>typeof n.content=="string"?n.content:JSON.stringify(n.content));return{request:o.at(-1)??"",priorRequests:o.slice(-5,-1)}}respond(e){return this.hasInvocation()&&g(this),this.responseUpdate(e)}complete(e){return this.hasInvocation()&&g(this),this.endUpdate(e)}withInvocation(e,t,o,n={},i=!1){return X(this,e,t,o,n,i)}invocationMode(){return Y(this)}priorNode(){return B(this)}isLocalOnlyInvocation(){return K(this)}nodeState(e){return j(this,e)}hasInvocation(){return P(this)}graphState(){return G(this)}getContext(){return q(this)}saveContext(e){g(this),this.assertContextChannel?.(),F(this,e)}stageContext(e){g(this),this.assertContextChannel?.(),W(this,e)}appendHistory(e,t){U(this,e,t)}invocationHistory(e){return _(this,e)}stagedUpdate(){return D(this)}stageNodeEntries(e){for(const[t,o]of Object.entries(e??{}))!o||typeof o!="object"||Array.isArray(o)||J(this,t,o)}saveNode(e,t){return z(this,e,t),{nodes:{[e]:this.nodeState(e)}}}saveNodeState(e,t){this.saveNode(v(e,"graph node"),t)}removeNode(e,...t){return this.saveNode(e,Object.fromEntries(t.map(o=>[o,void 0])))}}function te(r){if(!u(r))return r;if(Array.isArray(r.update))throw new Error("GraphNode Command updates must be state objects.");return r.update??{}}d(te,"commandUpdate");function C(r,e){if(!e.response?.trim())throw new Error(`Graph node '${r}' selected ${e.kind}() without a response.`);return e.response}d(C,"requireNodeResponse");function oe(r){if(typeof r!="string")return{ok:!0,value:r};try{return{ok:!0,value:JSON.parse(r)}}catch(e){return{ok:!1,error:`Tool arguments were not valid JSON: ${e instanceof Error?e.message:String(e)}`}}}d(oe,"coerceToolArgs");function ne(r){return r.issues.map(e=>e.path.length>0?`${e.path.join(".")}: ${e.message}`:e.message).join("; ")}d(ne,"formatToolArgumentError");export{Z as GRAPH_NODE_CLASS,Ee as GRAPH_NODE_LOCAL_STATE,E as GraphNode,Ce as GraphNodeRuntime,we as Tool};
@@ -1 +1 @@
1
- var y=Object.defineProperty;var h=(a,e)=>y(a,"name",{value:e,configurable:!0});var k=function(a,e,t,o){var s=arguments.length,n=s<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(a,e,t,o);else for(var r=a.length-1;r>=0;r--)(i=a[r])&&(n=(s<3?i(n):s>3?i(e,t,n):i(e,t))||n);return s>3&&n&&Object.defineProperty(e,t,n),n},m=function(a,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(a,e)};import{AIMessage as p,HumanMessage as L}from"@langchain/core/messages";import{Command as d,END as f}from"@langchain/langgraph";import{Tool as v}from"./graph-node.js";import{LlmNodeBase as R}from"./llm-node-base.js";import{stableClassId as I}from"./stable-id.js";import{TerminateSessionNode as M}from"./terminate-session.node.js";import{go as E,goTargetIds as u,isToolResponse as T}from"./tool-response.js";import{addTokenUsage as l}from"./token-usage.js";import{currentTurnSignal as g}from"./turn-context.js";class _ extends R{static{h(this,"LlmNode")}onEnter(e,t){return e}llmLifecycle(){return{...super.llmLifecycle(),onEnter:h(e=>this.onEnter(e,this.graph.hasInvocation()?this.graph.priorNode():void 0),"onEnter")}}onResponse(e,t){}managesLlmExecution(){return!0}isInternal(){return this.graph.hasInvocation()&&this.graph.invocationMode()==="internal"}includeTool(e,t){return!((t.mode==="internal"||t.mode===void 0&&this.isInternal())&&e==="terminate_session")}llmHistory(e){return this.isInternal()?[]:super.llmHistory(e)}async handleTool(e,t,o){if(this.isInternal()&&t.name==="terminate_session")throw this.invalidInternalOutcome(t.name);const s=await super.handleTool(e,t,o);return this.validateOutcome(s),s}validateLlmRecovery(e){e&&typeof e=="object"&&e.kind!=="retry_with_model"&&this.validateOutcome(e)}validateOutcome(e){const t=["target","targets","state","message","messages"].some(o=>o in e);if(e.kind==="taskResult"&&(!("value"in e)||e.value===void 0||t||["response","feedback","cleanup"].some(o=>o in e)))throw new Error(`LLM node '${this.id}' requires a taskResult value without conversation effects.`);if(e.targets!==void 0&&e.kind!=="go")throw new Error("Multiple targets are only supported by go().");if(e.kind==="go"&&u(e),this.isInternal()&&(e.kind!=="stay"&&e.kind!=="taskResult"&&e.kind!=="direct"||t))throw this.invalidInternalOutcome(e.kind)}invalidInternalOutcome(e){return new Error(`Internal LLM node '${this.id}' cannot use '${e}'; its caller owns conversation routing and completion.`)}async endChat(e){return E(M).withMessage(new L({content:e.message?.trim()||"The user asked to end the conversation.",additional_kwargs:{ezgraphInternal:!0}}))}async run(e){const t=await this.runLlm(e,{}),o=t.toolResponse;if(o&&(this.validateOutcome(o),o.kind!=="taskResult"&&o.kind!=="direct"))return this.resolveToolResponse(t,o);const s=o?.kind==="taskResult"?o.value:t.response;if(o?.kind!=="taskResult"&&(typeof s!="string"||!s.trim()))throw new Error(`LLM node '${this.id}' stopped without a response or tool transition.`);g()?.throwIfAborted();const n=await this.onResponse(s,e);g()?.throwIfAborted();let i=n===void 0?s:n,r=l(t.usage,o?.usage);if(T(n)){if(this.validateOutcome(n),n.cleanup)throw new Error(`LLM node '${this.id}' may use cleanup only from a tool handler.`);if(n.feedback!==void 0||n.messages)throw new Error(`LLM node '${this.id}' may use tool feedback/messages only from a tool handler.`);if(n.message&&n.kind!=="go"&&n.kind!=="directTo")throw new Error(`LLM node '${this.id}' may use withMessage() only with go() or directTo().`);if(n.kind==="stay")throw new Error(`LLM node '${this.id}' may return stay() only from a tool handler.`);if(n.kind!=="taskResult"&&n.kind!=="direct")return this.resolveToolResponse({...t,usage:r,messages:n.response?this.responseMessages(t,n.response):t.messages},n);i=n.kind==="taskResult"?n.value:n.response,r=l(r,n.usage)}if(typeof i=="string"&&!i.trim())throw new Error(`LLM node '${this.id}' onResponse() produced no response.`);if(this.isInternal())return{tokens:r};const c=typeof i=="string"?i:JSON.stringify(i);if(!c?.trim())throw new Error(`LLM node '${this.id}' onResponse() produced no response.`);return new d({update:{currentNode:this.id,response:c,inputConsumed:!0,completed:!1,...this.historyUpdate(this.responseMessages(t,c)),tokens:r},goto:f})}responseMessages(e,t){const o=[...e.messages],s=o.at(-1);return s&&p.isInstance(s)&&e.response!==void 0?t!==e.response&&(o[o.length-1]=new p({content:t,...s.id===void 0?{}:{id:s.id}})):o.push(new p(t)),o}resolveToolResponse(e,t){const o=this.historyUpdate(e.messages),s=l(e.usage,t.usage);if(t.kind==="go"){const n=u(t);if(n.length>1)return new d({update:{inputConsumed:!0,response:"",completed:!1,...o,tokens:s},goto:[...n]});if(!t.target)throw new Error(`LLM node '${this.id}' selected go() without a target.`);const i=n[0];return t.state&&this.graph.saveNodeState(t.target,t.state),t.message&&this.graph.appendHistory(this.graph.historySpace(i),[t.message]),new d({update:{currentNode:i,inputConsumed:!0,response:"",completed:!1,...o,tokens:s},goto:i})}if(t.kind==="directTo"){if(!t.target)throw new Error(`LLM node '${this.id}' selected directTo() without a target.`);const n=I(t.target,"graph node"),i=this.graph.historySpace(n);t.state&&this.graph.saveNodeState(t.target,t.state),t.message&&this.graph.appendHistory(i,[t.message]);const r=w(this.id,t);return i!==this.historySpace()&&this.graph.appendHistory(i,[new p(r)]),new d({update:{currentNode:n,response:r,inputConsumed:!0,completed:!1,...o,tokens:s},goto:f})}if(t.kind==="finish")return new d({update:{...this.graph.complete(w(this.id,t)),...o,tokens:s},goto:f});throw new Error(`LLM node '${this.id}' cannot publish '${t.kind}' as a conversation result.`)}}k([v("terminate_session"),m("design:type",Function),m("design:paramtypes",[Object]),m("design:returntype",Promise)],_.prototype,"endChat",null);function w(a,e){if(!e.response?.trim())throw new Error(`LLM node '${a}' selected ${e.kind}() without a response.`);return e.response}h(w,"requireResponse");export{_ as LlmNode};
1
+ var y=Object.defineProperty;var h=(a,e)=>y(a,"name",{value:e,configurable:!0});var k=function(a,e,t,o){var s=arguments.length,n=s<3?e:o===null?o=Object.getOwnPropertyDescriptor(e,t):o,i;if(typeof Reflect=="object"&&typeof Reflect.decorate=="function")n=Reflect.decorate(a,e,t,o);else for(var r=a.length-1;r>=0;r--)(i=a[r])&&(n=(s<3?i(n):s>3?i(e,t,n):i(e,t))||n);return s>3&&n&&Object.defineProperty(e,t,n),n},f=function(a,e){if(typeof Reflect=="object"&&typeof Reflect.metadata=="function")return Reflect.metadata(a,e)};import{AIMessage as p,HumanMessage as L}from"@langchain/core/messages";import{Command as d,END as m}from"@langchain/langgraph";import{Tool as v}from"./graph-node.js";import{LlmNodeBase as R}from"./llm-node-base.js";import{stableClassId as I}from"./stable-id.js";import{TerminateSessionNode as M}from"./terminate-session.node.js";import{go as E,goTargetIds as l,isToolResponse as T}from"./tool-response.js";import{addTokenUsage as u}from"./token-usage.js";import{currentTurnSignal as g}from"./turn-context.js";class _ extends R{static{h(this,"LlmNode")}onEnter(e,t){return e}llmLifecycle(){return{...super.llmLifecycle(),onEnter:h(e=>this.onEnter(e,this.graph.hasInvocation()?this.graph.priorNode():void 0),"onEnter")}}onResponse(e,t){}managesLlmExecution(){return!0}isInternal(){return this.graph.hasInvocation()&&this.graph.invocationMode()==="internal"}includeTool(e,t){return!((t.mode==="internal"||t.mode===void 0&&this.isInternal())&&e==="terminate_session")}llmHistory(e){return this.isInternal()?[]:super.llmHistory(e)}async handleTool(e,t,o){if(this.isInternal()&&t.name==="terminate_session")throw this.invalidInternalOutcome(t.name);const s=await super.handleTool(e,t,o);return this.validateOutcome(s),s}validateLlmRecovery(e){e&&typeof e=="object"&&e.kind!=="retry_with_model"&&this.validateOutcome(e)}validateOutcome(e){const t=["target","targets","state","message","messages"].some(o=>o in e);if(e.kind==="taskResult"&&(!("value"in e)||e.value===void 0||t||["response","feedback","cleanup"].some(o=>o in e)))throw new Error(`LLM node '${this.id}' requires a taskResult value without conversation effects.`);if(e.targets!==void 0&&e.kind!=="go")throw new Error("Multiple targets are only supported by fanout().");if(e.kind==="go"&&l(e),this.isInternal()&&(e.kind!=="stay"&&e.kind!=="taskResult"&&e.kind!=="direct"||t))throw this.invalidInternalOutcome(e.kind)}invalidInternalOutcome(e){return new Error(`Internal LLM node '${this.id}' cannot use '${e}'; its caller owns conversation routing and completion.`)}async endChat(e){return E(M).withMessage(new L({content:e.message?.trim()||"The user asked to end the conversation.",additional_kwargs:{ezgraphInternal:!0}}))}async run(e){const t=await this.runLlm(e,{}),o=t.toolResponse;if(o&&(this.validateOutcome(o),o.kind!=="taskResult"&&o.kind!=="direct"))return this.resolveToolResponse(t,o);const s=o?.kind==="taskResult"?o.value:t.response;if(o?.kind!=="taskResult"&&(typeof s!="string"||!s.trim()))throw new Error(`LLM node '${this.id}' stopped without a response or tool transition.`);g()?.throwIfAborted();const n=await this.onResponse(s,e);g()?.throwIfAborted();let i=n===void 0?s:n,r=u(t.usage,o?.usage);if(T(n)){if(this.validateOutcome(n),n.cleanup)throw new Error(`LLM node '${this.id}' may use cleanup only from a tool handler.`);if(n.feedback!==void 0||n.messages)throw new Error(`LLM node '${this.id}' may use tool feedback/messages only from a tool handler.`);if(n.message&&n.kind!=="go"&&n.kind!=="directTo")throw new Error(`LLM node '${this.id}' may use withMessage() only with go() or directTo().`);if(n.kind==="stay")throw new Error(`LLM node '${this.id}' may return stay() only from a tool handler.`);if(n.kind!=="taskResult"&&n.kind!=="direct")return this.resolveToolResponse({...t,usage:r,messages:n.response?this.responseMessages(t,n.response):t.messages},n);i=n.kind==="taskResult"?n.value:n.response,r=u(r,n.usage)}if(typeof i=="string"&&!i.trim())throw new Error(`LLM node '${this.id}' onResponse() produced no response.`);if(this.isInternal())return{tokens:r};const c=typeof i=="string"?i:JSON.stringify(i);if(!c?.trim())throw new Error(`LLM node '${this.id}' onResponse() produced no response.`);return new d({update:{currentNode:this.id,response:c,inputConsumed:!0,completed:!1,...this.historyUpdate(this.responseMessages(t,c)),tokens:r},goto:m})}responseMessages(e,t){const o=[...e.messages],s=o.at(-1);return s&&p.isInstance(s)&&e.response!==void 0?t!==e.response&&(o[o.length-1]=new p({content:t,...s.id===void 0?{}:{id:s.id}})):o.push(new p(t)),o}resolveToolResponse(e,t){const o=this.historyUpdate(e.messages),s=u(e.usage,t.usage);if(t.kind==="go"){const n=l(t);if(n.length>1)return new d({update:{inputConsumed:!0,response:"",completed:!1,...o,tokens:s},goto:[...n]});if(!t.target)throw new Error(`LLM node '${this.id}' selected go() without a target.`);const i=n[0];return t.state&&this.graph.saveNodeState(t.target,t.state),t.message&&this.graph.appendHistory(this.graph.historySpace(i),[t.message]),new d({update:{currentNode:i,inputConsumed:!0,response:"",completed:!1,...o,tokens:s},goto:i})}if(t.kind==="directTo"){if(!t.target)throw new Error(`LLM node '${this.id}' selected directTo() without a target.`);const n=I(t.target,"graph node"),i=this.graph.historySpace(n);t.state&&this.graph.saveNodeState(t.target,t.state),t.message&&this.graph.appendHistory(i,[t.message]);const r=w(this.id,t);return i!==this.historySpace()&&this.graph.appendHistory(i,[new p(r)]),new d({update:{currentNode:n,response:r,inputConsumed:!0,completed:!1,...o,tokens:s},goto:m})}if(t.kind==="finish")return new d({update:{...this.graph.complete(w(this.id,t)),...o,tokens:s},goto:m});throw new Error(`LLM node '${this.id}' cannot publish '${t.kind}' as a conversation result.`)}}k([v("terminate_session"),f("design:type",Function),f("design:paramtypes",[Object]),f("design:returntype",Promise)],_.prototype,"endChat",null);function w(a,e){if(!e.response?.trim())throw new Error(`LLM node '${a}' selected ${e.kind}() without a response.`);return e.response}h(w,"requireResponse");export{_ as LlmNode};
@@ -1 +1 @@
1
- var s=Object.defineProperty;var t=(e,i)=>s(e,"name",{value:i,configurable:!0});import{stableClassId as u}from"./stable-id.js";function l(e){return Object.freeze({kind:"taskResult",value:e})}t(l,"taskResult");function c(e,...i){const n=i.length===0?{kind:"go",target:e}:{kind:"go",targets:Object.freeze([e,...i])};return d(n),a(n)}t(c,"go");function d(e){if(e.kind!=="go")throw new Error("Expected a go() response.");if(e.targets!==void 0&&(!Array.isArray(e.targets)||e.targets.length<2||e.target!==void 0||e.state!==void 0||e.message!==void 0))throw new Error("Multi-target go() requires at least two targets and cannot use target, withState(), or withMessage().");const i=e.targets??(e.target?[e.target]:[]);if(i.length===0)throw new Error("go() requires a target.");const n=i.map(r=>{if(!r||typeof r.id!="function")throw new Error("go() requires registered GraphNode class targets.");return u(r,"graph node")});if(new Set(n).size!==n.length)throw new Error("Multi-target go() requires distinct graph node IDs.");return n}t(d,"goTargetIds");function h(e="OK"){return a({kind:"stay",feedback:e})}t(h,"stay");function w(e){return a({kind:"direct",response:o(e)})}t(w,"direct");function p(e,i){return a({kind:"directTo",target:e,response:o(i)})}t(p,"directTo");function k(e){return a({kind:"finish",response:o(e)})}t(k,"finish");function b(e){return!e||typeof e!="object"||!("kind"in e)?!1:["go","stay","direct","directTo","finish","taskResult"].includes(String(e.kind))}t(b,"isToolResponse");function o(e){return typeof e=="string"?e:JSON.stringify(e)}t(o,"responseContent");function a(e){const i={...e},n=t(r=>a({...e,...r}),"derive");return Object.defineProperties(i,{...e.targets===void 0?{withState:{enumerable:!1,value:t(r=>n({state:r}),"value")},withMessage:{enumerable:!1,value:t(r=>n({message:r}),"value")}}:{},withMessages:{enumerable:!1,value:t(r=>n({messages:r}),"value")},withCleanup:{enumerable:!1,value:t(r=>n({cleanup:r}),"value")},withToolFeedback:{enumerable:!1,value:t(r=>n({feedback:r}),"value")},withUsage:{enumerable:!1,value:t(r=>n({usage:r}),"value")}}),i}t(a,"createBuilder");export{w as direct,p as directTo,k as finish,c as go,d as goTargetIds,b as isToolResponse,h as stay,l as taskResult};
1
+ var u=Object.defineProperty;var r=(e,n)=>u(e,"name",{value:n,configurable:!0});import{stableClassId as f}from"./stable-id.js";function l(e){return Object.freeze({kind:"taskResult",value:e})}r(l,"taskResult");function c(e){if(arguments.length!==1)throw new Error("go() requires exactly one target; use fanout() for two or more targets.");const n={kind:"go",target:e};return s(n),o(n)}r(c,"go");function h(e,n,...i){if(arguments.length<2)throw new Error("fanout() requires at least two targets.");const t={kind:"go",targets:Object.freeze([e,n,...i])};return s(t),o(t)}r(h,"fanout");function s(e){if(e.kind!=="go")throw new Error("Expected a go() or fanout() response.");if(e.targets!==void 0&&(!Array.isArray(e.targets)||e.targets.length<2||e.target!==void 0||e.state!==void 0||e.message!==void 0))throw new Error("fanout() requires at least two targets and cannot use target, withState(), or withMessage().");const n=e.targets??(e.target?[e.target]:[]);if(n.length===0)throw new Error("go() requires a target.");const i=n.map(t=>{if(!t||typeof t.id!="function")throw new Error(`${e.targets===void 0?"go":"fanout"}() requires registered GraphNode class targets.`);return f(t,"graph node")});if(new Set(i).size!==i.length)throw new Error("fanout() requires distinct graph node IDs.");return i}r(s,"goTargetIds");function w(e="OK"){return o({kind:"stay",feedback:e})}r(w,"stay");function p(e){return o({kind:"direct",response:a(e)})}r(p,"direct");function k(e,n){return o({kind:"directTo",target:e,response:a(n)})}r(k,"directTo");function b(e){return o({kind:"finish",response:a(e)})}r(b,"finish");function m(e){return!e||typeof e!="object"||!("kind"in e)?!1:["go","stay","direct","directTo","finish","taskResult"].includes(String(e.kind))}r(m,"isToolResponse");function a(e){return typeof e=="string"?e:JSON.stringify(e)}r(a,"responseContent");function o(e){const n={...e},i=r(t=>o({...e,...t}),"derive");return Object.defineProperties(n,{...e.targets===void 0?{withState:{enumerable:!1,value:r(t=>i({state:t}),"value")},withMessage:{enumerable:!1,value:r(t=>i({message:t}),"value")}}:{},withMessages:{enumerable:!1,value:r(t=>i({messages:t}),"value")},withCleanup:{enumerable:!1,value:r(t=>i({cleanup:t}),"value")},withToolFeedback:{enumerable:!1,value:r(t=>i({feedback:t}),"value")},withUsage:{enumerable:!1,value:r(t=>i({usage:t}),"value")}}),n}r(o,"createBuilder");export{p as direct,k as directTo,h as fanout,b as finish,c as go,s as goTargetIds,m as isToolResponse,w as stay,l as taskResult};
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{GraphContextChannel as r}from"./framework/graph-context.js";import{BaseGraph as t}from"./framework/base-graph.js";import{GRAPH_NODE_CLASS as n,GraphNode as a,GraphNodeRuntime as m,Tool as p}from"./framework/graph-node.js";import{LlmNode as E}from"./framework/llm-node.js";import{LLM_GATEWAY_FACTORY as L,assertLlmTimeoutMs as f}from"./framework/llm-gateway.js";import{LlmRunner as d,DEFAULT_LLM_POLICY as g,DEFAULT_EMPTY_HISTORY_SEED as D,DEFAULT_EMPTY_RESPONSE_RECOVERY as T,DEFAULT_MAX_AGENT_ROUNDS as R,EmptyModelResponseError as _,assertEmptyResponseRetries as c,assertMaxAgentRounds as C}from"./framework/llm-runner.js";import{describeStopReason as u,isRetryableStopReason as A,modelStopReason as N}from"./framework/model-stop-reason.js";import{currentTurnContext as I,currentTurnSignal as G,withTurnContext as P}from"./framework/turn-context.js";import{direct as U,directTo as y,finish as v,go as F,isToolResponse as Y,stay as k,taskResult as H}from"./framework/tool-response.js";import{GraphStateSupport as b}from"./framework/graph-state-support.js";import{GRAPH_END_NODE as W,createGraphStateAnnotation as w}from"./framework/graph-state.js";import{GraphRegistry as q}from"./framework/graph-registry.js";import{GraphEngine as Q}from"./framework/graph-engine.js";import{ConfigManager as j}from"./framework/config-manager.js";import{StateGraphExt as Z}from"./framework/state-graph-ext.js";import{TerminateSessionNode as ee}from"./framework/terminate-session.node.js";import{SessionLogError as re,SessionLogDecision as se,SessionLogWarning as te,createSessionLogs as ie,drainSessionLogs as ne,restoreSessionLogs as ae,withSessionLogs as me}from"./framework/session-log.js";import{ProviderFileManager as Se}from"./framework/llm-file.js";import{SessionManager as xe,SessionTurnError as Le,SESSION_BUSY as fe,SESSION_CONFLICT as le,SESSION_COMPLETED as de,SESSION_DOCUMENT_VERSION as ge,MemorySessionDocumentContainer as De,sessionTurnLeaseMs as Te,sessionRevision as Re,isLiveSessionTurn as _e,matchesSessionWritePredicate as ce}from"./framework/persistence/session-manager.js";import{MongoDbSessionDocumentContainer as Me}from"./framework/persistence/mongodb-session-document.container.js";import{SqliteSessionDocumentContainer as Ae}from"./framework/persistence/sqlite-session-document.container.js";import{CosmosSessionDocumentContainer as Oe}from"./framework/persistence/cosmos-session-document.container.js";import{mergeNodeStates as Ge,replaceNodeStates as Pe}from"./framework/node-state.js";import{LangChainLlmGateway as Ue}from"./framework/langchain-llm-gateway.js";import{ModelProvider as ve}from"./framework/model-provider.js";import{langChainModelInitialization as Ye}from"./framework/langchain-provider.adapter.js";import{GRAPH_LLM_PROVIDERS as He,GRAPH_LLM_FAMILIES as Be,GRAPH_LLM_CAPABILITIES as be,BUILT_IN_MODEL_CATALOG as Ve,GraphLlm as We,ModelCatalog as we,ModelProviderRegistry as ze}from"./framework/graph-llm.config.js";import{addTokenUsage as Je,emptyTokenUsage as Qe,modelExecution as Xe,normalizeTokenUsage as je,tokenUsageFromMessage as Ke}from"./framework/token-usage.js";import{DecisionNode as $e}from"./framework/decision/decision-node.js";import{DecisionRunner as oo}from"./framework/decision/decision-runner.js";import{DecisionProvider as so,DecisionProviderRegistry as to}from"./framework/decision/decision-provider.js";import{TypeSafeClassifierAdapter as no}from"./framework/decision/typesafe-provider.js";import{DecisionConfigurationError as mo,DecisionTimeoutError as po,DecisionValidationError as So,DEFAULT_DECISION_OPTIONS as Eo,addDecisionUsage as xo,decisionUsage as Lo,emptyDecisionUsage as fo,normalizeDecisionUsage as lo,resolveDecisionOptions as go}from"./framework/decision/decision-types.js";import{assertJsonCompatible as To,validateDecisionQuestions as Ro,validateDecisionResult as _o}from"./framework/decision/decision-validation.js";import{retryWithModel as Co,LlmResponseBlockedError as Mo,LlmSetupError as uo}from"./framework/llm-lifecycle.js";export{Ve as BUILT_IN_MODEL_CATALOG,t as BaseGraph,j as ConfigManager,Oe as CosmosSessionDocumentContainer,Eo as DEFAULT_DECISION_OPTIONS,D as DEFAULT_EMPTY_HISTORY_SEED,T as DEFAULT_EMPTY_RESPONSE_RECOVERY,g as DEFAULT_LLM_POLICY,R as DEFAULT_MAX_AGENT_ROUNDS,mo as DecisionConfigurationError,$e as DecisionNode,so as DecisionProvider,to as DecisionProviderRegistry,oo as DecisionRunner,po as DecisionTimeoutError,So as DecisionValidationError,_ as EmptyModelResponseError,W as GRAPH_END_NODE,be as GRAPH_LLM_CAPABILITIES,Be as GRAPH_LLM_FAMILIES,He as GRAPH_LLM_PROVIDERS,n as GRAPH_NODE_CLASS,r as GraphContextChannel,Q as GraphEngine,We as GraphLlm,a as GraphNode,m as GraphNodeRuntime,q as GraphRegistry,b as GraphStateSupport,L as LLM_GATEWAY_FACTORY,Ue as LangChainLlmGateway,E as LlmNode,Mo as LlmResponseBlockedError,d as LlmRunner,uo as LlmSetupError,De as MemorySessionDocumentContainer,we as ModelCatalog,ve as ModelProvider,ze as ModelProviderRegistry,Me as MongoDbSessionDocumentContainer,Se as ProviderFileManager,fe as SESSION_BUSY,de as SESSION_COMPLETED,le as SESSION_CONFLICT,ge as SESSION_DOCUMENT_VERSION,se as SessionLogDecision,re as SessionLogError,te as SessionLogWarning,xe as SessionManager,Le as SessionTurnError,Ae as SqliteSessionDocumentContainer,Z as StateGraphExt,ee as TerminateSessionNode,p as Tool,no as TypeSafeClassifierAdapter,xo as addDecisionUsage,Je as addTokenUsage,c as assertEmptyResponseRetries,To as assertJsonCompatible,f as assertLlmTimeoutMs,C as assertMaxAgentRounds,w as createGraphStateAnnotation,ie as createSessionLogs,I as currentTurnContext,G as currentTurnSignal,Lo as decisionUsage,u as describeStopReason,U as direct,y as directTo,ne as drainSessionLogs,fo as emptyDecisionUsage,Qe as emptyTokenUsage,v as finish,F as go,_e as isLiveSessionTurn,A as isRetryableStopReason,Y as isToolResponse,Ye as langChainModelInitialization,ce as matchesSessionWritePredicate,Ge as mergeNodeStates,Xe as modelExecution,N as modelStopReason,lo as normalizeDecisionUsage,je as normalizeTokenUsage,Pe as replaceNodeStates,go as resolveDecisionOptions,ae as restoreSessionLogs,Co as retryWithModel,Re as sessionRevision,Te as sessionTurnLeaseMs,k as stay,H as taskResult,Ke as tokenUsageFromMessage,Ro as validateDecisionQuestions,_o as validateDecisionResult,me as withSessionLogs,P as withTurnContext};
1
+ import{GraphContextChannel as r}from"./framework/graph-context.js";import{BaseGraph as s}from"./framework/base-graph.js";import{GRAPH_NODE_CLASS as n,GraphNode as a,GraphNodeRuntime as m,Tool as p}from"./framework/graph-node.js";import{LlmNode as E}from"./framework/llm-node.js";import{LLM_GATEWAY_FACTORY as x,assertLlmTimeoutMs as L}from"./framework/llm-gateway.js";import{LlmRunner as d,DEFAULT_LLM_POLICY as g,DEFAULT_EMPTY_HISTORY_SEED as D,DEFAULT_EMPTY_RESPONSE_RECOVERY as T,DEFAULT_MAX_AGENT_ROUNDS as R,EmptyModelResponseError as _,assertEmptyResponseRetries as c,assertMaxAgentRounds as C}from"./framework/llm-runner.js";import{describeStopReason as u,isRetryableStopReason as A,modelStopReason as N}from"./framework/model-stop-reason.js";import{currentTurnContext as I,currentTurnSignal as G,withTurnContext as P}from"./framework/turn-context.js";import{direct as U,directTo as y,finish as v,fanout as F,go as Y,isToolResponse as k,stay as H,taskResult as B}from"./framework/tool-response.js";import{GraphStateSupport as V}from"./framework/graph-state-support.js";import{GRAPH_END_NODE as w,createGraphStateAnnotation as z}from"./framework/graph-state.js";import{GraphRegistry as J}from"./framework/graph-registry.js";import{GraphEngine as X}from"./framework/graph-engine.js";import{ConfigManager as K}from"./framework/config-manager.js";import{StateGraphExt as $}from"./framework/state-graph-ext.js";import{TerminateSessionNode as oe}from"./framework/terminate-session.node.js";import{SessionLogError as te,SessionLogDecision as se,SessionLogWarning as ie,createSessionLogs as ne,drainSessionLogs as ae,restoreSessionLogs as me,withSessionLogs as pe}from"./framework/session-log.js";import{ProviderFileManager as Ee}from"./framework/llm-file.js";import{SessionManager as xe,SessionTurnError as Le,SESSION_BUSY as le,SESSION_CONFLICT as de,SESSION_COMPLETED as ge,SESSION_DOCUMENT_VERSION as De,MemorySessionDocumentContainer as Te,sessionTurnLeaseMs as Re,sessionRevision as _e,isLiveSessionTurn as ce,matchesSessionWritePredicate as Ce}from"./framework/persistence/session-manager.js";import{MongoDbSessionDocumentContainer as ue}from"./framework/persistence/mongodb-session-document.container.js";import{SqliteSessionDocumentContainer as Ne}from"./framework/persistence/sqlite-session-document.container.js";import{CosmosSessionDocumentContainer as Ie}from"./framework/persistence/cosmos-session-document.container.js";import{mergeNodeStates as Pe,replaceNodeStates as he}from"./framework/node-state.js";import{LangChainLlmGateway as ye}from"./framework/langchain-llm-gateway.js";import{ModelProvider as Fe}from"./framework/model-provider.js";import{langChainModelInitialization as ke}from"./framework/langchain-provider.adapter.js";import{GRAPH_LLM_PROVIDERS as Be,GRAPH_LLM_FAMILIES as be,GRAPH_LLM_CAPABILITIES as Ve,BUILT_IN_MODEL_CATALOG as We,GraphLlm as we,ModelCatalog as ze,ModelProviderRegistry as qe}from"./framework/graph-llm.config.js";import{addTokenUsage as Qe,emptyTokenUsage as Xe,modelExecution as je,normalizeTokenUsage as Ke,tokenUsageFromMessage as Ze}from"./framework/token-usage.js";import{DecisionNode as eo}from"./framework/decision/decision-node.js";import{DecisionRunner as ro}from"./framework/decision/decision-runner.js";import{DecisionProvider as so,DecisionProviderRegistry as io}from"./framework/decision/decision-provider.js";import{TypeSafeClassifierAdapter as ao}from"./framework/decision/typesafe-provider.js";import{DecisionConfigurationError as po,DecisionTimeoutError as So,DecisionValidationError as Eo,DEFAULT_DECISION_OPTIONS as fo,addDecisionUsage as xo,decisionUsage as Lo,emptyDecisionUsage as lo,normalizeDecisionUsage as go,resolveDecisionOptions as Do}from"./framework/decision/decision-types.js";import{assertJsonCompatible as Ro,validateDecisionQuestions as _o,validateDecisionResult as co}from"./framework/decision/decision-validation.js";import{retryWithModel as Mo,LlmResponseBlockedError as uo,LlmSetupError as Ao}from"./framework/llm-lifecycle.js";export{We as BUILT_IN_MODEL_CATALOG,s as BaseGraph,K as ConfigManager,Ie as CosmosSessionDocumentContainer,fo as DEFAULT_DECISION_OPTIONS,D as DEFAULT_EMPTY_HISTORY_SEED,T as DEFAULT_EMPTY_RESPONSE_RECOVERY,g as DEFAULT_LLM_POLICY,R as DEFAULT_MAX_AGENT_ROUNDS,po as DecisionConfigurationError,eo as DecisionNode,so as DecisionProvider,io as DecisionProviderRegistry,ro as DecisionRunner,So as DecisionTimeoutError,Eo as DecisionValidationError,_ as EmptyModelResponseError,w as GRAPH_END_NODE,Ve as GRAPH_LLM_CAPABILITIES,be as GRAPH_LLM_FAMILIES,Be as GRAPH_LLM_PROVIDERS,n as GRAPH_NODE_CLASS,r as GraphContextChannel,X as GraphEngine,we as GraphLlm,a as GraphNode,m as GraphNodeRuntime,J as GraphRegistry,V as GraphStateSupport,x as LLM_GATEWAY_FACTORY,ye as LangChainLlmGateway,E as LlmNode,uo as LlmResponseBlockedError,d as LlmRunner,Ao as LlmSetupError,Te as MemorySessionDocumentContainer,ze as ModelCatalog,Fe as ModelProvider,qe as ModelProviderRegistry,ue as MongoDbSessionDocumentContainer,Ee as ProviderFileManager,le as SESSION_BUSY,ge as SESSION_COMPLETED,de as SESSION_CONFLICT,De as SESSION_DOCUMENT_VERSION,se as SessionLogDecision,te as SessionLogError,ie as SessionLogWarning,xe as SessionManager,Le as SessionTurnError,Ne as SqliteSessionDocumentContainer,$ as StateGraphExt,oe as TerminateSessionNode,p as Tool,ao as TypeSafeClassifierAdapter,xo as addDecisionUsage,Qe as addTokenUsage,c as assertEmptyResponseRetries,Ro as assertJsonCompatible,L as assertLlmTimeoutMs,C as assertMaxAgentRounds,z as createGraphStateAnnotation,ne as createSessionLogs,I as currentTurnContext,G as currentTurnSignal,Lo as decisionUsage,u as describeStopReason,U as direct,y as directTo,ae as drainSessionLogs,lo as emptyDecisionUsage,Xe as emptyTokenUsage,F as fanout,v as finish,Y as go,ce as isLiveSessionTurn,A as isRetryableStopReason,k as isToolResponse,ke as langChainModelInitialization,Ce as matchesSessionWritePredicate,Pe as mergeNodeStates,je as modelExecution,N as modelStopReason,go as normalizeDecisionUsage,Ke as normalizeTokenUsage,he as replaceNodeStates,Do as resolveDecisionOptions,me as restoreSessionLogs,Mo as retryWithModel,_e as sessionRevision,Re as sessionTurnLeaseMs,H as stay,B as taskResult,Ze as tokenUsageFromMessage,_o as validateDecisionQuestions,co as validateDecisionResult,pe as withSessionLogs,P as withTurnContext};
@@ -6,7 +6,7 @@ export { LLM_GATEWAY_FACTORY, assertLlmTimeoutMs, type LlmCallOptions, type LlmG
6
6
  export { LlmRunner, DEFAULT_LLM_POLICY, DEFAULT_EMPTY_HISTORY_SEED, DEFAULT_EMPTY_RESPONSE_RECOVERY, DEFAULT_MAX_AGENT_ROUNDS, EmptyModelResponseError, assertEmptyResponseRetries, assertMaxAgentRounds, type LlmPolicy, type LlmRunResult, type EmptyResponseRecovery, } from "../../src/framework/llm-runner.js";
7
7
  export { describeStopReason, isRetryableStopReason, modelStopReason, type ModelStopCategory, type ModelStopReason, } from "../../src/framework/model-stop-reason.js";
8
8
  export { currentTurnContext, currentTurnSignal, withTurnContext, type TurnContext, } from "../../src/framework/turn-context.js";
9
- export { direct, directTo, finish, go, isToolResponse, stay, taskResult, type FanOutResponseBuilder, type TaskResult, type ToolResponse, type ToolResponseBuilder, type ToolResponseKind, } from "../../src/framework/tool-response.js";
9
+ export { direct, directTo, finish, fanout, go, isToolResponse, stay, taskResult, type FanOutResponseBuilder, type TaskResult, type ToolResponse, type ToolResponseBuilder, type ToolResponseKind, } from "../../src/framework/tool-response.js";
10
10
  export { GraphStateSupport } from "../../src/framework/graph-state-support.js";
11
11
  export { GRAPH_END_NODE, createGraphStateAnnotation, type GraphState, } from "../../src/framework/graph-state.js";
12
12
  export { GraphRegistry, type RegisteredGraph, } from "../../src/framework/graph-registry.js";
@@ -35,7 +35,7 @@ export type FanOutResponseBuilder = ToolResponse & {
35
35
  withUsage(usage: TokenUsage): FanOutResponseBuilder;
36
36
  };
37
37
  export declare function go<NodeClass extends GraphNodeTarget>(target: NodeClass): ToolResponseBuilder<NodeClass>;
38
- export declare function go(first: GraphNodeTarget, second: GraphNodeTarget, ...rest: readonly GraphNodeTarget[]): FanOutResponseBuilder;
38
+ export declare function fanout(first: GraphNodeTarget, second: GraphNodeTarget, ...rest: readonly GraphNodeTarget[]): FanOutResponseBuilder;
39
39
  export declare function goTargetIds(response: ToolResponse): readonly string[];
40
40
  export declare function stay(feedback?: string): ToolResponseBuilder<GraphNodeTarget>;
41
41
  export declare function direct(content: string | object): ToolResponseBuilder<GraphNodeTarget>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picoflow/ezgraph",
3
- "version": "0.0.16",
3
+ "version": "0.0.17",
4
4
  "description": "Provider-neutral graph primitives built on LangGraph and LangChain.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",