@copilotkit/runtime 1.68.0 → 1.68.2
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/graphql/message-conversion/agui-to-gql.cjs +8 -0
- package/dist/graphql/message-conversion/agui-to-gql.cjs.map +1 -1
- package/dist/graphql/message-conversion/agui-to-gql.mjs +8 -0
- package/dist/graphql/message-conversion/agui-to-gql.mjs.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/runtime/package.mjs +1 -1
- package/dist/v2/runtime/core/channel-manager.cjs +25 -1
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.cts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.mts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +25 -1
- package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
- package/package.json +5 -5
- package/skills/runtime/SKILL.md +1 -1
|
@@ -16,11 +16,19 @@ function hasImageProperty(message) {
|
|
|
16
16
|
if (image.format === void 0 || image.bytes === void 0) return false;
|
|
17
17
|
return true;
|
|
18
18
|
}
|
|
19
|
+
const warnedContentPartTypes = /* @__PURE__ */ new Set();
|
|
20
|
+
function warnUnsupportedContentPart(type) {
|
|
21
|
+
const label = typeof type === "string" ? type : String(type);
|
|
22
|
+
if (warnedContentPartTypes.has(label)) return;
|
|
23
|
+
warnedContentPartTypes.add(label);
|
|
24
|
+
console.warn(`[CopilotKit] Dropping message content part of unsupported type "${label}". Only "text" and "binary" parts are carried through to the client; see https://github.com/CopilotKit/CopilotKit/issues/1748.`);
|
|
25
|
+
}
|
|
19
26
|
function normalizeMessageContent(content) {
|
|
20
27
|
if (typeof content === "string" || typeof content === "undefined") return content || "";
|
|
21
28
|
if (Array.isArray(content)) return content.map((part) => {
|
|
22
29
|
if (part?.type === "text") return part.text;
|
|
23
30
|
if (part?.type === "binary") return part.data || part.url || part.filename || `[binary:${part.mimeType}]`;
|
|
31
|
+
warnUnsupportedContentPart(part?.type);
|
|
24
32
|
return "";
|
|
25
33
|
}).filter(Boolean).join("\n");
|
|
26
34
|
if (content && typeof content === "object") try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agui-to-gql.cjs","names":[],"sources":["../../../src/graphql/message-conversion/agui-to-gql.ts"],"sourcesContent":["import * as gql from \"../types/converted/index\";\nimport { MessageRole } from \"../types/enums\";\nimport * as agui from \"@copilotkit/shared\"; // named agui for clarity, but this only includes agui message types\n\n// Helper function to extract agent name from message\nfunction extractAgentName(message: agui.Message): string {\n if (message.role !== \"assistant\") {\n throw new Error(\n `Cannot extract agent name from message with role ${message.role}`,\n );\n }\n\n return message.agentName || \"unknown\";\n}\n\n// Type guard for agent state message\nfunction isAgentStateMessage(message: agui.Message): boolean {\n return (\n message.role === \"assistant\" && \"agentName\" in message && \"state\" in message\n );\n}\n\n// Type guard for messages with image property\nfunction hasImageProperty(\n message: agui.Message,\n): message is agui.Message & { image: agui.ImageData } {\n const canContainImage =\n message.role === \"assistant\" || message.role === \"user\";\n if (!canContainImage) {\n return false;\n }\n\n const image: { format?: string; bytes?: string } | undefined =\n \"image\" in message ? message.image : undefined;\n if (image === undefined) {\n return false;\n }\n\n const isMalformed = image.format === undefined || image.bytes === undefined;\n if (isMalformed) {\n return false;\n }\n\n return true;\n}\n\nfunction normalizeMessageContent(content: agui.Message[\"content\"]): string {\n if (typeof content === \"string\" || typeof content === \"undefined\") {\n return content || \"\";\n }\n\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (part?.type === \"text\") {\n return part.text;\n }\n if (part?.type === \"binary\") {\n return (\n part.data ||\n part.url ||\n part.filename ||\n `[binary:${part.mimeType}]`\n );\n }\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n\n if (content && typeof content === \"object\") {\n try {\n return JSON.stringify(content);\n } catch (error) {\n console.warn(\"Failed to serialize message content\", error);\n }\n }\n\n return String(content ?? \"\");\n}\n\n/*\n ----------------------------\n AGUI Message -> GQL Message\n ----------------------------\n*/\nexport function aguiToGQL(\n messages: agui.Message[] | agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n const gqlMessages: gql.Message[] = [];\n messages = Array.isArray(messages) ? messages : [messages];\n\n // Track tool call names by their IDs for use in result messages\n const toolCallNames: Record<string, string> = {};\n\n for (const message of messages) {\n // Agent state message support\n if (isAgentStateMessage(message)) {\n const agentName = extractAgentName(message);\n const state = \"state\" in message && message.state ? message.state : {};\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName,\n state,\n role: gql.Role.assistant,\n }),\n );\n // Optionally preserve render function\n if (\n \"generativeUI\" in message &&\n message.generativeUI &&\n coAgentStateRenders\n ) {\n coAgentStateRenders[agentName] = {\n name: agentName,\n render: message.generativeUI,\n };\n }\n continue;\n }\n\n if (hasImageProperty(message)) {\n gqlMessages.push(aguiMessageWithImageToGQLMessage(message));\n continue;\n }\n\n // Action execution message support\n if (message.role === \"assistant\" && message.toolCalls) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n for (const toolCall of message.toolCalls) {\n // Track the tool call name by its ID\n toolCallNames[toolCall.id] = toolCall.function.name;\n\n const actionExecMsg = aguiToolCallToGQLActionExecution(\n toolCall,\n message.id,\n );\n // Preserve render function in actions context\n if (\"generativeUI\" in message && message.generativeUI && actions) {\n const actionName = toolCall.function.name;\n // Check for specific action first, then wild card action\n const specificAction = Object.values(actions).find(\n (action: any) => action.name === actionName,\n );\n const wildcardAction = Object.values(actions).find(\n (action: any) => action.name === \"*\",\n );\n\n // Assign render function to the matching action (specific takes priority)\n if (specificAction) {\n specificAction.render = message.generativeUI;\n } else if (wildcardAction) {\n wildcardAction.render = message.generativeUI;\n }\n }\n gqlMessages.push(actionExecMsg);\n }\n continue;\n }\n // Reasoning messages are ephemeral display-only content with no GQL equivalent — skip them\n if (message.role === \"reasoning\") {\n continue;\n }\n // Regular text messages\n if (\n message.role === \"developer\" ||\n message.role === \"system\" ||\n message.role === \"assistant\" ||\n message.role === \"user\"\n ) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n continue;\n }\n // Tool result message\n if (message.role === \"tool\") {\n gqlMessages.push(\n aguiToolMessageToGQLResultMessage(message, toolCallNames),\n );\n continue;\n }\n throw new Error(\n `Unknown message role: \"${(message as any).role}\" in message with id: ${(message as any).id}`,\n );\n }\n\n return gqlMessages;\n}\n\nexport function aguiTextMessageToGQLMessage(\n message: agui.Message,\n): gql.TextMessage {\n if (\n message.role !== \"developer\" &&\n message.role !== \"system\" &&\n message.role !== \"assistant\" &&\n message.role !== \"user\"\n ) {\n throw new Error(\n `Cannot convert message with role ${message.role} to TextMessage`,\n );\n }\n\n let roleValue: MessageRole;\n\n if (message.role === \"developer\") {\n roleValue = gql.Role.developer;\n } else if (message.role === \"system\") {\n roleValue = gql.Role.system;\n } else if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n return new gql.TextMessage({\n id: message.id,\n content: normalizeMessageContent(message.content),\n role: roleValue,\n });\n}\n\nexport function aguiToolCallToGQLActionExecution(\n toolCall: agui.ToolCall,\n parentMessageId: string,\n): gql.ActionExecutionMessage {\n if (toolCall.type !== \"function\") {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n\n // Handle arguments - they should be a JSON string in AGUI format,\n // but we need to convert them to an object for GQL format\n let argumentsObj: any;\n\n if (typeof toolCall.function.arguments === \"string\") {\n // Expected case: arguments is a JSON string\n try {\n argumentsObj = JSON.parse(toolCall.function.arguments);\n } catch {\n console.warn(\n `[CopilotKit] Failed to parse tool arguments, falling back to empty object`,\n );\n // Provide fallback empty object to prevent application crash\n argumentsObj = {};\n }\n } else if (\n typeof toolCall.function.arguments === \"object\" &&\n toolCall.function.arguments !== null\n ) {\n // Backward compatibility: arguments is already an object\n argumentsObj = toolCall.function.arguments;\n } else {\n // Fallback for undefined, null, or other types\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof toolCall.function.arguments}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Guard against successfully parsed non-object values (e.g. JSON.parse('\"\"') → \"\")\n if (\n typeof argumentsObj !== \"object\" ||\n argumentsObj === null ||\n Array.isArray(argumentsObj)\n ) {\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof argumentsObj}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Always include name and arguments\n return new gql.ActionExecutionMessage({\n id: toolCall.id,\n name: toolCall.function.name,\n arguments: argumentsObj,\n parentMessageId: parentMessageId,\n });\n}\n\nexport function aguiToolMessageToGQLResultMessage(\n message: agui.Message,\n toolCallNames: Record<string, string>,\n): gql.ResultMessage {\n if (message.role !== \"tool\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ResultMessage`,\n );\n }\n\n if (!message.toolCallId) {\n throw new Error(\"Tool message must have a toolCallId\");\n }\n\n const actionName = toolCallNames[message.toolCallId] || \"unknown\";\n\n // Handle result content - it could be a string or an object that needs serialization\n let resultContent: string;\n const messageContent = message.content || \"\";\n\n if (typeof messageContent === \"string\") {\n // Expected case: content is already a string\n resultContent = messageContent;\n } else if (typeof messageContent === \"object\" && messageContent !== null) {\n // Handle case where content is an object that needs to be serialized\n try {\n resultContent = JSON.stringify(messageContent);\n } catch (error) {\n console.warn(`Failed to stringify tool result for ${actionName}:`, error);\n resultContent = String(messageContent);\n }\n } else {\n // Handle other types (number, boolean, etc.)\n resultContent = String(messageContent);\n }\n\n return new gql.ResultMessage({\n id: message.id,\n result: resultContent,\n actionExecutionId: message.toolCallId,\n actionName: message.toolName || actionName,\n });\n}\n\n// New function to handle AGUI messages with render functions\nexport function aguiMessageWithRenderToGQL(\n message: agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n // Handle the special case: assistant messages with render function but no tool calls\n if (\n message.role === \"assistant\" &&\n \"generativeUI\" in message &&\n message.generativeUI &&\n !message.toolCalls\n ) {\n const gqlMessages: gql.Message[] = [];\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName: \"unknown\",\n state: {},\n role: gql.Role.assistant,\n }),\n );\n if (coAgentStateRenders) {\n coAgentStateRenders.unknown = {\n name: \"unknown\",\n render: message.generativeUI,\n };\n }\n return gqlMessages;\n }\n\n // For all other cases, delegate to aguiToGQL\n return aguiToGQL([message], actions, coAgentStateRenders);\n}\n\nexport function aguiMessageWithImageToGQLMessage(\n message: agui.Message,\n): gql.ImageMessage {\n if (!hasImageProperty(message)) {\n throw new Error(\n `Cannot convert message to ImageMessage: missing format or bytes`,\n );\n }\n\n let roleValue: MessageRole;\n if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n if (message.role !== \"assistant\" && message.role !== \"user\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ImageMessage`,\n );\n }\n\n return new gql.ImageMessage({\n id: message.id,\n format: message.image.format,\n bytes: message.image.bytes,\n role: roleValue,\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"agui-to-gql.cjs","names":[],"sources":["../../../src/graphql/message-conversion/agui-to-gql.ts"],"sourcesContent":["import * as gql from \"../types/converted/index\";\nimport { MessageRole } from \"../types/enums\";\nimport * as agui from \"@copilotkit/shared\"; // named agui for clarity, but this only includes agui message types\n\n// Helper function to extract agent name from message\nfunction extractAgentName(message: agui.Message): string {\n if (message.role !== \"assistant\") {\n throw new Error(\n `Cannot extract agent name from message with role ${message.role}`,\n );\n }\n\n return message.agentName || \"unknown\";\n}\n\n// Type guard for agent state message\nfunction isAgentStateMessage(message: agui.Message): boolean {\n return (\n message.role === \"assistant\" && \"agentName\" in message && \"state\" in message\n );\n}\n\n// Type guard for messages with image property\nfunction hasImageProperty(\n message: agui.Message,\n): message is agui.Message & { image: agui.ImageData } {\n const canContainImage =\n message.role === \"assistant\" || message.role === \"user\";\n if (!canContainImage) {\n return false;\n }\n\n const image: { format?: string; bytes?: string } | undefined =\n \"image\" in message ? message.image : undefined;\n if (image === undefined) {\n return false;\n }\n\n const isMalformed = image.format === undefined || image.bytes === undefined;\n if (isMalformed) {\n return false;\n }\n\n return true;\n}\n\n// Content part types we have already warned about. Streaming replays the same\n// unsupported part on every delta, so warn once per type rather than per part.\nconst warnedContentPartTypes = new Set<string>();\n\nfunction warnUnsupportedContentPart(type: unknown): void {\n const label = typeof type === \"string\" ? type : String(type);\n if (warnedContentPartTypes.has(label)) return;\n warnedContentPartTypes.add(label);\n console.warn(\n `[CopilotKit] Dropping message content part of unsupported type \"${label}\". ` +\n `Only \"text\" and \"binary\" parts are carried through to the client; ` +\n `see https://github.com/CopilotKit/CopilotKit/issues/1748.`,\n );\n}\n\nfunction normalizeMessageContent(content: agui.Message[\"content\"]): string {\n if (typeof content === \"string\" || typeof content === \"undefined\") {\n return content || \"\";\n }\n\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (part?.type === \"text\") {\n return part.text;\n }\n if (part?.type === \"binary\") {\n return (\n part.data ||\n part.url ||\n part.filename ||\n `[binary:${part.mimeType}]`\n );\n }\n warnUnsupportedContentPart(part?.type);\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n\n if (content && typeof content === \"object\") {\n try {\n return JSON.stringify(content);\n } catch (error) {\n console.warn(\"Failed to serialize message content\", error);\n }\n }\n\n return String(content ?? \"\");\n}\n\n/*\n ----------------------------\n AGUI Message -> GQL Message\n ----------------------------\n*/\nexport function aguiToGQL(\n messages: agui.Message[] | agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n const gqlMessages: gql.Message[] = [];\n messages = Array.isArray(messages) ? messages : [messages];\n\n // Track tool call names by their IDs for use in result messages\n const toolCallNames: Record<string, string> = {};\n\n for (const message of messages) {\n // Agent state message support\n if (isAgentStateMessage(message)) {\n const agentName = extractAgentName(message);\n const state = \"state\" in message && message.state ? message.state : {};\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName,\n state,\n role: gql.Role.assistant,\n }),\n );\n // Optionally preserve render function\n if (\n \"generativeUI\" in message &&\n message.generativeUI &&\n coAgentStateRenders\n ) {\n coAgentStateRenders[agentName] = {\n name: agentName,\n render: message.generativeUI,\n };\n }\n continue;\n }\n\n if (hasImageProperty(message)) {\n gqlMessages.push(aguiMessageWithImageToGQLMessage(message));\n continue;\n }\n\n // Action execution message support\n if (message.role === \"assistant\" && message.toolCalls) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n for (const toolCall of message.toolCalls) {\n // Track the tool call name by its ID\n toolCallNames[toolCall.id] = toolCall.function.name;\n\n const actionExecMsg = aguiToolCallToGQLActionExecution(\n toolCall,\n message.id,\n );\n // Preserve render function in actions context\n if (\"generativeUI\" in message && message.generativeUI && actions) {\n const actionName = toolCall.function.name;\n // Check for specific action first, then wild card action\n const specificAction = Object.values(actions).find(\n (action: any) => action.name === actionName,\n );\n const wildcardAction = Object.values(actions).find(\n (action: any) => action.name === \"*\",\n );\n\n // Assign render function to the matching action (specific takes priority)\n if (specificAction) {\n specificAction.render = message.generativeUI;\n } else if (wildcardAction) {\n wildcardAction.render = message.generativeUI;\n }\n }\n gqlMessages.push(actionExecMsg);\n }\n continue;\n }\n // Reasoning messages are ephemeral display-only content with no GQL equivalent — skip them\n if (message.role === \"reasoning\") {\n continue;\n }\n // Regular text messages\n if (\n message.role === \"developer\" ||\n message.role === \"system\" ||\n message.role === \"assistant\" ||\n message.role === \"user\"\n ) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n continue;\n }\n // Tool result message\n if (message.role === \"tool\") {\n gqlMessages.push(\n aguiToolMessageToGQLResultMessage(message, toolCallNames),\n );\n continue;\n }\n throw new Error(\n `Unknown message role: \"${(message as any).role}\" in message with id: ${(message as any).id}`,\n );\n }\n\n return gqlMessages;\n}\n\nexport function aguiTextMessageToGQLMessage(\n message: agui.Message,\n): gql.TextMessage {\n if (\n message.role !== \"developer\" &&\n message.role !== \"system\" &&\n message.role !== \"assistant\" &&\n message.role !== \"user\"\n ) {\n throw new Error(\n `Cannot convert message with role ${message.role} to TextMessage`,\n );\n }\n\n let roleValue: MessageRole;\n\n if (message.role === \"developer\") {\n roleValue = gql.Role.developer;\n } else if (message.role === \"system\") {\n roleValue = gql.Role.system;\n } else if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n return new gql.TextMessage({\n id: message.id,\n content: normalizeMessageContent(message.content),\n role: roleValue,\n });\n}\n\nexport function aguiToolCallToGQLActionExecution(\n toolCall: agui.ToolCall,\n parentMessageId: string,\n): gql.ActionExecutionMessage {\n if (toolCall.type !== \"function\") {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n\n // Handle arguments - they should be a JSON string in AGUI format,\n // but we need to convert them to an object for GQL format\n let argumentsObj: any;\n\n if (typeof toolCall.function.arguments === \"string\") {\n // Expected case: arguments is a JSON string\n try {\n argumentsObj = JSON.parse(toolCall.function.arguments);\n } catch {\n console.warn(\n `[CopilotKit] Failed to parse tool arguments, falling back to empty object`,\n );\n // Provide fallback empty object to prevent application crash\n argumentsObj = {};\n }\n } else if (\n typeof toolCall.function.arguments === \"object\" &&\n toolCall.function.arguments !== null\n ) {\n // Backward compatibility: arguments is already an object\n argumentsObj = toolCall.function.arguments;\n } else {\n // Fallback for undefined, null, or other types\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof toolCall.function.arguments}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Guard against successfully parsed non-object values (e.g. JSON.parse('\"\"') → \"\")\n if (\n typeof argumentsObj !== \"object\" ||\n argumentsObj === null ||\n Array.isArray(argumentsObj)\n ) {\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof argumentsObj}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Always include name and arguments\n return new gql.ActionExecutionMessage({\n id: toolCall.id,\n name: toolCall.function.name,\n arguments: argumentsObj,\n parentMessageId: parentMessageId,\n });\n}\n\nexport function aguiToolMessageToGQLResultMessage(\n message: agui.Message,\n toolCallNames: Record<string, string>,\n): gql.ResultMessage {\n if (message.role !== \"tool\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ResultMessage`,\n );\n }\n\n if (!message.toolCallId) {\n throw new Error(\"Tool message must have a toolCallId\");\n }\n\n const actionName = toolCallNames[message.toolCallId] || \"unknown\";\n\n // Handle result content - it could be a string or an object that needs serialization\n let resultContent: string;\n const messageContent = message.content || \"\";\n\n if (typeof messageContent === \"string\") {\n // Expected case: content is already a string\n resultContent = messageContent;\n } else if (typeof messageContent === \"object\" && messageContent !== null) {\n // Handle case where content is an object that needs to be serialized\n try {\n resultContent = JSON.stringify(messageContent);\n } catch (error) {\n console.warn(`Failed to stringify tool result for ${actionName}:`, error);\n resultContent = String(messageContent);\n }\n } else {\n // Handle other types (number, boolean, etc.)\n resultContent = String(messageContent);\n }\n\n return new gql.ResultMessage({\n id: message.id,\n result: resultContent,\n actionExecutionId: message.toolCallId,\n actionName: message.toolName || actionName,\n });\n}\n\n// New function to handle AGUI messages with render functions\nexport function aguiMessageWithRenderToGQL(\n message: agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n // Handle the special case: assistant messages with render function but no tool calls\n if (\n message.role === \"assistant\" &&\n \"generativeUI\" in message &&\n message.generativeUI &&\n !message.toolCalls\n ) {\n const gqlMessages: gql.Message[] = [];\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName: \"unknown\",\n state: {},\n role: gql.Role.assistant,\n }),\n );\n if (coAgentStateRenders) {\n coAgentStateRenders.unknown = {\n name: \"unknown\",\n render: message.generativeUI,\n };\n }\n return gqlMessages;\n }\n\n // For all other cases, delegate to aguiToGQL\n return aguiToGQL([message], actions, coAgentStateRenders);\n}\n\nexport function aguiMessageWithImageToGQLMessage(\n message: agui.Message,\n): gql.ImageMessage {\n if (!hasImageProperty(message)) {\n throw new Error(\n `Cannot convert message to ImageMessage: missing format or bytes`,\n );\n }\n\n let roleValue: MessageRole;\n if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n if (message.role !== \"assistant\" && message.role !== \"user\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ImageMessage`,\n );\n }\n\n return new gql.ImageMessage({\n id: message.id,\n format: message.image.format,\n bytes: message.image.bytes,\n role: roleValue,\n });\n}\n"],"mappings":";;;;AAKA,SAAS,iBAAiB,SAA+B;AACvD,KAAI,QAAQ,SAAS,YACnB,OAAM,IAAI,MACR,oDAAoD,QAAQ,OAC7D;AAGH,QAAO,QAAQ,aAAa;;AAI9B,SAAS,oBAAoB,SAAgC;AAC3D,QACE,QAAQ,SAAS,eAAe,eAAe,WAAW,WAAW;;AAKzE,SAAS,iBACP,SACqD;AAGrD,KAAI,EADF,QAAQ,SAAS,eAAe,QAAQ,SAAS,QAEjD,QAAO;CAGT,MAAM,QACJ,WAAW,UAAU,QAAQ,QAAQ;AACvC,KAAI,UAAU,OACZ,QAAO;AAIT,KADoB,MAAM,WAAW,UAAa,MAAM,UAAU,OAEhE,QAAO;AAGT,QAAO;;AAKT,MAAM,yCAAyB,IAAI,KAAa;AAEhD,SAAS,2BAA2B,MAAqB;CACvD,MAAM,QAAQ,OAAO,SAAS,WAAW,OAAO,OAAO,KAAK;AAC5D,KAAI,uBAAuB,IAAI,MAAM,CAAE;AACvC,wBAAuB,IAAI,MAAM;AACjC,SAAQ,KACN,mEAAmE,MAAM,gIAG1E;;AAGH,SAAS,wBAAwB,SAA0C;AACzE,KAAI,OAAO,YAAY,YAAY,OAAO,YAAY,YACpD,QAAO,WAAW;AAGpB,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,QACJ,KAAK,SAAS;AACb,MAAI,MAAM,SAAS,OACjB,QAAO,KAAK;AAEd,MAAI,MAAM,SAAS,SACjB,QACE,KAAK,QACL,KAAK,OACL,KAAK,YACL,WAAW,KAAK,SAAS;AAG7B,6BAA2B,MAAM,KAAK;AACtC,SAAO;GACP,CACD,OAAO,QAAQ,CACf,KAAK,KAAK;AAGf,KAAI,WAAW,OAAO,YAAY,SAChC,KAAI;AACF,SAAO,KAAK,UAAU,QAAQ;UACvB,OAAO;AACd,UAAQ,KAAK,uCAAuC,MAAM;;AAI9D,QAAO,OAAO,WAAW,GAAG;;AAQ9B,SAAgB,UACd,UACA,SACA,qBACe;CACf,MAAM,cAA6B,EAAE;AACrC,YAAW,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC,SAAS;CAG1D,MAAM,gBAAwC,EAAE;AAEhD,MAAK,MAAM,WAAW,UAAU;AAE9B,MAAI,oBAAoB,QAAQ,EAAE;GAChC,MAAM,YAAY,iBAAiB,QAAQ;GAC3C,MAAM,QAAQ,WAAW,WAAW,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACtE,eAAY,KACV,oCAA0B;IACxB,IAAI,QAAQ;IACZ;IACA;IACA,yBAAe;IAChB,CAAC,CACH;AAED,OACE,kBAAkB,WAClB,QAAQ,gBACR,oBAEA,qBAAoB,aAAa;IAC/B,MAAM;IACN,QAAQ,QAAQ;IACjB;AAEH;;AAGF,MAAI,iBAAiB,QAAQ,EAAE;AAC7B,eAAY,KAAK,iCAAiC,QAAQ,CAAC;AAC3D;;AAIF,MAAI,QAAQ,SAAS,eAAe,QAAQ,WAAW;AACrD,eAAY,KAAK,4BAA4B,QAAQ,CAAC;AACtD,QAAK,MAAM,YAAY,QAAQ,WAAW;AAExC,kBAAc,SAAS,MAAM,SAAS,SAAS;IAE/C,MAAM,gBAAgB,iCACpB,UACA,QAAQ,GACT;AAED,QAAI,kBAAkB,WAAW,QAAQ,gBAAgB,SAAS;KAChE,MAAM,aAAa,SAAS,SAAS;KAErC,MAAM,iBAAiB,OAAO,OAAO,QAAQ,CAAC,MAC3C,WAAgB,OAAO,SAAS,WAClC;KACD,MAAM,iBAAiB,OAAO,OAAO,QAAQ,CAAC,MAC3C,WAAgB,OAAO,SAAS,IAClC;AAGD,SAAI,eACF,gBAAe,SAAS,QAAQ;cACvB,eACT,gBAAe,SAAS,QAAQ;;AAGpC,gBAAY,KAAK,cAAc;;AAEjC;;AAGF,MAAI,QAAQ,SAAS,YACnB;AAGF,MACE,QAAQ,SAAS,eACjB,QAAQ,SAAS,YACjB,QAAQ,SAAS,eACjB,QAAQ,SAAS,QACjB;AACA,eAAY,KAAK,4BAA4B,QAAQ,CAAC;AACtD;;AAGF,MAAI,QAAQ,SAAS,QAAQ;AAC3B,eAAY,KACV,kCAAkC,SAAS,cAAc,CAC1D;AACD;;AAEF,QAAM,IAAI,MACR,0BAA2B,QAAgB,KAAK,wBAAyB,QAAgB,KAC1F;;AAGH,QAAO;;AAGT,SAAgB,4BACd,SACiB;AACjB,KACE,QAAQ,SAAS,eACjB,QAAQ,SAAS,YACjB,QAAQ,SAAS,eACjB,QAAQ,SAAS,OAEjB,OAAM,IAAI,MACR,oCAAoC,QAAQ,KAAK,iBAClD;CAGH,IAAI;AAEJ,KAAI,QAAQ,SAAS,YACnB,gCAAqB;UACZ,QAAQ,SAAS,SAC1B,gCAAqB;UACZ,QAAQ,SAAS,YAC1B,gCAAqB;KAErB,gCAAqB;AAGvB,QAAO,8BAAoB;EACzB,IAAI,QAAQ;EACZ,SAAS,wBAAwB,QAAQ,QAAQ;EACjD,MAAM;EACP,CAAC;;AAGJ,SAAgB,iCACd,UACA,iBAC4B;AAC5B,KAAI,SAAS,SAAS,WACpB,OAAM,IAAI,MAAM,+BAA+B,SAAS,OAAO;CAKjE,IAAI;AAEJ,KAAI,OAAO,SAAS,SAAS,cAAc,SAEzC,KAAI;AACF,iBAAe,KAAK,MAAM,SAAS,SAAS,UAAU;SAChD;AACN,UAAQ,KACN,4EACD;AAED,iBAAe,EAAE;;UAGnB,OAAO,SAAS,SAAS,cAAc,YACvC,SAAS,SAAS,cAAc,KAGhC,gBAAe,SAAS,SAAS;MAC5B;AAEL,UAAQ,KACN,qDAAqD,OAAO,SAAS,SAAS,UAAU,iCACzF;AACD,iBAAe,EAAE;;AAInB,KACE,OAAO,iBAAiB,YACxB,iBAAiB,QACjB,MAAM,QAAQ,aAAa,EAC3B;AACA,UAAQ,KACN,qDAAqD,OAAO,aAAa,iCAC1E;AACD,iBAAe,EAAE;;AAInB,QAAO,yCAA+B;EACpC,IAAI,SAAS;EACb,MAAM,SAAS,SAAS;EACxB,WAAW;EACM;EAClB,CAAC;;AAGJ,SAAgB,kCACd,SACA,eACmB;AACnB,KAAI,QAAQ,SAAS,OACnB,OAAM,IAAI,MACR,oCAAoC,QAAQ,KAAK,mBAClD;AAGH,KAAI,CAAC,QAAQ,WACX,OAAM,IAAI,MAAM,sCAAsC;CAGxD,MAAM,aAAa,cAAc,QAAQ,eAAe;CAGxD,IAAI;CACJ,MAAM,iBAAiB,QAAQ,WAAW;AAE1C,KAAI,OAAO,mBAAmB,SAE5B,iBAAgB;UACP,OAAO,mBAAmB,YAAY,mBAAmB,KAElE,KAAI;AACF,kBAAgB,KAAK,UAAU,eAAe;UACvC,OAAO;AACd,UAAQ,KAAK,uCAAuC,WAAW,IAAI,MAAM;AACzE,kBAAgB,OAAO,eAAe;;KAIxC,iBAAgB,OAAO,eAAe;AAGxC,QAAO,gCAAsB;EAC3B,IAAI,QAAQ;EACZ,QAAQ;EACR,mBAAmB,QAAQ;EAC3B,YAAY,QAAQ,YAAY;EACjC,CAAC;;AAsCJ,SAAgB,iCACd,SACkB;AAClB,KAAI,CAAC,iBAAiB,QAAQ,CAC5B,OAAM,IAAI,MACR,kEACD;CAGH,IAAI;AACJ,KAAI,QAAQ,SAAS,YACnB,gCAAqB;KAErB,gCAAqB;AAGvB,KAAI,QAAQ,SAAS,eAAe,QAAQ,SAAS,OACnD,OAAM,IAAI,MACR,oCAAoC,QAAQ,KAAK,kBAClD;AAGH,QAAO,+BAAqB;EAC1B,IAAI,QAAQ;EACZ,QAAQ,QAAQ,MAAM;EACtB,OAAO,QAAQ,MAAM;EACrB,MAAM;EACP,CAAC"}
|
|
@@ -16,11 +16,19 @@ function hasImageProperty(message) {
|
|
|
16
16
|
if (image.format === void 0 || image.bytes === void 0) return false;
|
|
17
17
|
return true;
|
|
18
18
|
}
|
|
19
|
+
const warnedContentPartTypes = /* @__PURE__ */ new Set();
|
|
20
|
+
function warnUnsupportedContentPart(type) {
|
|
21
|
+
const label = typeof type === "string" ? type : String(type);
|
|
22
|
+
if (warnedContentPartTypes.has(label)) return;
|
|
23
|
+
warnedContentPartTypes.add(label);
|
|
24
|
+
console.warn(`[CopilotKit] Dropping message content part of unsupported type "${label}". Only "text" and "binary" parts are carried through to the client; see https://github.com/CopilotKit/CopilotKit/issues/1748.`);
|
|
25
|
+
}
|
|
19
26
|
function normalizeMessageContent(content) {
|
|
20
27
|
if (typeof content === "string" || typeof content === "undefined") return content || "";
|
|
21
28
|
if (Array.isArray(content)) return content.map((part) => {
|
|
22
29
|
if (part?.type === "text") return part.text;
|
|
23
30
|
if (part?.type === "binary") return part.data || part.url || part.filename || `[binary:${part.mimeType}]`;
|
|
31
|
+
warnUnsupportedContentPart(part?.type);
|
|
24
32
|
return "";
|
|
25
33
|
}).filter(Boolean).join("\n");
|
|
26
34
|
if (content && typeof content === "object") try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agui-to-gql.mjs","names":["gql.AgentStateMessage","gql.TextMessage","gql.ActionExecutionMessage","gql.ResultMessage","gql.ImageMessage"],"sources":["../../../src/graphql/message-conversion/agui-to-gql.ts"],"sourcesContent":["import * as gql from \"../types/converted/index\";\nimport { MessageRole } from \"../types/enums\";\nimport * as agui from \"@copilotkit/shared\"; // named agui for clarity, but this only includes agui message types\n\n// Helper function to extract agent name from message\nfunction extractAgentName(message: agui.Message): string {\n if (message.role !== \"assistant\") {\n throw new Error(\n `Cannot extract agent name from message with role ${message.role}`,\n );\n }\n\n return message.agentName || \"unknown\";\n}\n\n// Type guard for agent state message\nfunction isAgentStateMessage(message: agui.Message): boolean {\n return (\n message.role === \"assistant\" && \"agentName\" in message && \"state\" in message\n );\n}\n\n// Type guard for messages with image property\nfunction hasImageProperty(\n message: agui.Message,\n): message is agui.Message & { image: agui.ImageData } {\n const canContainImage =\n message.role === \"assistant\" || message.role === \"user\";\n if (!canContainImage) {\n return false;\n }\n\n const image: { format?: string; bytes?: string } | undefined =\n \"image\" in message ? message.image : undefined;\n if (image === undefined) {\n return false;\n }\n\n const isMalformed = image.format === undefined || image.bytes === undefined;\n if (isMalformed) {\n return false;\n }\n\n return true;\n}\n\nfunction normalizeMessageContent(content: agui.Message[\"content\"]): string {\n if (typeof content === \"string\" || typeof content === \"undefined\") {\n return content || \"\";\n }\n\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (part?.type === \"text\") {\n return part.text;\n }\n if (part?.type === \"binary\") {\n return (\n part.data ||\n part.url ||\n part.filename ||\n `[binary:${part.mimeType}]`\n );\n }\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n\n if (content && typeof content === \"object\") {\n try {\n return JSON.stringify(content);\n } catch (error) {\n console.warn(\"Failed to serialize message content\", error);\n }\n }\n\n return String(content ?? \"\");\n}\n\n/*\n ----------------------------\n AGUI Message -> GQL Message\n ----------------------------\n*/\nexport function aguiToGQL(\n messages: agui.Message[] | agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n const gqlMessages: gql.Message[] = [];\n messages = Array.isArray(messages) ? messages : [messages];\n\n // Track tool call names by their IDs for use in result messages\n const toolCallNames: Record<string, string> = {};\n\n for (const message of messages) {\n // Agent state message support\n if (isAgentStateMessage(message)) {\n const agentName = extractAgentName(message);\n const state = \"state\" in message && message.state ? message.state : {};\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName,\n state,\n role: gql.Role.assistant,\n }),\n );\n // Optionally preserve render function\n if (\n \"generativeUI\" in message &&\n message.generativeUI &&\n coAgentStateRenders\n ) {\n coAgentStateRenders[agentName] = {\n name: agentName,\n render: message.generativeUI,\n };\n }\n continue;\n }\n\n if (hasImageProperty(message)) {\n gqlMessages.push(aguiMessageWithImageToGQLMessage(message));\n continue;\n }\n\n // Action execution message support\n if (message.role === \"assistant\" && message.toolCalls) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n for (const toolCall of message.toolCalls) {\n // Track the tool call name by its ID\n toolCallNames[toolCall.id] = toolCall.function.name;\n\n const actionExecMsg = aguiToolCallToGQLActionExecution(\n toolCall,\n message.id,\n );\n // Preserve render function in actions context\n if (\"generativeUI\" in message && message.generativeUI && actions) {\n const actionName = toolCall.function.name;\n // Check for specific action first, then wild card action\n const specificAction = Object.values(actions).find(\n (action: any) => action.name === actionName,\n );\n const wildcardAction = Object.values(actions).find(\n (action: any) => action.name === \"*\",\n );\n\n // Assign render function to the matching action (specific takes priority)\n if (specificAction) {\n specificAction.render = message.generativeUI;\n } else if (wildcardAction) {\n wildcardAction.render = message.generativeUI;\n }\n }\n gqlMessages.push(actionExecMsg);\n }\n continue;\n }\n // Reasoning messages are ephemeral display-only content with no GQL equivalent — skip them\n if (message.role === \"reasoning\") {\n continue;\n }\n // Regular text messages\n if (\n message.role === \"developer\" ||\n message.role === \"system\" ||\n message.role === \"assistant\" ||\n message.role === \"user\"\n ) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n continue;\n }\n // Tool result message\n if (message.role === \"tool\") {\n gqlMessages.push(\n aguiToolMessageToGQLResultMessage(message, toolCallNames),\n );\n continue;\n }\n throw new Error(\n `Unknown message role: \"${(message as any).role}\" in message with id: ${(message as any).id}`,\n );\n }\n\n return gqlMessages;\n}\n\nexport function aguiTextMessageToGQLMessage(\n message: agui.Message,\n): gql.TextMessage {\n if (\n message.role !== \"developer\" &&\n message.role !== \"system\" &&\n message.role !== \"assistant\" &&\n message.role !== \"user\"\n ) {\n throw new Error(\n `Cannot convert message with role ${message.role} to TextMessage`,\n );\n }\n\n let roleValue: MessageRole;\n\n if (message.role === \"developer\") {\n roleValue = gql.Role.developer;\n } else if (message.role === \"system\") {\n roleValue = gql.Role.system;\n } else if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n return new gql.TextMessage({\n id: message.id,\n content: normalizeMessageContent(message.content),\n role: roleValue,\n });\n}\n\nexport function aguiToolCallToGQLActionExecution(\n toolCall: agui.ToolCall,\n parentMessageId: string,\n): gql.ActionExecutionMessage {\n if (toolCall.type !== \"function\") {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n\n // Handle arguments - they should be a JSON string in AGUI format,\n // but we need to convert them to an object for GQL format\n let argumentsObj: any;\n\n if (typeof toolCall.function.arguments === \"string\") {\n // Expected case: arguments is a JSON string\n try {\n argumentsObj = JSON.parse(toolCall.function.arguments);\n } catch {\n console.warn(\n `[CopilotKit] Failed to parse tool arguments, falling back to empty object`,\n );\n // Provide fallback empty object to prevent application crash\n argumentsObj = {};\n }\n } else if (\n typeof toolCall.function.arguments === \"object\" &&\n toolCall.function.arguments !== null\n ) {\n // Backward compatibility: arguments is already an object\n argumentsObj = toolCall.function.arguments;\n } else {\n // Fallback for undefined, null, or other types\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof toolCall.function.arguments}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Guard against successfully parsed non-object values (e.g. JSON.parse('\"\"') → \"\")\n if (\n typeof argumentsObj !== \"object\" ||\n argumentsObj === null ||\n Array.isArray(argumentsObj)\n ) {\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof argumentsObj}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Always include name and arguments\n return new gql.ActionExecutionMessage({\n id: toolCall.id,\n name: toolCall.function.name,\n arguments: argumentsObj,\n parentMessageId: parentMessageId,\n });\n}\n\nexport function aguiToolMessageToGQLResultMessage(\n message: agui.Message,\n toolCallNames: Record<string, string>,\n): gql.ResultMessage {\n if (message.role !== \"tool\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ResultMessage`,\n );\n }\n\n if (!message.toolCallId) {\n throw new Error(\"Tool message must have a toolCallId\");\n }\n\n const actionName = toolCallNames[message.toolCallId] || \"unknown\";\n\n // Handle result content - it could be a string or an object that needs serialization\n let resultContent: string;\n const messageContent = message.content || \"\";\n\n if (typeof messageContent === \"string\") {\n // Expected case: content is already a string\n resultContent = messageContent;\n } else if (typeof messageContent === \"object\" && messageContent !== null) {\n // Handle case where content is an object that needs to be serialized\n try {\n resultContent = JSON.stringify(messageContent);\n } catch (error) {\n console.warn(`Failed to stringify tool result for ${actionName}:`, error);\n resultContent = String(messageContent);\n }\n } else {\n // Handle other types (number, boolean, etc.)\n resultContent = String(messageContent);\n }\n\n return new gql.ResultMessage({\n id: message.id,\n result: resultContent,\n actionExecutionId: message.toolCallId,\n actionName: message.toolName || actionName,\n });\n}\n\n// New function to handle AGUI messages with render functions\nexport function aguiMessageWithRenderToGQL(\n message: agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n // Handle the special case: assistant messages with render function but no tool calls\n if (\n message.role === \"assistant\" &&\n \"generativeUI\" in message &&\n message.generativeUI &&\n !message.toolCalls\n ) {\n const gqlMessages: gql.Message[] = [];\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName: \"unknown\",\n state: {},\n role: gql.Role.assistant,\n }),\n );\n if (coAgentStateRenders) {\n coAgentStateRenders.unknown = {\n name: \"unknown\",\n render: message.generativeUI,\n };\n }\n return gqlMessages;\n }\n\n // For all other cases, delegate to aguiToGQL\n return aguiToGQL([message], actions, coAgentStateRenders);\n}\n\nexport function aguiMessageWithImageToGQLMessage(\n message: agui.Message,\n): gql.ImageMessage {\n if (!hasImageProperty(message)) {\n throw new Error(\n `Cannot convert message to ImageMessage: missing format or bytes`,\n );\n }\n\n let roleValue: MessageRole;\n if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n if (message.role !== \"assistant\" && message.role !== \"user\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ImageMessage`,\n );\n }\n\n return new gql.ImageMessage({\n id: message.id,\n format: message.image.format,\n bytes: message.image.bytes,\n role: roleValue,\n });\n}\n"],"mappings":";;;;AAKA,SAAS,iBAAiB,SAA+B;AACvD,KAAI,QAAQ,SAAS,YACnB,OAAM,IAAI,MACR,oDAAoD,QAAQ,OAC7D;AAGH,QAAO,QAAQ,aAAa;;AAI9B,SAAS,oBAAoB,SAAgC;AAC3D,QACE,QAAQ,SAAS,eAAe,eAAe,WAAW,WAAW;;AAKzE,SAAS,iBACP,SACqD;AAGrD,KAAI,EADF,QAAQ,SAAS,eAAe,QAAQ,SAAS,QAEjD,QAAO;CAGT,MAAM,QACJ,WAAW,UAAU,QAAQ,QAAQ;AACvC,KAAI,UAAU,OACZ,QAAO;AAIT,KADoB,MAAM,WAAW,UAAa,MAAM,UAAU,OAEhE,QAAO;AAGT,QAAO;;AAGT,SAAS,wBAAwB,SAA0C;AACzE,KAAI,OAAO,YAAY,YAAY,OAAO,YAAY,YACpD,QAAO,WAAW;AAGpB,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,QACJ,KAAK,SAAS;AACb,MAAI,MAAM,SAAS,OACjB,QAAO,KAAK;AAEd,MAAI,MAAM,SAAS,SACjB,QACE,KAAK,QACL,KAAK,OACL,KAAK,YACL,WAAW,KAAK,SAAS;AAG7B,SAAO;GACP,CACD,OAAO,QAAQ,CACf,KAAK,KAAK;AAGf,KAAI,WAAW,OAAO,YAAY,SAChC,KAAI;AACF,SAAO,KAAK,UAAU,QAAQ;UACvB,OAAO;AACd,UAAQ,KAAK,uCAAuC,MAAM;;AAI9D,QAAO,OAAO,WAAW,GAAG;;AAQ9B,SAAgB,UACd,UACA,SACA,qBACe;CACf,MAAM,cAA6B,EAAE;AACrC,YAAW,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC,SAAS;CAG1D,MAAM,gBAAwC,EAAE;AAEhD,MAAK,MAAM,WAAW,UAAU;AAE9B,MAAI,oBAAoB,QAAQ,EAAE;GAChC,MAAM,YAAY,iBAAiB,QAAQ;GAC3C,MAAM,QAAQ,WAAW,WAAW,QAAQ,QAAQ,QAAQ,QAAQ,EAAE;AACtE,eAAY,KACV,IAAIA,kBAAsB;IACxB,IAAI,QAAQ;IACZ;IACA;IACA,WAAe;IAChB,CAAC,CACH;AAED,OACE,kBAAkB,WAClB,QAAQ,gBACR,oBAEA,qBAAoB,aAAa;IAC/B,MAAM;IACN,QAAQ,QAAQ;IACjB;AAEH;;AAGF,MAAI,iBAAiB,QAAQ,EAAE;AAC7B,eAAY,KAAK,iCAAiC,QAAQ,CAAC;AAC3D;;AAIF,MAAI,QAAQ,SAAS,eAAe,QAAQ,WAAW;AACrD,eAAY,KAAK,4BAA4B,QAAQ,CAAC;AACtD,QAAK,MAAM,YAAY,QAAQ,WAAW;AAExC,kBAAc,SAAS,MAAM,SAAS,SAAS;IAE/C,MAAM,gBAAgB,iCACpB,UACA,QAAQ,GACT;AAED,QAAI,kBAAkB,WAAW,QAAQ,gBAAgB,SAAS;KAChE,MAAM,aAAa,SAAS,SAAS;KAErC,MAAM,iBAAiB,OAAO,OAAO,QAAQ,CAAC,MAC3C,WAAgB,OAAO,SAAS,WAClC;KACD,MAAM,iBAAiB,OAAO,OAAO,QAAQ,CAAC,MAC3C,WAAgB,OAAO,SAAS,IAClC;AAGD,SAAI,eACF,gBAAe,SAAS,QAAQ;cACvB,eACT,gBAAe,SAAS,QAAQ;;AAGpC,gBAAY,KAAK,cAAc;;AAEjC;;AAGF,MAAI,QAAQ,SAAS,YACnB;AAGF,MACE,QAAQ,SAAS,eACjB,QAAQ,SAAS,YACjB,QAAQ,SAAS,eACjB,QAAQ,SAAS,QACjB;AACA,eAAY,KAAK,4BAA4B,QAAQ,CAAC;AACtD;;AAGF,MAAI,QAAQ,SAAS,QAAQ;AAC3B,eAAY,KACV,kCAAkC,SAAS,cAAc,CAC1D;AACD;;AAEF,QAAM,IAAI,MACR,0BAA2B,QAAgB,KAAK,wBAAyB,QAAgB,KAC1F;;AAGH,QAAO;;AAGT,SAAgB,4BACd,SACiB;AACjB,KACE,QAAQ,SAAS,eACjB,QAAQ,SAAS,YACjB,QAAQ,SAAS,eACjB,QAAQ,SAAS,OAEjB,OAAM,IAAI,MACR,oCAAoC,QAAQ,KAAK,iBAClD;CAGH,IAAI;AAEJ,KAAI,QAAQ,SAAS,YACnB,kBAAqB;UACZ,QAAQ,SAAS,SAC1B,kBAAqB;UACZ,QAAQ,SAAS,YAC1B,kBAAqB;KAErB,kBAAqB;AAGvB,QAAO,IAAIC,YAAgB;EACzB,IAAI,QAAQ;EACZ,SAAS,wBAAwB,QAAQ,QAAQ;EACjD,MAAM;EACP,CAAC;;AAGJ,SAAgB,iCACd,UACA,iBAC4B;AAC5B,KAAI,SAAS,SAAS,WACpB,OAAM,IAAI,MAAM,+BAA+B,SAAS,OAAO;CAKjE,IAAI;AAEJ,KAAI,OAAO,SAAS,SAAS,cAAc,SAEzC,KAAI;AACF,iBAAe,KAAK,MAAM,SAAS,SAAS,UAAU;SAChD;AACN,UAAQ,KACN,4EACD;AAED,iBAAe,EAAE;;UAGnB,OAAO,SAAS,SAAS,cAAc,YACvC,SAAS,SAAS,cAAc,KAGhC,gBAAe,SAAS,SAAS;MAC5B;AAEL,UAAQ,KACN,qDAAqD,OAAO,SAAS,SAAS,UAAU,iCACzF;AACD,iBAAe,EAAE;;AAInB,KACE,OAAO,iBAAiB,YACxB,iBAAiB,QACjB,MAAM,QAAQ,aAAa,EAC3B;AACA,UAAQ,KACN,qDAAqD,OAAO,aAAa,iCAC1E;AACD,iBAAe,EAAE;;AAInB,QAAO,IAAIC,uBAA2B;EACpC,IAAI,SAAS;EACb,MAAM,SAAS,SAAS;EACxB,WAAW;EACM;EAClB,CAAC;;AAGJ,SAAgB,kCACd,SACA,eACmB;AACnB,KAAI,QAAQ,SAAS,OACnB,OAAM,IAAI,MACR,oCAAoC,QAAQ,KAAK,mBAClD;AAGH,KAAI,CAAC,QAAQ,WACX,OAAM,IAAI,MAAM,sCAAsC;CAGxD,MAAM,aAAa,cAAc,QAAQ,eAAe;CAGxD,IAAI;CACJ,MAAM,iBAAiB,QAAQ,WAAW;AAE1C,KAAI,OAAO,mBAAmB,SAE5B,iBAAgB;UACP,OAAO,mBAAmB,YAAY,mBAAmB,KAElE,KAAI;AACF,kBAAgB,KAAK,UAAU,eAAe;UACvC,OAAO;AACd,UAAQ,KAAK,uCAAuC,WAAW,IAAI,MAAM;AACzE,kBAAgB,OAAO,eAAe;;KAIxC,iBAAgB,OAAO,eAAe;AAGxC,QAAO,IAAIC,cAAkB;EAC3B,IAAI,QAAQ;EACZ,QAAQ;EACR,mBAAmB,QAAQ;EAC3B,YAAY,QAAQ,YAAY;EACjC,CAAC;;AAsCJ,SAAgB,iCACd,SACkB;AAClB,KAAI,CAAC,iBAAiB,QAAQ,CAC5B,OAAM,IAAI,MACR,kEACD;CAGH,IAAI;AACJ,KAAI,QAAQ,SAAS,YACnB,kBAAqB;KAErB,kBAAqB;AAGvB,KAAI,QAAQ,SAAS,eAAe,QAAQ,SAAS,OACnD,OAAM,IAAI,MACR,oCAAoC,QAAQ,KAAK,kBAClD;AAGH,QAAO,IAAIC,aAAiB;EAC1B,IAAI,QAAQ;EACZ,QAAQ,QAAQ,MAAM;EACtB,OAAO,QAAQ,MAAM;EACrB,MAAM;EACP,CAAC"}
|
|
1
|
+
{"version":3,"file":"agui-to-gql.mjs","names":["gql.AgentStateMessage","gql.TextMessage","gql.ActionExecutionMessage","gql.ResultMessage","gql.ImageMessage"],"sources":["../../../src/graphql/message-conversion/agui-to-gql.ts"],"sourcesContent":["import * as gql from \"../types/converted/index\";\nimport { MessageRole } from \"../types/enums\";\nimport * as agui from \"@copilotkit/shared\"; // named agui for clarity, but this only includes agui message types\n\n// Helper function to extract agent name from message\nfunction extractAgentName(message: agui.Message): string {\n if (message.role !== \"assistant\") {\n throw new Error(\n `Cannot extract agent name from message with role ${message.role}`,\n );\n }\n\n return message.agentName || \"unknown\";\n}\n\n// Type guard for agent state message\nfunction isAgentStateMessage(message: agui.Message): boolean {\n return (\n message.role === \"assistant\" && \"agentName\" in message && \"state\" in message\n );\n}\n\n// Type guard for messages with image property\nfunction hasImageProperty(\n message: agui.Message,\n): message is agui.Message & { image: agui.ImageData } {\n const canContainImage =\n message.role === \"assistant\" || message.role === \"user\";\n if (!canContainImage) {\n return false;\n }\n\n const image: { format?: string; bytes?: string } | undefined =\n \"image\" in message ? message.image : undefined;\n if (image === undefined) {\n return false;\n }\n\n const isMalformed = image.format === undefined || image.bytes === undefined;\n if (isMalformed) {\n return false;\n }\n\n return true;\n}\n\n// Content part types we have already warned about. Streaming replays the same\n// unsupported part on every delta, so warn once per type rather than per part.\nconst warnedContentPartTypes = new Set<string>();\n\nfunction warnUnsupportedContentPart(type: unknown): void {\n const label = typeof type === \"string\" ? type : String(type);\n if (warnedContentPartTypes.has(label)) return;\n warnedContentPartTypes.add(label);\n console.warn(\n `[CopilotKit] Dropping message content part of unsupported type \"${label}\". ` +\n `Only \"text\" and \"binary\" parts are carried through to the client; ` +\n `see https://github.com/CopilotKit/CopilotKit/issues/1748.`,\n );\n}\n\nfunction normalizeMessageContent(content: agui.Message[\"content\"]): string {\n if (typeof content === \"string\" || typeof content === \"undefined\") {\n return content || \"\";\n }\n\n if (Array.isArray(content)) {\n return content\n .map((part) => {\n if (part?.type === \"text\") {\n return part.text;\n }\n if (part?.type === \"binary\") {\n return (\n part.data ||\n part.url ||\n part.filename ||\n `[binary:${part.mimeType}]`\n );\n }\n warnUnsupportedContentPart(part?.type);\n return \"\";\n })\n .filter(Boolean)\n .join(\"\\n\");\n }\n\n if (content && typeof content === \"object\") {\n try {\n return JSON.stringify(content);\n } catch (error) {\n console.warn(\"Failed to serialize message content\", error);\n }\n }\n\n return String(content ?? \"\");\n}\n\n/*\n ----------------------------\n AGUI Message -> GQL Message\n ----------------------------\n*/\nexport function aguiToGQL(\n messages: agui.Message[] | agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n const gqlMessages: gql.Message[] = [];\n messages = Array.isArray(messages) ? messages : [messages];\n\n // Track tool call names by their IDs for use in result messages\n const toolCallNames: Record<string, string> = {};\n\n for (const message of messages) {\n // Agent state message support\n if (isAgentStateMessage(message)) {\n const agentName = extractAgentName(message);\n const state = \"state\" in message && message.state ? message.state : {};\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName,\n state,\n role: gql.Role.assistant,\n }),\n );\n // Optionally preserve render function\n if (\n \"generativeUI\" in message &&\n message.generativeUI &&\n coAgentStateRenders\n ) {\n coAgentStateRenders[agentName] = {\n name: agentName,\n render: message.generativeUI,\n };\n }\n continue;\n }\n\n if (hasImageProperty(message)) {\n gqlMessages.push(aguiMessageWithImageToGQLMessage(message));\n continue;\n }\n\n // Action execution message support\n if (message.role === \"assistant\" && message.toolCalls) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n for (const toolCall of message.toolCalls) {\n // Track the tool call name by its ID\n toolCallNames[toolCall.id] = toolCall.function.name;\n\n const actionExecMsg = aguiToolCallToGQLActionExecution(\n toolCall,\n message.id,\n );\n // Preserve render function in actions context\n if (\"generativeUI\" in message && message.generativeUI && actions) {\n const actionName = toolCall.function.name;\n // Check for specific action first, then wild card action\n const specificAction = Object.values(actions).find(\n (action: any) => action.name === actionName,\n );\n const wildcardAction = Object.values(actions).find(\n (action: any) => action.name === \"*\",\n );\n\n // Assign render function to the matching action (specific takes priority)\n if (specificAction) {\n specificAction.render = message.generativeUI;\n } else if (wildcardAction) {\n wildcardAction.render = message.generativeUI;\n }\n }\n gqlMessages.push(actionExecMsg);\n }\n continue;\n }\n // Reasoning messages are ephemeral display-only content with no GQL equivalent — skip them\n if (message.role === \"reasoning\") {\n continue;\n }\n // Regular text messages\n if (\n message.role === \"developer\" ||\n message.role === \"system\" ||\n message.role === \"assistant\" ||\n message.role === \"user\"\n ) {\n gqlMessages.push(aguiTextMessageToGQLMessage(message));\n continue;\n }\n // Tool result message\n if (message.role === \"tool\") {\n gqlMessages.push(\n aguiToolMessageToGQLResultMessage(message, toolCallNames),\n );\n continue;\n }\n throw new Error(\n `Unknown message role: \"${(message as any).role}\" in message with id: ${(message as any).id}`,\n );\n }\n\n return gqlMessages;\n}\n\nexport function aguiTextMessageToGQLMessage(\n message: agui.Message,\n): gql.TextMessage {\n if (\n message.role !== \"developer\" &&\n message.role !== \"system\" &&\n message.role !== \"assistant\" &&\n message.role !== \"user\"\n ) {\n throw new Error(\n `Cannot convert message with role ${message.role} to TextMessage`,\n );\n }\n\n let roleValue: MessageRole;\n\n if (message.role === \"developer\") {\n roleValue = gql.Role.developer;\n } else if (message.role === \"system\") {\n roleValue = gql.Role.system;\n } else if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n return new gql.TextMessage({\n id: message.id,\n content: normalizeMessageContent(message.content),\n role: roleValue,\n });\n}\n\nexport function aguiToolCallToGQLActionExecution(\n toolCall: agui.ToolCall,\n parentMessageId: string,\n): gql.ActionExecutionMessage {\n if (toolCall.type !== \"function\") {\n throw new Error(`Unsupported tool call type: ${toolCall.type}`);\n }\n\n // Handle arguments - they should be a JSON string in AGUI format,\n // but we need to convert them to an object for GQL format\n let argumentsObj: any;\n\n if (typeof toolCall.function.arguments === \"string\") {\n // Expected case: arguments is a JSON string\n try {\n argumentsObj = JSON.parse(toolCall.function.arguments);\n } catch {\n console.warn(\n `[CopilotKit] Failed to parse tool arguments, falling back to empty object`,\n );\n // Provide fallback empty object to prevent application crash\n argumentsObj = {};\n }\n } else if (\n typeof toolCall.function.arguments === \"object\" &&\n toolCall.function.arguments !== null\n ) {\n // Backward compatibility: arguments is already an object\n argumentsObj = toolCall.function.arguments;\n } else {\n // Fallback for undefined, null, or other types\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof toolCall.function.arguments}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Guard against successfully parsed non-object values (e.g. JSON.parse('\"\"') → \"\")\n if (\n typeof argumentsObj !== \"object\" ||\n argumentsObj === null ||\n Array.isArray(argumentsObj)\n ) {\n console.warn(\n `[CopilotKit] Tool arguments parsed to non-object (${typeof argumentsObj}), falling back to empty object`,\n );\n argumentsObj = {};\n }\n\n // Always include name and arguments\n return new gql.ActionExecutionMessage({\n id: toolCall.id,\n name: toolCall.function.name,\n arguments: argumentsObj,\n parentMessageId: parentMessageId,\n });\n}\n\nexport function aguiToolMessageToGQLResultMessage(\n message: agui.Message,\n toolCallNames: Record<string, string>,\n): gql.ResultMessage {\n if (message.role !== \"tool\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ResultMessage`,\n );\n }\n\n if (!message.toolCallId) {\n throw new Error(\"Tool message must have a toolCallId\");\n }\n\n const actionName = toolCallNames[message.toolCallId] || \"unknown\";\n\n // Handle result content - it could be a string or an object that needs serialization\n let resultContent: string;\n const messageContent = message.content || \"\";\n\n if (typeof messageContent === \"string\") {\n // Expected case: content is already a string\n resultContent = messageContent;\n } else if (typeof messageContent === \"object\" && messageContent !== null) {\n // Handle case where content is an object that needs to be serialized\n try {\n resultContent = JSON.stringify(messageContent);\n } catch (error) {\n console.warn(`Failed to stringify tool result for ${actionName}:`, error);\n resultContent = String(messageContent);\n }\n } else {\n // Handle other types (number, boolean, etc.)\n resultContent = String(messageContent);\n }\n\n return new gql.ResultMessage({\n id: message.id,\n result: resultContent,\n actionExecutionId: message.toolCallId,\n actionName: message.toolName || actionName,\n });\n}\n\n// New function to handle AGUI messages with render functions\nexport function aguiMessageWithRenderToGQL(\n message: agui.Message,\n actions?: Record<string, any>,\n coAgentStateRenders?: Record<string, any>,\n): gql.Message[] {\n // Handle the special case: assistant messages with render function but no tool calls\n if (\n message.role === \"assistant\" &&\n \"generativeUI\" in message &&\n message.generativeUI &&\n !message.toolCalls\n ) {\n const gqlMessages: gql.Message[] = [];\n gqlMessages.push(\n new gql.AgentStateMessage({\n id: message.id,\n agentName: \"unknown\",\n state: {},\n role: gql.Role.assistant,\n }),\n );\n if (coAgentStateRenders) {\n coAgentStateRenders.unknown = {\n name: \"unknown\",\n render: message.generativeUI,\n };\n }\n return gqlMessages;\n }\n\n // For all other cases, delegate to aguiToGQL\n return aguiToGQL([message], actions, coAgentStateRenders);\n}\n\nexport function aguiMessageWithImageToGQLMessage(\n message: agui.Message,\n): gql.ImageMessage {\n if (!hasImageProperty(message)) {\n throw new Error(\n `Cannot convert message to ImageMessage: missing format or bytes`,\n );\n }\n\n let roleValue: MessageRole;\n if (message.role === \"assistant\") {\n roleValue = gql.Role.assistant;\n } else {\n roleValue = gql.Role.user;\n }\n\n if (message.role !== \"assistant\" && message.role !== \"user\") {\n throw new Error(\n `Cannot convert message with role ${message.role} to ImageMessage`,\n );\n }\n\n return new gql.ImageMessage({\n id: message.id,\n format: message.image.format,\n bytes: message.image.bytes,\n role: roleValue,\n });\n}\n"],"mappings":"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"}
|
package/dist/package.cjs
CHANGED
|
@@ -5,7 +5,7 @@ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
|
5
5
|
var require_package = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
|
6
6
|
module.exports = {
|
|
7
7
|
"name": "@copilotkit/runtime",
|
|
8
|
-
"version": "1.68.
|
|
8
|
+
"version": "1.68.2",
|
|
9
9
|
"private": false,
|
|
10
10
|
"keywords": [
|
|
11
11
|
"ai",
|
package/dist/runtime/package.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { __commonJSMin } from "../_virtual/_rolldown/runtime.mjs";
|
|
|
5
5
|
var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6
6
|
module.exports = {
|
|
7
7
|
"name": "@copilotkit/runtime",
|
|
8
|
-
"version": "1.68.
|
|
8
|
+
"version": "1.68.2",
|
|
9
9
|
"private": false,
|
|
10
10
|
"keywords": [
|
|
11
11
|
"ai",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require("reflect-metadata");
|
|
2
2
|
const require_runtime = require('../../../_virtual/_rolldown/runtime.cjs');
|
|
3
|
+
const require_telemetry_client = require('../telemetry/telemetry-client.cjs');
|
|
3
4
|
const require_learning = require('./learning.cjs');
|
|
4
5
|
const require_channel_activation_config = require('./channel-activation-config.cjs');
|
|
5
6
|
const require_client = require('../intelligence-platform/client.cjs');
|
|
@@ -797,19 +798,42 @@ var ChannelManager = class {
|
|
|
797
798
|
if (state === "reconnecting") {
|
|
798
799
|
entry.status = "reconnecting";
|
|
799
800
|
entry.downSince ??= Date.now();
|
|
801
|
+
if (cause !== void 0) entry.downCause = cause;
|
|
800
802
|
this.log?.(`channel "${name}" managed session dropped; reconnecting (Phoenix auto-rejoin)${because}`);
|
|
803
|
+
this.captureChannelTelemetry("oss.runtime.channel_session_dropped", {
|
|
804
|
+
...detail?.reason !== void 0 ? { reason: detail.reason } : {},
|
|
805
|
+
...detail?.code !== void 0 ? { code: detail.code } : {}
|
|
806
|
+
});
|
|
801
807
|
this.startReconnectLog(name, entry);
|
|
802
808
|
} else if (state === "online") {
|
|
803
809
|
entry.status = "online";
|
|
804
810
|
this.clearReconnectLog(entry);
|
|
811
|
+
const downSince = entry.downSince;
|
|
805
812
|
entry.downSince = void 0;
|
|
813
|
+
entry.downCause = void 0;
|
|
806
814
|
this.log?.(`channel "${name}" managed session back online`);
|
|
815
|
+
if (downSince !== void 0) this.captureChannelTelemetry("oss.runtime.channel_session_recovered", { downForMs: Date.now() - downSince });
|
|
807
816
|
} else if (state === "gave_up") {
|
|
808
817
|
entry.status = "error";
|
|
809
818
|
this.log?.(`channel "${name}" managed session gave up reconnecting after ${this.downFor(entry)}; marking error (still retrying — a successful rejoin restores online)${because}`);
|
|
810
819
|
}
|
|
811
820
|
});
|
|
812
821
|
}
|
|
822
|
+
/**
|
|
823
|
+
* Report a Channel connection event. A managed session that drops is
|
|
824
|
+
* otherwise invisible outside the host process — the `log` seam reaches only
|
|
825
|
+
* whoever reads that process's stdout, which for a self-hosted runtime is
|
|
826
|
+
* nobody who can act on it.
|
|
827
|
+
*
|
|
828
|
+
* Fire-and-forget, and failures are swallowed: telemetry must never break a
|
|
829
|
+
* live session. Same contract as `fireInstanceCreatedTelemetry`. The `try`
|
|
830
|
+
* also covers a `capture` that throws synchronously or returns no promise.
|
|
831
|
+
*/
|
|
832
|
+
captureChannelTelemetry(event, props) {
|
|
833
|
+
try {
|
|
834
|
+
require_telemetry_client.default.capture(event, props).catch(() => {});
|
|
835
|
+
} catch {}
|
|
836
|
+
}
|
|
813
837
|
/** Rendered downtime for this outage episode (`"45s"`), or `"unknown"`. */
|
|
814
838
|
downFor(entry) {
|
|
815
839
|
return entry.downSince === void 0 ? "unknown" : `${Math.round((Date.now() - entry.downSince) / 1e3)}s`;
|
|
@@ -829,7 +853,7 @@ var ChannelManager = class {
|
|
|
829
853
|
this.clearReconnectLog(entry);
|
|
830
854
|
return;
|
|
831
855
|
}
|
|
832
|
-
this.log?.(`channel "${name}" managed session still down after ${this.downFor(entry)}; Phoenix is retrying`);
|
|
856
|
+
this.log?.(`channel "${name}" managed session still down after ${this.downFor(entry)}; Phoenix is retrying` + (entry.downCause !== void 0 ? ` — ${entry.downCause}` : ""));
|
|
833
857
|
entry.reconnectLogDelayMs = Math.min(delayMs * 2, Math.max(this.reconnectLogIntervalMs, DEFAULT_RECONNECT_LOG_MAX_INTERVAL_MS));
|
|
834
858
|
this.startReconnectLog(name, entry);
|
|
835
859
|
}, delayMs);
|