@copilotkit/sdk-js 1.57.3 → 1.58.0-canary.thread-id-propagation

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.
@@ -169,22 +169,38 @@ async function copilotkitEmitMessage(config, message) {
169
169
  * ```typescript
170
170
  * import { copilotkitEmitToolCall } from "@copilotkit/sdk-js";
171
171
  *
172
- * await copilotkitEmitToolCall(config, name="SearchTool", args={"steps": 10})
172
+ * const autoId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 });
173
+ *
174
+ * // With a custom ID for correlation/idempotency:
175
+ * const customId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 }, { toolCallId: "my-custom-id" });
173
176
  * ```
177
+ *
178
+ * @returns The tool call ID used for the emitted call — equals `options.toolCallId`
179
+ * when provided, otherwise a randomly generated ID.
174
180
  */
175
- async function copilotkitEmitToolCall(config, name, args) {
181
+ async function copilotkitEmitToolCall(config, name, args, options) {
176
182
  if (!config) throw new _copilotkit_shared.CopilotKitMisuseError({ message: "LangGraph configuration is required for copilotkitEmitToolCall" });
177
- if (!name || typeof name !== "string") throw new _copilotkit_shared.CopilotKitMisuseError({ message: "Tool name must be a non-empty string for copilotkitEmitToolCall" });
183
+ if (typeof name !== "string" || name.trim().length === 0) throw new _copilotkit_shared.CopilotKitMisuseError({ message: "Tool name must be a non-empty string for copilotkitEmitToolCall" });
184
+ if (options?.toolCallId !== void 0 && (typeof options.toolCallId !== "string" || options.toolCallId.trim().length === 0)) throw new _copilotkit_shared.CopilotKitMisuseError({ message: "Tool call id must be a non-empty string when provided for copilotkitEmitToolCall" });
178
185
  if (args === void 0) throw new _copilotkit_shared.CopilotKitMisuseError({ message: "Tool arguments are required for copilotkitEmitToolCall" });
186
+ try {
187
+ JSON.stringify(args);
188
+ } catch (error) {
189
+ throw new _copilotkit_shared.CopilotKitMisuseError({ message: `Tool arguments for '${name}' are not JSON-serializable: ${error instanceof Error ? error.message : String(error)}` });
190
+ }
191
+ const toolCallId = options?.toolCallId ?? (0, _copilotkit_shared.randomUUID)();
179
192
  try {
180
193
  await (0, _langchain_core_callbacks_dispatch.dispatchCustomEvent)("copilotkit_manually_emit_tool_call", {
181
194
  name,
182
195
  args,
183
- id: (0, _copilotkit_shared.randomId)()
196
+ id: toolCallId
184
197
  }, config);
185
198
  } catch (error) {
186
- throw new _copilotkit_shared.CopilotKitMisuseError({ message: `Failed to emit tool call '${name}': ${error instanceof Error ? error.message : String(error)}` });
199
+ const wrapped = /* @__PURE__ */ new Error(`copilotkitEmitToolCall dispatch failed for tool="${name}" id="${toolCallId}": ${error instanceof Error ? error.message : String(error)}`);
200
+ wrapped.cause = error;
201
+ throw wrapped;
187
202
  }
203
+ return toolCallId;
188
204
  }
189
205
  function convertActionToDynamicStructuredTool(actionInput) {
190
206
  if (!actionInput) throw new _copilotkit_shared.CopilotKitMisuseError({ message: "Action input is required but was not provided" });
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","names":["CopilotKitMisuseError","DynamicStructuredTool","AIMessage"],"sources":["../../src/langgraph/utils.ts"],"sourcesContent":["import { RunnableConfig } from \"@langchain/core/runnables\";\nimport { dispatchCustomEvent } from \"@langchain/core/callbacks/dispatch\";\nimport {\n convertJsonSchemaToZodSchema,\n randomId,\n CopilotKitMisuseError,\n} from \"@copilotkit/shared\";\nimport { interrupt } from \"@langchain/langgraph\";\nimport { DynamicStructuredTool } from \"@langchain/core/tools\";\nimport { AIMessage } from \"@langchain/core/messages\";\nimport { OptionsConfig } from \"./types\";\n\n/**\n * Customize the LangGraph configuration for use in CopilotKit.\n *\n * To the CopilotKit SDK, run:\n *\n * ```bash\n * npm install @copilotkit/sdk-js\n * ```\n *\n * ### Examples\n *\n * Disable emitting messages and tool calls:\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitMessages=false,\n * emitToolCalls=false\n * )\n * ```\n *\n * To emit a tool call as streaming LangGraph state, pass the destination key in state,\n * the tool name and optionally the tool argument. (If you don't pass the argument name,\n * all arguments are emitted under the state key.)\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitIntermediateState=[\n * {\n * \"stateKey\": \"steps\",\n * \"tool\": \"SearchTool\",\n * \"toolArgument\": \"steps\",\n * },\n * ],\n * )\n * ```\n */\nexport function copilotkitCustomizeConfig(\n /**\n * The LangChain/LangGraph configuration to customize.\n */\n baseConfig: RunnableConfig,\n /**\n * Configuration options:\n * - `emitMessages: boolean?`\n * Configure how messages are emitted. By default, all messages are emitted. Pass false to\n * disable emitting messages.\n * - `emitToolCalls: boolean | string | string[]?`\n * Configure how tool calls are emitted. By default, all tool calls are emitted. Pass false to\n * disable emitting tool calls. Pass a string or list of strings to emit only specific tool calls.\n * - `emitIntermediateState: IntermediateStateConfig[]?`\n * Lets you emit tool calls as streaming LangGraph state.\n */\n options?: OptionsConfig,\n): RunnableConfig {\n if (baseConfig && typeof baseConfig !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"baseConfig must be an object or null/undefined\",\n });\n }\n\n if (options && typeof options !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"options must be an object when provided\",\n });\n }\n\n // Validate emitIntermediateState structure\n if (options?.emitIntermediateState) {\n if (!Array.isArray(options.emitIntermediateState)) {\n throw new CopilotKitMisuseError({\n message: \"emitIntermediateState must be an array when provided\",\n });\n }\n\n options.emitIntermediateState.forEach((state, index) => {\n if (!state || typeof state !== \"object\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must be an object`,\n });\n }\n\n if (!state.stateKey || typeof state.stateKey !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'stateKey' string property`,\n });\n }\n\n if (!state.tool || typeof state.tool !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'tool' string property`,\n });\n }\n\n if (state.toolArgument && typeof state.toolArgument !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}].toolArgument must be a string when provided`,\n });\n }\n });\n }\n\n try {\n const metadata = baseConfig?.metadata || {};\n\n if (options?.emitAll) {\n metadata[\"copilotkit:emit-tool-calls\"] = true;\n metadata[\"copilotkit:emit-messages\"] = true;\n } else {\n if (options?.emitToolCalls !== undefined) {\n metadata[\"copilotkit:emit-tool-calls\"] = options.emitToolCalls;\n }\n if (options?.emitMessages !== undefined) {\n metadata[\"copilotkit:emit-messages\"] = options.emitMessages;\n }\n }\n\n if (options?.emitIntermediateState) {\n const snakeCaseIntermediateState = options.emitIntermediateState.map(\n (state) => ({\n tool: state.tool,\n tool_argument: state.toolArgument,\n state_key: state.stateKey,\n }),\n );\n\n metadata[\"copilotkit:emit-intermediate-state\"] =\n snakeCaseIntermediateState;\n }\n\n baseConfig = baseConfig || {};\n\n return {\n ...baseConfig,\n metadata: metadata,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to customize config: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Exits the current agent after the run completes. Calling copilotkit_exit() will\n * not immediately stop the agent. Instead, it signals to CopilotKit to stop the agent after\n * the run completes.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitExit } from \"@copilotkit/sdk-js\";\n *\n * async function myNode(state: Any):\n * await copilotkitExit(config)\n * return state\n * ```\n */\nexport async function copilotkitExit(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitExit\",\n });\n }\n\n try {\n await dispatchCustomEvent(\"copilotkit_exit\", {}, config);\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to dispatch exit event: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Emits intermediate state to CopilotKit. Useful if you have a longer running node and you want to\n * update the user with the current state of the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitState } from \"@copilotkit/sdk-js\";\n *\n * for (let i = 0; i < 10; i++) {\n * await someLongRunningOperation(i);\n * await copilotkitEmitState(config, { progress: i });\n * }\n * ```\n */\nexport async function copilotkitEmitState(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The state to emit.\n */\n state: any,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitState\",\n });\n }\n\n if (state === undefined) {\n throw new CopilotKitMisuseError({\n message: \"State is required for copilotkitEmitState\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_intermediate_state\",\n state,\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit state: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a message to CopilotKit. Useful in longer running nodes to update the user.\n * Important: You still need to return the messages from the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitMessage } from \"@copilotkit/sdk-js\";\n *\n * const message = \"Step 1 of 10 complete\";\n * await copilotkitEmitMessage(config, message);\n *\n * // Return the message from the node\n * return {\n * \"messages\": [AIMessage(content=message)]\n * }\n * ```\n */\nexport async function copilotkitEmitMessage(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The message to emit.\n */\n message: string,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitMessage\",\n });\n }\n\n if (!message || typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a non-empty string for copilotkitEmitMessage\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_message\",\n { message, message_id: randomId(), role: \"assistant\" },\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit message: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a tool call to CopilotKit.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitToolCall } from \"@copilotkit/sdk-js\";\n *\n * await copilotkitEmitToolCall(config, name=\"SearchTool\", args={\"steps\": 10})\n * ```\n */\nexport async function copilotkitEmitToolCall(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The name of the tool to emit.\n */\n name: string,\n /**\n * The arguments to emit.\n */\n args: any,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitToolCall\",\n });\n }\n\n if (!name || typeof name !== \"string\") {\n throw new CopilotKitMisuseError({\n message:\n \"Tool name must be a non-empty string for copilotkitEmitToolCall\",\n });\n }\n\n if (args === undefined) {\n throw new CopilotKitMisuseError({\n message: \"Tool arguments are required for copilotkitEmitToolCall\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_tool_call\",\n { name, args, id: randomId() },\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit tool call '${name}': ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n\nexport function convertActionToDynamicStructuredTool(\n actionInput: any,\n): DynamicStructuredTool<any> {\n if (!actionInput) {\n throw new CopilotKitMisuseError({\n message: \"Action input is required but was not provided\",\n });\n }\n\n if (!actionInput.name || typeof actionInput.name !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must have a valid 'name' property of type string\",\n });\n }\n\n if (\n actionInput.description == undefined ||\n actionInput.description == null ||\n typeof actionInput.description !== \"string\"\n ) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a valid 'description' property of type string`,\n });\n }\n\n if (!actionInput.parameters) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a 'parameters' property`,\n });\n }\n\n try {\n return new DynamicStructuredTool({\n name: actionInput.name,\n description: actionInput.description,\n schema: convertJsonSchemaToZodSchema(actionInput.parameters, true),\n func: async () => {\n return \"\";\n },\n });\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action '${actionInput.name}' to DynamicStructuredTool: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Use this function to convert a list of actions you get from state\n * to a list of dynamic structured tools.\n *\n * ### Examples\n *\n * ```typescript\n * import { convertActionsToDynamicStructuredTools } from \"@copilotkit/sdk-js\";\n *\n * const tools = convertActionsToDynamicStructuredTools(state.copilotkit.actions);\n * ```\n */\nexport function convertActionsToDynamicStructuredTools(\n /**\n * The list of actions to convert.\n */\n actions: any[],\n): DynamicStructuredTool<any>[] {\n if (!Array.isArray(actions)) {\n throw new CopilotKitMisuseError({\n message: \"Actions must be an array\",\n });\n }\n\n return actions.map((action, index) => {\n try {\n return convertActionToDynamicStructuredTool(\n action.type === \"function\" ? action.function : action,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action at index ${index}: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n });\n}\n\nexport function copilotKitInterrupt({\n message,\n action,\n args,\n}: {\n message?: string;\n action?: string;\n args?: Record<string, any>;\n}) {\n if (!message && !action) {\n throw new CopilotKitMisuseError({\n message:\n \"Either message or action (and optional arguments) must be provided for copilotKitInterrupt\",\n });\n }\n\n if (action && typeof action !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (message && typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (args && typeof args !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"Args must be an object when provided to copilotKitInterrupt\",\n });\n }\n\n let interruptValues = null;\n let interruptMessage = null;\n let answer = null;\n\n try {\n if (message) {\n interruptValues = message;\n interruptMessage = new AIMessage({ content: message, id: randomId() });\n } else {\n const toolId = randomId();\n interruptMessage = new AIMessage({\n content: \"\",\n tool_calls: [{ id: toolId, name: action, args: args ?? {} }],\n });\n interruptValues = {\n action,\n args: args ?? {},\n };\n }\n\n const response = interrupt({\n __copilotkit_interrupt_value__: interruptValues,\n __copilotkit_messages__: [interruptMessage],\n });\n answer = response[response.length - 1].content;\n\n return {\n answer,\n messages: response,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to create interrupt: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utils.cjs","names":["CopilotKitMisuseError","DynamicStructuredTool","AIMessage"],"sources":["../../src/langgraph/utils.ts"],"sourcesContent":["import type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { dispatchCustomEvent } from \"@langchain/core/callbacks/dispatch\";\nimport {\n convertJsonSchemaToZodSchema,\n randomId,\n randomUUID,\n CopilotKitMisuseError,\n} from \"@copilotkit/shared\";\nimport { interrupt } from \"@langchain/langgraph\";\nimport { DynamicStructuredTool } from \"@langchain/core/tools\";\nimport { AIMessage } from \"@langchain/core/messages\";\nimport type { OptionsConfig } from \"./types\";\n\n/**\n * Customize the LangGraph configuration for use in CopilotKit.\n *\n * To the CopilotKit SDK, run:\n *\n * ```bash\n * npm install @copilotkit/sdk-js\n * ```\n *\n * ### Examples\n *\n * Disable emitting messages and tool calls:\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitMessages=false,\n * emitToolCalls=false\n * )\n * ```\n *\n * To emit a tool call as streaming LangGraph state, pass the destination key in state,\n * the tool name and optionally the tool argument. (If you don't pass the argument name,\n * all arguments are emitted under the state key.)\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitIntermediateState=[\n * {\n * \"stateKey\": \"steps\",\n * \"tool\": \"SearchTool\",\n * \"toolArgument\": \"steps\",\n * },\n * ],\n * )\n * ```\n */\nexport function copilotkitCustomizeConfig(\n /**\n * The LangChain/LangGraph configuration to customize.\n */\n baseConfig: RunnableConfig,\n /**\n * Configuration options:\n * - `emitMessages: boolean?`\n * Configure how messages are emitted. By default, all messages are emitted. Pass false to\n * disable emitting messages.\n * - `emitToolCalls: boolean | string | string[]?`\n * Configure how tool calls are emitted. By default, all tool calls are emitted. Pass false to\n * disable emitting tool calls. Pass a string or list of strings to emit only specific tool calls.\n * - `emitIntermediateState: IntermediateStateConfig[]?`\n * Lets you emit tool calls as streaming LangGraph state.\n */\n options?: OptionsConfig,\n): RunnableConfig {\n if (baseConfig && typeof baseConfig !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"baseConfig must be an object or null/undefined\",\n });\n }\n\n if (options && typeof options !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"options must be an object when provided\",\n });\n }\n\n // Validate emitIntermediateState structure\n if (options?.emitIntermediateState) {\n if (!Array.isArray(options.emitIntermediateState)) {\n throw new CopilotKitMisuseError({\n message: \"emitIntermediateState must be an array when provided\",\n });\n }\n\n options.emitIntermediateState.forEach((state, index) => {\n if (!state || typeof state !== \"object\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must be an object`,\n });\n }\n\n if (!state.stateKey || typeof state.stateKey !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'stateKey' string property`,\n });\n }\n\n if (!state.tool || typeof state.tool !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'tool' string property`,\n });\n }\n\n if (state.toolArgument && typeof state.toolArgument !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}].toolArgument must be a string when provided`,\n });\n }\n });\n }\n\n try {\n const metadata = baseConfig?.metadata || {};\n\n if (options?.emitAll) {\n metadata[\"copilotkit:emit-tool-calls\"] = true;\n metadata[\"copilotkit:emit-messages\"] = true;\n } else {\n if (options?.emitToolCalls !== undefined) {\n metadata[\"copilotkit:emit-tool-calls\"] = options.emitToolCalls;\n }\n if (options?.emitMessages !== undefined) {\n metadata[\"copilotkit:emit-messages\"] = options.emitMessages;\n }\n }\n\n if (options?.emitIntermediateState) {\n const snakeCaseIntermediateState = options.emitIntermediateState.map(\n (state) => ({\n tool: state.tool,\n tool_argument: state.toolArgument,\n state_key: state.stateKey,\n }),\n );\n\n metadata[\"copilotkit:emit-intermediate-state\"] =\n snakeCaseIntermediateState;\n }\n\n baseConfig = baseConfig || {};\n\n return {\n ...baseConfig,\n metadata: metadata,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to customize config: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Exits the current agent after the run completes. Calling copilotkit_exit() will\n * not immediately stop the agent. Instead, it signals to CopilotKit to stop the agent after\n * the run completes.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitExit } from \"@copilotkit/sdk-js\";\n *\n * async function myNode(state: Any):\n * await copilotkitExit(config)\n * return state\n * ```\n */\nexport async function copilotkitExit(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitExit\",\n });\n }\n\n try {\n await dispatchCustomEvent(\"copilotkit_exit\", {}, config);\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to dispatch exit event: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Emits intermediate state to CopilotKit. Useful if you have a longer running node and you want to\n * update the user with the current state of the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitState } from \"@copilotkit/sdk-js\";\n *\n * for (let i = 0; i < 10; i++) {\n * await someLongRunningOperation(i);\n * await copilotkitEmitState(config, { progress: i });\n * }\n * ```\n */\nexport async function copilotkitEmitState(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The state to emit.\n */\n state: any,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitState\",\n });\n }\n\n if (state === undefined) {\n throw new CopilotKitMisuseError({\n message: \"State is required for copilotkitEmitState\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_intermediate_state\",\n state,\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit state: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a message to CopilotKit. Useful in longer running nodes to update the user.\n * Important: You still need to return the messages from the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitMessage } from \"@copilotkit/sdk-js\";\n *\n * const message = \"Step 1 of 10 complete\";\n * await copilotkitEmitMessage(config, message);\n *\n * // Return the message from the node\n * return {\n * \"messages\": [AIMessage(content=message)]\n * }\n * ```\n */\nexport async function copilotkitEmitMessage(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The message to emit.\n */\n message: string,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitMessage\",\n });\n }\n\n if (!message || typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a non-empty string for copilotkitEmitMessage\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_message\",\n { message, message_id: randomId(), role: \"assistant\" },\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit message: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a tool call to CopilotKit.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitToolCall } from \"@copilotkit/sdk-js\";\n *\n * const autoId = await copilotkitEmitToolCall(config, \"SearchTool\", { steps: 10 });\n *\n * // With a custom ID for correlation/idempotency:\n * const customId = await copilotkitEmitToolCall(config, \"SearchTool\", { steps: 10 }, { toolCallId: \"my-custom-id\" });\n * ```\n *\n * @returns The tool call ID used for the emitted call — equals `options.toolCallId`\n * when provided, otherwise a randomly generated ID.\n */\nexport async function copilotkitEmitToolCall(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The name of the tool to emit.\n */\n name: string,\n /**\n * The arguments to emit.\n */\n args: any,\n /**\n * Options for the tool call emission.\n */\n options?: {\n /**\n * Optional tool call ID. If not provided, a random ID is generated.\n * When provided, this ID is used as the toolCallId and parentMessageId\n * in AG-UI protocol events. The caller is responsible for ensuring uniqueness.\n */\n toolCallId?: string;\n },\n): Promise<string> {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitToolCall\",\n });\n }\n\n if (typeof name !== \"string\" || name.trim().length === 0) {\n throw new CopilotKitMisuseError({\n message:\n \"Tool name must be a non-empty string for copilotkitEmitToolCall\",\n });\n }\n\n if (\n options?.toolCallId !== undefined &&\n (typeof options.toolCallId !== \"string\" ||\n options.toolCallId.trim().length === 0)\n ) {\n throw new CopilotKitMisuseError({\n message:\n \"Tool call id must be a non-empty string when provided for copilotkitEmitToolCall\",\n });\n }\n\n if (args === undefined) {\n throw new CopilotKitMisuseError({\n message: \"Tool arguments are required for copilotkitEmitToolCall\",\n });\n }\n\n try {\n JSON.stringify(args);\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Tool arguments for '${name}' are not JSON-serializable: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n const toolCallId = options?.toolCallId ?? randomUUID();\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_tool_call\",\n { name, args, id: toolCallId },\n config,\n );\n } catch (error) {\n const wrapped = new Error(\n `copilotkitEmitToolCall dispatch failed for tool=\"${name}\" id=\"${toolCallId}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n (wrapped as any).cause = error;\n throw wrapped;\n }\n\n return toolCallId;\n}\n\nexport function convertActionToDynamicStructuredTool(\n actionInput: any,\n): DynamicStructuredTool<any> {\n if (!actionInput) {\n throw new CopilotKitMisuseError({\n message: \"Action input is required but was not provided\",\n });\n }\n\n if (!actionInput.name || typeof actionInput.name !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must have a valid 'name' property of type string\",\n });\n }\n\n if (\n actionInput.description == undefined ||\n actionInput.description == null ||\n typeof actionInput.description !== \"string\"\n ) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a valid 'description' property of type string`,\n });\n }\n\n if (!actionInput.parameters) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a 'parameters' property`,\n });\n }\n\n try {\n return new DynamicStructuredTool({\n name: actionInput.name,\n description: actionInput.description,\n schema: convertJsonSchemaToZodSchema(actionInput.parameters, true),\n func: async () => {\n return \"\";\n },\n });\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action '${actionInput.name}' to DynamicStructuredTool: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Use this function to convert a list of actions you get from state\n * to a list of dynamic structured tools.\n *\n * ### Examples\n *\n * ```typescript\n * import { convertActionsToDynamicStructuredTools } from \"@copilotkit/sdk-js\";\n *\n * const tools = convertActionsToDynamicStructuredTools(state.copilotkit.actions);\n * ```\n */\nexport function convertActionsToDynamicStructuredTools(\n /**\n * The list of actions to convert.\n */\n actions: any[],\n): DynamicStructuredTool<any>[] {\n if (!Array.isArray(actions)) {\n throw new CopilotKitMisuseError({\n message: \"Actions must be an array\",\n });\n }\n\n return actions.map((action, index) => {\n try {\n return convertActionToDynamicStructuredTool(\n action.type === \"function\" ? action.function : action,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action at index ${index}: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n });\n}\n\nexport function copilotKitInterrupt({\n message,\n action,\n args,\n}: {\n message?: string;\n action?: string;\n args?: Record<string, any>;\n}) {\n if (!message && !action) {\n throw new CopilotKitMisuseError({\n message:\n \"Either message or action (and optional arguments) must be provided for copilotKitInterrupt\",\n });\n }\n\n if (action && typeof action !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (message && typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (args && typeof args !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"Args must be an object when provided to copilotKitInterrupt\",\n });\n }\n\n let interruptValues = null;\n let interruptMessage = null;\n let answer = null;\n\n try {\n if (message) {\n interruptValues = message;\n interruptMessage = new AIMessage({ content: message, id: randomId() });\n } else {\n const toolId = randomId();\n interruptMessage = new AIMessage({\n content: \"\",\n tool_calls: [{ id: toolId, name: action, args: args ?? {} }],\n });\n interruptValues = {\n action,\n args: args ?? {},\n };\n }\n\n const response = interrupt({\n __copilotkit_interrupt_value__: interruptValues,\n __copilotkit_messages__: [interruptMessage],\n });\n answer = response[response.length - 1].content;\n\n return {\n answer,\n messages: response,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to create interrupt: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n"],"mappings":"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"}
@@ -141,8 +141,14 @@ message: string): Promise<void>;
141
141
  * ```typescript
142
142
  * import { copilotkitEmitToolCall } from "@copilotkit/sdk-js";
143
143
  *
144
- * await copilotkitEmitToolCall(config, name="SearchTool", args={"steps": 10})
144
+ * const autoId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 });
145
+ *
146
+ * // With a custom ID for correlation/idempotency:
147
+ * const customId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 }, { toolCallId: "my-custom-id" });
145
148
  * ```
149
+ *
150
+ * @returns The tool call ID used for the emitted call — equals `options.toolCallId`
151
+ * when provided, otherwise a randomly generated ID.
146
152
  */
147
153
  declare function copilotkitEmitToolCall(
148
154
  /**
@@ -156,7 +162,18 @@ name: string,
156
162
  /**
157
163
  * The arguments to emit.
158
164
  */
159
- args: any): Promise<void>;
165
+ args: any,
166
+ /**
167
+ * Options for the tool call emission.
168
+ */
169
+ options?: {
170
+ /**
171
+ * Optional tool call ID. If not provided, a random ID is generated.
172
+ * When provided, this ID is used as the toolCallId and parentMessageId
173
+ * in AG-UI protocol events. The caller is responsible for ensuring uniqueness.
174
+ */
175
+ toolCallId?: string;
176
+ }): Promise<string>;
160
177
  declare function convertActionToDynamicStructuredTool(actionInput: any): DynamicStructuredTool<any>;
161
178
  /**
162
179
  * Use this function to convert a list of actions you get from state
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.cts","names":[],"sources":["../../src/langgraph/utils.ts"],"mappings":";;;;;;;AAsDA;;;;;;;;;;;;;;;AAwHA;;;;;;;;;AAmCA;;;;;;;;;;AAoDA;;;;;;iBA/MgB,yBAAA;;;;AAId,UAAA,EAAY,cAAA;;;;;;;;;;;AAsSd;AA1RE,OAAA,GAAU,aAAA,GACT,cAAA;;;;AAmVH;;;;;AAyBA;;;;;;;iBArQsB,cAAA;;;;AAIpB,MAAA,EAAQ,cAAA,GAAc,OAAA;;;;;;;;;;;;;;;;iBA+BF,mBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,KAAA,QAAU,OAAA;;;;;;;;;;;;;;;;;;;iBA4CU,qBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,OAAA,WAAe,OAAA;;;;;;;;;;;;iBAqCK,sBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,IAAA;;;;AAIA,IAAA,QAAS,OAAA;AAAA,iBAkCK,oCAAA,CACd,WAAA,QACC,qBAAA;;;;;;;;;;;;;iBAwDa,sCAAA;;;;AAId,OAAA,UACC,qBAAA;AAAA,iBAoBa,mBAAA,CAAA;EACd,OAAA;EACA,MAAA;EACA;AAAA;EAEA,OAAA;EACA,MAAA;EACA,IAAA,GAAO,MAAA;AAAA"}
1
+ {"version":3,"file":"utils.d.cts","names":[],"sources":["../../src/langgraph/utils.ts"],"mappings":";;;;;;;AAuDA;;;;;;;;;;;;;;;AAwHA;;;;;;;;;AAmCA;;;;;;;;;;AAoDA;;;;;;iBA/MgB,yBAAA;;;;AAId,UAAA,EAAY,cAAA;;;;;;;;;;;;AAYZ,OAAA,GAAU,aAAA,GACT,cAAA;AAmUH;;;;;AA0DA;;;;;AAyBA;;;;;AAnFA,iBA5NsB,cAAA;;;;AAIpB,MAAA,EAAQ,cAAA,GAAc,OAAA;;;;;;;;;;;;;;;;iBA+BF,mBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,KAAA,QAAU,OAAA;;;;;;;;;;;;;;;;;;;iBA4CU,qBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,OAAA,WAAe,OAAA;;;;;;;;;;;;;;;;;;iBA2CK,sBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,IAAA;;;;AAIA,IAAA;;;;AAIA,OAAA;;;;;;EAME,UAAA;AAAA,IAED,OAAA;AAAA,iBA0Da,oCAAA,CACd,WAAA,QACC,qBAAA;;;;;;;;;;;;;iBAwDa,sCAAA;;;;AAId,OAAA,UACC,qBAAA;AAAA,iBAoBa,mBAAA,CAAA;EACd,OAAA;EACA,MAAA;EACA;AAAA;EAEA,OAAA;EACA,MAAA;EACA,IAAA,GAAO,MAAA;AAAA"}
@@ -141,8 +141,14 @@ message: string): Promise<void>;
141
141
  * ```typescript
142
142
  * import { copilotkitEmitToolCall } from "@copilotkit/sdk-js";
143
143
  *
144
- * await copilotkitEmitToolCall(config, name="SearchTool", args={"steps": 10})
144
+ * const autoId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 });
145
+ *
146
+ * // With a custom ID for correlation/idempotency:
147
+ * const customId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 }, { toolCallId: "my-custom-id" });
145
148
  * ```
149
+ *
150
+ * @returns The tool call ID used for the emitted call — equals `options.toolCallId`
151
+ * when provided, otherwise a randomly generated ID.
146
152
  */
147
153
  declare function copilotkitEmitToolCall(
148
154
  /**
@@ -156,7 +162,18 @@ name: string,
156
162
  /**
157
163
  * The arguments to emit.
158
164
  */
159
- args: any): Promise<void>;
165
+ args: any,
166
+ /**
167
+ * Options for the tool call emission.
168
+ */
169
+ options?: {
170
+ /**
171
+ * Optional tool call ID. If not provided, a random ID is generated.
172
+ * When provided, this ID is used as the toolCallId and parentMessageId
173
+ * in AG-UI protocol events. The caller is responsible for ensuring uniqueness.
174
+ */
175
+ toolCallId?: string;
176
+ }): Promise<string>;
160
177
  declare function convertActionToDynamicStructuredTool(actionInput: any): DynamicStructuredTool<any>;
161
178
  /**
162
179
  * Use this function to convert a list of actions you get from state
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.mts","names":[],"sources":["../../src/langgraph/utils.ts"],"mappings":";;;;;;;AAsDA;;;;;;;;;;;;;;;AAwHA;;;;;;;;;AAmCA;;;;;;;;;;AAoDA;;;;;;iBA/MgB,yBAAA;;;;AAId,UAAA,EAAY,cAAA;;;;;;;;;;;AAsSd;AA1RE,OAAA,GAAU,aAAA,GACT,cAAA;;;;AAmVH;;;;;AAyBA;;;;;;;iBArQsB,cAAA;;;;AAIpB,MAAA,EAAQ,cAAA,GAAc,OAAA;;;;;;;;;;;;;;;;iBA+BF,mBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,KAAA,QAAU,OAAA;;;;;;;;;;;;;;;;;;;iBA4CU,qBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,OAAA,WAAe,OAAA;;;;;;;;;;;;iBAqCK,sBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,IAAA;;;;AAIA,IAAA,QAAS,OAAA;AAAA,iBAkCK,oCAAA,CACd,WAAA,QACC,qBAAA;;;;;;;;;;;;;iBAwDa,sCAAA;;;;AAId,OAAA,UACC,qBAAA;AAAA,iBAoBa,mBAAA,CAAA;EACd,OAAA;EACA,MAAA;EACA;AAAA;EAEA,OAAA;EACA,MAAA;EACA,IAAA,GAAO,MAAA;AAAA"}
1
+ {"version":3,"file":"utils.d.mts","names":[],"sources":["../../src/langgraph/utils.ts"],"mappings":";;;;;;;AAuDA;;;;;;;;;;;;;;;AAwHA;;;;;;;;;AAmCA;;;;;;;;;;AAoDA;;;;;;iBA/MgB,yBAAA;;;;AAId,UAAA,EAAY,cAAA;;;;;;;;;;;;AAYZ,OAAA,GAAU,aAAA,GACT,cAAA;AAmUH;;;;;AA0DA;;;;;AAyBA;;;;;AAnFA,iBA5NsB,cAAA;;;;AAIpB,MAAA,EAAQ,cAAA,GAAc,OAAA;;;;;;;;;;;;;;;;iBA+BF,mBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,KAAA,QAAU,OAAA;;;;;;;;;;;;;;;;;;;iBA4CU,qBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,OAAA,WAAe,OAAA;;;;;;;;;;;;;;;;;;iBA2CK,sBAAA;;;;AAIpB,MAAA,EAAQ,cAAA;;;;AAIR,IAAA;;;;AAIA,IAAA;;;;AAIA,OAAA;;;;;;EAME,UAAA;AAAA,IAED,OAAA;AAAA,iBA0Da,oCAAA,CACd,WAAA,QACC,qBAAA;;;;;;;;;;;;;iBAwDa,sCAAA;;;;AAId,OAAA,UACC,qBAAA;AAAA,iBAoBa,mBAAA,CAAA;EACd,OAAA;EACA,MAAA;EACA;AAAA;EAEA,OAAA;EACA,MAAA;EACA,IAAA,GAAO,MAAA;AAAA"}
@@ -1,6 +1,6 @@
1
1
  import { interrupt } from "@langchain/langgraph";
2
2
  import { dispatchCustomEvent } from "@langchain/core/callbacks/dispatch";
3
- import { CopilotKitMisuseError, convertJsonSchemaToZodSchema, randomId } from "@copilotkit/shared";
3
+ import { CopilotKitMisuseError, convertJsonSchemaToZodSchema, randomId, randomUUID } from "@copilotkit/shared";
4
4
  import { DynamicStructuredTool } from "@langchain/core/tools";
5
5
  import { AIMessage } from "@langchain/core/messages";
6
6
 
@@ -168,22 +168,38 @@ async function copilotkitEmitMessage(config, message) {
168
168
  * ```typescript
169
169
  * import { copilotkitEmitToolCall } from "@copilotkit/sdk-js";
170
170
  *
171
- * await copilotkitEmitToolCall(config, name="SearchTool", args={"steps": 10})
171
+ * const autoId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 });
172
+ *
173
+ * // With a custom ID for correlation/idempotency:
174
+ * const customId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 }, { toolCallId: "my-custom-id" });
172
175
  * ```
176
+ *
177
+ * @returns The tool call ID used for the emitted call — equals `options.toolCallId`
178
+ * when provided, otherwise a randomly generated ID.
173
179
  */
174
- async function copilotkitEmitToolCall(config, name, args) {
180
+ async function copilotkitEmitToolCall(config, name, args, options) {
175
181
  if (!config) throw new CopilotKitMisuseError({ message: "LangGraph configuration is required for copilotkitEmitToolCall" });
176
- if (!name || typeof name !== "string") throw new CopilotKitMisuseError({ message: "Tool name must be a non-empty string for copilotkitEmitToolCall" });
182
+ if (typeof name !== "string" || name.trim().length === 0) throw new CopilotKitMisuseError({ message: "Tool name must be a non-empty string for copilotkitEmitToolCall" });
183
+ if (options?.toolCallId !== void 0 && (typeof options.toolCallId !== "string" || options.toolCallId.trim().length === 0)) throw new CopilotKitMisuseError({ message: "Tool call id must be a non-empty string when provided for copilotkitEmitToolCall" });
177
184
  if (args === void 0) throw new CopilotKitMisuseError({ message: "Tool arguments are required for copilotkitEmitToolCall" });
185
+ try {
186
+ JSON.stringify(args);
187
+ } catch (error) {
188
+ throw new CopilotKitMisuseError({ message: `Tool arguments for '${name}' are not JSON-serializable: ${error instanceof Error ? error.message : String(error)}` });
189
+ }
190
+ const toolCallId = options?.toolCallId ?? randomUUID();
178
191
  try {
179
192
  await dispatchCustomEvent("copilotkit_manually_emit_tool_call", {
180
193
  name,
181
194
  args,
182
- id: randomId()
195
+ id: toolCallId
183
196
  }, config);
184
197
  } catch (error) {
185
- throw new CopilotKitMisuseError({ message: `Failed to emit tool call '${name}': ${error instanceof Error ? error.message : String(error)}` });
198
+ const wrapped = /* @__PURE__ */ new Error(`copilotkitEmitToolCall dispatch failed for tool="${name}" id="${toolCallId}": ${error instanceof Error ? error.message : String(error)}`);
199
+ wrapped.cause = error;
200
+ throw wrapped;
186
201
  }
202
+ return toolCallId;
187
203
  }
188
204
  function convertActionToDynamicStructuredTool(actionInput) {
189
205
  if (!actionInput) throw new CopilotKitMisuseError({ message: "Action input is required but was not provided" });
@@ -1 +1 @@
1
- {"version":3,"file":"utils.mjs","names":[],"sources":["../../src/langgraph/utils.ts"],"sourcesContent":["import { RunnableConfig } from \"@langchain/core/runnables\";\nimport { dispatchCustomEvent } from \"@langchain/core/callbacks/dispatch\";\nimport {\n convertJsonSchemaToZodSchema,\n randomId,\n CopilotKitMisuseError,\n} from \"@copilotkit/shared\";\nimport { interrupt } from \"@langchain/langgraph\";\nimport { DynamicStructuredTool } from \"@langchain/core/tools\";\nimport { AIMessage } from \"@langchain/core/messages\";\nimport { OptionsConfig } from \"./types\";\n\n/**\n * Customize the LangGraph configuration for use in CopilotKit.\n *\n * To the CopilotKit SDK, run:\n *\n * ```bash\n * npm install @copilotkit/sdk-js\n * ```\n *\n * ### Examples\n *\n * Disable emitting messages and tool calls:\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitMessages=false,\n * emitToolCalls=false\n * )\n * ```\n *\n * To emit a tool call as streaming LangGraph state, pass the destination key in state,\n * the tool name and optionally the tool argument. (If you don't pass the argument name,\n * all arguments are emitted under the state key.)\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitIntermediateState=[\n * {\n * \"stateKey\": \"steps\",\n * \"tool\": \"SearchTool\",\n * \"toolArgument\": \"steps\",\n * },\n * ],\n * )\n * ```\n */\nexport function copilotkitCustomizeConfig(\n /**\n * The LangChain/LangGraph configuration to customize.\n */\n baseConfig: RunnableConfig,\n /**\n * Configuration options:\n * - `emitMessages: boolean?`\n * Configure how messages are emitted. By default, all messages are emitted. Pass false to\n * disable emitting messages.\n * - `emitToolCalls: boolean | string | string[]?`\n * Configure how tool calls are emitted. By default, all tool calls are emitted. Pass false to\n * disable emitting tool calls. Pass a string or list of strings to emit only specific tool calls.\n * - `emitIntermediateState: IntermediateStateConfig[]?`\n * Lets you emit tool calls as streaming LangGraph state.\n */\n options?: OptionsConfig,\n): RunnableConfig {\n if (baseConfig && typeof baseConfig !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"baseConfig must be an object or null/undefined\",\n });\n }\n\n if (options && typeof options !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"options must be an object when provided\",\n });\n }\n\n // Validate emitIntermediateState structure\n if (options?.emitIntermediateState) {\n if (!Array.isArray(options.emitIntermediateState)) {\n throw new CopilotKitMisuseError({\n message: \"emitIntermediateState must be an array when provided\",\n });\n }\n\n options.emitIntermediateState.forEach((state, index) => {\n if (!state || typeof state !== \"object\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must be an object`,\n });\n }\n\n if (!state.stateKey || typeof state.stateKey !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'stateKey' string property`,\n });\n }\n\n if (!state.tool || typeof state.tool !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'tool' string property`,\n });\n }\n\n if (state.toolArgument && typeof state.toolArgument !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}].toolArgument must be a string when provided`,\n });\n }\n });\n }\n\n try {\n const metadata = baseConfig?.metadata || {};\n\n if (options?.emitAll) {\n metadata[\"copilotkit:emit-tool-calls\"] = true;\n metadata[\"copilotkit:emit-messages\"] = true;\n } else {\n if (options?.emitToolCalls !== undefined) {\n metadata[\"copilotkit:emit-tool-calls\"] = options.emitToolCalls;\n }\n if (options?.emitMessages !== undefined) {\n metadata[\"copilotkit:emit-messages\"] = options.emitMessages;\n }\n }\n\n if (options?.emitIntermediateState) {\n const snakeCaseIntermediateState = options.emitIntermediateState.map(\n (state) => ({\n tool: state.tool,\n tool_argument: state.toolArgument,\n state_key: state.stateKey,\n }),\n );\n\n metadata[\"copilotkit:emit-intermediate-state\"] =\n snakeCaseIntermediateState;\n }\n\n baseConfig = baseConfig || {};\n\n return {\n ...baseConfig,\n metadata: metadata,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to customize config: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Exits the current agent after the run completes. Calling copilotkit_exit() will\n * not immediately stop the agent. Instead, it signals to CopilotKit to stop the agent after\n * the run completes.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitExit } from \"@copilotkit/sdk-js\";\n *\n * async function myNode(state: Any):\n * await copilotkitExit(config)\n * return state\n * ```\n */\nexport async function copilotkitExit(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitExit\",\n });\n }\n\n try {\n await dispatchCustomEvent(\"copilotkit_exit\", {}, config);\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to dispatch exit event: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Emits intermediate state to CopilotKit. Useful if you have a longer running node and you want to\n * update the user with the current state of the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitState } from \"@copilotkit/sdk-js\";\n *\n * for (let i = 0; i < 10; i++) {\n * await someLongRunningOperation(i);\n * await copilotkitEmitState(config, { progress: i });\n * }\n * ```\n */\nexport async function copilotkitEmitState(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The state to emit.\n */\n state: any,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitState\",\n });\n }\n\n if (state === undefined) {\n throw new CopilotKitMisuseError({\n message: \"State is required for copilotkitEmitState\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_intermediate_state\",\n state,\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit state: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a message to CopilotKit. Useful in longer running nodes to update the user.\n * Important: You still need to return the messages from the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitMessage } from \"@copilotkit/sdk-js\";\n *\n * const message = \"Step 1 of 10 complete\";\n * await copilotkitEmitMessage(config, message);\n *\n * // Return the message from the node\n * return {\n * \"messages\": [AIMessage(content=message)]\n * }\n * ```\n */\nexport async function copilotkitEmitMessage(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The message to emit.\n */\n message: string,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitMessage\",\n });\n }\n\n if (!message || typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a non-empty string for copilotkitEmitMessage\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_message\",\n { message, message_id: randomId(), role: \"assistant\" },\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit message: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a tool call to CopilotKit.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitToolCall } from \"@copilotkit/sdk-js\";\n *\n * await copilotkitEmitToolCall(config, name=\"SearchTool\", args={\"steps\": 10})\n * ```\n */\nexport async function copilotkitEmitToolCall(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The name of the tool to emit.\n */\n name: string,\n /**\n * The arguments to emit.\n */\n args: any,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitToolCall\",\n });\n }\n\n if (!name || typeof name !== \"string\") {\n throw new CopilotKitMisuseError({\n message:\n \"Tool name must be a non-empty string for copilotkitEmitToolCall\",\n });\n }\n\n if (args === undefined) {\n throw new CopilotKitMisuseError({\n message: \"Tool arguments are required for copilotkitEmitToolCall\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_tool_call\",\n { name, args, id: randomId() },\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit tool call '${name}': ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n\nexport function convertActionToDynamicStructuredTool(\n actionInput: any,\n): DynamicStructuredTool<any> {\n if (!actionInput) {\n throw new CopilotKitMisuseError({\n message: \"Action input is required but was not provided\",\n });\n }\n\n if (!actionInput.name || typeof actionInput.name !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must have a valid 'name' property of type string\",\n });\n }\n\n if (\n actionInput.description == undefined ||\n actionInput.description == null ||\n typeof actionInput.description !== \"string\"\n ) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a valid 'description' property of type string`,\n });\n }\n\n if (!actionInput.parameters) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a 'parameters' property`,\n });\n }\n\n try {\n return new DynamicStructuredTool({\n name: actionInput.name,\n description: actionInput.description,\n schema: convertJsonSchemaToZodSchema(actionInput.parameters, true),\n func: async () => {\n return \"\";\n },\n });\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action '${actionInput.name}' to DynamicStructuredTool: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Use this function to convert a list of actions you get from state\n * to a list of dynamic structured tools.\n *\n * ### Examples\n *\n * ```typescript\n * import { convertActionsToDynamicStructuredTools } from \"@copilotkit/sdk-js\";\n *\n * const tools = convertActionsToDynamicStructuredTools(state.copilotkit.actions);\n * ```\n */\nexport function convertActionsToDynamicStructuredTools(\n /**\n * The list of actions to convert.\n */\n actions: any[],\n): DynamicStructuredTool<any>[] {\n if (!Array.isArray(actions)) {\n throw new CopilotKitMisuseError({\n message: \"Actions must be an array\",\n });\n }\n\n return actions.map((action, index) => {\n try {\n return convertActionToDynamicStructuredTool(\n action.type === \"function\" ? action.function : action,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action at index ${index}: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n });\n}\n\nexport function copilotKitInterrupt({\n message,\n action,\n args,\n}: {\n message?: string;\n action?: string;\n args?: Record<string, any>;\n}) {\n if (!message && !action) {\n throw new CopilotKitMisuseError({\n message:\n \"Either message or action (and optional arguments) must be provided for copilotKitInterrupt\",\n });\n }\n\n if (action && typeof action !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (message && typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (args && typeof args !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"Args must be an object when provided to copilotKitInterrupt\",\n });\n }\n\n let interruptValues = null;\n let interruptMessage = null;\n let answer = null;\n\n try {\n if (message) {\n interruptValues = message;\n interruptMessage = new AIMessage({ content: message, id: randomId() });\n } else {\n const toolId = randomId();\n interruptMessage = new AIMessage({\n content: \"\",\n tool_calls: [{ id: toolId, name: action, args: args ?? {} }],\n });\n interruptValues = {\n action,\n args: args ?? {},\n };\n }\n\n const response = interrupt({\n __copilotkit_interrupt_value__: interruptValues,\n __copilotkit_messages__: [interruptMessage],\n });\n answer = response[response.length - 1].content;\n\n return {\n answer,\n messages: response,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to create interrupt: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"utils.mjs","names":[],"sources":["../../src/langgraph/utils.ts"],"sourcesContent":["import type { RunnableConfig } from \"@langchain/core/runnables\";\nimport { dispatchCustomEvent } from \"@langchain/core/callbacks/dispatch\";\nimport {\n convertJsonSchemaToZodSchema,\n randomId,\n randomUUID,\n CopilotKitMisuseError,\n} from \"@copilotkit/shared\";\nimport { interrupt } from \"@langchain/langgraph\";\nimport { DynamicStructuredTool } from \"@langchain/core/tools\";\nimport { AIMessage } from \"@langchain/core/messages\";\nimport type { OptionsConfig } from \"./types\";\n\n/**\n * Customize the LangGraph configuration for use in CopilotKit.\n *\n * To the CopilotKit SDK, run:\n *\n * ```bash\n * npm install @copilotkit/sdk-js\n * ```\n *\n * ### Examples\n *\n * Disable emitting messages and tool calls:\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitMessages=false,\n * emitToolCalls=false\n * )\n * ```\n *\n * To emit a tool call as streaming LangGraph state, pass the destination key in state,\n * the tool name and optionally the tool argument. (If you don't pass the argument name,\n * all arguments are emitted under the state key.)\n *\n * ```typescript\n * import { copilotkitCustomizeConfig } from \"@copilotkit/sdk-js\";\n *\n * config = copilotkitCustomizeConfig(\n * config,\n * emitIntermediateState=[\n * {\n * \"stateKey\": \"steps\",\n * \"tool\": \"SearchTool\",\n * \"toolArgument\": \"steps\",\n * },\n * ],\n * )\n * ```\n */\nexport function copilotkitCustomizeConfig(\n /**\n * The LangChain/LangGraph configuration to customize.\n */\n baseConfig: RunnableConfig,\n /**\n * Configuration options:\n * - `emitMessages: boolean?`\n * Configure how messages are emitted. By default, all messages are emitted. Pass false to\n * disable emitting messages.\n * - `emitToolCalls: boolean | string | string[]?`\n * Configure how tool calls are emitted. By default, all tool calls are emitted. Pass false to\n * disable emitting tool calls. Pass a string or list of strings to emit only specific tool calls.\n * - `emitIntermediateState: IntermediateStateConfig[]?`\n * Lets you emit tool calls as streaming LangGraph state.\n */\n options?: OptionsConfig,\n): RunnableConfig {\n if (baseConfig && typeof baseConfig !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"baseConfig must be an object or null/undefined\",\n });\n }\n\n if (options && typeof options !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"options must be an object when provided\",\n });\n }\n\n // Validate emitIntermediateState structure\n if (options?.emitIntermediateState) {\n if (!Array.isArray(options.emitIntermediateState)) {\n throw new CopilotKitMisuseError({\n message: \"emitIntermediateState must be an array when provided\",\n });\n }\n\n options.emitIntermediateState.forEach((state, index) => {\n if (!state || typeof state !== \"object\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must be an object`,\n });\n }\n\n if (!state.stateKey || typeof state.stateKey !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'stateKey' string property`,\n });\n }\n\n if (!state.tool || typeof state.tool !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}] must have a valid 'tool' string property`,\n });\n }\n\n if (state.toolArgument && typeof state.toolArgument !== \"string\") {\n throw new CopilotKitMisuseError({\n message: `emitIntermediateState[${index}].toolArgument must be a string when provided`,\n });\n }\n });\n }\n\n try {\n const metadata = baseConfig?.metadata || {};\n\n if (options?.emitAll) {\n metadata[\"copilotkit:emit-tool-calls\"] = true;\n metadata[\"copilotkit:emit-messages\"] = true;\n } else {\n if (options?.emitToolCalls !== undefined) {\n metadata[\"copilotkit:emit-tool-calls\"] = options.emitToolCalls;\n }\n if (options?.emitMessages !== undefined) {\n metadata[\"copilotkit:emit-messages\"] = options.emitMessages;\n }\n }\n\n if (options?.emitIntermediateState) {\n const snakeCaseIntermediateState = options.emitIntermediateState.map(\n (state) => ({\n tool: state.tool,\n tool_argument: state.toolArgument,\n state_key: state.stateKey,\n }),\n );\n\n metadata[\"copilotkit:emit-intermediate-state\"] =\n snakeCaseIntermediateState;\n }\n\n baseConfig = baseConfig || {};\n\n return {\n ...baseConfig,\n metadata: metadata,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to customize config: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Exits the current agent after the run completes. Calling copilotkit_exit() will\n * not immediately stop the agent. Instead, it signals to CopilotKit to stop the agent after\n * the run completes.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitExit } from \"@copilotkit/sdk-js\";\n *\n * async function myNode(state: Any):\n * await copilotkitExit(config)\n * return state\n * ```\n */\nexport async function copilotkitExit(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitExit\",\n });\n }\n\n try {\n await dispatchCustomEvent(\"copilotkit_exit\", {}, config);\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to dispatch exit event: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Emits intermediate state to CopilotKit. Useful if you have a longer running node and you want to\n * update the user with the current state of the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitState } from \"@copilotkit/sdk-js\";\n *\n * for (let i = 0; i < 10; i++) {\n * await someLongRunningOperation(i);\n * await copilotkitEmitState(config, { progress: i });\n * }\n * ```\n */\nexport async function copilotkitEmitState(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The state to emit.\n */\n state: any,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitState\",\n });\n }\n\n if (state === undefined) {\n throw new CopilotKitMisuseError({\n message: \"State is required for copilotkitEmitState\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_intermediate_state\",\n state,\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit state: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a message to CopilotKit. Useful in longer running nodes to update the user.\n * Important: You still need to return the messages from the node.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitMessage } from \"@copilotkit/sdk-js\";\n *\n * const message = \"Step 1 of 10 complete\";\n * await copilotkitEmitMessage(config, message);\n *\n * // Return the message from the node\n * return {\n * \"messages\": [AIMessage(content=message)]\n * }\n * ```\n */\nexport async function copilotkitEmitMessage(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The message to emit.\n */\n message: string,\n) {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitMessage\",\n });\n }\n\n if (!message || typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a non-empty string for copilotkitEmitMessage\",\n });\n }\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_message\",\n { message, message_id: randomId(), role: \"assistant\" },\n config,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to emit message: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Manually emits a tool call to CopilotKit.\n *\n * ### Examples\n *\n * ```typescript\n * import { copilotkitEmitToolCall } from \"@copilotkit/sdk-js\";\n *\n * const autoId = await copilotkitEmitToolCall(config, \"SearchTool\", { steps: 10 });\n *\n * // With a custom ID for correlation/idempotency:\n * const customId = await copilotkitEmitToolCall(config, \"SearchTool\", { steps: 10 }, { toolCallId: \"my-custom-id\" });\n * ```\n *\n * @returns The tool call ID used for the emitted call — equals `options.toolCallId`\n * when provided, otherwise a randomly generated ID.\n */\nexport async function copilotkitEmitToolCall(\n /**\n * The LangChain/LangGraph configuration.\n */\n config: RunnableConfig,\n /**\n * The name of the tool to emit.\n */\n name: string,\n /**\n * The arguments to emit.\n */\n args: any,\n /**\n * Options for the tool call emission.\n */\n options?: {\n /**\n * Optional tool call ID. If not provided, a random ID is generated.\n * When provided, this ID is used as the toolCallId and parentMessageId\n * in AG-UI protocol events. The caller is responsible for ensuring uniqueness.\n */\n toolCallId?: string;\n },\n): Promise<string> {\n if (!config) {\n throw new CopilotKitMisuseError({\n message: \"LangGraph configuration is required for copilotkitEmitToolCall\",\n });\n }\n\n if (typeof name !== \"string\" || name.trim().length === 0) {\n throw new CopilotKitMisuseError({\n message:\n \"Tool name must be a non-empty string for copilotkitEmitToolCall\",\n });\n }\n\n if (\n options?.toolCallId !== undefined &&\n (typeof options.toolCallId !== \"string\" ||\n options.toolCallId.trim().length === 0)\n ) {\n throw new CopilotKitMisuseError({\n message:\n \"Tool call id must be a non-empty string when provided for copilotkitEmitToolCall\",\n });\n }\n\n if (args === undefined) {\n throw new CopilotKitMisuseError({\n message: \"Tool arguments are required for copilotkitEmitToolCall\",\n });\n }\n\n try {\n JSON.stringify(args);\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Tool arguments for '${name}' are not JSON-serializable: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n\n const toolCallId = options?.toolCallId ?? randomUUID();\n\n try {\n await dispatchCustomEvent(\n \"copilotkit_manually_emit_tool_call\",\n { name, args, id: toolCallId },\n config,\n );\n } catch (error) {\n const wrapped = new Error(\n `copilotkitEmitToolCall dispatch failed for tool=\"${name}\" id=\"${toolCallId}\": ${error instanceof Error ? error.message : String(error)}`,\n );\n (wrapped as any).cause = error;\n throw wrapped;\n }\n\n return toolCallId;\n}\n\nexport function convertActionToDynamicStructuredTool(\n actionInput: any,\n): DynamicStructuredTool<any> {\n if (!actionInput) {\n throw new CopilotKitMisuseError({\n message: \"Action input is required but was not provided\",\n });\n }\n\n if (!actionInput.name || typeof actionInput.name !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must have a valid 'name' property of type string\",\n });\n }\n\n if (\n actionInput.description == undefined ||\n actionInput.description == null ||\n typeof actionInput.description !== \"string\"\n ) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a valid 'description' property of type string`,\n });\n }\n\n if (!actionInput.parameters) {\n throw new CopilotKitMisuseError({\n message: `Action '${actionInput.name}' must have a 'parameters' property`,\n });\n }\n\n try {\n return new DynamicStructuredTool({\n name: actionInput.name,\n description: actionInput.description,\n schema: convertJsonSchemaToZodSchema(actionInput.parameters, true),\n func: async () => {\n return \"\";\n },\n });\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action '${actionInput.name}' to DynamicStructuredTool: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n/**\n * Use this function to convert a list of actions you get from state\n * to a list of dynamic structured tools.\n *\n * ### Examples\n *\n * ```typescript\n * import { convertActionsToDynamicStructuredTools } from \"@copilotkit/sdk-js\";\n *\n * const tools = convertActionsToDynamicStructuredTools(state.copilotkit.actions);\n * ```\n */\nexport function convertActionsToDynamicStructuredTools(\n /**\n * The list of actions to convert.\n */\n actions: any[],\n): DynamicStructuredTool<any>[] {\n if (!Array.isArray(actions)) {\n throw new CopilotKitMisuseError({\n message: \"Actions must be an array\",\n });\n }\n\n return actions.map((action, index) => {\n try {\n return convertActionToDynamicStructuredTool(\n action.type === \"function\" ? action.function : action,\n );\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to convert action at index ${index}: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n });\n}\n\nexport function copilotKitInterrupt({\n message,\n action,\n args,\n}: {\n message?: string;\n action?: string;\n args?: Record<string, any>;\n}) {\n if (!message && !action) {\n throw new CopilotKitMisuseError({\n message:\n \"Either message or action (and optional arguments) must be provided for copilotKitInterrupt\",\n });\n }\n\n if (action && typeof action !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Action must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (message && typeof message !== \"string\") {\n throw new CopilotKitMisuseError({\n message: \"Message must be a string when provided to copilotKitInterrupt\",\n });\n }\n\n if (args && typeof args !== \"object\") {\n throw new CopilotKitMisuseError({\n message: \"Args must be an object when provided to copilotKitInterrupt\",\n });\n }\n\n let interruptValues = null;\n let interruptMessage = null;\n let answer = null;\n\n try {\n if (message) {\n interruptValues = message;\n interruptMessage = new AIMessage({ content: message, id: randomId() });\n } else {\n const toolId = randomId();\n interruptMessage = new AIMessage({\n content: \"\",\n tool_calls: [{ id: toolId, name: action, args: args ?? {} }],\n });\n interruptValues = {\n action,\n args: args ?? {},\n };\n }\n\n const response = interrupt({\n __copilotkit_interrupt_value__: interruptValues,\n __copilotkit_messages__: [interruptMessage],\n });\n answer = response[response.length - 1].content;\n\n return {\n answer,\n messages: response,\n };\n } catch (error) {\n throw new CopilotKitMisuseError({\n message: `Failed to create interrupt: ${error instanceof Error ? error.message : String(error)}`,\n });\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@copilotkit/sdk-js",
3
- "version": "1.57.3",
3
+ "version": "1.58.0-canary.thread-id-propagation",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "ai",
@@ -48,8 +48,8 @@
48
48
  "access": "public"
49
49
  },
50
50
  "dependencies": {
51
- "@ag-ui/langgraph": "0.0.31",
52
- "@copilotkit/shared": "1.57.3"
51
+ "@ag-ui/langgraph": "0.0.34",
52
+ "@copilotkit/shared": "1.58.0-canary.thread-id-propagation"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@langchain/core": "^1.1.41",
@@ -1,9 +1,16 @@
1
+ import { vi } from "vitest";
2
+ import { dispatchCustomEvent } from "@langchain/core/callbacks/dispatch";
1
3
  import {
2
4
  copilotkitCustomizeConfig,
5
+ copilotkitEmitToolCall,
3
6
  convertActionsToDynamicStructuredTools,
4
7
  convertActionToDynamicStructuredTool,
5
8
  } from "../utils";
6
9
 
10
+ vi.mock("@langchain/core/callbacks/dispatch", () => ({
11
+ dispatchCustomEvent: vi.fn().mockResolvedValue(undefined),
12
+ }));
13
+
7
14
  describe("copilotkitCustomizeConfig", () => {
8
15
  it("returns config unchanged when no options provided", () => {
9
16
  const baseConfig = { metadata: { existing: true } };
@@ -252,3 +259,105 @@ describe("convertActionsToDynamicStructuredTools", () => {
252
259
  );
253
260
  });
254
261
  });
262
+
263
+ describe("copilotkitEmitToolCall", () => {
264
+ const mockConfig = { metadata: {} } as any;
265
+ const mockedDispatch = vi.mocked(dispatchCustomEvent);
266
+
267
+ beforeEach(() => {
268
+ mockedDispatch.mockClear();
269
+ });
270
+
271
+ it("returns a generated id when no id is provided", async () => {
272
+ const result = await copilotkitEmitToolCall(mockConfig, "SearchTool", {
273
+ steps: 10,
274
+ });
275
+
276
+ expect(typeof result).toBe("string");
277
+ expect(result.length).toBeGreaterThan(0);
278
+ expect(mockedDispatch).toHaveBeenCalledWith(
279
+ "copilotkit_manually_emit_tool_call",
280
+ { name: "SearchTool", args: { steps: 10 }, id: result },
281
+ mockConfig,
282
+ );
283
+ });
284
+
285
+ it("uses caller-provided toolCallId verbatim", async () => {
286
+ const result = await copilotkitEmitToolCall(
287
+ mockConfig,
288
+ "SearchTool",
289
+ { steps: 10 },
290
+ { toolCallId: "custom-abc" },
291
+ );
292
+
293
+ expect(result).toBe("custom-abc");
294
+ expect(mockedDispatch).toHaveBeenCalledWith(
295
+ "copilotkit_manually_emit_tool_call",
296
+ { name: "SearchTool", args: { steps: 10 }, id: "custom-abc" },
297
+ mockConfig,
298
+ );
299
+ });
300
+
301
+ it("treats undefined options the same as omitted", async () => {
302
+ const result = await copilotkitEmitToolCall(
303
+ mockConfig,
304
+ "SearchTool",
305
+ {},
306
+ undefined,
307
+ );
308
+
309
+ expect(typeof result).toBe("string");
310
+ expect(result.length).toBeGreaterThan(0);
311
+ expect(mockedDispatch).toHaveBeenCalledWith(
312
+ "copilotkit_manually_emit_tool_call",
313
+ { name: "SearchTool", args: {}, id: result },
314
+ mockConfig,
315
+ );
316
+ });
317
+
318
+ it("throws on empty string toolCallId", async () => {
319
+ await expect(
320
+ copilotkitEmitToolCall(mockConfig, "SearchTool", {}, { toolCallId: "" }),
321
+ ).rejects.toThrow("non-empty string");
322
+ });
323
+
324
+ it("throws on whitespace-only toolCallId", async () => {
325
+ await expect(
326
+ copilotkitEmitToolCall(
327
+ mockConfig,
328
+ "SearchTool",
329
+ {},
330
+ { toolCallId: " " },
331
+ ),
332
+ ).rejects.toThrow("non-empty string");
333
+ });
334
+
335
+ it("throws on whitespace-only name", async () => {
336
+ await expect(copilotkitEmitToolCall(mockConfig, " ", {})).rejects.toThrow(
337
+ "non-empty string",
338
+ );
339
+ });
340
+
341
+ it("throws on undefined args", async () => {
342
+ await expect(
343
+ copilotkitEmitToolCall(mockConfig, "SearchTool", undefined),
344
+ ).rejects.toThrow("required");
345
+ });
346
+
347
+ it("throws on non-JSON-serializable args", async () => {
348
+ const circular: any = {};
349
+ circular.self = circular;
350
+ await expect(
351
+ copilotkitEmitToolCall(mockConfig, "SearchTool", circular),
352
+ ).rejects.toThrow("not JSON-serializable");
353
+ });
354
+
355
+ it("propagates dispatch errors with tool-call context", async () => {
356
+ mockedDispatch.mockRejectedValueOnce(new Error("transport closed"));
357
+ await expect(
358
+ copilotkitEmitToolCall(mockConfig, "SearchTool", {}),
359
+ ).rejects.toThrow(
360
+ /copilotkitEmitToolCall dispatch failed.*SearchTool.*transport closed/,
361
+ );
362
+ });
363
+ });
@@ -1,14 +1,15 @@
1
- import { RunnableConfig } from "@langchain/core/runnables";
1
+ import type { RunnableConfig } from "@langchain/core/runnables";
2
2
  import { dispatchCustomEvent } from "@langchain/core/callbacks/dispatch";
3
3
  import {
4
4
  convertJsonSchemaToZodSchema,
5
5
  randomId,
6
+ randomUUID,
6
7
  CopilotKitMisuseError,
7
8
  } from "@copilotkit/shared";
8
9
  import { interrupt } from "@langchain/langgraph";
9
10
  import { DynamicStructuredTool } from "@langchain/core/tools";
10
11
  import { AIMessage } from "@langchain/core/messages";
11
- import { OptionsConfig } from "./types";
12
+ import type { OptionsConfig } from "./types";
12
13
 
13
14
  /**
14
15
  * Customize the LangGraph configuration for use in CopilotKit.
@@ -301,8 +302,14 @@ export async function copilotkitEmitMessage(
301
302
  * ```typescript
302
303
  * import { copilotkitEmitToolCall } from "@copilotkit/sdk-js";
303
304
  *
304
- * await copilotkitEmitToolCall(config, name="SearchTool", args={"steps": 10})
305
+ * const autoId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 });
306
+ *
307
+ * // With a custom ID for correlation/idempotency:
308
+ * const customId = await copilotkitEmitToolCall(config, "SearchTool", { steps: 10 }, { toolCallId: "my-custom-id" });
305
309
  * ```
310
+ *
311
+ * @returns The tool call ID used for the emitted call — equals `options.toolCallId`
312
+ * when provided, otherwise a randomly generated ID.
306
313
  */
307
314
  export async function copilotkitEmitToolCall(
308
315
  /**
@@ -317,37 +324,73 @@ export async function copilotkitEmitToolCall(
317
324
  * The arguments to emit.
318
325
  */
319
326
  args: any,
320
- ) {
327
+ /**
328
+ * Options for the tool call emission.
329
+ */
330
+ options?: {
331
+ /**
332
+ * Optional tool call ID. If not provided, a random ID is generated.
333
+ * When provided, this ID is used as the toolCallId and parentMessageId
334
+ * in AG-UI protocol events. The caller is responsible for ensuring uniqueness.
335
+ */
336
+ toolCallId?: string;
337
+ },
338
+ ): Promise<string> {
321
339
  if (!config) {
322
340
  throw new CopilotKitMisuseError({
323
341
  message: "LangGraph configuration is required for copilotkitEmitToolCall",
324
342
  });
325
343
  }
326
344
 
327
- if (!name || typeof name !== "string") {
345
+ if (typeof name !== "string" || name.trim().length === 0) {
328
346
  throw new CopilotKitMisuseError({
329
347
  message:
330
348
  "Tool name must be a non-empty string for copilotkitEmitToolCall",
331
349
  });
332
350
  }
333
351
 
352
+ if (
353
+ options?.toolCallId !== undefined &&
354
+ (typeof options.toolCallId !== "string" ||
355
+ options.toolCallId.trim().length === 0)
356
+ ) {
357
+ throw new CopilotKitMisuseError({
358
+ message:
359
+ "Tool call id must be a non-empty string when provided for copilotkitEmitToolCall",
360
+ });
361
+ }
362
+
334
363
  if (args === undefined) {
335
364
  throw new CopilotKitMisuseError({
336
365
  message: "Tool arguments are required for copilotkitEmitToolCall",
337
366
  });
338
367
  }
339
368
 
369
+ try {
370
+ JSON.stringify(args);
371
+ } catch (error) {
372
+ throw new CopilotKitMisuseError({
373
+ message: `Tool arguments for '${name}' are not JSON-serializable: ${error instanceof Error ? error.message : String(error)}`,
374
+ });
375
+ }
376
+
377
+ const toolCallId = options?.toolCallId ?? randomUUID();
378
+
340
379
  try {
341
380
  await dispatchCustomEvent(
342
381
  "copilotkit_manually_emit_tool_call",
343
- { name, args, id: randomId() },
382
+ { name, args, id: toolCallId },
344
383
  config,
345
384
  );
346
385
  } catch (error) {
347
- throw new CopilotKitMisuseError({
348
- message: `Failed to emit tool call '${name}': ${error instanceof Error ? error.message : String(error)}`,
349
- });
386
+ const wrapped = new Error(
387
+ `copilotkitEmitToolCall dispatch failed for tool="${name}" id="${toolCallId}": ${error instanceof Error ? error.message : String(error)}`,
388
+ );
389
+ (wrapped as any).cause = error;
390
+ throw wrapped;
350
391
  }
392
+
393
+ return toolCallId;
351
394
  }
352
395
 
353
396
  export function convertActionToDynamicStructuredTool(