@copilotkit/vue 1.73.0 → 1.73.1
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/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +42 -41
- package/dist/index.mjs.map +1 -1
- package/dist/use-render-activity-message-6LwUTCNm.cjs +85 -0
- package/dist/use-render-activity-message-6LwUTCNm.cjs.map +1 -0
- package/dist/{use-render-activity-message-DI4kGqHF.js → use-render-activity-message-Di_L8HCv.js} +3513 -3468
- package/dist/use-render-activity-message-Di_L8HCv.js.map +1 -0
- package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
- package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
- package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts +25 -1
- package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
- package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/v2/components/chat/CopilotChat.vue +2 -8
- package/src/v2/components/chat/CopilotChatMessageView.vue +29 -3
- package/src/v2/components/chat/__tests__/CopilotChatMessageView.rowKeys.test.ts +140 -0
- package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +32 -6
- package/src/v2/hooks/use-human-in-the-loop.ts +1 -0
- package/src/v2/providers/CopilotKitProvider.types.ts +28 -1
- package/src/v2/providers/CopilotKitProvider.vue +86 -6
- package/src/v2/providers/__tests__/CopilotKitProvider.hitl.e2e.test.ts +192 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.messageFilter.test.ts +159 -0
- package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +275 -21
- package/src/v2/providers/__tests__/CopilotKitProvider.wildcard.test.ts +19 -1
- package/dist/use-render-activity-message-C45MYgwB.cjs +0 -85
- package/dist/use-render-activity-message-C45MYgwB.cjs.map +0 -1
- package/dist/use-render-activity-message-DI4kGqHF.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopilotChat.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/chat/CopilotChat.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CopilotChat.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/chat/CopilotChat.vue"],"names":[],"mappings":"AA83BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAiBnD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,KAAK,EACV,yBAAyB,EACzB,gBAAgB,EAChB,6BAA6B,EAC7B,kCAAkC,EAClC,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,SAAS,CAAC;AAcjB,KAAK,WAAW,GAAG;IACjB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,OAAO,CAAC;IACnE,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE;QACvB,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,SAAS,EAAE,OAAO,CAAC;KACpB,KAAK,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,OAAO,CAAC;IAC9D,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,OAAO,CAAC;IACtD,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,kCAAkC,KAAK,OAAO,CAAC;IAC3E,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,iCAAiC,KAAK,OAAO,CAAC;IACzE,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAC;IAElC,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;CACtD,CAAC;AAk3BF,QAAA,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;6EAQnB,CAAC;wBACkB,eAAe,CAAC,OAAO,eAAe,EAAE,WAAW,CAAC;AAAzE,wBAA0E;AAa1E,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopilotChatMessageView.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/chat/CopilotChatMessageView.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CopilotChatMessageView.vue.d.ts","sourceRoot":"","sources":["../../../../src/v2/components/chat/CopilotChatMessageView.vue"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-human-in-the-loop.d.ts","sourceRoot":"","sources":["../../../src/v2/hooks/use-human-in-the-loop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAKvC,OAAO,KAAK,EAEV,iBAAiB,EAGlB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC1B,IAAI,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"use-human-in-the-loop.d.ts","sourceRoot":"","sources":["../../../src/v2/hooks/use-human-in-the-loop.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,KAAK,CAAC;AAKvC,OAAO,KAAK,EAEV,iBAAiB,EAGlB,MAAM,UAAU,CAAC;AAElB;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjE,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAC1B,IAAI,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,EAAE,QA6F9B"}
|
package/dist/v2/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@copilotkit/core"),i=require("@ag-ui/client"),e=require("../use-render-activity-message-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("@copilotkit/core"),i=require("@ag-ui/client"),e=require("../use-render-activity-message-6LwUTCNm.cjs"),n=require("@copilotkit/shared");exports.A2UIActivityContentSchema=e.A2UIActivityContentSchema;exports.A2UISurfaceActivityRenderer=e._sfc_main;exports.A2UISurfaceActivityType=e.A2UISurfaceActivityType;exports.CopilotChat=e.CopilotChat;exports.CopilotChatAssistantMessage=e._sfc_main$1;exports.CopilotChatAttachmentQueue=e._sfc_main$2;exports.CopilotChatAttachmentRenderer=e._sfc_main$3;exports.CopilotChatAudioRecorder=e._sfc_main$4;exports.CopilotChatConfigurationProvider=e._sfc_main$5;exports.CopilotChatDefaultLabels=e.CopilotChatDefaultLabels;exports.CopilotChatInput=e._sfc_main$6;exports.CopilotChatMessageView=e._sfc_main$7;exports.CopilotChatReasoningMessage=e._sfc_main$8;exports.CopilotChatSuggestionPill=e._sfc_main$9;exports.CopilotChatSuggestionView=e._sfc_main$10;exports.CopilotChatToggleButton=e.CopilotChatToggleButton;exports.CopilotChatToggleButtonCloseIcon=e.CopilotChatToggleButtonCloseIcon;exports.CopilotChatToggleButtonOpenIcon=e.CopilotChatToggleButtonOpenIcon;exports.CopilotChatToolCallsView=e._sfc_main$11;exports.CopilotChatUserMessage=e._sfc_main$12;exports.CopilotChatView=e._sfc_main$13;exports.CopilotKitCoreVue=e.CopilotKitCoreVue;exports.CopilotKitInspector=e._sfc_main$14;exports.CopilotKitProvider=e._sfc_main$15;exports.CopilotModalHeader=e.CopilotModalHeader;exports.CopilotPopup=e._sfc_main$16;exports.CopilotPopupView=e.CopilotPopupView;exports.CopilotSidebar=e._sfc_main$17;exports.CopilotSidebarView=e.CopilotSidebarView;exports.CopilotThreadsDrawer=e._sfc_main$18;exports.GenerateSandboxedUiArgsSchema=e.GenerateSandboxedUiArgsSchema;exports.LicenseContextKey=e.LicenseContextKey;exports.MCPAppsActivityContentSchema=e.MCPAppsActivityContentSchema;exports.MCPAppsActivityRenderer=e.MCPAppsActivityRenderer;exports.MCPAppsActivityType=e.MCPAppsActivityType;exports.OpenGenerativeUIActivityRenderer=e.OpenGenerativeUIActivityRenderer;exports.OpenGenerativeUIActivityType=e.OpenGenerativeUIActivityType;exports.OpenGenerativeUIContentSchema=e.OpenGenerativeUIContentSchema;exports.OpenGenerativeUIRenderer=e.OpenGenerativeUIRenderer;exports.OpenGenerativeUIToolRenderer=e.OpenGenerativeUIToolRenderer;exports.UseAgentUpdate=e.UseAgentUpdate;exports.createA2UIMessageRenderer=e.createA2UIMessageRenderer;exports.createDefaultLicenseRef=e.createDefaultLicenseRef;exports.defineToolCallRenderer=e.defineToolCallRenderer;exports.extractCompleteStyles=e.extractCompleteStyles;exports.getOperationSurfaceId=e.getOperationSurfaceId;exports.processPartialHtml=e.processPartialHtml;exports.useAgent=e.useAgent;exports.useAgentContext=e.useAgentContext;exports.useAttachments=e.useAttachments;exports.useCapabilities=e.useCapabilities;exports.useComponent=e.useComponent;exports.useConfigureSuggestions=e.useConfigureSuggestions;exports.useCopilotChatConfiguration=e.useCopilotChatConfiguration;exports.useCopilotKit=e.useCopilotKit;exports.useDefaultRenderTool=e.useDefaultRenderTool;exports.useFrontendTool=e.useFrontendTool;exports.useHumanInTheLoop=e.useHumanInTheLoop;exports.useInterrupt=e.useInterrupt;exports.useKatexStyles=e.useKatexStyles;exports.useKeyboardHeight=e.useKeyboardHeight;exports.useLicenseContext=e.useLicenseContext;exports.useRenderActivityMessage=e.useRenderActivityMessage;exports.useRenderCustomMessages=e.useRenderCustomMessages;exports.useRenderTool=e.useRenderTool;exports.useSandboxFunctions=e.useSandboxFunctions;exports.useSuggestions=e.useSuggestions;exports.useThreads=e.useThreads;exports.vueBasicCatalog=e.vueBasicCatalog;Object.defineProperty(exports,"createLicenseContextValue",{enumerable:!0,get:()=>n.createLicenseContextValue});Object.keys(o).forEach(t=>{t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:()=>o[t]})});Object.keys(i).forEach(t=>{t!=="default"&&!Object.prototype.hasOwnProperty.call(exports,t)&&Object.defineProperty(exports,t,{enumerable:!0,get:()=>i[t]})});
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/v2/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from "@copilotkit/core";
|
|
2
2
|
export * from "@ag-ui/client";
|
|
3
|
-
import { A as o, _ as i, a as n, C, b as r, c as p, d as l, e as u, f as c, g, h as d, i as h, j as A, k as v, l as S, m, n as y, o as I, p as f, q as R, r as T, s as U, t as x, u as M, v as P, w as b, x as V, y as w, z as K, B as O, G, L, M as B, D, E as H, O as F, F as Q, H as j, I as k, J as q, U as z, K as E, N as J, P as N, Q as W, R as X, S as Y, T as Z, V as _, W as $, X as ee, Y as ae, Z as te, $ as se, a0 as oe, a1 as ie, a2 as ne, a3 as Ce, a4 as re, a5 as pe, a6 as le, a7 as ue, a8 as ce, a9 as ge, aa as de, ab as he, ac as Ae, ad as ve, ae as Se } from "../use-render-activity-message-
|
|
3
|
+
import { A as o, _ as i, a as n, C, b as r, c as p, d as l, e as u, f as c, g, h as d, i as h, j as A, k as v, l as S, m, n as y, o as I, p as f, q as R, r as T, s as U, t as x, u as M, v as P, w as b, x as V, y as w, z as K, B as O, G, L, M as B, D, E as H, O as F, F as Q, H as j, I as k, J as q, U as z, K as E, N as J, P as N, Q as W, R as X, S as Y, T as Z, V as _, W as $, X as ee, Y as ae, Z as te, $ as se, a0 as oe, a1 as ie, a2 as ne, a3 as Ce, a4 as re, a5 as pe, a6 as le, a7 as ue, a8 as ce, a9 as ge, aa as de, ab as he, ac as Ae, ad as ve, ae as Se } from "../use-render-activity-message-Di_L8HCv.js";
|
|
4
4
|
import { createLicenseContextValue as ye } from "@copilotkit/shared";
|
|
5
5
|
export {
|
|
6
6
|
o as A2UIActivityContentSchema,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AbstractAgent } from "@ag-ui/client";
|
|
2
|
-
import type { CopilotKitCoreErrorCode } from "@copilotkit/core";
|
|
2
|
+
import type { CopilotKitCoreErrorCode, CopilotKitMessageFilter } from "@copilotkit/core";
|
|
3
3
|
import type { DebugConfig } from "@copilotkit/shared";
|
|
4
4
|
import type { A2UITheme, SandboxFunction, VueActivityMessageRenderer, VueCustomMessageRenderer, VueFrontendTool, VueHumanInTheLoop, VueToolCallRenderer } from "../types";
|
|
5
5
|
import type { Component } from "vue";
|
|
@@ -7,6 +7,30 @@ export interface CopilotKitProviderProps {
|
|
|
7
7
|
runtimeUrl?: string;
|
|
8
8
|
headers?: Record<string, string> | (() => Record<string, string>);
|
|
9
9
|
credentials?: RequestCredentials;
|
|
10
|
+
/**
|
|
11
|
+
* Rewrites the message list sent to runtime agents on every run.
|
|
12
|
+
*
|
|
13
|
+
* CopilotKit sends the whole thread each time. When your agent already
|
|
14
|
+
* stores the conversation, most of that payload is waste, and an agent that
|
|
15
|
+
* merges the inbound list with its own store can show the model every turn
|
|
16
|
+
* twice. Return the messages to send:
|
|
17
|
+
*
|
|
18
|
+
* ```vue
|
|
19
|
+
* <CopilotKitProvider
|
|
20
|
+
* runtime-url="/api/copilotkit"
|
|
21
|
+
* :message-filter="(messages) => messages.slice(-1)"
|
|
22
|
+
* />
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* The filter changes the request body only. The transcript the UI renders is
|
|
26
|
+
* untouched. Broken tool-call pairs are repaired before the request is sent,
|
|
27
|
+
* so a filter this blunt cannot strand a tool result mid-HITL.
|
|
28
|
+
*
|
|
29
|
+
* Agents reached through your CopilotRuntime honor this. An agent your app
|
|
30
|
+
* passes in directly does not, and neither Intelligence runs nor suggestion
|
|
31
|
+
* runs are ever filtered.
|
|
32
|
+
*/
|
|
33
|
+
messageFilter?: CopilotKitMessageFilter;
|
|
10
34
|
defaultThrottleMs?: number;
|
|
11
35
|
publicApiKey?: string;
|
|
12
36
|
publicLicenseKey?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopilotKitProvider.types.d.ts","sourceRoot":"","sources":["../../../src/v2/providers/CopilotKitProvider.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"CopilotKitProvider.types.d.ts","sourceRoot":"","sources":["../../../src/v2/providers/CopilotKitProvider.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EACV,SAAS,EACT,eAAe,EACf,0BAA0B,EAC1B,wBAAwB,EACxB,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAErC,MAAM,WAAW,uBAAuB;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAClE,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,aAAa,CAAC,EAAE,uBAAuB,CAAC;IACxC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxD,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAClD,eAAe,CAAC,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,CAAC;IAC7C,sBAAsB,CAAC,EAAE,0BAA0B,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/D,oBAAoB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAClD,aAAa,CAAC,EAAE,eAAe,EAAE,CAAC;IAClC,cAAc,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACrC,gBAAgB,CAAC,EAAE;QACjB,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;QACrC,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAClC;;;;OAIG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAChB,KAAK,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,uBAAuB,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC9B,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,CAAC,EAAE;QACL,KAAK,CAAC,EAAE,SAAS,CAAC;QAClB,OAAO,CAAC,EAAE,GAAG,CAAC;QACd,gBAAgB,CAAC,EAAE,SAAS,CAAC;QAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,CAAC;IACF;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CopilotKitProvider.vue.d.ts","sourceRoot":"","sources":["../../../src/v2/providers/CopilotKitProvider.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CopilotKitProvider.vue.d.ts","sourceRoot":"","sources":["../../../src/v2/providers/CopilotKitProvider.vue"],"names":[],"mappings":"AAgzBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAsCnD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,KAAK,EACV,eAAe,EACf,0BAA0B,EAC1B,eAAe,EAGhB,MAAM,UAAU,CAAC;AA0yBlB,QAAA,IAAI,OAAO,IAAW,CAAE;AACxB,KAAK,WAAW,GAAG,EAAE,GACnB;IAAE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,OAAO,KAAK,GAAG,CAAA;CAAE,CAAC;AA4B/C,QAAA,MAAM,eAAe;;;;;;;;;;;wBAh4BrB,CApuBmC;mBAouBnC,CAnuBkC;;;;aAmuBlC,CA3tBiD;eA2tBjD,CA1tBW;wBA0tBX,CA1tBuC;qBA0tBvC,CA1tBsE;;6EAimDpE,CAAC;wBACkB,eAAe,CAAC,OAAO,eAAe,EAAE,WAAW,CAAC;AAAzE,wBAA0E;AAa1E,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KAEV,CAAA;CACD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@copilotkit/vue",
|
|
3
|
-
"version": "1.73.
|
|
3
|
+
"version": "1.73.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Vue 3 components and composables for CopilotKit",
|
|
6
6
|
"keywords": [
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"streamdown-vue": "^1.0.29",
|
|
71
71
|
"zod": "^3.25.75",
|
|
72
72
|
"zod-to-json-schema": "^3.24.5",
|
|
73
|
-
"@copilotkit/core": "1.73.
|
|
74
|
-
"@copilotkit/shared": "1.73.
|
|
75
|
-
"@copilotkit/web-
|
|
76
|
-
"@copilotkit/web-
|
|
73
|
+
"@copilotkit/core": "1.73.1",
|
|
74
|
+
"@copilotkit/shared": "1.73.1",
|
|
75
|
+
"@copilotkit/web-inspector": "1.73.1",
|
|
76
|
+
"@copilotkit/web-components": "1.73.1"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@eslint/js": "^9.39.2",
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
HttpAgent,
|
|
6
6
|
} from "@ag-ui/client";
|
|
7
7
|
import {
|
|
8
|
+
createAttachmentContent,
|
|
8
9
|
DEFAULT_AGENT_ID,
|
|
9
10
|
randomUUID,
|
|
10
11
|
TranscriptionErrorCode,
|
|
@@ -581,14 +582,7 @@ async function handleSubmitMessage(value: string) {
|
|
|
581
582
|
contentParts.push({ type: "text", text: value });
|
|
582
583
|
}
|
|
583
584
|
for (const attachment of readyAttachments) {
|
|
584
|
-
contentParts.push(
|
|
585
|
-
type: attachment.type,
|
|
586
|
-
source: attachment.source,
|
|
587
|
-
metadata: {
|
|
588
|
-
...(attachment.filename ? { filename: attachment.filename } : {}),
|
|
589
|
-
...attachment.metadata,
|
|
590
|
-
},
|
|
591
|
-
} as InputContent);
|
|
585
|
+
contentParts.push(createAttachmentContent(attachment));
|
|
592
586
|
}
|
|
593
587
|
agent.value.addMessage({
|
|
594
588
|
id: randomUUID(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { computed, ref, useSlots, watch } from "vue";
|
|
2
|
+
import { computed, onMounted, ref, useSlots, watch } from "vue";
|
|
3
3
|
import type { Component } from "vue";
|
|
4
4
|
import type {
|
|
5
5
|
ActivityMessage,
|
|
@@ -9,7 +9,12 @@ import type {
|
|
|
9
9
|
ToolMessage,
|
|
10
10
|
UserMessage,
|
|
11
11
|
} from "@ag-ui/core";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DEFAULT_AGENT_ID,
|
|
14
|
+
commitRowKeyStore,
|
|
15
|
+
createRowKeyStore,
|
|
16
|
+
resolveRowRenderKeysById,
|
|
17
|
+
} from "@copilotkit/shared";
|
|
13
18
|
import type {
|
|
14
19
|
InterruptRenderProps,
|
|
15
20
|
VueCustomMessageRendererProps,
|
|
@@ -185,6 +190,24 @@ function deduplicateMessages(messages: Message[]): Message[] {
|
|
|
185
190
|
const deduplicatedMessages = computed(() =>
|
|
186
191
|
deduplicateMessages(props.messages),
|
|
187
192
|
);
|
|
193
|
+
|
|
194
|
+
// Stable per-row keys. Backends can re-key a message mid-stream, and keying
|
|
195
|
+
// rows by the canonical id tears the row down on that swap (the HITL chat
|
|
196
|
+
// flash). See @copilotkit/shared row-render-keys for the mechanism.
|
|
197
|
+
const rowKeyStore = createRowKeyStore();
|
|
198
|
+
const rowRenderKeys = computed(() =>
|
|
199
|
+
resolveRowRenderKeysById(rowKeyStore, deduplicatedMessages.value),
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
// Record what the DOM was patched with, never what a computed merely
|
|
203
|
+
// evaluated: an anchor from an evaluation Vue never patches would re-key a
|
|
204
|
+
// rendered row and tear it down.
|
|
205
|
+
onMounted(() => commitRowKeyStore(rowKeyStore, deduplicatedMessages.value));
|
|
206
|
+
watch(
|
|
207
|
+
deduplicatedMessages,
|
|
208
|
+
(messages) => commitRowKeyStore(rowKeyStore, messages),
|
|
209
|
+
{ flush: "post" },
|
|
210
|
+
);
|
|
188
211
|
const lastMessage = computed(() => props.messages[props.messages.length - 1]);
|
|
189
212
|
const showCursor = computed(
|
|
190
213
|
() => props.isRunning && lastMessage.value?.role !== "reasoning",
|
|
@@ -343,7 +366,10 @@ function resolveToolMessage(
|
|
|
343
366
|
|
|
344
367
|
<template>
|
|
345
368
|
<div data-copilotkit class="cpk:flex cpk:flex-col" v-bind="$attrs">
|
|
346
|
-
<template
|
|
369
|
+
<template
|
|
370
|
+
v-for="message in deduplicatedMessages"
|
|
371
|
+
:key="rowRenderKeys.get(message.id) ?? message.id"
|
|
372
|
+
>
|
|
347
373
|
<slot
|
|
348
374
|
v-if="componentSlots['message-before']"
|
|
349
375
|
name="message-before"
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { defineComponent, ref } from "vue";
|
|
2
|
+
import { render, screen } from "@testing-library/vue";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import type { Message, ToolCall } from "@ag-ui/core";
|
|
5
|
+
import CopilotKitProvider from "../../../providers/CopilotKitProvider.vue";
|
|
6
|
+
import CopilotChatConfigurationProvider from "../../../providers/CopilotChatConfigurationProvider.vue";
|
|
7
|
+
import CopilotChatMessageView from "../CopilotChatMessageView.vue";
|
|
8
|
+
|
|
9
|
+
const AGENT_ID = "default";
|
|
10
|
+
const THREAD_ID = "thread-test";
|
|
11
|
+
|
|
12
|
+
function toolCall(id: string, name = "approve"): ToolCall {
|
|
13
|
+
return { id, type: "function", function: { name, arguments: "{}" } };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function assistantMsg(id: string, content?: string, toolCalls?: ToolCall[]) {
|
|
17
|
+
return { id, role: "assistant" as const, content, toolCalls } as Message;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Renders the view over a reactive message list and returns a setter, so a test
|
|
22
|
+
* can swap the list on the SAME mounted instance. Row teardown-vs-reuse is only
|
|
23
|
+
* observable that way — comparing DOM node identity across an update.
|
|
24
|
+
*/
|
|
25
|
+
function renderWithSwappableMessages(initial: Message[]) {
|
|
26
|
+
const messages = ref<Message[]>(initial);
|
|
27
|
+
|
|
28
|
+
const Host = defineComponent({
|
|
29
|
+
components: {
|
|
30
|
+
CopilotKitProvider,
|
|
31
|
+
CopilotChatConfigurationProvider,
|
|
32
|
+
CopilotChatMessageView,
|
|
33
|
+
},
|
|
34
|
+
setup() {
|
|
35
|
+
return { messages, agentId: AGENT_ID, threadId: THREAD_ID };
|
|
36
|
+
},
|
|
37
|
+
template: `
|
|
38
|
+
<CopilotKitProvider runtime-url="/api/copilotkit">
|
|
39
|
+
<CopilotChatConfigurationProvider :agent-id="agentId" :thread-id="threadId">
|
|
40
|
+
<CopilotChatMessageView :messages="messages" />
|
|
41
|
+
</CopilotChatConfigurationProvider>
|
|
42
|
+
</CopilotKitProvider>
|
|
43
|
+
`,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
render(Host);
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
async setMessages(next: Message[]) {
|
|
50
|
+
messages.value = next;
|
|
51
|
+
// Let Vue flush the patch (and the post-flush prune watcher).
|
|
52
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function assistantRow() {
|
|
58
|
+
return screen.getByTestId("copilot-assistant-message");
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
describe("CopilotChatMessageView stable row keys", () => {
|
|
62
|
+
it("reuses the row when the message id changes but a tool call is stable", async () => {
|
|
63
|
+
const { setMessages } = renderWithSwappableMessages([
|
|
64
|
+
assistantMsg("lc_run--1", "Working...", [toolCall("call_A")]),
|
|
65
|
+
]);
|
|
66
|
+
const node = assistantRow();
|
|
67
|
+
|
|
68
|
+
await setMessages([assistantMsg("resp_1", "Done", [toolCall("call_A")])]);
|
|
69
|
+
|
|
70
|
+
expect(assistantRow()).toBe(node);
|
|
71
|
+
expect(assistantRow().textContent).toContain("Done");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("does not tear down the row when a tool call arrives mid-stream", async () => {
|
|
75
|
+
// Regression guard: keying by the tool-call id instead of recording an
|
|
76
|
+
// override tears the row down here, for every provider.
|
|
77
|
+
const { setMessages } = renderWithSwappableMessages([
|
|
78
|
+
assistantMsg("lc_run--1", "Let me check that..."),
|
|
79
|
+
]);
|
|
80
|
+
const node = assistantRow();
|
|
81
|
+
|
|
82
|
+
await setMessages([
|
|
83
|
+
assistantMsg("lc_run--1", "Let me check that...", [toolCall("call_A")]),
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
expect(assistantRow()).toBe(node);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("survives the whole sequence: text, then tool call, then id re-key", async () => {
|
|
90
|
+
const { setMessages } = renderWithSwappableMessages([
|
|
91
|
+
assistantMsg("lc_run--1", "Let me check..."),
|
|
92
|
+
]);
|
|
93
|
+
const node = assistantRow();
|
|
94
|
+
|
|
95
|
+
await setMessages([
|
|
96
|
+
assistantMsg("lc_run--1", "Let me check...", [toolCall("call_A")]),
|
|
97
|
+
]);
|
|
98
|
+
expect(assistantRow()).toBe(node);
|
|
99
|
+
|
|
100
|
+
await setMessages([assistantMsg("resp_1", "Done", [toolCall("call_A")])]);
|
|
101
|
+
expect(assistantRow()).toBe(node);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("tears down a text-only row on an id change (documented limitation)", async () => {
|
|
105
|
+
const { setMessages } = renderWithSwappableMessages([
|
|
106
|
+
assistantMsg("lc_run--1", "Working..."),
|
|
107
|
+
]);
|
|
108
|
+
const node = assistantRow();
|
|
109
|
+
|
|
110
|
+
await setMessages([assistantMsg("resp_1", "Done")]);
|
|
111
|
+
|
|
112
|
+
expect(assistantRow()).not.toBe(node);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("renders both rows when a tool-call id is shared", async () => {
|
|
116
|
+
renderWithSwappableMessages([
|
|
117
|
+
assistantMsg("a-1", "First", [toolCall("call_X")]),
|
|
118
|
+
assistantMsg("a-2", "Second", [toolCall("call_X")]),
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
const rows = screen.getAllByTestId("copilot-assistant-message");
|
|
122
|
+
expect(rows).toHaveLength(2);
|
|
123
|
+
expect(rows[0]!.textContent).toContain("First");
|
|
124
|
+
expect(rows[1]!.textContent).toContain("Second");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("keeps the first row when the list grows around it", async () => {
|
|
128
|
+
const { setMessages } = renderWithSwappableMessages([
|
|
129
|
+
assistantMsg("lc_run--1", "First", [toolCall("call_A")]),
|
|
130
|
+
]);
|
|
131
|
+
const node = assistantRow();
|
|
132
|
+
|
|
133
|
+
await setMessages([
|
|
134
|
+
assistantMsg("resp_1", "First", [toolCall("call_A")]),
|
|
135
|
+
assistantMsg("lc_run--2", "Second", [toolCall("call_B", "b")]),
|
|
136
|
+
]);
|
|
137
|
+
|
|
138
|
+
expect(screen.getAllByTestId("copilot-assistant-message")[0]).toBe(node);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineComponent, ref, watch } from "vue";
|
|
2
2
|
import type { PropType } from "vue";
|
|
3
3
|
import { screen, fireEvent, waitFor, cleanup } from "@testing-library/vue";
|
|
4
|
-
import { afterEach, describe, expect, it } from "vitest";
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import type { AssistantMessage, Message } from "@ag-ui/core";
|
|
7
7
|
import { ToolCallStatus } from "@copilotkit/core";
|
|
@@ -1100,6 +1100,7 @@ describe("HITL Run Abort", () => {
|
|
|
1100
1100
|
describe("HITL Thread Reconnection Bug", () => {
|
|
1101
1101
|
it("should show executing status when reconnecting to thread with pending HITL", async () => {
|
|
1102
1102
|
const agent = new MockReconnectableAgent();
|
|
1103
|
+
const handlerStarted = vi.fn();
|
|
1103
1104
|
|
|
1104
1105
|
const HITLRenderer = defineComponent({
|
|
1105
1106
|
props: {
|
|
@@ -1116,7 +1117,7 @@ describe("HITL Thread Reconnection Bug", () => {
|
|
|
1116
1117
|
<div data-testid="hitl-tool">
|
|
1117
1118
|
<div data-testid="hitl-status">{{ status }}</div>
|
|
1118
1119
|
<div data-testid="hitl-action">{{ args.action ?? "no-action" }}</div>
|
|
1119
|
-
<button v-if="respond" data-testid="hitl-respond">Respond</button>
|
|
1120
|
+
<button v-if="respond" data-testid="hitl-respond" @click="respond('approved')">Respond</button>
|
|
1120
1121
|
</div>
|
|
1121
1122
|
`,
|
|
1122
1123
|
});
|
|
@@ -1130,6 +1131,19 @@ describe("HITL Thread Reconnection Bug", () => {
|
|
|
1130
1131
|
render: HITLRenderer,
|
|
1131
1132
|
};
|
|
1132
1133
|
useHumanInTheLoop(hitlTool);
|
|
1134
|
+
const { copilotkit } = useCopilotKit();
|
|
1135
|
+
const registered = copilotkit.value.getTool({
|
|
1136
|
+
toolName: "approvalTool",
|
|
1137
|
+
});
|
|
1138
|
+
if (!registered?.handler) {
|
|
1139
|
+
throw new Error("HITL handler was not registered");
|
|
1140
|
+
}
|
|
1141
|
+
const originalHandler = registered.handler;
|
|
1142
|
+
registered.handler = (...args) => {
|
|
1143
|
+
const pending = originalHandler(...args);
|
|
1144
|
+
handlerStarted();
|
|
1145
|
+
return pending;
|
|
1146
|
+
};
|
|
1133
1147
|
return {};
|
|
1134
1148
|
},
|
|
1135
1149
|
template: `<div />`,
|
|
@@ -1196,11 +1210,23 @@ describe("HITL Thread Reconnection Bug", () => {
|
|
|
1196
1210
|
expect(screen.getByTestId("hitl-action").textContent).toBe("delete");
|
|
1197
1211
|
});
|
|
1198
1212
|
|
|
1199
|
-
// Core-level coverage asserts that passive replay does not re-invoke local
|
|
1200
|
-
// frontend handlers for replayed assistant tool calls.
|
|
1201
1213
|
await waitFor(() => {
|
|
1202
|
-
expect(screen.getByTestId("hitl-status").textContent).
|
|
1203
|
-
|
|
1214
|
+
expect(screen.getByTestId("hitl-status").textContent).toBe(
|
|
1215
|
+
ToolCallStatus.Executing,
|
|
1216
|
+
);
|
|
1217
|
+
});
|
|
1218
|
+
// Vue can paint Executing during the awaited execution-start notification,
|
|
1219
|
+
// before core invokes the handler. Wait for the remounted hook to install
|
|
1220
|
+
// its response resolver before dispatching a synchronous test click.
|
|
1221
|
+
await waitFor(() => expect(handlerStarted).toHaveBeenCalledTimes(2));
|
|
1222
|
+
await fireEvent.click(screen.getByTestId("hitl-respond"));
|
|
1223
|
+
await waitFor(() => {
|
|
1224
|
+
expect(agent.messages).toContainEqual(
|
|
1225
|
+
expect.objectContaining({
|
|
1226
|
+
role: "tool",
|
|
1227
|
+
toolCallId,
|
|
1228
|
+
content: "approved",
|
|
1229
|
+
}),
|
|
1204
1230
|
);
|
|
1205
1231
|
});
|
|
1206
1232
|
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { AbstractAgent } from "@ag-ui/client";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
CopilotKitCoreErrorCode,
|
|
4
|
+
CopilotKitMessageFilter,
|
|
5
|
+
} from "@copilotkit/core";
|
|
3
6
|
import type { DebugConfig } from "@copilotkit/shared";
|
|
4
7
|
import type {
|
|
5
8
|
A2UITheme,
|
|
@@ -16,6 +19,30 @@ export interface CopilotKitProviderProps {
|
|
|
16
19
|
runtimeUrl?: string;
|
|
17
20
|
headers?: Record<string, string> | (() => Record<string, string>);
|
|
18
21
|
credentials?: RequestCredentials;
|
|
22
|
+
/**
|
|
23
|
+
* Rewrites the message list sent to runtime agents on every run.
|
|
24
|
+
*
|
|
25
|
+
* CopilotKit sends the whole thread each time. When your agent already
|
|
26
|
+
* stores the conversation, most of that payload is waste, and an agent that
|
|
27
|
+
* merges the inbound list with its own store can show the model every turn
|
|
28
|
+
* twice. Return the messages to send:
|
|
29
|
+
*
|
|
30
|
+
* ```vue
|
|
31
|
+
* <CopilotKitProvider
|
|
32
|
+
* runtime-url="/api/copilotkit"
|
|
33
|
+
* :message-filter="(messages) => messages.slice(-1)"
|
|
34
|
+
* />
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* The filter changes the request body only. The transcript the UI renders is
|
|
38
|
+
* untouched. Broken tool-call pairs are repaired before the request is sent,
|
|
39
|
+
* so a filter this blunt cannot strand a tool result mid-HITL.
|
|
40
|
+
*
|
|
41
|
+
* Agents reached through your CopilotRuntime honor this. An agent your app
|
|
42
|
+
* passes in directly does not, and neither Intelligence runs nor suggestion
|
|
43
|
+
* runs are ever filtered.
|
|
44
|
+
*/
|
|
45
|
+
messageFilter?: CopilotKitMessageFilter;
|
|
19
46
|
defaultThrottleMs?: number;
|
|
20
47
|
publicApiKey?: string;
|
|
21
48
|
publicLicenseKey?: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {
|
|
3
3
|
computed,
|
|
4
|
+
h,
|
|
4
5
|
onMounted,
|
|
5
6
|
provide,
|
|
6
7
|
ref,
|
|
@@ -10,6 +11,7 @@ import {
|
|
|
10
11
|
} from "vue";
|
|
11
12
|
import { z } from "zod";
|
|
12
13
|
import type { AbstractAgent } from "@ag-ui/client";
|
|
14
|
+
import { ToolCallStatus } from "@copilotkit/core";
|
|
13
15
|
import type {
|
|
14
16
|
CopilotKitCoreErrorCode,
|
|
15
17
|
CopilotKitCoreSubscriber,
|
|
@@ -52,6 +54,7 @@ import type {
|
|
|
52
54
|
VueActivityMessageRenderer,
|
|
53
55
|
VueFrontendTool,
|
|
54
56
|
VueToolCallRenderer,
|
|
57
|
+
VueToolCallRendererRenderProps,
|
|
55
58
|
} from "../types";
|
|
56
59
|
|
|
57
60
|
const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
|
|
@@ -70,6 +73,10 @@ const RENDER_ACTIVITY_MESSAGES_STABLE_WARNING =
|
|
|
70
73
|
"renderActivityMessages must be a stable array.";
|
|
71
74
|
const SANDBOX_FUNCTIONS_STABLE_WARNING =
|
|
72
75
|
"openGenerativeUI.sandboxFunctions must be a stable array.";
|
|
76
|
+
// Matches the message React's `useHumanInTheLoop` rejects with, so an aborted
|
|
77
|
+
// interrupt reads the same across frameworks (see #5554).
|
|
78
|
+
const HUMAN_IN_THE_LOOP_ABORTED_MESSAGE =
|
|
79
|
+
"Human-in-the-loop interaction aborted";
|
|
73
80
|
const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follow these design principles inspired by shadcn/ui:
|
|
74
81
|
|
|
75
82
|
- Use a minimal, flat aesthetic. Avoid drop shadows and gradients — rely on subtle borders (1px solid, light gray like #e5e7eb) to define surfaces.
|
|
@@ -228,29 +235,99 @@ watch(
|
|
|
228
235
|
{ immediate: true },
|
|
229
236
|
);
|
|
230
237
|
|
|
238
|
+
/**
|
|
239
|
+
* A human-in-the-loop tool call from the `humanInTheLoop` prop that is waiting
|
|
240
|
+
* on the user. Keyed by tool call id so parallel interrupts on the same tool
|
|
241
|
+
* stay independent.
|
|
242
|
+
*/
|
|
243
|
+
type PendingHumanInTheLoop = {
|
|
244
|
+
resolve: (result: unknown) => void;
|
|
245
|
+
detachAbort?: () => void;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const pendingHumanInTheLoop = new Map<string, PendingHumanInTheLoop>();
|
|
249
|
+
|
|
250
|
+
/** Removes a pending interaction and detaches its abort listener. */
|
|
251
|
+
const takePendingHumanInTheLoop = (key: string) => {
|
|
252
|
+
const pending = pendingHumanInTheLoop.get(key);
|
|
253
|
+
if (!pending) return undefined;
|
|
254
|
+
pending.detachAbort?.();
|
|
255
|
+
pendingHumanInTheLoop.delete(key);
|
|
256
|
+
return pending;
|
|
257
|
+
};
|
|
258
|
+
|
|
231
259
|
const processedHumanInTheLoop = computed(() => {
|
|
232
260
|
const tools: FrontendTool[] = [];
|
|
233
261
|
const renderToolCalls: VueToolCallRenderer<unknown>[] = [];
|
|
234
262
|
|
|
235
263
|
for (const tool of props.humanInTheLoop) {
|
|
236
264
|
tools.push({
|
|
265
|
+
type: "human-in-the-loop",
|
|
237
266
|
name: tool.name,
|
|
238
267
|
description: tool.description,
|
|
239
268
|
parameters: tool.parameters,
|
|
240
269
|
followUp: tool.followUp,
|
|
241
270
|
...(tool.agentId && { agentId: tool.agentId }),
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
271
|
+
// Keep the tool call pending until the render calls `respond`, matching
|
|
272
|
+
// the `useHumanInTheLoop` composable. Resolving immediately made the HITL
|
|
273
|
+
// UI flash and disappear without ever waiting for the user.
|
|
274
|
+
handler: async (_args, context) => {
|
|
275
|
+
const signal = context?.signal;
|
|
276
|
+
const key = context?.toolCall?.id ?? tool.name;
|
|
277
|
+
|
|
278
|
+
return new Promise((resolve, reject) => {
|
|
279
|
+
// Already aborted before the handler ran — reject so core records an
|
|
280
|
+
// explicit error tool result rather than silently resolving empty.
|
|
281
|
+
if (signal?.aborted) {
|
|
282
|
+
reject(new Error(HUMAN_IN_THE_LOOP_ABORTED_MESSAGE));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const pending: PendingHumanInTheLoop = { resolve };
|
|
287
|
+
pendingHumanInTheLoop.set(key, pending);
|
|
288
|
+
|
|
289
|
+
if (signal) {
|
|
290
|
+
const onAbort = () => {
|
|
291
|
+
pendingHumanInTheLoop.delete(key);
|
|
292
|
+
reject(new Error(HUMAN_IN_THE_LOOP_ABORTED_MESSAGE));
|
|
293
|
+
};
|
|
294
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
295
|
+
pending.detachAbort = () => {
|
|
296
|
+
signal.removeEventListener("abort", onAbort);
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
});
|
|
247
300
|
},
|
|
248
301
|
});
|
|
249
302
|
if (tool.render) {
|
|
303
|
+
const ToolComponent = tool.render;
|
|
304
|
+
const render: VueToolCallRenderer<unknown>["render"] = (
|
|
305
|
+
renderProps: VueToolCallRendererRenderProps<unknown>,
|
|
306
|
+
) => {
|
|
307
|
+
const key = renderProps.toolCallId ?? tool.name;
|
|
308
|
+
return h(ToolComponent as Parameters<typeof h>[0], {
|
|
309
|
+
...renderProps,
|
|
310
|
+
// `renderProps.name` is the tool that was actually invoked. It equals
|
|
311
|
+
// `tool.name` for a named registration; for a wildcard (`"*"`) it is
|
|
312
|
+
// the only place the real name exists.
|
|
313
|
+
name: tool.name === "*" ? renderProps.name : tool.name,
|
|
314
|
+
description: tool.description || "",
|
|
315
|
+
agentId: tool.agentId,
|
|
316
|
+
// `respond` is live only while the tool is executing — the one phase
|
|
317
|
+
// with a promise waiting on the user.
|
|
318
|
+
respond:
|
|
319
|
+
renderProps.status === ToolCallStatus.Executing
|
|
320
|
+
? async (result: unknown) => {
|
|
321
|
+
takePendingHumanInTheLoop(key)?.resolve(result);
|
|
322
|
+
}
|
|
323
|
+
: undefined,
|
|
324
|
+
});
|
|
325
|
+
};
|
|
326
|
+
|
|
250
327
|
renderToolCalls.push({
|
|
251
328
|
name: tool.name,
|
|
252
329
|
args: tool.parameters ?? z.any(),
|
|
253
|
-
render
|
|
330
|
+
render,
|
|
254
331
|
...(tool.agentId && { agentId: tool.agentId }),
|
|
255
332
|
} as VueToolCallRenderer<unknown>);
|
|
256
333
|
}
|
|
@@ -407,6 +484,7 @@ const createCopilotKit = () => {
|
|
|
407
484
|
: "auto",
|
|
408
485
|
headers: mergedHeaders.value,
|
|
409
486
|
credentials: props.credentials,
|
|
487
|
+
messageFilter: props.messageFilter,
|
|
410
488
|
properties: resolvedProperties.value,
|
|
411
489
|
agents__unsafe_dev_only: mergedAgents.value,
|
|
412
490
|
tools: allTools.value,
|
|
@@ -525,6 +603,7 @@ function syncRuntimeConfig() {
|
|
|
525
603
|
);
|
|
526
604
|
copilotkit.value.setHeaders(mergedHeaders.value);
|
|
527
605
|
copilotkit.value.setCredentials(props.credentials);
|
|
606
|
+
copilotkit.value.setMessageFilter(props.messageFilter);
|
|
528
607
|
copilotkit.value.setProperties(resolvedProperties.value);
|
|
529
608
|
copilotkit.value.setAgents__unsafe_dev_only(mergedAgents.value);
|
|
530
609
|
copilotkit.value.setDebug(props.debug);
|
|
@@ -536,6 +615,7 @@ watch(
|
|
|
536
615
|
() => chatApiEndpoint.value,
|
|
537
616
|
() => mergedHeaders.value,
|
|
538
617
|
() => props.credentials,
|
|
618
|
+
() => props.messageFilter,
|
|
539
619
|
() => resolvedProperties.value,
|
|
540
620
|
() => mergedAgents.value,
|
|
541
621
|
() => props.useSingleEndpoint,
|