@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.
- package/dist/langgraph/utils.cjs +21 -5
- package/dist/langgraph/utils.cjs.map +1 -1
- package/dist/langgraph/utils.d.cts +19 -2
- package/dist/langgraph/utils.d.cts.map +1 -1
- package/dist/langgraph/utils.d.mts +19 -2
- package/dist/langgraph/utils.d.mts.map +1 -1
- package/dist/langgraph/utils.mjs +22 -6
- package/dist/langgraph/utils.mjs.map +1 -1
- package/package.json +3 -3
- package/src/langgraph/__tests__/utils.test.ts +109 -0
- package/src/langgraph/utils.ts +52 -9
package/dist/langgraph/utils.cjs
CHANGED
|
@@ -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,
|
|
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 (
|
|
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:
|
|
196
|
+
id: toolCallId
|
|
184
197
|
}, config);
|
|
185
198
|
} catch (error) {
|
|
186
|
-
|
|
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,
|
|
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
|
|
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":";;;;;;;
|
|
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,
|
|
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
|
|
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":";;;;;;;
|
|
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"}
|
package/dist/langgraph/utils.mjs
CHANGED
|
@@ -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,
|
|
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 (
|
|
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:
|
|
195
|
+
id: toolCallId
|
|
183
196
|
}, config);
|
|
184
197
|
} catch (error) {
|
|
185
|
-
|
|
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.
|
|
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.
|
|
52
|
-
"@copilotkit/shared": "1.
|
|
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
|
+
});
|
package/src/langgraph/utils.ts
CHANGED
|
@@ -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,
|
|
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 (
|
|
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:
|
|
382
|
+
{ name, args, id: toolCallId },
|
|
344
383
|
config,
|
|
345
384
|
);
|
|
346
385
|
} catch (error) {
|
|
347
|
-
|
|
348
|
-
|
|
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(
|