@copilotkit/shared 1.75.1 → 1.76.0
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/attachments/utils.cjs +3 -0
- package/dist/attachments/utils.cjs.map +1 -1
- package/dist/attachments/utils.d.cts +2 -0
- package/dist/attachments/utils.d.cts.map +1 -1
- package/dist/attachments/utils.d.mts +2 -0
- package/dist/attachments/utils.d.mts.map +1 -1
- package/dist/attachments/utils.mjs +3 -0
- package/dist/attachments/utils.mjs.map +1 -1
- package/dist/finalize-events.cjs +69 -8
- package/dist/finalize-events.cjs.map +1 -1
- package/dist/finalize-events.d.cts +12 -2
- package/dist/finalize-events.d.cts.map +1 -1
- package/dist/finalize-events.d.mts +12 -2
- package/dist/finalize-events.d.mts.map +1 -1
- package/dist/finalize-events.mjs +69 -8
- package/dist/finalize-events.mjs.map +1 -1
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +106 -9
- package/dist/index.umd.js.map +1 -1
- package/dist/intelligence-routing-fields.cjs +35 -0
- package/dist/intelligence-routing-fields.cjs.map +1 -0
- package/dist/intelligence-routing-fields.d.cts +18 -0
- package/dist/intelligence-routing-fields.d.cts.map +1 -0
- package/dist/intelligence-routing-fields.d.mts +18 -0
- package/dist/intelligence-routing-fields.d.mts.map +1 -0
- package/dist/intelligence-routing-fields.mjs +34 -0
- package/dist/intelligence-routing-fields.mjs.map +1 -0
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/package.json +3 -2
- package/src/attachments/__tests__/utils.test.ts +16 -0
- package/src/attachments/utils.ts +5 -0
- package/src/finalize-events.test.ts +138 -0
- package/src/finalize-events.ts +103 -7
- package/src/index.ts +1 -0
- package/src/intelligence-routing-fields.test.ts +51 -0
- package/src/intelligence-routing-fields.ts +40 -0
|
@@ -105,9 +105,12 @@ function matchesAcceptFilter(file, accept) {
|
|
|
105
105
|
/**
|
|
106
106
|
* Convert an InputContentSource to a usable URL string.
|
|
107
107
|
* For data sources, returns a base64 data URL; for URL sources, returns the URL directly.
|
|
108
|
+
* A provider file handle (AG-UI 1.0 `file` source) has no address a browser
|
|
109
|
+
* can load, so it returns an empty string and the caller shows no preview.
|
|
108
110
|
*/
|
|
109
111
|
function getSourceUrl(source) {
|
|
110
112
|
if (source.type === "url") return source.value;
|
|
113
|
+
if (source.type === "file") return "";
|
|
111
114
|
return `data:${source.mimeType};base64,${source.value}`;
|
|
112
115
|
}
|
|
113
116
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.cjs","names":[],"sources":["../../src/attachments/utils.ts"],"sourcesContent":["import type { AttachmentModality } from \"./types\";\nimport type { InputContentSource } from \"../types/message\";\n\nconst DEFAULT_MAX_SIZE = 20 * 1024 * 1024; // 20MB\n\n/**\n * Derive the attachment modality from a MIME type string.\n */\nexport function getModalityFromMimeType(mimeType: string): AttachmentModality {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\n/**\n * Format a byte count as a human-readable file size string.\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Check if a file exceeds the maximum allowed size.\n */\nexport function exceedsMaxSize(\n file: File,\n maxSize: number = DEFAULT_MAX_SIZE,\n): boolean {\n return file.size > maxSize;\n}\n\n/**\n * Read a File as a base64 string (without the data URL prefix).\n */\nexport function readFileAsBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (e) => {\n const result = e.target?.result as string;\n const base64 = result?.split(\",\")[1];\n if (base64) {\n resolve(base64);\n } else {\n reject(new Error(\"Failed to read file as base64\"));\n }\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * Generate a thumbnail data URL from a video file by capturing a frame near the start (at 0.1s).\n * Returns undefined if thumbnail generation fails or if called outside a browser environment.\n */\nexport function generateVideoThumbnail(\n file: File,\n): Promise<string | undefined> {\n if (typeof document === \"undefined\") {\n return Promise.resolve(undefined);\n }\n return new Promise((resolve) => {\n let resolved = false;\n const video = document.createElement(\"video\");\n const canvas = document.createElement(\"canvas\");\n const url = URL.createObjectURL(file);\n\n const cleanup = (result: string | undefined) => {\n if (resolved) return;\n resolved = true;\n URL.revokeObjectURL(url);\n resolve(result);\n };\n\n const timeout = setTimeout(() => {\n console.warn(\n `[CopilotKit] generateVideoThumbnail: timed out for file \"${file.name}\"`,\n );\n cleanup(undefined);\n }, 10000);\n\n video.preload = \"metadata\";\n video.muted = true;\n video.playsInline = true;\n\n video.onloadeddata = () => {\n video.currentTime = 0.1;\n };\n\n video.onseeked = () => {\n clearTimeout(timeout);\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n ctx.drawImage(video, 0, 0);\n const thumbnail = canvas.toDataURL(\"image/jpeg\", 0.7);\n cleanup(thumbnail);\n } else {\n console.warn(\n \"[CopilotKit] generateVideoThumbnail: could not get 2d canvas context\",\n );\n cleanup(undefined);\n }\n };\n\n video.onerror = () => {\n clearTimeout(timeout);\n console.warn(\n `[CopilotKit] generateVideoThumbnail: video element error for file \"${file.name}\"`,\n );\n cleanup(undefined);\n };\n\n video.src = url;\n });\n}\n\n/**\n * Check if a file's MIME type matches an accept filter string.\n * Handles file extensions (e.g. \".pdf\"), MIME wildcards (\"image/*\"), and comma-separated lists.\n */\nexport function matchesAcceptFilter(file: File, accept: string): boolean {\n if (!accept || accept === \"*/*\") return true;\n\n const filters = accept.split(\",\").map((f) => f.trim());\n return filters.some((filter) => {\n if (filter.startsWith(\".\")) {\n return (file.name ?? \"\").toLowerCase().endsWith(filter.toLowerCase());\n }\n if (filter.endsWith(\"/*\")) {\n const prefix = filter.slice(0, -2);\n return file.type.startsWith(prefix + \"/\");\n }\n return file.type === filter;\n });\n}\n\n/**\n * Convert an InputContentSource to a usable URL string.\n * For data sources, returns a base64 data URL; for URL sources, returns the URL directly.\n */\nexport function getSourceUrl(source: InputContentSource): string {\n if (source.type === \"url\") {\n return source.value;\n }\n return `data:${source.mimeType};base64,${source.value}`;\n}\n\n/**\n * Return a short human-readable label for a document MIME type (e.g. \"PDF\", \"DOC\").\n */\nexport function getDocumentIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"sheet\") || mimeType.includes(\"excel\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\"))\n return \"PPT\";\n if (mimeType.includes(\"word\") || mimeType.includes(\"document\")) return \"DOC\";\n if (mimeType.includes(\"text/\")) return \"TXT\";\n return \"FILE\";\n}\n"],"mappings":";;AAGA,MAAM,mBAAmB,KAAK,OAAO;;;;AAKrC,SAAgB,wBAAwB,UAAsC;AAC5E,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,QAAO;;;;;AAMT,SAAgB,eAAe,OAAuB;AACpD,KAAI,QAAQ,KAAM,QAAO,GAAG,MAAM;AAClC,KAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAC7D,QAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC;;;;;AAM/C,SAAgB,eACd,MACA,UAAkB,kBACT;AACT,QAAO,KAAK,OAAO;;;;;AAMrB,SAAgB,iBAAiB,MAA6B;AAC5D,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAS,IAAI,YAAY;AAC/B,SAAO,UAAU,MAAM;GAErB,MAAM,UADS,EAAE,QAAQ,SACF,MAAM,IAAI,CAAC;AAClC,OAAI,OACF,SAAQ,OAAO;OAEf,wBAAO,IAAI,MAAM,gCAAgC,CAAC;;AAGtD,SAAO,UAAU;AACjB,SAAO,cAAc,KAAK;GAC1B;;;;;;AAOJ,SAAgB,uBACd,MAC6B;AAC7B,KAAI,OAAO,aAAa,YACtB,QAAO,QAAQ,QAAQ,OAAU;AAEnC,QAAO,IAAI,SAAS,YAAY;EAC9B,IAAI,WAAW;EACf,MAAM,QAAQ,SAAS,cAAc,QAAQ;EAC7C,MAAM,SAAS,SAAS,cAAc,SAAS;EAC/C,MAAM,MAAM,IAAI,gBAAgB,KAAK;EAErC,MAAM,WAAW,WAA+B;AAC9C,OAAI,SAAU;AACd,cAAW;AACX,OAAI,gBAAgB,IAAI;AACxB,WAAQ,OAAO;;EAGjB,MAAM,UAAU,iBAAiB;AAC/B,WAAQ,KACN,4DAA4D,KAAK,KAAK,GACvE;AACD,WAAQ,OAAU;KACjB,IAAM;AAET,QAAM,UAAU;AAChB,QAAM,QAAQ;AACd,QAAM,cAAc;AAEpB,QAAM,qBAAqB;AACzB,SAAM,cAAc;;AAGtB,QAAM,iBAAiB;AACrB,gBAAa,QAAQ;AACrB,UAAO,QAAQ,MAAM;AACrB,UAAO,SAAS,MAAM;GACtB,MAAM,MAAM,OAAO,WAAW,KAAK;AACnC,OAAI,KAAK;AACP,QAAI,UAAU,OAAO,GAAG,EAAE;AAE1B,YADkB,OAAO,UAAU,cAAc,GAAI,CACnC;UACb;AACL,YAAQ,KACN,uEACD;AACD,YAAQ,OAAU;;;AAItB,QAAM,gBAAgB;AACpB,gBAAa,QAAQ;AACrB,WAAQ,KACN,sEAAsE,KAAK,KAAK,GACjF;AACD,WAAQ,OAAU;;AAGpB,QAAM,MAAM;GACZ;;;;;;AAOJ,SAAgB,oBAAoB,MAAY,QAAyB;AACvE,KAAI,CAAC,UAAU,WAAW,MAAO,QAAO;AAGxC,QADgB,OAAO,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CACvC,MAAM,WAAW;AAC9B,MAAI,OAAO,WAAW,IAAI,CACxB,SAAQ,KAAK,QAAQ,IAAI,aAAa,CAAC,SAAS,OAAO,aAAa,CAAC;AAEvE,MAAI,OAAO,SAAS,KAAK,EAAE;GACzB,MAAM,SAAS,OAAO,MAAM,GAAG,GAAG;AAClC,UAAO,KAAK,KAAK,WAAW,SAAS,IAAI;;AAE3C,SAAO,KAAK,SAAS;GACrB
|
|
1
|
+
{"version":3,"file":"utils.cjs","names":[],"sources":["../../src/attachments/utils.ts"],"sourcesContent":["import type { AttachmentModality } from \"./types\";\nimport type { InputContentSource } from \"../types/message\";\n\nconst DEFAULT_MAX_SIZE = 20 * 1024 * 1024; // 20MB\n\n/**\n * Derive the attachment modality from a MIME type string.\n */\nexport function getModalityFromMimeType(mimeType: string): AttachmentModality {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\n/**\n * Format a byte count as a human-readable file size string.\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Check if a file exceeds the maximum allowed size.\n */\nexport function exceedsMaxSize(\n file: File,\n maxSize: number = DEFAULT_MAX_SIZE,\n): boolean {\n return file.size > maxSize;\n}\n\n/**\n * Read a File as a base64 string (without the data URL prefix).\n */\nexport function readFileAsBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (e) => {\n const result = e.target?.result as string;\n const base64 = result?.split(\",\")[1];\n if (base64) {\n resolve(base64);\n } else {\n reject(new Error(\"Failed to read file as base64\"));\n }\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * Generate a thumbnail data URL from a video file by capturing a frame near the start (at 0.1s).\n * Returns undefined if thumbnail generation fails or if called outside a browser environment.\n */\nexport function generateVideoThumbnail(\n file: File,\n): Promise<string | undefined> {\n if (typeof document === \"undefined\") {\n return Promise.resolve(undefined);\n }\n return new Promise((resolve) => {\n let resolved = false;\n const video = document.createElement(\"video\");\n const canvas = document.createElement(\"canvas\");\n const url = URL.createObjectURL(file);\n\n const cleanup = (result: string | undefined) => {\n if (resolved) return;\n resolved = true;\n URL.revokeObjectURL(url);\n resolve(result);\n };\n\n const timeout = setTimeout(() => {\n console.warn(\n `[CopilotKit] generateVideoThumbnail: timed out for file \"${file.name}\"`,\n );\n cleanup(undefined);\n }, 10000);\n\n video.preload = \"metadata\";\n video.muted = true;\n video.playsInline = true;\n\n video.onloadeddata = () => {\n video.currentTime = 0.1;\n };\n\n video.onseeked = () => {\n clearTimeout(timeout);\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n ctx.drawImage(video, 0, 0);\n const thumbnail = canvas.toDataURL(\"image/jpeg\", 0.7);\n cleanup(thumbnail);\n } else {\n console.warn(\n \"[CopilotKit] generateVideoThumbnail: could not get 2d canvas context\",\n );\n cleanup(undefined);\n }\n };\n\n video.onerror = () => {\n clearTimeout(timeout);\n console.warn(\n `[CopilotKit] generateVideoThumbnail: video element error for file \"${file.name}\"`,\n );\n cleanup(undefined);\n };\n\n video.src = url;\n });\n}\n\n/**\n * Check if a file's MIME type matches an accept filter string.\n * Handles file extensions (e.g. \".pdf\"), MIME wildcards (\"image/*\"), and comma-separated lists.\n */\nexport function matchesAcceptFilter(file: File, accept: string): boolean {\n if (!accept || accept === \"*/*\") return true;\n\n const filters = accept.split(\",\").map((f) => f.trim());\n return filters.some((filter) => {\n if (filter.startsWith(\".\")) {\n return (file.name ?? \"\").toLowerCase().endsWith(filter.toLowerCase());\n }\n if (filter.endsWith(\"/*\")) {\n const prefix = filter.slice(0, -2);\n return file.type.startsWith(prefix + \"/\");\n }\n return file.type === filter;\n });\n}\n\n/**\n * Convert an InputContentSource to a usable URL string.\n * For data sources, returns a base64 data URL; for URL sources, returns the URL directly.\n * A provider file handle (AG-UI 1.0 `file` source) has no address a browser\n * can load, so it returns an empty string and the caller shows no preview.\n */\nexport function getSourceUrl(source: InputContentSource): string {\n if (source.type === \"url\") {\n return source.value;\n }\n if (source.type === \"file\") {\n return \"\";\n }\n return `data:${source.mimeType};base64,${source.value}`;\n}\n\n/**\n * Return a short human-readable label for a document MIME type (e.g. \"PDF\", \"DOC\").\n */\nexport function getDocumentIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"sheet\") || mimeType.includes(\"excel\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\"))\n return \"PPT\";\n if (mimeType.includes(\"word\") || mimeType.includes(\"document\")) return \"DOC\";\n if (mimeType.includes(\"text/\")) return \"TXT\";\n return \"FILE\";\n}\n"],"mappings":"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"}
|
|
@@ -31,6 +31,8 @@ declare function matchesAcceptFilter(file: File, accept: string): boolean;
|
|
|
31
31
|
/**
|
|
32
32
|
* Convert an InputContentSource to a usable URL string.
|
|
33
33
|
* For data sources, returns a base64 data URL; for URL sources, returns the URL directly.
|
|
34
|
+
* A provider file handle (AG-UI 1.0 `file` source) has no address a browser
|
|
35
|
+
* can load, so it returns an empty string and the caller shows no preview.
|
|
34
36
|
*/
|
|
35
37
|
declare function getSourceUrl(source: InputContentSource): string;
|
|
36
38
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.cts","names":[],"sources":["../../src/attachments/utils.ts"],"mappings":";;;;;;AAQA;iBAAgB,uBAAA,CAAwB,QAAA,WAAmB,kBAAA;;;;iBAU3C,cAAA,CAAe,KAAA;;;;iBASf,cAAA,CACd,IAAA,EAAM,IAAA,EACN,OAAA;AAFF;;;AAAA,iBAUgB,gBAAA,CAAiB,IAAA,EAAM,IAAA,GAAO,OAAA;;;;;iBAqB9B,sBAAA,CACd,IAAA,EAAM,IAAA,GACL,OAAA;AAvBH;;;;AAAA,iBAwFgB,mBAAA,CAAoB,IAAA,EAAM,IAAA,EAAM,MAAA;;;;;
|
|
1
|
+
{"version":3,"file":"utils.d.cts","names":[],"sources":["../../src/attachments/utils.ts"],"mappings":";;;;;;AAQA;iBAAgB,uBAAA,CAAwB,QAAA,WAAmB,kBAAA;;;;iBAU3C,cAAA,CAAe,KAAA;;;;iBASf,cAAA,CACd,IAAA,EAAM,IAAA,EACN,OAAA;AAFF;;;AAAA,iBAUgB,gBAAA,CAAiB,IAAA,EAAM,IAAA,GAAO,OAAA;;;;;iBAqB9B,sBAAA,CACd,IAAA,EAAM,IAAA,GACL,OAAA;AAvBH;;;;AAAA,iBAwFgB,mBAAA,CAAoB,IAAA,EAAM,IAAA,EAAM,MAAA;;;;;AAnEhD;;iBAyFgB,YAAA,CAAa,MAAA,EAAQ,kBAAA;;;;iBAarB,eAAA,CAAgB,QAAA"}
|
|
@@ -31,6 +31,8 @@ declare function matchesAcceptFilter(file: File, accept: string): boolean;
|
|
|
31
31
|
/**
|
|
32
32
|
* Convert an InputContentSource to a usable URL string.
|
|
33
33
|
* For data sources, returns a base64 data URL; for URL sources, returns the URL directly.
|
|
34
|
+
* A provider file handle (AG-UI 1.0 `file` source) has no address a browser
|
|
35
|
+
* can load, so it returns an empty string and the caller shows no preview.
|
|
34
36
|
*/
|
|
35
37
|
declare function getSourceUrl(source: InputContentSource): string;
|
|
36
38
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.mts","names":[],"sources":["../../src/attachments/utils.ts"],"mappings":";;;;;;AAQA;iBAAgB,uBAAA,CAAwB,QAAA,WAAmB,kBAAA;;;;iBAU3C,cAAA,CAAe,KAAA;;;;iBASf,cAAA,CACd,IAAA,EAAM,IAAA,EACN,OAAA;AAFF;;;AAAA,iBAUgB,gBAAA,CAAiB,IAAA,EAAM,IAAA,GAAO,OAAA;;;;;iBAqB9B,sBAAA,CACd,IAAA,EAAM,IAAA,GACL,OAAA;AAvBH;;;;AAAA,iBAwFgB,mBAAA,CAAoB,IAAA,EAAM,IAAA,EAAM,MAAA;;;;;
|
|
1
|
+
{"version":3,"file":"utils.d.mts","names":[],"sources":["../../src/attachments/utils.ts"],"mappings":";;;;;;AAQA;iBAAgB,uBAAA,CAAwB,QAAA,WAAmB,kBAAA;;;;iBAU3C,cAAA,CAAe,KAAA;;;;iBASf,cAAA,CACd,IAAA,EAAM,IAAA,EACN,OAAA;AAFF;;;AAAA,iBAUgB,gBAAA,CAAiB,IAAA,EAAM,IAAA,GAAO,OAAA;;;;;iBAqB9B,sBAAA,CACd,IAAA,EAAM,IAAA,GACL,OAAA;AAvBH;;;;AAAA,iBAwFgB,mBAAA,CAAoB,IAAA,EAAM,IAAA,EAAM,MAAA;;;;;AAnEhD;;iBAyFgB,YAAA,CAAa,MAAA,EAAQ,kBAAA;;;;iBAarB,eAAA,CAAgB,QAAA"}
|
|
@@ -104,9 +104,12 @@ function matchesAcceptFilter(file, accept) {
|
|
|
104
104
|
/**
|
|
105
105
|
* Convert an InputContentSource to a usable URL string.
|
|
106
106
|
* For data sources, returns a base64 data URL; for URL sources, returns the URL directly.
|
|
107
|
+
* A provider file handle (AG-UI 1.0 `file` source) has no address a browser
|
|
108
|
+
* can load, so it returns an empty string and the caller shows no preview.
|
|
107
109
|
*/
|
|
108
110
|
function getSourceUrl(source) {
|
|
109
111
|
if (source.type === "url") return source.value;
|
|
112
|
+
if (source.type === "file") return "";
|
|
110
113
|
return `data:${source.mimeType};base64,${source.value}`;
|
|
111
114
|
}
|
|
112
115
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.mjs","names":[],"sources":["../../src/attachments/utils.ts"],"sourcesContent":["import type { AttachmentModality } from \"./types\";\nimport type { InputContentSource } from \"../types/message\";\n\nconst DEFAULT_MAX_SIZE = 20 * 1024 * 1024; // 20MB\n\n/**\n * Derive the attachment modality from a MIME type string.\n */\nexport function getModalityFromMimeType(mimeType: string): AttachmentModality {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\n/**\n * Format a byte count as a human-readable file size string.\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Check if a file exceeds the maximum allowed size.\n */\nexport function exceedsMaxSize(\n file: File,\n maxSize: number = DEFAULT_MAX_SIZE,\n): boolean {\n return file.size > maxSize;\n}\n\n/**\n * Read a File as a base64 string (without the data URL prefix).\n */\nexport function readFileAsBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (e) => {\n const result = e.target?.result as string;\n const base64 = result?.split(\",\")[1];\n if (base64) {\n resolve(base64);\n } else {\n reject(new Error(\"Failed to read file as base64\"));\n }\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * Generate a thumbnail data URL from a video file by capturing a frame near the start (at 0.1s).\n * Returns undefined if thumbnail generation fails or if called outside a browser environment.\n */\nexport function generateVideoThumbnail(\n file: File,\n): Promise<string | undefined> {\n if (typeof document === \"undefined\") {\n return Promise.resolve(undefined);\n }\n return new Promise((resolve) => {\n let resolved = false;\n const video = document.createElement(\"video\");\n const canvas = document.createElement(\"canvas\");\n const url = URL.createObjectURL(file);\n\n const cleanup = (result: string | undefined) => {\n if (resolved) return;\n resolved = true;\n URL.revokeObjectURL(url);\n resolve(result);\n };\n\n const timeout = setTimeout(() => {\n console.warn(\n `[CopilotKit] generateVideoThumbnail: timed out for file \"${file.name}\"`,\n );\n cleanup(undefined);\n }, 10000);\n\n video.preload = \"metadata\";\n video.muted = true;\n video.playsInline = true;\n\n video.onloadeddata = () => {\n video.currentTime = 0.1;\n };\n\n video.onseeked = () => {\n clearTimeout(timeout);\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n ctx.drawImage(video, 0, 0);\n const thumbnail = canvas.toDataURL(\"image/jpeg\", 0.7);\n cleanup(thumbnail);\n } else {\n console.warn(\n \"[CopilotKit] generateVideoThumbnail: could not get 2d canvas context\",\n );\n cleanup(undefined);\n }\n };\n\n video.onerror = () => {\n clearTimeout(timeout);\n console.warn(\n `[CopilotKit] generateVideoThumbnail: video element error for file \"${file.name}\"`,\n );\n cleanup(undefined);\n };\n\n video.src = url;\n });\n}\n\n/**\n * Check if a file's MIME type matches an accept filter string.\n * Handles file extensions (e.g. \".pdf\"), MIME wildcards (\"image/*\"), and comma-separated lists.\n */\nexport function matchesAcceptFilter(file: File, accept: string): boolean {\n if (!accept || accept === \"*/*\") return true;\n\n const filters = accept.split(\",\").map((f) => f.trim());\n return filters.some((filter) => {\n if (filter.startsWith(\".\")) {\n return (file.name ?? \"\").toLowerCase().endsWith(filter.toLowerCase());\n }\n if (filter.endsWith(\"/*\")) {\n const prefix = filter.slice(0, -2);\n return file.type.startsWith(prefix + \"/\");\n }\n return file.type === filter;\n });\n}\n\n/**\n * Convert an InputContentSource to a usable URL string.\n * For data sources, returns a base64 data URL; for URL sources, returns the URL directly.\n */\nexport function getSourceUrl(source: InputContentSource): string {\n if (source.type === \"url\") {\n return source.value;\n }\n return `data:${source.mimeType};base64,${source.value}`;\n}\n\n/**\n * Return a short human-readable label for a document MIME type (e.g. \"PDF\", \"DOC\").\n */\nexport function getDocumentIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"sheet\") || mimeType.includes(\"excel\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\"))\n return \"PPT\";\n if (mimeType.includes(\"word\") || mimeType.includes(\"document\")) return \"DOC\";\n if (mimeType.includes(\"text/\")) return \"TXT\";\n return \"FILE\";\n}\n"],"mappings":";AAGA,MAAM,mBAAmB,KAAK,OAAO;;;;AAKrC,SAAgB,wBAAwB,UAAsC;AAC5E,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,QAAO;;;;;AAMT,SAAgB,eAAe,OAAuB;AACpD,KAAI,QAAQ,KAAM,QAAO,GAAG,MAAM;AAClC,KAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAC7D,QAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC;;;;;AAM/C,SAAgB,eACd,MACA,UAAkB,kBACT;AACT,QAAO,KAAK,OAAO;;;;;AAMrB,SAAgB,iBAAiB,MAA6B;AAC5D,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAS,IAAI,YAAY;AAC/B,SAAO,UAAU,MAAM;GAErB,MAAM,UADS,EAAE,QAAQ,SACF,MAAM,IAAI,CAAC;AAClC,OAAI,OACF,SAAQ,OAAO;OAEf,wBAAO,IAAI,MAAM,gCAAgC,CAAC;;AAGtD,SAAO,UAAU;AACjB,SAAO,cAAc,KAAK;GAC1B;;;;;;AAOJ,SAAgB,uBACd,MAC6B;AAC7B,KAAI,OAAO,aAAa,YACtB,QAAO,QAAQ,QAAQ,OAAU;AAEnC,QAAO,IAAI,SAAS,YAAY;EAC9B,IAAI,WAAW;EACf,MAAM,QAAQ,SAAS,cAAc,QAAQ;EAC7C,MAAM,SAAS,SAAS,cAAc,SAAS;EAC/C,MAAM,MAAM,IAAI,gBAAgB,KAAK;EAErC,MAAM,WAAW,WAA+B;AAC9C,OAAI,SAAU;AACd,cAAW;AACX,OAAI,gBAAgB,IAAI;AACxB,WAAQ,OAAO;;EAGjB,MAAM,UAAU,iBAAiB;AAC/B,WAAQ,KACN,4DAA4D,KAAK,KAAK,GACvE;AACD,WAAQ,OAAU;KACjB,IAAM;AAET,QAAM,UAAU;AAChB,QAAM,QAAQ;AACd,QAAM,cAAc;AAEpB,QAAM,qBAAqB;AACzB,SAAM,cAAc;;AAGtB,QAAM,iBAAiB;AACrB,gBAAa,QAAQ;AACrB,UAAO,QAAQ,MAAM;AACrB,UAAO,SAAS,MAAM;GACtB,MAAM,MAAM,OAAO,WAAW,KAAK;AACnC,OAAI,KAAK;AACP,QAAI,UAAU,OAAO,GAAG,EAAE;AAE1B,YADkB,OAAO,UAAU,cAAc,GAAI,CACnC;UACb;AACL,YAAQ,KACN,uEACD;AACD,YAAQ,OAAU;;;AAItB,QAAM,gBAAgB;AACpB,gBAAa,QAAQ;AACrB,WAAQ,KACN,sEAAsE,KAAK,KAAK,GACjF;AACD,WAAQ,OAAU;;AAGpB,QAAM,MAAM;GACZ;;;;;;AAOJ,SAAgB,oBAAoB,MAAY,QAAyB;AACvE,KAAI,CAAC,UAAU,WAAW,MAAO,QAAO;AAGxC,QADgB,OAAO,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CACvC,MAAM,WAAW;AAC9B,MAAI,OAAO,WAAW,IAAI,CACxB,SAAQ,KAAK,QAAQ,IAAI,aAAa,CAAC,SAAS,OAAO,aAAa,CAAC;AAEvE,MAAI,OAAO,SAAS,KAAK,EAAE;GACzB,MAAM,SAAS,OAAO,MAAM,GAAG,GAAG;AAClC,UAAO,KAAK,KAAK,WAAW,SAAS,IAAI;;AAE3C,SAAO,KAAK,SAAS;GACrB
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../../src/attachments/utils.ts"],"sourcesContent":["import type { AttachmentModality } from \"./types\";\nimport type { InputContentSource } from \"../types/message\";\n\nconst DEFAULT_MAX_SIZE = 20 * 1024 * 1024; // 20MB\n\n/**\n * Derive the attachment modality from a MIME type string.\n */\nexport function getModalityFromMimeType(mimeType: string): AttachmentModality {\n if (mimeType.startsWith(\"image/\")) return \"image\";\n if (mimeType.startsWith(\"audio/\")) return \"audio\";\n if (mimeType.startsWith(\"video/\")) return \"video\";\n return \"document\";\n}\n\n/**\n * Format a byte count as a human-readable file size string.\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n/**\n * Check if a file exceeds the maximum allowed size.\n */\nexport function exceedsMaxSize(\n file: File,\n maxSize: number = DEFAULT_MAX_SIZE,\n): boolean {\n return file.size > maxSize;\n}\n\n/**\n * Read a File as a base64 string (without the data URL prefix).\n */\nexport function readFileAsBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (e) => {\n const result = e.target?.result as string;\n const base64 = result?.split(\",\")[1];\n if (base64) {\n resolve(base64);\n } else {\n reject(new Error(\"Failed to read file as base64\"));\n }\n };\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * Generate a thumbnail data URL from a video file by capturing a frame near the start (at 0.1s).\n * Returns undefined if thumbnail generation fails or if called outside a browser environment.\n */\nexport function generateVideoThumbnail(\n file: File,\n): Promise<string | undefined> {\n if (typeof document === \"undefined\") {\n return Promise.resolve(undefined);\n }\n return new Promise((resolve) => {\n let resolved = false;\n const video = document.createElement(\"video\");\n const canvas = document.createElement(\"canvas\");\n const url = URL.createObjectURL(file);\n\n const cleanup = (result: string | undefined) => {\n if (resolved) return;\n resolved = true;\n URL.revokeObjectURL(url);\n resolve(result);\n };\n\n const timeout = setTimeout(() => {\n console.warn(\n `[CopilotKit] generateVideoThumbnail: timed out for file \"${file.name}\"`,\n );\n cleanup(undefined);\n }, 10000);\n\n video.preload = \"metadata\";\n video.muted = true;\n video.playsInline = true;\n\n video.onloadeddata = () => {\n video.currentTime = 0.1;\n };\n\n video.onseeked = () => {\n clearTimeout(timeout);\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n ctx.drawImage(video, 0, 0);\n const thumbnail = canvas.toDataURL(\"image/jpeg\", 0.7);\n cleanup(thumbnail);\n } else {\n console.warn(\n \"[CopilotKit] generateVideoThumbnail: could not get 2d canvas context\",\n );\n cleanup(undefined);\n }\n };\n\n video.onerror = () => {\n clearTimeout(timeout);\n console.warn(\n `[CopilotKit] generateVideoThumbnail: video element error for file \"${file.name}\"`,\n );\n cleanup(undefined);\n };\n\n video.src = url;\n });\n}\n\n/**\n * Check if a file's MIME type matches an accept filter string.\n * Handles file extensions (e.g. \".pdf\"), MIME wildcards (\"image/*\"), and comma-separated lists.\n */\nexport function matchesAcceptFilter(file: File, accept: string): boolean {\n if (!accept || accept === \"*/*\") return true;\n\n const filters = accept.split(\",\").map((f) => f.trim());\n return filters.some((filter) => {\n if (filter.startsWith(\".\")) {\n return (file.name ?? \"\").toLowerCase().endsWith(filter.toLowerCase());\n }\n if (filter.endsWith(\"/*\")) {\n const prefix = filter.slice(0, -2);\n return file.type.startsWith(prefix + \"/\");\n }\n return file.type === filter;\n });\n}\n\n/**\n * Convert an InputContentSource to a usable URL string.\n * For data sources, returns a base64 data URL; for URL sources, returns the URL directly.\n * A provider file handle (AG-UI 1.0 `file` source) has no address a browser\n * can load, so it returns an empty string and the caller shows no preview.\n */\nexport function getSourceUrl(source: InputContentSource): string {\n if (source.type === \"url\") {\n return source.value;\n }\n if (source.type === \"file\") {\n return \"\";\n }\n return `data:${source.mimeType};base64,${source.value}`;\n}\n\n/**\n * Return a short human-readable label for a document MIME type (e.g. \"PDF\", \"DOC\").\n */\nexport function getDocumentIcon(mimeType: string): string {\n if (mimeType.includes(\"pdf\")) return \"PDF\";\n if (mimeType.includes(\"sheet\") || mimeType.includes(\"excel\")) return \"XLS\";\n if (mimeType.includes(\"presentation\") || mimeType.includes(\"powerpoint\"))\n return \"PPT\";\n if (mimeType.includes(\"word\") || mimeType.includes(\"document\")) return \"DOC\";\n if (mimeType.includes(\"text/\")) return \"TXT\";\n return \"FILE\";\n}\n"],"mappings":";AAGA,MAAM,mBAAmB,KAAK,OAAO;;;;AAKrC,SAAgB,wBAAwB,UAAsC;AAC5E,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,KAAI,SAAS,WAAW,SAAS,CAAE,QAAO;AAC1C,QAAO;;;;;AAMT,SAAgB,eAAe,OAAuB;AACpD,KAAI,QAAQ,KAAM,QAAO,GAAG,MAAM;AAClC,KAAI,QAAQ,OAAO,KAAM,QAAO,IAAI,QAAQ,MAAM,QAAQ,EAAE,CAAC;AAC7D,QAAO,IAAI,SAAS,OAAO,OAAO,QAAQ,EAAE,CAAC;;;;;AAM/C,SAAgB,eACd,MACA,UAAkB,kBACT;AACT,QAAO,KAAK,OAAO;;;;;AAMrB,SAAgB,iBAAiB,MAA6B;AAC5D,QAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,SAAS,IAAI,YAAY;AAC/B,SAAO,UAAU,MAAM;GAErB,MAAM,UADS,EAAE,QAAQ,SACF,MAAM,IAAI,CAAC;AAClC,OAAI,OACF,SAAQ,OAAO;OAEf,wBAAO,IAAI,MAAM,gCAAgC,CAAC;;AAGtD,SAAO,UAAU;AACjB,SAAO,cAAc,KAAK;GAC1B;;;;;;AAOJ,SAAgB,uBACd,MAC6B;AAC7B,KAAI,OAAO,aAAa,YACtB,QAAO,QAAQ,QAAQ,OAAU;AAEnC,QAAO,IAAI,SAAS,YAAY;EAC9B,IAAI,WAAW;EACf,MAAM,QAAQ,SAAS,cAAc,QAAQ;EAC7C,MAAM,SAAS,SAAS,cAAc,SAAS;EAC/C,MAAM,MAAM,IAAI,gBAAgB,KAAK;EAErC,MAAM,WAAW,WAA+B;AAC9C,OAAI,SAAU;AACd,cAAW;AACX,OAAI,gBAAgB,IAAI;AACxB,WAAQ,OAAO;;EAGjB,MAAM,UAAU,iBAAiB;AAC/B,WAAQ,KACN,4DAA4D,KAAK,KAAK,GACvE;AACD,WAAQ,OAAU;KACjB,IAAM;AAET,QAAM,UAAU;AAChB,QAAM,QAAQ;AACd,QAAM,cAAc;AAEpB,QAAM,qBAAqB;AACzB,SAAM,cAAc;;AAGtB,QAAM,iBAAiB;AACrB,gBAAa,QAAQ;AACrB,UAAO,QAAQ,MAAM;AACrB,UAAO,SAAS,MAAM;GACtB,MAAM,MAAM,OAAO,WAAW,KAAK;AACnC,OAAI,KAAK;AACP,QAAI,UAAU,OAAO,GAAG,EAAE;AAE1B,YADkB,OAAO,UAAU,cAAc,GAAI,CACnC;UACb;AACL,YAAQ,KACN,uEACD;AACD,YAAQ,OAAU;;;AAItB,QAAM,gBAAgB;AACpB,gBAAa,QAAQ;AACrB,WAAQ,KACN,sEAAsE,KAAK,KAAK,GACjF;AACD,WAAQ,OAAU;;AAGpB,QAAM,MAAM;GACZ;;;;;;AAOJ,SAAgB,oBAAoB,MAAY,QAAyB;AACvE,KAAI,CAAC,UAAU,WAAW,MAAO,QAAO;AAGxC,QADgB,OAAO,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC,CACvC,MAAM,WAAW;AAC9B,MAAI,OAAO,WAAW,IAAI,CACxB,SAAQ,KAAK,QAAQ,IAAI,aAAa,CAAC,SAAS,OAAO,aAAa,CAAC;AAEvE,MAAI,OAAO,SAAS,KAAK,EAAE;GACzB,MAAM,SAAS,OAAO,MAAM,GAAG,GAAG;AAClC,UAAO,KAAK,KAAK,WAAW,SAAS,IAAI;;AAE3C,SAAO,KAAK,SAAS;GACrB;;;;;;;;AASJ,SAAgB,aAAa,QAAoC;AAC/D,KAAI,OAAO,SAAS,MAClB,QAAO,OAAO;AAEhB,KAAI,OAAO,SAAS,OAClB,QAAO;AAET,QAAO,QAAQ,OAAO,SAAS,UAAU,OAAO;;;;;AAMlD,SAAgB,gBAAgB,UAA0B;AACxD,KAAI,SAAS,SAAS,MAAM,CAAE,QAAO;AACrC,KAAI,SAAS,SAAS,QAAQ,IAAI,SAAS,SAAS,QAAQ,CAAE,QAAO;AACrE,KAAI,SAAS,SAAS,eAAe,IAAI,SAAS,SAAS,aAAa,CACtE,QAAO;AACT,KAAI,SAAS,SAAS,OAAO,IAAI,SAAS,SAAS,WAAW,CAAE,QAAO;AACvE,KAAI,SAAS,SAAS,QAAQ,CAAE,QAAO;AACvC,QAAO"}
|
package/dist/finalize-events.cjs
CHANGED
|
@@ -7,17 +7,50 @@ const defaultAbruptEndMessage = "Run ended without emitting a terminal event";
|
|
|
7
7
|
/**
|
|
8
8
|
* Incremental finalizer for a streamed AG-UI run. Feed every event to
|
|
9
9
|
* `observe`; when the stream ends without a terminal event, `finalize` returns
|
|
10
|
-
* the closers for text messages and tool calls still open plus a
|
|
11
|
-
* event.
|
|
10
|
+
* the closers for reasoning, text messages and tool calls still open plus a
|
|
11
|
+
* terminal event. AG-UI 1.0 fails a run that ends with reasoning still open,
|
|
12
|
+
* so reasoning is closed too. It also fails a RUN_FINISHED while a subagent
|
|
13
|
+
* is still open, so a stop closes open subagents as well; a RUN_ERROR
|
|
14
|
+
* abandons them, which the protocol allows. Closed lifecycles are forgotten at once and payloads are never kept,
|
|
12
15
|
* so a caller does not have to retain the event array for this purpose.
|
|
13
16
|
*/
|
|
14
17
|
function createRunEventFinalizer() {
|
|
15
18
|
const openMessageIds = /* @__PURE__ */ new Set();
|
|
19
|
+
const openReasoningMessageIds = /* @__PURE__ */ new Set();
|
|
20
|
+
const openReasoningSpanIds = /* @__PURE__ */ new Set();
|
|
16
21
|
const openToolCalls = /* @__PURE__ */ new Map();
|
|
22
|
+
const openSubagentRunIds = /* @__PURE__ */ new Set();
|
|
23
|
+
let runIdentity = {};
|
|
17
24
|
let terminalEventObserved = false;
|
|
25
|
+
const clearOpen = () => {
|
|
26
|
+
openMessageIds.clear();
|
|
27
|
+
openReasoningMessageIds.clear();
|
|
28
|
+
openReasoningSpanIds.clear();
|
|
29
|
+
openToolCalls.clear();
|
|
30
|
+
openSubagentRunIds.clear();
|
|
31
|
+
};
|
|
18
32
|
const observe = (event) => {
|
|
19
33
|
if (terminalEventObserved) return;
|
|
20
34
|
switch (event.type) {
|
|
35
|
+
case _ag_ui_client.EventType.RUN_STARTED: {
|
|
36
|
+
const { threadId, runId } = event;
|
|
37
|
+
runIdentity = {
|
|
38
|
+
threadId,
|
|
39
|
+
runId
|
|
40
|
+
};
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
case _ag_ui_client.EventType.REASONING_START:
|
|
44
|
+
case _ag_ui_client.EventType.REASONING_END:
|
|
45
|
+
case _ag_ui_client.EventType.REASONING_MESSAGE_START:
|
|
46
|
+
case _ag_ui_client.EventType.REASONING_MESSAGE_END: {
|
|
47
|
+
const messageId = event.messageId;
|
|
48
|
+
if (typeof messageId !== "string") break;
|
|
49
|
+
const open = event.type === _ag_ui_client.EventType.REASONING_START || event.type === _ag_ui_client.EventType.REASONING_END ? openReasoningSpanIds : openReasoningMessageIds;
|
|
50
|
+
if (event.type === _ag_ui_client.EventType.REASONING_START || event.type === _ag_ui_client.EventType.REASONING_MESSAGE_START) open.add(messageId);
|
|
51
|
+
else open.delete(messageId);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
21
54
|
case _ag_ui_client.EventType.TEXT_MESSAGE_START: {
|
|
22
55
|
const messageId = event.messageId;
|
|
23
56
|
if (messageId) openMessageIds.add(messageId);
|
|
@@ -47,11 +80,19 @@ function createRunEventFinalizer() {
|
|
|
47
80
|
if (info.hasEnd && info.hasResult) openToolCalls.delete(toolCallId);
|
|
48
81
|
break;
|
|
49
82
|
}
|
|
83
|
+
case _ag_ui_client.EventType.SUBAGENT_STARTED:
|
|
84
|
+
case _ag_ui_client.EventType.SUBAGENT_FINISHED:
|
|
85
|
+
case _ag_ui_client.EventType.SUBAGENT_ERROR: {
|
|
86
|
+
const subagentRunId = event.subagentRunId;
|
|
87
|
+
if (!subagentRunId) break;
|
|
88
|
+
if (event.type === _ag_ui_client.EventType.SUBAGENT_STARTED) openSubagentRunIds.add(subagentRunId);
|
|
89
|
+
else openSubagentRunIds.delete(subagentRunId);
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
50
92
|
case _ag_ui_client.EventType.RUN_FINISHED:
|
|
51
93
|
case _ag_ui_client.EventType.RUN_ERROR:
|
|
52
94
|
terminalEventObserved = true;
|
|
53
|
-
|
|
54
|
-
openToolCalls.clear();
|
|
95
|
+
clearOpen();
|
|
55
96
|
break;
|
|
56
97
|
default: break;
|
|
57
98
|
}
|
|
@@ -62,6 +103,14 @@ function createRunEventFinalizer() {
|
|
|
62
103
|
const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;
|
|
63
104
|
const resolvedAbruptMessage = interruptionMessage && interruptionMessage !== defaultStopMessage ? interruptionMessage : defaultAbruptEndMessage;
|
|
64
105
|
const appended = [];
|
|
106
|
+
for (const messageId of openReasoningMessageIds) appended.push({
|
|
107
|
+
type: _ag_ui_client.EventType.REASONING_MESSAGE_END,
|
|
108
|
+
messageId
|
|
109
|
+
});
|
|
110
|
+
for (const messageId of openReasoningSpanIds) appended.push({
|
|
111
|
+
type: _ag_ui_client.EventType.REASONING_END,
|
|
112
|
+
messageId
|
|
113
|
+
});
|
|
65
114
|
for (const messageId of openMessageIds) appended.push({
|
|
66
115
|
type: _ag_ui_client.EventType.TEXT_MESSAGE_END,
|
|
67
116
|
messageId
|
|
@@ -87,8 +136,21 @@ function createRunEventFinalizer() {
|
|
|
87
136
|
})
|
|
88
137
|
});
|
|
89
138
|
}
|
|
90
|
-
if (stopRequested)
|
|
91
|
-
|
|
139
|
+
if (stopRequested) {
|
|
140
|
+
const openIds = [...openSubagentRunIds];
|
|
141
|
+
for (let index = openIds.length - 1; index >= 0; index -= 1) appended.push({
|
|
142
|
+
type: _ag_ui_client.EventType.SUBAGENT_ERROR,
|
|
143
|
+
subagentRunId: openIds[index],
|
|
144
|
+
message: resolvedStopMessage,
|
|
145
|
+
code: "CANCELLED"
|
|
146
|
+
});
|
|
147
|
+
appended.push({
|
|
148
|
+
type: _ag_ui_client.EventType.RUN_FINISHED,
|
|
149
|
+
...runIdentity.threadId !== void 0 ? { threadId: runIdentity.threadId } : {},
|
|
150
|
+
...runIdentity.runId !== void 0 ? { runId: runIdentity.runId } : {},
|
|
151
|
+
...options.protocolVersion !== void 0 ? { outcome: { type: "cancelled" } } : {}
|
|
152
|
+
});
|
|
153
|
+
} else {
|
|
92
154
|
const errorEvent = {
|
|
93
155
|
type: _ag_ui_client.EventType.RUN_ERROR,
|
|
94
156
|
message: resolvedAbruptMessage,
|
|
@@ -97,8 +159,7 @@ function createRunEventFinalizer() {
|
|
|
97
159
|
appended.push(errorEvent);
|
|
98
160
|
}
|
|
99
161
|
terminalEventObserved = true;
|
|
100
|
-
|
|
101
|
-
openToolCalls.clear();
|
|
162
|
+
clearOpen();
|
|
102
163
|
return appended;
|
|
103
164
|
};
|
|
104
165
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finalize-events.cjs","names":["EventType"],"sources":["../src/finalize-events.ts"],"sourcesContent":["import type { BaseEvent, RunErrorEvent } from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface FinalizeRunOptions {\n stopRequested?: boolean;\n interruptionMessage?: string;\n}\n\nexport interface RunEventFinalizer {\n /** Observe one streamed event. Only the ids of open lifecycles are kept. */\n observe(event: BaseEvent): void;\n /** Return the events that close an interrupted or abruptly ended stream. */\n finalize(options?: FinalizeRunOptions): BaseEvent[];\n}\n\nconst defaultStopMessage = \"Run stopped by user\";\nconst defaultAbruptEndMessage = \"Run ended without emitting a terminal event\";\n\ninterface OpenToolCall {\n hasEnd: boolean;\n hasResult: boolean;\n}\n\n/**\n * Incremental finalizer for a streamed AG-UI run. Feed every event to\n * `observe`; when the stream ends without a terminal event, `finalize` returns\n * the closers for text messages and tool calls still open plus a terminal\n * event. Closed lifecycles are forgotten at once and payloads are never kept,\n * so a caller does not have to retain the event array for this purpose.\n */\nexport function createRunEventFinalizer(): RunEventFinalizer {\n const openMessageIds = new Set<string>();\n const openToolCalls = new Map<string, OpenToolCall>();\n let terminalEventObserved = false;\n\n const observe = (event: BaseEvent) => {\n if (terminalEventObserved) return;\n\n switch (event.type) {\n case EventType.TEXT_MESSAGE_START: {\n const messageId = (event as { messageId?: string }).messageId;\n if (messageId) openMessageIds.add(messageId);\n break;\n }\n case EventType.TEXT_MESSAGE_END: {\n const messageId = (event as { messageId?: string }).messageId;\n if (typeof messageId === \"string\") openMessageIds.delete(messageId);\n break;\n }\n case EventType.TOOL_CALL_START: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (toolCallId && !openToolCalls.has(toolCallId)) {\n openToolCalls.set(toolCallId, { hasEnd: false, hasResult: false });\n }\n break;\n }\n case EventType.TOOL_CALL_END:\n case EventType.TOOL_CALL_RESULT: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (!toolCallId) break;\n const info = openToolCalls.get(toolCallId);\n if (!info) break;\n\n if (event.type === EventType.TOOL_CALL_END) info.hasEnd = true;\n else info.hasResult = true;\n if (info.hasEnd && info.hasResult) openToolCalls.delete(toolCallId);\n break;\n }\n case EventType.RUN_FINISHED:\n case EventType.RUN_ERROR:\n terminalEventObserved = true;\n openMessageIds.clear();\n openToolCalls.clear();\n break;\n default:\n break;\n }\n };\n\n const finalize = (options: FinalizeRunOptions = {}): BaseEvent[] => {\n if (terminalEventObserved) return [];\n\n const { stopRequested = false, interruptionMessage } = options;\n const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;\n const resolvedAbruptMessage =\n interruptionMessage && interruptionMessage !== defaultStopMessage\n ? interruptionMessage\n : defaultAbruptEndMessage;\n const appended: BaseEvent[] = [];\n\n for (const messageId of openMessageIds) {\n appended.push({\n type: EventType.TEXT_MESSAGE_END,\n messageId,\n } as BaseEvent);\n }\n\n for (const [toolCallId, info] of openToolCalls) {\n if (!info.hasEnd) {\n appended.push({\n type: EventType.TOOL_CALL_END,\n toolCallId,\n } as BaseEvent);\n }\n\n if (!info.hasResult) {\n appended.push({\n type: EventType.TOOL_CALL_RESULT,\n toolCallId,\n messageId: `${toolCallId}-result`,\n role: \"tool\",\n content: JSON.stringify(\n stopRequested\n ? {\n status: \"stopped\",\n reason: \"stop_requested\",\n message: resolvedStopMessage,\n }\n : {\n status: \"error\",\n reason: \"missing_terminal_event\",\n message: resolvedAbruptMessage,\n },\n ),\n } as BaseEvent);\n }\n }\n\n if (stopRequested) {\n appended.push({ type: EventType.RUN_FINISHED } as BaseEvent);\n } else {\n const errorEvent: RunErrorEvent = {\n type: EventType.RUN_ERROR,\n message: resolvedAbruptMessage,\n code: \"INCOMPLETE_STREAM\",\n };\n appended.push(errorEvent);\n }\n\n terminalEventObserved = true;\n openMessageIds.clear();\n openToolCalls.clear();\n return appended;\n };\n\n return { observe, finalize };\n}\n\n/**\n * Array form of {@link createRunEventFinalizer} for callers that already keep\n * the run's events (runners persist them). Appends the closers to `events` in\n * place and returns them.\n */\nexport function finalizeRunEvents(\n events: BaseEvent[],\n options: FinalizeRunOptions = {},\n): BaseEvent[] {\n const finalizer = createRunEventFinalizer();\n for (const event of events) finalizer.observe(event);\n\n const appended = finalizer.finalize(options);\n events.push(...appended);\n return appended;\n}\n"],"mappings":";;;;AAeA,MAAM,qBAAqB;AAC3B,MAAM,0BAA0B;;;;;;;;AAchC,SAAgB,0BAA6C;CAC3D,MAAM,iCAAiB,IAAI,KAAa;CACxC,MAAM,gCAAgB,IAAI,KAA2B;CACrD,IAAI,wBAAwB;CAE5B,MAAM,WAAW,UAAqB;AACpC,MAAI,sBAAuB;AAE3B,UAAQ,MAAM,MAAd;GACE,KAAKA,wBAAU,oBAAoB;IACjC,MAAM,YAAa,MAAiC;AACpD,QAAI,UAAW,gBAAe,IAAI,UAAU;AAC5C;;GAEF,KAAKA,wBAAU,kBAAkB;IAC/B,MAAM,YAAa,MAAiC;AACpD,QAAI,OAAO,cAAc,SAAU,gBAAe,OAAO,UAAU;AACnE;;GAEF,KAAKA,wBAAU,iBAAiB;IAC9B,MAAM,aAAc,MAAkC;AACtD,QAAI,cAAc,CAAC,cAAc,IAAI,WAAW,CAC9C,eAAc,IAAI,YAAY;KAAE,QAAQ;KAAO,WAAW;KAAO,CAAC;AAEpE;;GAEF,KAAKA,wBAAU;GACf,KAAKA,wBAAU,kBAAkB;IAC/B,MAAM,aAAc,MAAkC;AACtD,QAAI,CAAC,WAAY;IACjB,MAAM,OAAO,cAAc,IAAI,WAAW;AAC1C,QAAI,CAAC,KAAM;AAEX,QAAI,MAAM,SAASA,wBAAU,cAAe,MAAK,SAAS;QACrD,MAAK,YAAY;AACtB,QAAI,KAAK,UAAU,KAAK,UAAW,eAAc,OAAO,WAAW;AACnE;;GAEF,KAAKA,wBAAU;GACf,KAAKA,wBAAU;AACb,4BAAwB;AACxB,mBAAe,OAAO;AACtB,kBAAc,OAAO;AACrB;GACF,QACE;;;CAIN,MAAM,YAAY,UAA8B,EAAE,KAAkB;AAClE,MAAI,sBAAuB,QAAO,EAAE;EAEpC,MAAM,EAAE,gBAAgB,OAAO,wBAAwB;EACvD,MAAM,sBAAsB,uBAAuB;EACnD,MAAM,wBACJ,uBAAuB,wBAAwB,qBAC3C,sBACA;EACN,MAAM,WAAwB,EAAE;AAEhC,OAAK,MAAM,aAAa,eACtB,UAAS,KAAK;GACZ,MAAMA,wBAAU;GAChB;GACD,CAAc;AAGjB,OAAK,MAAM,CAAC,YAAY,SAAS,eAAe;AAC9C,OAAI,CAAC,KAAK,OACR,UAAS,KAAK;IACZ,MAAMA,wBAAU;IAChB;IACD,CAAc;AAGjB,OAAI,CAAC,KAAK,UACR,UAAS,KAAK;IACZ,MAAMA,wBAAU;IAChB;IACA,WAAW,GAAG,WAAW;IACzB,MAAM;IACN,SAAS,KAAK,UACZ,gBACI;KACE,QAAQ;KACR,QAAQ;KACR,SAAS;KACV,GACD;KACE,QAAQ;KACR,QAAQ;KACR,SAAS;KACV,CACN;IACF,CAAc;;AAInB,MAAI,cACF,UAAS,KAAK,EAAE,MAAMA,wBAAU,cAAc,CAAc;OACvD;GACL,MAAM,aAA4B;IAChC,MAAMA,wBAAU;IAChB,SAAS;IACT,MAAM;IACP;AACD,YAAS,KAAK,WAAW;;AAG3B,0BAAwB;AACxB,iBAAe,OAAO;AACtB,gBAAc,OAAO;AACrB,SAAO;;AAGT,QAAO;EAAE;EAAS;EAAU;;;;;;;AAQ9B,SAAgB,kBACd,QACA,UAA8B,EAAE,EACnB;CACb,MAAM,YAAY,yBAAyB;AAC3C,MAAK,MAAM,SAAS,OAAQ,WAAU,QAAQ,MAAM;CAEpD,MAAM,WAAW,UAAU,SAAS,QAAQ;AAC5C,QAAO,KAAK,GAAG,SAAS;AACxB,QAAO"}
|
|
1
|
+
{"version":3,"file":"finalize-events.cjs","names":["EventType"],"sources":["../src/finalize-events.ts"],"sourcesContent":["import type { BaseEvent, RunErrorEvent } from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface FinalizeRunOptions {\n stopRequested?: boolean;\n interruptionMessage?: string;\n /**\n * The `protocolVersion` the client declared on its RunAgentInput. When it is\n * set, a stopped run finishes with the AG-UI 1.0 `cancelled` outcome. A\n * client that declares no version predates 1.0 and cannot parse that\n * outcome, so it gets the plain RUN_FINISHED it always got.\n */\n protocolVersion?: string;\n}\n\nexport interface RunEventFinalizer {\n /** Observe one streamed event. Only the ids of open lifecycles are kept. */\n observe(event: BaseEvent): void;\n /** Return the events that close an interrupted or abruptly ended stream. */\n finalize(options?: FinalizeRunOptions): BaseEvent[];\n}\n\nconst defaultStopMessage = \"Run stopped by user\";\nconst defaultAbruptEndMessage = \"Run ended without emitting a terminal event\";\n\ninterface OpenToolCall {\n hasEnd: boolean;\n hasResult: boolean;\n}\n\n/**\n * Incremental finalizer for a streamed AG-UI run. Feed every event to\n * `observe`; when the stream ends without a terminal event, `finalize` returns\n * the closers for reasoning, text messages and tool calls still open plus a\n * terminal event. AG-UI 1.0 fails a run that ends with reasoning still open,\n * so reasoning is closed too. It also fails a RUN_FINISHED while a subagent\n * is still open, so a stop closes open subagents as well; a RUN_ERROR\n * abandons them, which the protocol allows. Closed lifecycles are forgotten at once and payloads are never kept,\n * so a caller does not have to retain the event array for this purpose.\n */\nexport function createRunEventFinalizer(): RunEventFinalizer {\n const openMessageIds = new Set<string>();\n const openReasoningMessageIds = new Set<string>();\n const openReasoningSpanIds = new Set<string>();\n const openToolCalls = new Map<string, OpenToolCall>();\n // Insertion order is start order, so closing in reverse closes children first.\n const openSubagentRunIds = new Set<string>();\n let runIdentity: { threadId?: string; runId?: string } = {};\n let terminalEventObserved = false;\n\n const clearOpen = () => {\n openMessageIds.clear();\n openReasoningMessageIds.clear();\n openReasoningSpanIds.clear();\n openToolCalls.clear();\n openSubagentRunIds.clear();\n };\n\n const observe = (event: BaseEvent) => {\n if (terminalEventObserved) return;\n\n switch (event.type) {\n case EventType.RUN_STARTED: {\n const { threadId, runId } = event as {\n threadId?: string;\n runId?: string;\n };\n runIdentity = { threadId, runId };\n break;\n }\n case EventType.REASONING_START:\n case EventType.REASONING_END:\n case EventType.REASONING_MESSAGE_START:\n case EventType.REASONING_MESSAGE_END: {\n const messageId = (event as { messageId?: string }).messageId;\n if (typeof messageId !== \"string\") break;\n const open =\n event.type === EventType.REASONING_START ||\n event.type === EventType.REASONING_END\n ? openReasoningSpanIds\n : openReasoningMessageIds;\n if (\n event.type === EventType.REASONING_START ||\n event.type === EventType.REASONING_MESSAGE_START\n ) {\n open.add(messageId);\n } else {\n open.delete(messageId);\n }\n break;\n }\n case EventType.TEXT_MESSAGE_START: {\n const messageId = (event as { messageId?: string }).messageId;\n if (messageId) openMessageIds.add(messageId);\n break;\n }\n case EventType.TEXT_MESSAGE_END: {\n const messageId = (event as { messageId?: string }).messageId;\n if (typeof messageId === \"string\") openMessageIds.delete(messageId);\n break;\n }\n case EventType.TOOL_CALL_START: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (toolCallId && !openToolCalls.has(toolCallId)) {\n openToolCalls.set(toolCallId, { hasEnd: false, hasResult: false });\n }\n break;\n }\n case EventType.TOOL_CALL_END:\n case EventType.TOOL_CALL_RESULT: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (!toolCallId) break;\n const info = openToolCalls.get(toolCallId);\n if (!info) break;\n\n if (event.type === EventType.TOOL_CALL_END) info.hasEnd = true;\n else info.hasResult = true;\n if (info.hasEnd && info.hasResult) openToolCalls.delete(toolCallId);\n break;\n }\n case EventType.SUBAGENT_STARTED:\n case EventType.SUBAGENT_FINISHED:\n case EventType.SUBAGENT_ERROR: {\n const subagentRunId = (event as { subagentRunId?: string })\n .subagentRunId;\n if (!subagentRunId) break;\n if (event.type === EventType.SUBAGENT_STARTED) {\n openSubagentRunIds.add(subagentRunId);\n } else {\n openSubagentRunIds.delete(subagentRunId);\n }\n break;\n }\n case EventType.RUN_FINISHED:\n case EventType.RUN_ERROR:\n terminalEventObserved = true;\n clearOpen();\n break;\n default:\n break;\n }\n };\n\n const finalize = (options: FinalizeRunOptions = {}): BaseEvent[] => {\n if (terminalEventObserved) return [];\n\n const { stopRequested = false, interruptionMessage } = options;\n const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;\n const resolvedAbruptMessage =\n interruptionMessage && interruptionMessage !== defaultStopMessage\n ? interruptionMessage\n : defaultAbruptEndMessage;\n const appended: BaseEvent[] = [];\n\n // A reasoning message closes before the span that holds it.\n for (const messageId of openReasoningMessageIds) {\n appended.push({\n type: EventType.REASONING_MESSAGE_END,\n messageId,\n } as BaseEvent);\n }\n for (const messageId of openReasoningSpanIds) {\n appended.push({ type: EventType.REASONING_END, messageId } as BaseEvent);\n }\n\n for (const messageId of openMessageIds) {\n appended.push({\n type: EventType.TEXT_MESSAGE_END,\n messageId,\n } as BaseEvent);\n }\n\n for (const [toolCallId, info] of openToolCalls) {\n if (!info.hasEnd) {\n appended.push({\n type: EventType.TOOL_CALL_END,\n toolCallId,\n } as BaseEvent);\n }\n\n if (!info.hasResult) {\n appended.push({\n type: EventType.TOOL_CALL_RESULT,\n toolCallId,\n messageId: `${toolCallId}-result`,\n role: \"tool\",\n content: JSON.stringify(\n stopRequested\n ? {\n status: \"stopped\",\n reason: \"stop_requested\",\n message: resolvedStopMessage,\n }\n : {\n status: \"error\",\n reason: \"missing_terminal_event\",\n message: resolvedAbruptMessage,\n },\n ),\n } as BaseEvent);\n }\n }\n\n if (stopRequested) {\n // Newest first, so a nested subagent closes before its parent. An index\n // loop, because `toReversed` is ES2023 and this package targets older.\n const openIds = [...openSubagentRunIds];\n for (let index = openIds.length - 1; index >= 0; index -= 1) {\n appended.push({\n type: EventType.SUBAGENT_ERROR,\n subagentRunId: openIds[index],\n message: resolvedStopMessage,\n code: \"CANCELLED\",\n } as BaseEvent);\n }\n appended.push({\n type: EventType.RUN_FINISHED,\n ...(runIdentity.threadId !== undefined\n ? { threadId: runIdentity.threadId }\n : {}),\n ...(runIdentity.runId !== undefined\n ? { runId: runIdentity.runId }\n : {}),\n ...(options.protocolVersion !== undefined\n ? { outcome: { type: \"cancelled\" } }\n : {}),\n } as BaseEvent);\n } else {\n const errorEvent: RunErrorEvent = {\n type: EventType.RUN_ERROR,\n message: resolvedAbruptMessage,\n code: \"INCOMPLETE_STREAM\",\n };\n appended.push(errorEvent);\n }\n\n terminalEventObserved = true;\n clearOpen();\n return appended;\n };\n\n return { observe, finalize };\n}\n\n/**\n * Array form of {@link createRunEventFinalizer} for callers that already keep\n * the run's events (runners persist them). Appends the closers to `events` in\n * place and returns them.\n */\nexport function finalizeRunEvents(\n events: BaseEvent[],\n options: FinalizeRunOptions = {},\n): BaseEvent[] {\n const finalizer = createRunEventFinalizer();\n for (const event of events) finalizer.observe(event);\n\n const appended = finalizer.finalize(options);\n events.push(...appended);\n return appended;\n}\n"],"mappings":"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"}
|
|
@@ -4,6 +4,13 @@ import { BaseEvent } from "@ag-ui/client";
|
|
|
4
4
|
interface FinalizeRunOptions {
|
|
5
5
|
stopRequested?: boolean;
|
|
6
6
|
interruptionMessage?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The `protocolVersion` the client declared on its RunAgentInput. When it is
|
|
9
|
+
* set, a stopped run finishes with the AG-UI 1.0 `cancelled` outcome. A
|
|
10
|
+
* client that declares no version predates 1.0 and cannot parse that
|
|
11
|
+
* outcome, so it gets the plain RUN_FINISHED it always got.
|
|
12
|
+
*/
|
|
13
|
+
protocolVersion?: string;
|
|
7
14
|
}
|
|
8
15
|
interface RunEventFinalizer {
|
|
9
16
|
/** Observe one streamed event. Only the ids of open lifecycles are kept. */
|
|
@@ -14,8 +21,11 @@ interface RunEventFinalizer {
|
|
|
14
21
|
/**
|
|
15
22
|
* Incremental finalizer for a streamed AG-UI run. Feed every event to
|
|
16
23
|
* `observe`; when the stream ends without a terminal event, `finalize` returns
|
|
17
|
-
* the closers for text messages and tool calls still open plus a
|
|
18
|
-
* event.
|
|
24
|
+
* the closers for reasoning, text messages and tool calls still open plus a
|
|
25
|
+
* terminal event. AG-UI 1.0 fails a run that ends with reasoning still open,
|
|
26
|
+
* so reasoning is closed too. It also fails a RUN_FINISHED while a subagent
|
|
27
|
+
* is still open, so a stop closes open subagents as well; a RUN_ERROR
|
|
28
|
+
* abandons them, which the protocol allows. Closed lifecycles are forgotten at once and payloads are never kept,
|
|
19
29
|
* so a caller does not have to retain the event array for this purpose.
|
|
20
30
|
*/
|
|
21
31
|
declare function createRunEventFinalizer(): RunEventFinalizer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finalize-events.d.cts","names":[],"sources":["../src/finalize-events.ts"],"mappings":";;;UAGiB,kBAAA;EACf,aAAA;EACA,mBAAA;AAAA;AAAA,UAGe,iBAAA;
|
|
1
|
+
{"version":3,"file":"finalize-events.d.cts","names":[],"sources":["../src/finalize-events.ts"],"mappings":";;;UAGiB,kBAAA;EACf,aAAA;EACA,mBAAA;EAFiC;;;;;;EASjC,eAAA;AAAA;AAAA,UAGe,iBAAA;EAAiB;EAEhC,OAAA,CAAQ,KAAA,EAAO,SAAA;EAAA;EAEf,QAAA,CAAS,OAAA,GAAU,kBAAA,GAAqB,SAAA;AAAA;;;;;;;;;;;iBAqB1B,uBAAA,CAAA,GAA2B,iBAAA;AAA3C;;;;;AAAA,iBAiNgB,iBAAA,CACd,MAAA,EAAQ,SAAA,IACR,OAAA,GAAS,kBAAA,GACR,SAAA"}
|
|
@@ -4,6 +4,13 @@ import { BaseEvent } from "@ag-ui/client";
|
|
|
4
4
|
interface FinalizeRunOptions {
|
|
5
5
|
stopRequested?: boolean;
|
|
6
6
|
interruptionMessage?: string;
|
|
7
|
+
/**
|
|
8
|
+
* The `protocolVersion` the client declared on its RunAgentInput. When it is
|
|
9
|
+
* set, a stopped run finishes with the AG-UI 1.0 `cancelled` outcome. A
|
|
10
|
+
* client that declares no version predates 1.0 and cannot parse that
|
|
11
|
+
* outcome, so it gets the plain RUN_FINISHED it always got.
|
|
12
|
+
*/
|
|
13
|
+
protocolVersion?: string;
|
|
7
14
|
}
|
|
8
15
|
interface RunEventFinalizer {
|
|
9
16
|
/** Observe one streamed event. Only the ids of open lifecycles are kept. */
|
|
@@ -14,8 +21,11 @@ interface RunEventFinalizer {
|
|
|
14
21
|
/**
|
|
15
22
|
* Incremental finalizer for a streamed AG-UI run. Feed every event to
|
|
16
23
|
* `observe`; when the stream ends without a terminal event, `finalize` returns
|
|
17
|
-
* the closers for text messages and tool calls still open plus a
|
|
18
|
-
* event.
|
|
24
|
+
* the closers for reasoning, text messages and tool calls still open plus a
|
|
25
|
+
* terminal event. AG-UI 1.0 fails a run that ends with reasoning still open,
|
|
26
|
+
* so reasoning is closed too. It also fails a RUN_FINISHED while a subagent
|
|
27
|
+
* is still open, so a stop closes open subagents as well; a RUN_ERROR
|
|
28
|
+
* abandons them, which the protocol allows. Closed lifecycles are forgotten at once and payloads are never kept,
|
|
19
29
|
* so a caller does not have to retain the event array for this purpose.
|
|
20
30
|
*/
|
|
21
31
|
declare function createRunEventFinalizer(): RunEventFinalizer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finalize-events.d.mts","names":[],"sources":["../src/finalize-events.ts"],"mappings":";;;UAGiB,kBAAA;EACf,aAAA;EACA,mBAAA;AAAA;AAAA,UAGe,iBAAA;
|
|
1
|
+
{"version":3,"file":"finalize-events.d.mts","names":[],"sources":["../src/finalize-events.ts"],"mappings":";;;UAGiB,kBAAA;EACf,aAAA;EACA,mBAAA;EAFiC;;;;;;EASjC,eAAA;AAAA;AAAA,UAGe,iBAAA;EAAiB;EAEhC,OAAA,CAAQ,KAAA,EAAO,SAAA;EAAA;EAEf,QAAA,CAAS,OAAA,GAAU,kBAAA,GAAqB,SAAA;AAAA;;;;;;;;;;;iBAqB1B,uBAAA,CAAA,GAA2B,iBAAA;AAA3C;;;;;AAAA,iBAiNgB,iBAAA,CACd,MAAA,EAAQ,SAAA,IACR,OAAA,GAAS,kBAAA,GACR,SAAA"}
|
package/dist/finalize-events.mjs
CHANGED
|
@@ -6,17 +6,50 @@ const defaultAbruptEndMessage = "Run ended without emitting a terminal event";
|
|
|
6
6
|
/**
|
|
7
7
|
* Incremental finalizer for a streamed AG-UI run. Feed every event to
|
|
8
8
|
* `observe`; when the stream ends without a terminal event, `finalize` returns
|
|
9
|
-
* the closers for text messages and tool calls still open plus a
|
|
10
|
-
* event.
|
|
9
|
+
* the closers for reasoning, text messages and tool calls still open plus a
|
|
10
|
+
* terminal event. AG-UI 1.0 fails a run that ends with reasoning still open,
|
|
11
|
+
* so reasoning is closed too. It also fails a RUN_FINISHED while a subagent
|
|
12
|
+
* is still open, so a stop closes open subagents as well; a RUN_ERROR
|
|
13
|
+
* abandons them, which the protocol allows. Closed lifecycles are forgotten at once and payloads are never kept,
|
|
11
14
|
* so a caller does not have to retain the event array for this purpose.
|
|
12
15
|
*/
|
|
13
16
|
function createRunEventFinalizer() {
|
|
14
17
|
const openMessageIds = /* @__PURE__ */ new Set();
|
|
18
|
+
const openReasoningMessageIds = /* @__PURE__ */ new Set();
|
|
19
|
+
const openReasoningSpanIds = /* @__PURE__ */ new Set();
|
|
15
20
|
const openToolCalls = /* @__PURE__ */ new Map();
|
|
21
|
+
const openSubagentRunIds = /* @__PURE__ */ new Set();
|
|
22
|
+
let runIdentity = {};
|
|
16
23
|
let terminalEventObserved = false;
|
|
24
|
+
const clearOpen = () => {
|
|
25
|
+
openMessageIds.clear();
|
|
26
|
+
openReasoningMessageIds.clear();
|
|
27
|
+
openReasoningSpanIds.clear();
|
|
28
|
+
openToolCalls.clear();
|
|
29
|
+
openSubagentRunIds.clear();
|
|
30
|
+
};
|
|
17
31
|
const observe = (event) => {
|
|
18
32
|
if (terminalEventObserved) return;
|
|
19
33
|
switch (event.type) {
|
|
34
|
+
case EventType.RUN_STARTED: {
|
|
35
|
+
const { threadId, runId } = event;
|
|
36
|
+
runIdentity = {
|
|
37
|
+
threadId,
|
|
38
|
+
runId
|
|
39
|
+
};
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case EventType.REASONING_START:
|
|
43
|
+
case EventType.REASONING_END:
|
|
44
|
+
case EventType.REASONING_MESSAGE_START:
|
|
45
|
+
case EventType.REASONING_MESSAGE_END: {
|
|
46
|
+
const messageId = event.messageId;
|
|
47
|
+
if (typeof messageId !== "string") break;
|
|
48
|
+
const open = event.type === EventType.REASONING_START || event.type === EventType.REASONING_END ? openReasoningSpanIds : openReasoningMessageIds;
|
|
49
|
+
if (event.type === EventType.REASONING_START || event.type === EventType.REASONING_MESSAGE_START) open.add(messageId);
|
|
50
|
+
else open.delete(messageId);
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
20
53
|
case EventType.TEXT_MESSAGE_START: {
|
|
21
54
|
const messageId = event.messageId;
|
|
22
55
|
if (messageId) openMessageIds.add(messageId);
|
|
@@ -46,11 +79,19 @@ function createRunEventFinalizer() {
|
|
|
46
79
|
if (info.hasEnd && info.hasResult) openToolCalls.delete(toolCallId);
|
|
47
80
|
break;
|
|
48
81
|
}
|
|
82
|
+
case EventType.SUBAGENT_STARTED:
|
|
83
|
+
case EventType.SUBAGENT_FINISHED:
|
|
84
|
+
case EventType.SUBAGENT_ERROR: {
|
|
85
|
+
const subagentRunId = event.subagentRunId;
|
|
86
|
+
if (!subagentRunId) break;
|
|
87
|
+
if (event.type === EventType.SUBAGENT_STARTED) openSubagentRunIds.add(subagentRunId);
|
|
88
|
+
else openSubagentRunIds.delete(subagentRunId);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
49
91
|
case EventType.RUN_FINISHED:
|
|
50
92
|
case EventType.RUN_ERROR:
|
|
51
93
|
terminalEventObserved = true;
|
|
52
|
-
|
|
53
|
-
openToolCalls.clear();
|
|
94
|
+
clearOpen();
|
|
54
95
|
break;
|
|
55
96
|
default: break;
|
|
56
97
|
}
|
|
@@ -61,6 +102,14 @@ function createRunEventFinalizer() {
|
|
|
61
102
|
const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;
|
|
62
103
|
const resolvedAbruptMessage = interruptionMessage && interruptionMessage !== defaultStopMessage ? interruptionMessage : defaultAbruptEndMessage;
|
|
63
104
|
const appended = [];
|
|
105
|
+
for (const messageId of openReasoningMessageIds) appended.push({
|
|
106
|
+
type: EventType.REASONING_MESSAGE_END,
|
|
107
|
+
messageId
|
|
108
|
+
});
|
|
109
|
+
for (const messageId of openReasoningSpanIds) appended.push({
|
|
110
|
+
type: EventType.REASONING_END,
|
|
111
|
+
messageId
|
|
112
|
+
});
|
|
64
113
|
for (const messageId of openMessageIds) appended.push({
|
|
65
114
|
type: EventType.TEXT_MESSAGE_END,
|
|
66
115
|
messageId
|
|
@@ -86,8 +135,21 @@ function createRunEventFinalizer() {
|
|
|
86
135
|
})
|
|
87
136
|
});
|
|
88
137
|
}
|
|
89
|
-
if (stopRequested)
|
|
90
|
-
|
|
138
|
+
if (stopRequested) {
|
|
139
|
+
const openIds = [...openSubagentRunIds];
|
|
140
|
+
for (let index = openIds.length - 1; index >= 0; index -= 1) appended.push({
|
|
141
|
+
type: EventType.SUBAGENT_ERROR,
|
|
142
|
+
subagentRunId: openIds[index],
|
|
143
|
+
message: resolvedStopMessage,
|
|
144
|
+
code: "CANCELLED"
|
|
145
|
+
});
|
|
146
|
+
appended.push({
|
|
147
|
+
type: EventType.RUN_FINISHED,
|
|
148
|
+
...runIdentity.threadId !== void 0 ? { threadId: runIdentity.threadId } : {},
|
|
149
|
+
...runIdentity.runId !== void 0 ? { runId: runIdentity.runId } : {},
|
|
150
|
+
...options.protocolVersion !== void 0 ? { outcome: { type: "cancelled" } } : {}
|
|
151
|
+
});
|
|
152
|
+
} else {
|
|
91
153
|
const errorEvent = {
|
|
92
154
|
type: EventType.RUN_ERROR,
|
|
93
155
|
message: resolvedAbruptMessage,
|
|
@@ -96,8 +158,7 @@ function createRunEventFinalizer() {
|
|
|
96
158
|
appended.push(errorEvent);
|
|
97
159
|
}
|
|
98
160
|
terminalEventObserved = true;
|
|
99
|
-
|
|
100
|
-
openToolCalls.clear();
|
|
161
|
+
clearOpen();
|
|
101
162
|
return appended;
|
|
102
163
|
};
|
|
103
164
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"finalize-events.mjs","names":[],"sources":["../src/finalize-events.ts"],"sourcesContent":["import type { BaseEvent, RunErrorEvent } from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface FinalizeRunOptions {\n stopRequested?: boolean;\n interruptionMessage?: string;\n}\n\nexport interface RunEventFinalizer {\n /** Observe one streamed event. Only the ids of open lifecycles are kept. */\n observe(event: BaseEvent): void;\n /** Return the events that close an interrupted or abruptly ended stream. */\n finalize(options?: FinalizeRunOptions): BaseEvent[];\n}\n\nconst defaultStopMessage = \"Run stopped by user\";\nconst defaultAbruptEndMessage = \"Run ended without emitting a terminal event\";\n\ninterface OpenToolCall {\n hasEnd: boolean;\n hasResult: boolean;\n}\n\n/**\n * Incremental finalizer for a streamed AG-UI run. Feed every event to\n * `observe`; when the stream ends without a terminal event, `finalize` returns\n * the closers for text messages and tool calls still open plus a terminal\n * event. Closed lifecycles are forgotten at once and payloads are never kept,\n * so a caller does not have to retain the event array for this purpose.\n */\nexport function createRunEventFinalizer(): RunEventFinalizer {\n const openMessageIds = new Set<string>();\n const openToolCalls = new Map<string, OpenToolCall>();\n let terminalEventObserved = false;\n\n const observe = (event: BaseEvent) => {\n if (terminalEventObserved) return;\n\n switch (event.type) {\n case EventType.TEXT_MESSAGE_START: {\n const messageId = (event as { messageId?: string }).messageId;\n if (messageId) openMessageIds.add(messageId);\n break;\n }\n case EventType.TEXT_MESSAGE_END: {\n const messageId = (event as { messageId?: string }).messageId;\n if (typeof messageId === \"string\") openMessageIds.delete(messageId);\n break;\n }\n case EventType.TOOL_CALL_START: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (toolCallId && !openToolCalls.has(toolCallId)) {\n openToolCalls.set(toolCallId, { hasEnd: false, hasResult: false });\n }\n break;\n }\n case EventType.TOOL_CALL_END:\n case EventType.TOOL_CALL_RESULT: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (!toolCallId) break;\n const info = openToolCalls.get(toolCallId);\n if (!info) break;\n\n if (event.type === EventType.TOOL_CALL_END) info.hasEnd = true;\n else info.hasResult = true;\n if (info.hasEnd && info.hasResult) openToolCalls.delete(toolCallId);\n break;\n }\n case EventType.RUN_FINISHED:\n case EventType.RUN_ERROR:\n terminalEventObserved = true;\n openMessageIds.clear();\n openToolCalls.clear();\n break;\n default:\n break;\n }\n };\n\n const finalize = (options: FinalizeRunOptions = {}): BaseEvent[] => {\n if (terminalEventObserved) return [];\n\n const { stopRequested = false, interruptionMessage } = options;\n const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;\n const resolvedAbruptMessage =\n interruptionMessage && interruptionMessage !== defaultStopMessage\n ? interruptionMessage\n : defaultAbruptEndMessage;\n const appended: BaseEvent[] = [];\n\n for (const messageId of openMessageIds) {\n appended.push({\n type: EventType.TEXT_MESSAGE_END,\n messageId,\n } as BaseEvent);\n }\n\n for (const [toolCallId, info] of openToolCalls) {\n if (!info.hasEnd) {\n appended.push({\n type: EventType.TOOL_CALL_END,\n toolCallId,\n } as BaseEvent);\n }\n\n if (!info.hasResult) {\n appended.push({\n type: EventType.TOOL_CALL_RESULT,\n toolCallId,\n messageId: `${toolCallId}-result`,\n role: \"tool\",\n content: JSON.stringify(\n stopRequested\n ? {\n status: \"stopped\",\n reason: \"stop_requested\",\n message: resolvedStopMessage,\n }\n : {\n status: \"error\",\n reason: \"missing_terminal_event\",\n message: resolvedAbruptMessage,\n },\n ),\n } as BaseEvent);\n }\n }\n\n if (stopRequested) {\n appended.push({ type: EventType.RUN_FINISHED } as BaseEvent);\n } else {\n const errorEvent: RunErrorEvent = {\n type: EventType.RUN_ERROR,\n message: resolvedAbruptMessage,\n code: \"INCOMPLETE_STREAM\",\n };\n appended.push(errorEvent);\n }\n\n terminalEventObserved = true;\n openMessageIds.clear();\n openToolCalls.clear();\n return appended;\n };\n\n return { observe, finalize };\n}\n\n/**\n * Array form of {@link createRunEventFinalizer} for callers that already keep\n * the run's events (runners persist them). Appends the closers to `events` in\n * place and returns them.\n */\nexport function finalizeRunEvents(\n events: BaseEvent[],\n options: FinalizeRunOptions = {},\n): BaseEvent[] {\n const finalizer = createRunEventFinalizer();\n for (const event of events) finalizer.observe(event);\n\n const appended = finalizer.finalize(options);\n events.push(...appended);\n return appended;\n}\n"],"mappings":";;;AAeA,MAAM,qBAAqB;AAC3B,MAAM,0BAA0B;;;;;;;;AAchC,SAAgB,0BAA6C;CAC3D,MAAM,iCAAiB,IAAI,KAAa;CACxC,MAAM,gCAAgB,IAAI,KAA2B;CACrD,IAAI,wBAAwB;CAE5B,MAAM,WAAW,UAAqB;AACpC,MAAI,sBAAuB;AAE3B,UAAQ,MAAM,MAAd;GACE,KAAK,UAAU,oBAAoB;IACjC,MAAM,YAAa,MAAiC;AACpD,QAAI,UAAW,gBAAe,IAAI,UAAU;AAC5C;;GAEF,KAAK,UAAU,kBAAkB;IAC/B,MAAM,YAAa,MAAiC;AACpD,QAAI,OAAO,cAAc,SAAU,gBAAe,OAAO,UAAU;AACnE;;GAEF,KAAK,UAAU,iBAAiB;IAC9B,MAAM,aAAc,MAAkC;AACtD,QAAI,cAAc,CAAC,cAAc,IAAI,WAAW,CAC9C,eAAc,IAAI,YAAY;KAAE,QAAQ;KAAO,WAAW;KAAO,CAAC;AAEpE;;GAEF,KAAK,UAAU;GACf,KAAK,UAAU,kBAAkB;IAC/B,MAAM,aAAc,MAAkC;AACtD,QAAI,CAAC,WAAY;IACjB,MAAM,OAAO,cAAc,IAAI,WAAW;AAC1C,QAAI,CAAC,KAAM;AAEX,QAAI,MAAM,SAAS,UAAU,cAAe,MAAK,SAAS;QACrD,MAAK,YAAY;AACtB,QAAI,KAAK,UAAU,KAAK,UAAW,eAAc,OAAO,WAAW;AACnE;;GAEF,KAAK,UAAU;GACf,KAAK,UAAU;AACb,4BAAwB;AACxB,mBAAe,OAAO;AACtB,kBAAc,OAAO;AACrB;GACF,QACE;;;CAIN,MAAM,YAAY,UAA8B,EAAE,KAAkB;AAClE,MAAI,sBAAuB,QAAO,EAAE;EAEpC,MAAM,EAAE,gBAAgB,OAAO,wBAAwB;EACvD,MAAM,sBAAsB,uBAAuB;EACnD,MAAM,wBACJ,uBAAuB,wBAAwB,qBAC3C,sBACA;EACN,MAAM,WAAwB,EAAE;AAEhC,OAAK,MAAM,aAAa,eACtB,UAAS,KAAK;GACZ,MAAM,UAAU;GAChB;GACD,CAAc;AAGjB,OAAK,MAAM,CAAC,YAAY,SAAS,eAAe;AAC9C,OAAI,CAAC,KAAK,OACR,UAAS,KAAK;IACZ,MAAM,UAAU;IAChB;IACD,CAAc;AAGjB,OAAI,CAAC,KAAK,UACR,UAAS,KAAK;IACZ,MAAM,UAAU;IAChB;IACA,WAAW,GAAG,WAAW;IACzB,MAAM;IACN,SAAS,KAAK,UACZ,gBACI;KACE,QAAQ;KACR,QAAQ;KACR,SAAS;KACV,GACD;KACE,QAAQ;KACR,QAAQ;KACR,SAAS;KACV,CACN;IACF,CAAc;;AAInB,MAAI,cACF,UAAS,KAAK,EAAE,MAAM,UAAU,cAAc,CAAc;OACvD;GACL,MAAM,aAA4B;IAChC,MAAM,UAAU;IAChB,SAAS;IACT,MAAM;IACP;AACD,YAAS,KAAK,WAAW;;AAG3B,0BAAwB;AACxB,iBAAe,OAAO;AACtB,gBAAc,OAAO;AACrB,SAAO;;AAGT,QAAO;EAAE;EAAS;EAAU;;;;;;;AAQ9B,SAAgB,kBACd,QACA,UAA8B,EAAE,EACnB;CACb,MAAM,YAAY,yBAAyB;AAC3C,MAAK,MAAM,SAAS,OAAQ,WAAU,QAAQ,MAAM;CAEpD,MAAM,WAAW,UAAU,SAAS,QAAQ;AAC5C,QAAO,KAAK,GAAG,SAAS;AACxB,QAAO"}
|
|
1
|
+
{"version":3,"file":"finalize-events.mjs","names":[],"sources":["../src/finalize-events.ts"],"sourcesContent":["import type { BaseEvent, RunErrorEvent } from \"@ag-ui/client\";\nimport { EventType } from \"@ag-ui/client\";\n\nexport interface FinalizeRunOptions {\n stopRequested?: boolean;\n interruptionMessage?: string;\n /**\n * The `protocolVersion` the client declared on its RunAgentInput. When it is\n * set, a stopped run finishes with the AG-UI 1.0 `cancelled` outcome. A\n * client that declares no version predates 1.0 and cannot parse that\n * outcome, so it gets the plain RUN_FINISHED it always got.\n */\n protocolVersion?: string;\n}\n\nexport interface RunEventFinalizer {\n /** Observe one streamed event. Only the ids of open lifecycles are kept. */\n observe(event: BaseEvent): void;\n /** Return the events that close an interrupted or abruptly ended stream. */\n finalize(options?: FinalizeRunOptions): BaseEvent[];\n}\n\nconst defaultStopMessage = \"Run stopped by user\";\nconst defaultAbruptEndMessage = \"Run ended without emitting a terminal event\";\n\ninterface OpenToolCall {\n hasEnd: boolean;\n hasResult: boolean;\n}\n\n/**\n * Incremental finalizer for a streamed AG-UI run. Feed every event to\n * `observe`; when the stream ends without a terminal event, `finalize` returns\n * the closers for reasoning, text messages and tool calls still open plus a\n * terminal event. AG-UI 1.0 fails a run that ends with reasoning still open,\n * so reasoning is closed too. It also fails a RUN_FINISHED while a subagent\n * is still open, so a stop closes open subagents as well; a RUN_ERROR\n * abandons them, which the protocol allows. Closed lifecycles are forgotten at once and payloads are never kept,\n * so a caller does not have to retain the event array for this purpose.\n */\nexport function createRunEventFinalizer(): RunEventFinalizer {\n const openMessageIds = new Set<string>();\n const openReasoningMessageIds = new Set<string>();\n const openReasoningSpanIds = new Set<string>();\n const openToolCalls = new Map<string, OpenToolCall>();\n // Insertion order is start order, so closing in reverse closes children first.\n const openSubagentRunIds = new Set<string>();\n let runIdentity: { threadId?: string; runId?: string } = {};\n let terminalEventObserved = false;\n\n const clearOpen = () => {\n openMessageIds.clear();\n openReasoningMessageIds.clear();\n openReasoningSpanIds.clear();\n openToolCalls.clear();\n openSubagentRunIds.clear();\n };\n\n const observe = (event: BaseEvent) => {\n if (terminalEventObserved) return;\n\n switch (event.type) {\n case EventType.RUN_STARTED: {\n const { threadId, runId } = event as {\n threadId?: string;\n runId?: string;\n };\n runIdentity = { threadId, runId };\n break;\n }\n case EventType.REASONING_START:\n case EventType.REASONING_END:\n case EventType.REASONING_MESSAGE_START:\n case EventType.REASONING_MESSAGE_END: {\n const messageId = (event as { messageId?: string }).messageId;\n if (typeof messageId !== \"string\") break;\n const open =\n event.type === EventType.REASONING_START ||\n event.type === EventType.REASONING_END\n ? openReasoningSpanIds\n : openReasoningMessageIds;\n if (\n event.type === EventType.REASONING_START ||\n event.type === EventType.REASONING_MESSAGE_START\n ) {\n open.add(messageId);\n } else {\n open.delete(messageId);\n }\n break;\n }\n case EventType.TEXT_MESSAGE_START: {\n const messageId = (event as { messageId?: string }).messageId;\n if (messageId) openMessageIds.add(messageId);\n break;\n }\n case EventType.TEXT_MESSAGE_END: {\n const messageId = (event as { messageId?: string }).messageId;\n if (typeof messageId === \"string\") openMessageIds.delete(messageId);\n break;\n }\n case EventType.TOOL_CALL_START: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (toolCallId && !openToolCalls.has(toolCallId)) {\n openToolCalls.set(toolCallId, { hasEnd: false, hasResult: false });\n }\n break;\n }\n case EventType.TOOL_CALL_END:\n case EventType.TOOL_CALL_RESULT: {\n const toolCallId = (event as { toolCallId?: string }).toolCallId;\n if (!toolCallId) break;\n const info = openToolCalls.get(toolCallId);\n if (!info) break;\n\n if (event.type === EventType.TOOL_CALL_END) info.hasEnd = true;\n else info.hasResult = true;\n if (info.hasEnd && info.hasResult) openToolCalls.delete(toolCallId);\n break;\n }\n case EventType.SUBAGENT_STARTED:\n case EventType.SUBAGENT_FINISHED:\n case EventType.SUBAGENT_ERROR: {\n const subagentRunId = (event as { subagentRunId?: string })\n .subagentRunId;\n if (!subagentRunId) break;\n if (event.type === EventType.SUBAGENT_STARTED) {\n openSubagentRunIds.add(subagentRunId);\n } else {\n openSubagentRunIds.delete(subagentRunId);\n }\n break;\n }\n case EventType.RUN_FINISHED:\n case EventType.RUN_ERROR:\n terminalEventObserved = true;\n clearOpen();\n break;\n default:\n break;\n }\n };\n\n const finalize = (options: FinalizeRunOptions = {}): BaseEvent[] => {\n if (terminalEventObserved) return [];\n\n const { stopRequested = false, interruptionMessage } = options;\n const resolvedStopMessage = interruptionMessage ?? defaultStopMessage;\n const resolvedAbruptMessage =\n interruptionMessage && interruptionMessage !== defaultStopMessage\n ? interruptionMessage\n : defaultAbruptEndMessage;\n const appended: BaseEvent[] = [];\n\n // A reasoning message closes before the span that holds it.\n for (const messageId of openReasoningMessageIds) {\n appended.push({\n type: EventType.REASONING_MESSAGE_END,\n messageId,\n } as BaseEvent);\n }\n for (const messageId of openReasoningSpanIds) {\n appended.push({ type: EventType.REASONING_END, messageId } as BaseEvent);\n }\n\n for (const messageId of openMessageIds) {\n appended.push({\n type: EventType.TEXT_MESSAGE_END,\n messageId,\n } as BaseEvent);\n }\n\n for (const [toolCallId, info] of openToolCalls) {\n if (!info.hasEnd) {\n appended.push({\n type: EventType.TOOL_CALL_END,\n toolCallId,\n } as BaseEvent);\n }\n\n if (!info.hasResult) {\n appended.push({\n type: EventType.TOOL_CALL_RESULT,\n toolCallId,\n messageId: `${toolCallId}-result`,\n role: \"tool\",\n content: JSON.stringify(\n stopRequested\n ? {\n status: \"stopped\",\n reason: \"stop_requested\",\n message: resolvedStopMessage,\n }\n : {\n status: \"error\",\n reason: \"missing_terminal_event\",\n message: resolvedAbruptMessage,\n },\n ),\n } as BaseEvent);\n }\n }\n\n if (stopRequested) {\n // Newest first, so a nested subagent closes before its parent. An index\n // loop, because `toReversed` is ES2023 and this package targets older.\n const openIds = [...openSubagentRunIds];\n for (let index = openIds.length - 1; index >= 0; index -= 1) {\n appended.push({\n type: EventType.SUBAGENT_ERROR,\n subagentRunId: openIds[index],\n message: resolvedStopMessage,\n code: \"CANCELLED\",\n } as BaseEvent);\n }\n appended.push({\n type: EventType.RUN_FINISHED,\n ...(runIdentity.threadId !== undefined\n ? { threadId: runIdentity.threadId }\n : {}),\n ...(runIdentity.runId !== undefined\n ? { runId: runIdentity.runId }\n : {}),\n ...(options.protocolVersion !== undefined\n ? { outcome: { type: \"cancelled\" } }\n : {}),\n } as BaseEvent);\n } else {\n const errorEvent: RunErrorEvent = {\n type: EventType.RUN_ERROR,\n message: resolvedAbruptMessage,\n code: \"INCOMPLETE_STREAM\",\n };\n appended.push(errorEvent);\n }\n\n terminalEventObserved = true;\n clearOpen();\n return appended;\n };\n\n return { observe, finalize };\n}\n\n/**\n * Array form of {@link createRunEventFinalizer} for callers that already keep\n * the run's events (runners persist them). Appends the closers to `events` in\n * place and returns them.\n */\nexport function finalizeRunEvents(\n events: BaseEvent[],\n options: FinalizeRunOptions = {},\n): BaseEvent[] {\n const finalizer = createRunEventFinalizer();\n for (const event of events) finalizer.observe(event);\n\n const appended = finalizer.finalize(options);\n events.push(...appended);\n return appended;\n}\n"],"mappings":"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"}
|
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ const require_content = require('./attachments/content.cjs');
|
|
|
23
23
|
const require_utils = require('./attachments/utils.cjs');
|
|
24
24
|
const require_logger = require('./logger.cjs');
|
|
25
25
|
const require_finalize_events = require('./finalize-events.cjs');
|
|
26
|
+
const require_intelligence_routing_fields = require('./intelligence-routing-fields.cjs');
|
|
26
27
|
const require_transcription_errors = require('./transcription-errors.cjs');
|
|
27
28
|
const require_package = require('./package.cjs');
|
|
28
29
|
const require_a2ui_prompts = require('./a2ui-prompts.cjs');
|
|
@@ -160,6 +161,7 @@ exports.resolveRowRenderKeysById = require_row_render_keys.resolveRowRenderKeysB
|
|
|
160
161
|
exports.safeParseToolArgs = require_index.safeParseToolArgs;
|
|
161
162
|
exports.schemaToJsonSchema = require_standard_schema.schemaToJsonSchema;
|
|
162
163
|
exports.shouldEnableInspector = require_inspector_visibility.shouldEnableInspector;
|
|
164
|
+
exports.stripIntelligenceRoutingFields = require_intelligence_routing_fields.stripIntelligenceRoutingFields;
|
|
163
165
|
exports.styledConsole = require_console_styling.styledConsole;
|
|
164
166
|
exports.tryMap = require_index.tryMap;
|
|
165
167
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./utils\";\nexport * from \"./constants\";\n// Telemetry is split deliberately. `TelemetryClient` imports\n// `@segment/analytics-node`, which imports `node-fetch`, which imports the\n// Node built-ins `stream`, `http`, `https` and `zlib`. Browser bundlers\n// resolve the whole module graph before they tree-shake, so re-exporting\n// that module here made every browser build of a dependent package print\n// \"Module ... has been externalized for browser compatibility\" warnings,\n// even when the consumer never touched telemetry (#4151). Only the\n// browser-safe telemetry surface is re-exported from this entry. Server\n// code that needs the client imports it from `@copilotkit/shared/telemetry`.\n// This mirrors the license-verifier note below.\nexport { isTelemetryDisabled } from \"./telemetry/telemetry-disabled\";\nexport * from \"./telemetry/sampling\";\n// Pure string classification with no imports, so it carries no runtime edge\n// into browser builds — same reasoning as `sampling` above.\nexport * from \"./telemetry/model-host\";\nexport {\n firstNonBlankTelemetryId,\n lambdaClient,\n parseTelemetryIdFromLicense,\n parseAndWarnTelemetryId,\n} from \"./telemetry/lambda-client\";\nexport type { LambdaSendOptions } from \"./telemetry/lambda-client\";\n// Types only: erased at build time, so they add no runtime edge to\n// `telemetry-client.ts` and therefore none to @segment/analytics-node.\nexport type {\n TelemetryCapture,\n TelemetryIdentity,\n} from \"./telemetry/telemetry-client\";\nexport * from \"./debug\";\nexport * from \"./standard-schema\";\nexport * from \"./attachments\";\n\nexport { logger } from \"./logger\";\nexport {\n createRunEventFinalizer,\n finalizeRunEvents,\n type FinalizeRunOptions,\n type RunEventFinalizer,\n} from \"./finalize-events\";\n\nexport {\n TranscriptionErrorCode,\n TranscriptionErrors,\n type TranscriptionErrorResponse,\n} from \"./transcription-errors\";\n\nimport * as packageJson from \"../package.json\";\nexport const COPILOTKIT_VERSION = packageJson.version;\n\n// Re-export only types from license-verifier (types are erased at compile time,\n// so they don't pull in the Node-only `crypto` dependency into client bundles).\n// Server-side packages (e.g. @copilotkit/runtime) should import runtime functions\n// like createLicenseChecker and getLicenseWarningHeader directly from\n// @copilotkit/license-verifier.\nexport type {\n LicenseChecker,\n LicenseStatus,\n LicensePayload,\n LicenseFeatures,\n LicenseTier,\n LicenseOwner,\n} from \"@copilotkit/license-verifier\";\n\nimport type { LicensePayload } from \"@copilotkit/license-verifier\";\nimport type {\n RuntimeEntitlementResponse,\n RuntimeLicenseStatus,\n} from \"./utils/types\";\n\n// LicenseContextValue was dropped from license-verifier's public API in\n// 0.3.0, so it is defined here. The context shape is owned by this package\n// anyway via createLicenseContextValue below.\n\n/**\n * License context value exposed to child components.\n * Frontend providers create their own context using this shape.\n */\nexport interface LicenseContextValue {\n /** Effective license status after structured entitlement precedence. Null until known. */\n status: RuntimeLicenseStatus | null;\n /** The license payload if available. Always null on the client; the payload stays server-side. */\n license: LicensePayload | null;\n /** Whether a feature is licensed. Ready entitlements override legacy status behavior. */\n checkFeature: (feature: string) => boolean;\n /** Get a numeric feature limit. Zero means unlimited; null means not applicable. */\n getLimit: (feature: string) => number | null;\n}\n\n/** Read a record value without traversing its prototype chain. */\nfunction getOwnRecordValue<Value>(\n record: Readonly<Record<string, Value>>,\n key: string,\n): Value | undefined {\n return Object.prototype.hasOwnProperty.call(record, key)\n ? record[key]\n : undefined;\n}\n\n/** Legacy UI surfaces that remain available for every active entitlement. */\nfunction isLegacyUiFeature(feature: string): boolean {\n return feature === \"chat\" || feature === \"popup\" || feature === \"sidebar\";\n}\n\n/**\n * Client-safe license context factory, driven by the license authority the\n * runtime reports via /info.\n *\n * A ready managed entitlement is authoritative in both directions. A ready\n * active self-hosted entitlement is also authoritative, while an inactive\n * self-hosted response preserves the legacy signed-license fallback. Active\n * entitlements supply feature grants and limits; authoritative inactive\n * entitlements deny every feature and limit. Older runtimes that report only a\n * status retain the legacy behavior: features are enabled unless the status is\n * \"expired\" or \"invalid\", and no limits are reported. This is inlined here to\n * avoid importing the full license-verifier bundle (which depends on Node's\n * `crypto`) into browser bundles.\n */\nexport function createLicenseContextValue(\n status: RuntimeLicenseStatus | null | undefined,\n runtimeEntitlements?: RuntimeEntitlementResponse,\n): LicenseContextValue {\n const readyEntitlement =\n runtimeEntitlements?.status === \"ready\"\n ? runtimeEntitlements.entitlement\n : null;\n const hasUsableSelfHostedLegacyFallback =\n readyEntitlement &&\n !readyEntitlement.active &&\n readyEntitlement.source === \"selfHostedDeploymentLicense\" &&\n (status === \"valid\" || status === \"expiring\");\n const featureAuthority =\n readyEntitlement && !hasUsableSelfHostedLegacyFallback\n ? readyEntitlement\n : null;\n const activeEntitlement = featureAuthority?.active ? featureAuthority : null;\n const resolvedStatus = activeEntitlement\n ? \"valid\"\n : readyEntitlement?.source === \"managedOrgSubscription\" ||\n readyEntitlement?.source === \"awsMarketplaceDeploymentLicense\"\n ? \"none\"\n : featureAuthority\n ? (status ?? \"none\")\n : (status ?? null);\n const featuresEnabled =\n resolvedStatus !== \"expired\" && resolvedStatus !== \"invalid\";\n\n return {\n status: resolvedStatus,\n license: null,\n checkFeature: (feature) =>\n featureAuthority\n ? activeEntitlement\n ? feature === \"threads\" &&\n Object.prototype.hasOwnProperty.call(\n activeEntitlement.limits,\n \"threads.max_count\",\n )\n ? true\n : (getOwnRecordValue(activeEntitlement.features, feature) ??\n isLegacyUiFeature(feature))\n : false\n : featuresEnabled,\n getLimit: (feature) =>\n activeEntitlement\n ? (getOwnRecordValue(activeEntitlement.limits, feature) ?? null)\n : null,\n };\n}\n\nexport {\n A2UI_DEFAULT_GENERATION_GUIDELINES,\n A2UI_DEFAULT_DESIGN_GUIDELINES,\n} from \"./a2ui-prompts\";\n\nexport type { DebugEventEnvelope } from \"./debug-event-envelope\";\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["export * from \"./types\";\nexport * from \"./utils\";\nexport * from \"./constants\";\n// Telemetry is split deliberately. `TelemetryClient` imports\n// `@segment/analytics-node`, which imports `node-fetch`, which imports the\n// Node built-ins `stream`, `http`, `https` and `zlib`. Browser bundlers\n// resolve the whole module graph before they tree-shake, so re-exporting\n// that module here made every browser build of a dependent package print\n// \"Module ... has been externalized for browser compatibility\" warnings,\n// even when the consumer never touched telemetry (#4151). Only the\n// browser-safe telemetry surface is re-exported from this entry. Server\n// code that needs the client imports it from `@copilotkit/shared/telemetry`.\n// This mirrors the license-verifier note below.\nexport { isTelemetryDisabled } from \"./telemetry/telemetry-disabled\";\nexport * from \"./telemetry/sampling\";\n// Pure string classification with no imports, so it carries no runtime edge\n// into browser builds — same reasoning as `sampling` above.\nexport * from \"./telemetry/model-host\";\nexport {\n firstNonBlankTelemetryId,\n lambdaClient,\n parseTelemetryIdFromLicense,\n parseAndWarnTelemetryId,\n} from \"./telemetry/lambda-client\";\nexport type { LambdaSendOptions } from \"./telemetry/lambda-client\";\n// Types only: erased at build time, so they add no runtime edge to\n// `telemetry-client.ts` and therefore none to @segment/analytics-node.\nexport type {\n TelemetryCapture,\n TelemetryIdentity,\n} from \"./telemetry/telemetry-client\";\nexport * from \"./debug\";\nexport * from \"./standard-schema\";\nexport * from \"./attachments\";\n\nexport { logger } from \"./logger\";\nexport {\n createRunEventFinalizer,\n finalizeRunEvents,\n type FinalizeRunOptions,\n type RunEventFinalizer,\n} from \"./finalize-events\";\nexport { stripIntelligenceRoutingFields } from \"./intelligence-routing-fields\";\n\nexport {\n TranscriptionErrorCode,\n TranscriptionErrors,\n type TranscriptionErrorResponse,\n} from \"./transcription-errors\";\n\nimport * as packageJson from \"../package.json\";\nexport const COPILOTKIT_VERSION = packageJson.version;\n\n// Re-export only types from license-verifier (types are erased at compile time,\n// so they don't pull in the Node-only `crypto` dependency into client bundles).\n// Server-side packages (e.g. @copilotkit/runtime) should import runtime functions\n// like createLicenseChecker and getLicenseWarningHeader directly from\n// @copilotkit/license-verifier.\nexport type {\n LicenseChecker,\n LicenseStatus,\n LicensePayload,\n LicenseFeatures,\n LicenseTier,\n LicenseOwner,\n} from \"@copilotkit/license-verifier\";\n\nimport type { LicensePayload } from \"@copilotkit/license-verifier\";\nimport type {\n RuntimeEntitlementResponse,\n RuntimeLicenseStatus,\n} from \"./utils/types\";\n\n// LicenseContextValue was dropped from license-verifier's public API in\n// 0.3.0, so it is defined here. The context shape is owned by this package\n// anyway via createLicenseContextValue below.\n\n/**\n * License context value exposed to child components.\n * Frontend providers create their own context using this shape.\n */\nexport interface LicenseContextValue {\n /** Effective license status after structured entitlement precedence. Null until known. */\n status: RuntimeLicenseStatus | null;\n /** The license payload if available. Always null on the client; the payload stays server-side. */\n license: LicensePayload | null;\n /** Whether a feature is licensed. Ready entitlements override legacy status behavior. */\n checkFeature: (feature: string) => boolean;\n /** Get a numeric feature limit. Zero means unlimited; null means not applicable. */\n getLimit: (feature: string) => number | null;\n}\n\n/** Read a record value without traversing its prototype chain. */\nfunction getOwnRecordValue<Value>(\n record: Readonly<Record<string, Value>>,\n key: string,\n): Value | undefined {\n return Object.prototype.hasOwnProperty.call(record, key)\n ? record[key]\n : undefined;\n}\n\n/** Legacy UI surfaces that remain available for every active entitlement. */\nfunction isLegacyUiFeature(feature: string): boolean {\n return feature === \"chat\" || feature === \"popup\" || feature === \"sidebar\";\n}\n\n/**\n * Client-safe license context factory, driven by the license authority the\n * runtime reports via /info.\n *\n * A ready managed entitlement is authoritative in both directions. A ready\n * active self-hosted entitlement is also authoritative, while an inactive\n * self-hosted response preserves the legacy signed-license fallback. Active\n * entitlements supply feature grants and limits; authoritative inactive\n * entitlements deny every feature and limit. Older runtimes that report only a\n * status retain the legacy behavior: features are enabled unless the status is\n * \"expired\" or \"invalid\", and no limits are reported. This is inlined here to\n * avoid importing the full license-verifier bundle (which depends on Node's\n * `crypto`) into browser bundles.\n */\nexport function createLicenseContextValue(\n status: RuntimeLicenseStatus | null | undefined,\n runtimeEntitlements?: RuntimeEntitlementResponse,\n): LicenseContextValue {\n const readyEntitlement =\n runtimeEntitlements?.status === \"ready\"\n ? runtimeEntitlements.entitlement\n : null;\n const hasUsableSelfHostedLegacyFallback =\n readyEntitlement &&\n !readyEntitlement.active &&\n readyEntitlement.source === \"selfHostedDeploymentLicense\" &&\n (status === \"valid\" || status === \"expiring\");\n const featureAuthority =\n readyEntitlement && !hasUsableSelfHostedLegacyFallback\n ? readyEntitlement\n : null;\n const activeEntitlement = featureAuthority?.active ? featureAuthority : null;\n const resolvedStatus = activeEntitlement\n ? \"valid\"\n : readyEntitlement?.source === \"managedOrgSubscription\" ||\n readyEntitlement?.source === \"awsMarketplaceDeploymentLicense\"\n ? \"none\"\n : featureAuthority\n ? (status ?? \"none\")\n : (status ?? null);\n const featuresEnabled =\n resolvedStatus !== \"expired\" && resolvedStatus !== \"invalid\";\n\n return {\n status: resolvedStatus,\n license: null,\n checkFeature: (feature) =>\n featureAuthority\n ? activeEntitlement\n ? feature === \"threads\" &&\n Object.prototype.hasOwnProperty.call(\n activeEntitlement.limits,\n \"threads.max_count\",\n )\n ? true\n : (getOwnRecordValue(activeEntitlement.features, feature) ??\n isLegacyUiFeature(feature))\n : false\n : featuresEnabled,\n getLimit: (feature) =>\n activeEntitlement\n ? (getOwnRecordValue(activeEntitlement.limits, feature) ?? null)\n : null,\n };\n}\n\nexport {\n A2UI_DEFAULT_GENERATION_GUIDELINES,\n A2UI_DEFAULT_DESIGN_GUIDELINES,\n} from \"./a2ui-prompts\";\n\nexport type { DebugEventEnvelope } from \"./debug-event-envelope\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,MAAa;;AA0Cb,SAAS,kBACP,QACA,KACmB;AACnB,QAAO,OAAO,UAAU,eAAe,KAAK,QAAQ,IAAI,GACpD,OAAO,OACP;;;AAIN,SAAS,kBAAkB,SAA0B;AACnD,QAAO,YAAY,UAAU,YAAY,WAAW,YAAY;;;;;;;;;;;;;;;;AAiBlE,SAAgB,0BACd,QACA,qBACqB;CACrB,MAAM,mBACJ,qBAAqB,WAAW,UAC5B,oBAAoB,cACpB;CACN,MAAM,oCACJ,oBACA,CAAC,iBAAiB,UAClB,iBAAiB,WAAW,kCAC3B,WAAW,WAAW,WAAW;CACpC,MAAM,mBACJ,oBAAoB,CAAC,oCACjB,mBACA;CACN,MAAM,oBAAoB,kBAAkB,SAAS,mBAAmB;CACxE,MAAM,iBAAiB,oBACnB,UACA,kBAAkB,WAAW,4BAC3B,kBAAkB,WAAW,oCAC7B,SACA,mBACG,UAAU,SACV,UAAU;CACnB,MAAM,kBACJ,mBAAmB,aAAa,mBAAmB;AAErD,QAAO;EACL,QAAQ;EACR,SAAS;EACT,eAAe,YACb,mBACI,oBACE,YAAY,aACZ,OAAO,UAAU,eAAe,KAC9B,kBAAkB,QAClB,oBACD,GACC,OACC,kBAAkB,kBAAkB,UAAU,QAAQ,IACvD,kBAAkB,QAAQ,GAC5B,QACF;EACN,WAAW,YACT,oBACK,kBAAkB,kBAAkB,QAAQ,QAAQ,IAAI,OACzD;EACP"}
|