@copilotkit/vue 2.0.0-rc.20 → 2.0.0-rc.21

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.
Files changed (193) hide show
  1. package/dist/index.cjs +1 -1
  2. package/dist/index.mjs +13 -13
  3. package/dist/use-render-activity-message-BAhbpSDh.js +16200 -0
  4. package/dist/use-render-activity-message-BAhbpSDh.js.map +1 -0
  5. package/dist/use-render-activity-message-DJ6q1qHV.cjs +114 -0
  6. package/dist/use-render-activity-message-DJ6q1qHV.cjs.map +1 -0
  7. package/dist/v2/components/A2UIMessageRenderer.d.ts +14 -0
  8. package/dist/v2/components/A2UIMessageRenderer.d.ts.map +1 -1
  9. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts +10 -3
  10. package/dist/v2/components/A2UISurfaceActivityRenderer.vue.d.ts.map +1 -1
  11. package/dist/v2/components/CopilotKitInspector.vue.d.ts +5 -1
  12. package/dist/v2/components/CopilotKitInspector.vue.d.ts.map +1 -1
  13. package/dist/v2/components/MCPAppsActivityRenderer.d.ts.map +1 -1
  14. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts +7 -21
  15. package/dist/v2/components/OpenGenerativeUIRenderer.d.ts.map +1 -1
  16. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts +0 -5
  17. package/dist/v2/components/a2ui/A2UIBuiltInToolCallRenderer.d.ts.map +1 -1
  18. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts +10 -15
  19. package/dist/v2/components/a2ui/A2UICatalogContext.d.ts.map +1 -1
  20. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts +14 -138
  21. package/dist/v2/components/a2ui/A2UIRecoveryStates.d.ts.map +1 -1
  22. package/dist/v2/components/a2ui/catalog.d.ts.map +1 -1
  23. package/dist/v2/components/a2ui/utils.d.ts +3 -15
  24. package/dist/v2/components/a2ui/utils.d.ts.map +1 -1
  25. package/dist/v2/components/a2ui.d.ts +6 -1
  26. package/dist/v2/components/a2ui.d.ts.map +1 -1
  27. package/dist/v2/components/chat/CopilotChat.vue.d.ts.map +1 -1
  28. package/dist/v2/components/chat/CopilotChatAttachmentQueue.vue.d.ts.map +1 -1
  29. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts +4 -8
  30. package/dist/v2/components/chat/CopilotChatAudioRecorder.vue.d.ts.map +1 -1
  31. package/dist/v2/components/chat/CopilotChatInput.vue.d.ts.map +1 -1
  32. package/dist/v2/components/chat/CopilotChatLightbox.vue.d.ts.map +1 -1
  33. package/dist/v2/components/chat/CopilotChatMessageView.vue.d.ts.map +1 -1
  34. package/dist/v2/components/chat/CopilotChatToolCallGroup.vue.d.ts.map +1 -1
  35. package/dist/v2/components/chat/CopilotChatToolCallItem.vue.d.ts.map +1 -1
  36. package/dist/v2/components/chat/CopilotChatToolCallsView.vue.d.ts.map +1 -1
  37. package/dist/v2/components/chat/CopilotChatView.vue.d.ts +1 -1
  38. package/dist/v2/components/chat/CopilotChatView.vue.d.ts.map +1 -1
  39. package/dist/v2/components/chat/CopilotPopupViewInternal.vue.d.ts.map +1 -1
  40. package/dist/v2/components/chat/CopilotSidebarView.vue.d.ts +1 -1
  41. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts +1 -1
  42. package/dist/v2/components/chat/CopilotSidebarViewInternal.vue.d.ts.map +1 -1
  43. package/dist/v2/components/chat/CopilotThreadsDrawer.vue.d.ts.map +1 -1
  44. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts +1 -0
  45. package/dist/v2/components/chat/StreamingMarkdownDefault.vue.d.ts.map +1 -1
  46. package/dist/v2/components/chat/audioRecorder.d.ts +3 -4
  47. package/dist/v2/components/chat/audioRecorder.d.ts.map +1 -1
  48. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts +3 -2
  49. package/dist/v2/components/chat/copilotChatToolCallItemRender.d.ts.map +1 -1
  50. package/dist/v2/components/chat/index.d.ts +6 -6
  51. package/dist/v2/components/chat/tool-call-display-context.d.ts +3 -1
  52. package/dist/v2/components/chat/tool-call-display-context.d.ts.map +1 -1
  53. package/dist/v2/components/chat/tool-call-group-parts.d.ts.map +1 -1
  54. package/dist/v2/components/chat/types.d.ts +1 -1
  55. package/dist/v2/components/chat/types.d.ts.map +1 -1
  56. package/dist/v2/components/chat/use-lightbox.d.ts.map +1 -1
  57. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts +1 -1
  58. package/dist/v2/components/ui/CopilotDropdownMenuContent.vue.d.ts.map +1 -1
  59. package/dist/v2/hooks/use-agent-context.d.ts +2 -3
  60. package/dist/v2/hooks/use-agent-context.d.ts.map +1 -1
  61. package/dist/v2/hooks/use-agent.d.ts +4 -1
  62. package/dist/v2/hooks/use-agent.d.ts.map +1 -1
  63. package/dist/v2/hooks/use-attachments.d.ts +7 -0
  64. package/dist/v2/hooks/use-attachments.d.ts.map +1 -1
  65. package/dist/v2/hooks/use-capabilities.d.ts.map +1 -1
  66. package/dist/v2/hooks/use-component.d.ts +1 -0
  67. package/dist/v2/hooks/use-component.d.ts.map +1 -1
  68. package/dist/v2/hooks/use-configure-suggestions.d.ts +4 -9
  69. package/dist/v2/hooks/use-configure-suggestions.d.ts.map +1 -1
  70. package/dist/v2/hooks/use-default-render-tool.d.ts.map +1 -1
  71. package/dist/v2/hooks/use-human-in-the-loop.d.ts +2 -1
  72. package/dist/v2/hooks/use-human-in-the-loop.d.ts.map +1 -1
  73. package/dist/v2/hooks/use-interrupt.d.ts +0 -1
  74. package/dist/v2/hooks/use-interrupt.d.ts.map +1 -1
  75. package/dist/v2/hooks/use-render-activity-message.d.ts.map +1 -1
  76. package/dist/v2/hooks/use-render-custom-messages.d.ts.map +1 -1
  77. package/dist/v2/hooks/use-suggestions.d.ts.map +1 -1
  78. package/dist/v2/hooks/use-threads.d.ts +0 -8
  79. package/dist/v2/hooks/use-threads.d.ts.map +1 -1
  80. package/dist/v2/index.cjs +1 -1
  81. package/dist/v2/index.mjs +1 -1
  82. package/dist/v2/lib/vue-core.d.ts +12 -11
  83. package/dist/v2/lib/vue-core.d.ts.map +1 -1
  84. package/dist/v2/providers/CopilotChatConfigurationProvider.vue.d.ts.map +1 -1
  85. package/dist/v2/providers/CopilotKitProvider.types.d.ts +9 -124
  86. package/dist/v2/providers/CopilotKitProvider.types.d.ts.map +1 -1
  87. package/dist/v2/providers/CopilotKitProvider.vue.d.ts +9 -10
  88. package/dist/v2/providers/CopilotKitProvider.vue.d.ts.map +1 -1
  89. package/dist/v2/providers/chat-configuration-store-key.d.ts +8 -0
  90. package/dist/v2/providers/chat-configuration-store-key.d.ts.map +1 -0
  91. package/dist/v2/providers/markdown-renderer.d.ts +3 -1
  92. package/dist/v2/providers/markdown-renderer.d.ts.map +1 -1
  93. package/dist/v2/providers/use-inspector-thread-override.d.ts +5 -0
  94. package/dist/v2/providers/use-inspector-thread-override.d.ts.map +1 -1
  95. package/package.json +8 -8
  96. package/src/v2/__tests__/exports.test.ts +10 -0
  97. package/src/v2/__tests__/mocks/web-inspector.ts +6 -0
  98. package/src/v2/__tests__/utils/test-helpers.ts +34 -4
  99. package/src/v2/components/A2UIMessageRenderer.ts +98 -68
  100. package/src/v2/components/A2UISurfaceActivityRenderer.vue +68 -103
  101. package/src/v2/components/CopilotKitInspector.vue +104 -51
  102. package/src/v2/components/MCPAppsActivityRenderer.ts +75 -201
  103. package/src/v2/components/OpenGenerativeUIRenderer.ts +78 -80
  104. package/src/v2/components/__tests__/A2UIMessageRenderer.test.ts +171 -8
  105. package/src/v2/components/__tests__/CopilotKitInspector.test.ts +42 -0
  106. package/src/v2/components/__tests__/OpenGenerativeUIRenderer.test.ts +9 -2
  107. package/src/v2/components/__tests__/OpenGenerativeUIToolRenderer.test.ts +38 -0
  108. package/src/v2/components/a2ui/A2UIBuiltInToolCallRenderer.ts +1 -6
  109. package/src/v2/components/a2ui/A2UICatalogContext.ts +27 -93
  110. package/src/v2/components/a2ui/A2UIRecoveryStates.ts +127 -327
  111. package/src/v2/components/a2ui/catalog.ts +2 -3
  112. package/src/v2/components/a2ui/utils.ts +13 -67
  113. package/src/v2/components/a2ui.ts +14 -21
  114. package/src/v2/components/chat/CopilotChat.vue +136 -324
  115. package/src/v2/components/chat/CopilotChatAttachmentQueue.vue +22 -45
  116. package/src/v2/components/chat/CopilotChatAudioRecorder.vue +19 -246
  117. package/src/v2/components/chat/CopilotChatInput.vue +69 -407
  118. package/src/v2/components/chat/CopilotChatLightbox.vue +10 -31
  119. package/src/v2/components/chat/CopilotChatMessageView.vue +52 -112
  120. package/src/v2/components/chat/CopilotChatToolCallGroup.vue +14 -45
  121. package/src/v2/components/chat/CopilotChatToolCallItem.vue +6 -4
  122. package/src/v2/components/chat/CopilotChatToolCallsView.vue +16 -19
  123. package/src/v2/components/chat/CopilotChatView.vue +28 -23
  124. package/src/v2/components/chat/CopilotPopupViewInternal.vue +21 -97
  125. package/src/v2/components/chat/CopilotSidebarViewInternal.vue +24 -25
  126. package/src/v2/components/chat/CopilotThreadsDrawer.vue +37 -102
  127. package/src/v2/components/chat/StreamingMarkdownDefault.vue +13 -26
  128. package/src/v2/components/chat/__tests__/CopilotChat.test.ts +12 -10
  129. package/src/v2/components/chat/__tests__/CopilotChatAttachmentQueue.test.ts +28 -0
  130. package/src/v2/components/chat/__tests__/CopilotChatInput.test.ts +56 -0
  131. package/src/v2/components/chat/__tests__/CopilotPopupView.test.ts +19 -0
  132. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.ts +32 -8
  133. package/src/v2/components/chat/__tests__/CopilotSidebarView.test.ts +2 -1
  134. package/src/v2/components/chat/__tests__/StreamingMarkdownDefault.test.ts +54 -0
  135. package/src/v2/components/chat/audioRecorder.ts +4 -7
  136. package/src/v2/components/chat/copilotChatToolCallItemRender.ts +22 -71
  137. package/src/v2/components/chat/tool-call-display-context.ts +6 -1
  138. package/src/v2/components/chat/tool-call-group-parts.ts +13 -33
  139. package/src/v2/components/chat/types.ts +1 -1
  140. package/src/v2/components/chat/use-lightbox.ts +15 -33
  141. package/src/v2/hooks/__tests__/use-agent-error-state.test.ts +5 -3
  142. package/src/v2/hooks/__tests__/use-agent-stability.test.ts +25 -4
  143. package/src/v2/hooks/__tests__/use-agent-throttle.test.ts +5 -1
  144. package/src/v2/hooks/__tests__/use-agent.test.ts +6 -3
  145. package/src/v2/hooks/__tests__/use-component.test.ts +21 -0
  146. package/src/v2/hooks/__tests__/use-configure-suggestions.test.ts +30 -1
  147. package/src/v2/hooks/__tests__/use-default-render-tool.test.ts +10 -10
  148. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.ts +4 -0
  149. package/src/v2/hooks/__tests__/use-human-in-the-loop.e2e.test.ts +6 -1
  150. package/src/v2/hooks/__tests__/use-human-in-the-loop.test.ts +187 -12
  151. package/src/v2/hooks/__tests__/use-interrupt.test.ts +97 -0
  152. package/src/v2/hooks/__tests__/use-render-activity-message.test.ts +2 -1
  153. package/src/v2/hooks/__tests__/use-threads.test.ts +48 -6
  154. package/src/v2/hooks/use-agent-context.ts +4 -10
  155. package/src/v2/hooks/use-agent.ts +86 -290
  156. package/src/v2/hooks/use-attachments.ts +42 -166
  157. package/src/v2/hooks/use-capabilities.ts +2 -7
  158. package/src/v2/hooks/use-component.ts +7 -4
  159. package/src/v2/hooks/use-configure-suggestions.ts +28 -218
  160. package/src/v2/hooks/use-default-render-tool.ts +34 -94
  161. package/src/v2/hooks/use-human-in-the-loop.ts +11 -80
  162. package/src/v2/hooks/use-interrupt.ts +29 -308
  163. package/src/v2/hooks/use-render-activity-message.ts +17 -20
  164. package/src/v2/hooks/use-render-custom-messages.ts +20 -63
  165. package/src/v2/hooks/use-suggestions.ts +9 -33
  166. package/src/v2/hooks/use-threads.ts +43 -273
  167. package/src/v2/lib/__tests__/vue-core-renderers.test.ts +42 -0
  168. package/src/v2/lib/vue-core.ts +67 -72
  169. package/src/v2/providers/CopilotChatConfigurationProvider.vue +48 -186
  170. package/src/v2/providers/CopilotKitProvider.types.ts +12 -127
  171. package/src/v2/providers/CopilotKitProvider.vue +188 -402
  172. package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.ts +22 -2
  173. package/src/v2/providers/__tests__/CopilotKitProvider.a2ui.test.ts +19 -1
  174. package/src/v2/providers/__tests__/CopilotKitProvider.config.test.ts +124 -0
  175. package/src/v2/providers/__tests__/CopilotKitProvider.sandboxFunctions.test.ts +4 -1
  176. package/src/v2/providers/__tests__/CopilotKitProvider.test.ts +45 -2
  177. package/src/v2/providers/chat-configuration-store-key.ts +9 -0
  178. package/src/v2/providers/markdown-renderer.ts +7 -1
  179. package/src/v2/providers/use-inspector-thread-override.ts +22 -80
  180. package/vite.config.ts +5 -1
  181. package/vitest.config.ts +12 -7
  182. package/dist/use-render-activity-message-CsWYyd6r.cjs +0 -91
  183. package/dist/use-render-activity-message-CsWYyd6r.cjs.map +0 -1
  184. package/dist/use-render-activity-message-DntKKNdd.js +0 -17418
  185. package/dist/use-render-activity-message-DntKKNdd.js.map +0 -1
  186. package/dist/v2/components/chat/normalize-auto-scroll.d.ts +0 -3
  187. package/dist/v2/components/chat/normalize-auto-scroll.d.ts.map +0 -1
  188. package/dist/v2/lib/is-mobile-viewport.d.ts +0 -2
  189. package/dist/v2/lib/is-mobile-viewport.d.ts.map +0 -1
  190. package/src/v2/components/__tests__/A2UICatalogContext.test.ts +0 -63
  191. package/src/v2/components/a2ui/__tests__/A2UIRecoveryStates.test.ts +0 -175
  192. package/src/v2/components/chat/normalize-auto-scroll.ts +0 -3
  193. package/src/v2/lib/is-mobile-viewport.ts +0 -5
@@ -1,15 +1,12 @@
1
1
  import { computed, shallowRef, toValue, triggerRef, watch } from "vue";
2
2
  import type { MaybeRefOrGetter } from "vue";
3
- import { DEFAULT_AGENT_ID } from "@copilotkit/shared";
4
3
  import type { AbstractAgent } from "@ag-ui/client";
5
4
  import {
6
- ProxiedCopilotRuntimeAgent,
7
- CopilotKitCoreRuntimeConnectionStatus,
8
- ɵisHttpAgent,
9
- } from "@copilotkit/core";
10
- import type {
11
- CopilotRuntimeTransport,
12
- SubscribeToAgentSubscriber,
5
+ ɵgetAgentResolver,
6
+ ɵresolveAgentId,
7
+ ɵresolveAgentThreadId,
8
+ ɵsubscribeToAgentUpdates,
9
+ ɵvalidateAgentBinding,
13
10
  } from "@copilotkit/core";
14
11
  import { useCopilotKit } from "../providers/useCopilotKit";
15
12
  import { useCopilotChatConfiguration } from "../providers/useCopilotChatConfiguration";
@@ -126,7 +123,9 @@ export type UseAgentProps = UseAgentPropsBase &
126
123
  *
127
124
  * It returns a reactive `agent` ref that updates when the selected agent
128
125
  * changes, when runtime connection state changes, or when subscribed update
129
- * events fire.
126
+ * events fire, and an `isReady` ref: `false` while `agent` is a provisional
127
+ * stand-in used before the runtime `/info` sync lands (or after it failed),
128
+ * `true` once it is the real agent.
130
129
  *
131
130
  * @example
132
131
  * ```ts
@@ -134,348 +133,145 @@ export type UseAgentProps = UseAgentPropsBase &
134
133
  * ```
135
134
  */
136
135
  export function useAgent(props: UseAgentProps = {}) {
137
- // `threadId`, `runtimeAgentId` and an explicit `agentId` are all-or-nothing.
138
- // UseAgentProps rejects a partial set at compile time; these are the runtime
139
- // backstop for callers TypeScript doesn't reach (plain JS, `as any`). Same
140
- // three checks, same messages, as React's useAgent.
141
- const hasThreadId = props.threadId !== undefined;
142
- const hasRuntimeAgentId = props.runtimeAgentId !== undefined;
143
- const hasAgentId = props.agentId !== undefined;
144
-
145
- if (hasThreadId && !hasRuntimeAgentId) {
146
- throw new Error(
147
- "useAgent: `threadId` requires `runtimeAgentId`. A threadId is written onto a " +
148
- "single agent, but an agent resolved by agentId alone is shared, so scoping a " +
149
- "thread to it would clobber other useAgent callers. Pass a distinct local `agentId` " +
150
- 'and the runtime agent to route to, e.g. useAgent({ agentId: "chat-1", ' +
151
- 'runtimeAgentId: "assistant", threadId }).',
152
- );
153
- }
154
-
155
- if (hasRuntimeAgentId && !hasThreadId) {
156
- throw new Error(
157
- "useAgent: `runtimeAgentId` requires `threadId`. A proxied agent exists to scope a " +
158
- "thread to a private instance; without a threadId it behaves like the shared agent " +
159
- "while adding a registration and a local agentId to keep unique. Either pass the " +
160
- "thread, or bind to the agent directly with useAgent({ agentId }).",
161
- );
162
- }
163
-
164
- if (hasRuntimeAgentId && !hasAgentId) {
165
- throw new Error(
166
- "useAgent: `runtimeAgentId` requires an explicit `agentId`. The proxied agent is " +
167
- "registered under `agentId`, and the usual fallbacks (chat configuration, then " +
168
- `"${DEFAULT_AGENT_ID}") name agents that already exist — registering over one throws ` +
169
- "or shadows it. Pick a local id for this hook, e.g. " +
170
- 'useAgent({ agentId: "chat-1", runtimeAgentId: "assistant", threadId }).',
171
- );
172
- }
173
-
174
- // After the guards, all three are present or none are.
175
- const isThreadScoped = hasRuntimeAgentId;
136
+ // Runtime backstop for the all-or-nothing rule UseAgentProps enforces at
137
+ // compile time (plain JS, `as any`). Same checks and messages as React.
138
+ ɵvalidateAgentBinding({
139
+ agentId: toValue(props.agentId),
140
+ threadId: toValue(props.threadId),
141
+ runtimeAgentId: toValue(props.runtimeAgentId),
142
+ });
143
+ const isThreadScoped = props.runtimeAgentId !== undefined;
176
144
 
177
145
  const chatConfig = useCopilotChatConfiguration();
178
- const agentId = computed(
179
- () =>
180
- toValue(props.agentId) ?? chatConfig.value?.agentId ?? DEFAULT_AGENT_ID,
146
+ const agentId = computed(() =>
147
+ ɵresolveAgentId({
148
+ agentId: toValue(props.agentId),
149
+ chatAgentId: chatConfig.value?.agentId,
150
+ }),
181
151
  );
182
152
  const runtimeAgentId = computed(() =>
183
153
  isThreadScoped ? toValue(props.runtimeAgentId) : undefined,
184
154
  );
185
- // Mirrors React: an explicit `threadId` prop wins, otherwise the chat
186
- // configuration's thread, gated on `hasExplicitThreadId` so a
187
- // ThreadsProvider-minted placeholder UUID doesn't overwrite the agent's own
188
- // auto-minted one (both are random and useless to the backend).
189
- const resolvedThreadId = computed(
190
- () =>
191
- toValue(props.threadId) ??
192
- (chatConfig.value?.hasExplicitThreadId
193
- ? chatConfig.value.threadId
194
- : undefined),
155
+ const resolvedThreadId = computed(() =>
156
+ ɵresolveAgentThreadId({
157
+ threadId: toValue(props.threadId),
158
+ chatThreadId: chatConfig.value?.threadId,
159
+ chatHasExplicitThreadId: chatConfig.value?.hasExplicitThreadId,
160
+ }),
195
161
  );
196
162
  const { copilotkit } = useCopilotKit();
163
+ const resolver = computed(() => ɵgetAgentResolver(copilotkit.value));
197
164
  const updateFlags = computed(() => props.updates ?? ALL_UPDATES);
198
165
  // Read the provider-level default so it appears in the subscribe watcher
199
- // deps. `subscribeToAgentWithOptions` reads it from the core instance, but
200
- // Vue still needs the dep to know when to resubscribe (same role it plays
201
- // in React's `useEffect` dep array).
166
+ // deps: core reads it, but Vue needs the dep to resubscribe.
202
167
  const providerThrottleMs = computed(() => copilotkit.value.defaultThrottleMs);
203
168
  const hookThrottleMs = computed(() => toValue(props.throttleMs));
204
169
 
205
170
  const agent = shallowRef<AbstractAgent | null>(null);
206
- const subscriptionAgent = shallowRef<AbstractAgent | null>(null);
207
- const provisionalAgentCache = new Map<string, ProxiedCopilotRuntimeAgent>();
208
-
209
- const createProvisionalAgent = (
210
- id: string,
211
- runtimeUrl: string,
212
- transport: CopilotRuntimeTransport,
213
- ) => {
214
- const provisional = new ProxiedCopilotRuntimeAgent({
215
- runtimeUrl,
216
- agentId: id,
217
- transport,
218
- runtimeMode: "pending",
219
- });
220
- // Never invokes the headers builder — installs `ɵruntimeFetch` and
221
- // own-only headers on this proxied agent, so a request it actually sends
222
- // resolves the current headers at send time (#1937).
223
- copilotkit.value.applyHeadersToAgent(provisional);
224
- return provisional;
225
- };
171
+ const isReady = shallowRef(false);
172
+ const resolverRevision = shallowRef(0);
173
+ watch(
174
+ resolver,
175
+ (current, _old, onCleanup) => {
176
+ onCleanup(
177
+ current.subscribe(() => {
178
+ resolverRevision.value = current.getSnapshot();
179
+ }),
180
+ );
181
+ },
182
+ { immediate: true },
183
+ );
226
184
 
227
- // On the thread-scoped path this hook owns an agent registered under
228
- // `agentId` that routes to `runtimeAgentId`. Register/unregister as one
229
- // balanced watcher — the cleanup runs both when the ids change and when the
230
- // scope is disposed. Mirrors React's registration effect, including its dep
231
- // set (core identity plus the two ids).
232
- const registeredProxy = shallowRef<AbstractAgent | null>(null);
185
+ // Thread-scoped path: this hook owns a proxied agent registered under
186
+ // `agentId` that routes to `runtimeAgentId`. The cleanup unregisters both
187
+ // when the ids change and when the scope is disposed.
233
188
  if (isThreadScoped) {
234
189
  watch(
235
- [agentId, runtimeAgentId, () => copilotkit.value],
236
- ([id, rtId], _old, onCleanup) => {
237
- const { agent: proxy, unregister } =
238
- copilotkit.value.registerProxiedAgent({
239
- agentId: id as string,
240
- runtimeAgentId: rtId as string,
241
- });
242
- provisionalAgentCache.delete(id as string);
243
- registeredProxy.value = proxy;
244
- onCleanup(() => {
245
- unregister();
246
- registeredProxy.value = null;
247
- });
190
+ [agentId, runtimeAgentId, resolver],
191
+ ([id, rtId, current], _old, onCleanup) => {
192
+ if (rtId === undefined) return;
193
+ onCleanup(current.bindProxy({ agentId: id, runtimeAgentId: rtId }));
248
194
  },
249
195
  { immediate: true },
250
196
  );
251
197
  }
252
198
 
253
199
  const resolveAgent = () => {
254
- const id = agentId.value;
255
- const core = copilotkit.value;
256
-
257
- // Proxied path: this hook registered its own agent, so bypass the shared
258
- // registry lookup. Until registration lands, hand back a provisional proxy
259
- // so `agent` is never null and its identity stays stable.
260
- if (isThreadScoped) {
261
- const proxy = registeredProxy.value;
262
- if (proxy) {
263
- provisionalAgentCache.delete(id);
264
- const shouldForceUpdate = agent.value === proxy;
265
- agent.value = proxy;
266
- subscriptionAgent.value = proxy;
267
- if (shouldForceUpdate) triggerRef(agent);
268
- return;
269
- }
270
-
271
- const cachedProxy = provisionalAgentCache.get(id);
272
- if (cachedProxy) {
273
- core.applyHeadersToAgent(cachedProxy);
274
- agent.value = cachedProxy;
275
- subscriptionAgent.value = cachedProxy;
276
- return;
277
- }
278
-
279
- const provisionalProxy = new ProxiedCopilotRuntimeAgent({
280
- runtimeUrl: core.runtimeUrl,
281
- agentId: id,
282
- runtimeAgentId: runtimeAgentId.value as string,
283
- transport: core.runtimeTransport,
284
- runtimeMode: "pending",
285
- });
286
- core.applyHeadersToAgent(provisionalProxy);
287
- provisionalAgentCache.set(id, provisionalProxy);
288
- agent.value = provisionalProxy;
289
- subscriptionAgent.value = provisionalProxy;
290
- return;
291
- }
292
-
293
- const existing = core.getAgent(id);
294
- if (existing) {
295
- provisionalAgentCache.delete(id);
296
-
297
- const shouldForceUpdate = agent.value === existing;
298
- agent.value = existing;
299
- subscriptionAgent.value = existing;
300
- if (shouldForceUpdate) {
301
- triggerRef(agent);
302
- }
303
- return;
304
- }
305
-
306
- const isRuntimeConfigured = core.runtimeUrl !== undefined;
307
- const status = core.runtimeConnectionStatus;
308
-
309
- if (
310
- isRuntimeConfigured &&
311
- (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected ||
312
- status === CopilotKitCoreRuntimeConnectionStatus.Connecting ||
313
- status === CopilotKitCoreRuntimeConnectionStatus.Error)
314
- ) {
315
- const cached = provisionalAgentCache.get(id);
316
- if (cached) {
317
- core.applyHeadersToAgent(cached);
318
- agent.value = cached;
319
- subscriptionAgent.value = cached;
320
- return;
321
- }
322
-
323
- const provisional = createProvisionalAgent(
324
- id,
325
- core.runtimeUrl!,
326
- core.runtimeTransport,
327
- );
328
- provisionalAgentCache.set(id, provisional);
329
- agent.value = provisional;
330
- subscriptionAgent.value = provisional;
200
+ const resolved = resolver.value.resolve({
201
+ agentId: agentId.value,
202
+ runtimeAgentId: runtimeAgentId.value,
203
+ caller: "useAgent",
204
+ });
205
+ isReady.value = resolved.isReady;
206
+ if (agent.value === resolved.agent) {
207
+ triggerRef(agent);
331
208
  return;
332
209
  }
333
-
334
- const knownAgents = Object.keys(core.agents ?? {});
335
- const runtimePart = isRuntimeConfigured
336
- ? `runtimeUrl=${core.runtimeUrl}`
337
- : "no runtimeUrl";
338
- throw new Error(
339
- `useAgent: Agent '${id}' not found after runtime sync (${runtimePart}). ` +
340
- (knownAgents.length
341
- ? `Known agents: [${knownAgents.join(", ")}]`
342
- : "No agents registered.") +
343
- " Verify your runtime /info and/or agents__unsafe_dev_only.",
344
- );
210
+ agent.value = resolved.agent;
345
211
  };
346
212
 
347
213
  // Keyed on `ɵheadersGeneration`, not header VALUES: a builder's returned
348
214
  // token can change on every resolution without a new source ever being
349
- // set (a run refreshing the snapshot), and this must not re-run
350
- // `resolveAgent` (and force-trigger `agent`) on that (#1937).
351
- // A genuine source change (a real `setHeaders()` call) still re-runs it,
352
- // refreshing a cached provisional's headers via the branches above.
215
+ // set, and this must not re-run `resolveAgent` on that (#1937).
353
216
  //
354
- // `registeredProxy` is wrapped as a getter (`() => registeredProxy.value`)
355
- // rather than passed directly: Vue's multi-source `watch` sets
356
- // `forceTrigger = true` for the WHOLE array whenever any raw element is
357
- // itself a shallowRef/reactive object, which makes the callback run on
358
- // ANY dependency dirtying regardless of whether a source's value actually
359
- // changed — silently defeating the `ɵheadersGeneration` rekey above (and
360
- // every other source's diffing) the moment `registeredProxy` is present.
361
- // A getter reads the same value without contributing to that flag.
217
+ // Sources are getters, not refs: Vue's multi-source `watch` force-triggers
218
+ // the whole array when any raw element is a shallowRef, which would defeat
219
+ // the diffing of every other source.
362
220
  watch(
363
221
  [
364
222
  agentId,
365
- () => registeredProxy.value,
223
+ () => resolverRevision.value,
366
224
  () => copilotkit.value.agents,
367
225
  () => copilotkit.value.runtimeConnectionStatus,
368
226
  () => copilotkit.value.runtimeUrl,
369
227
  () => copilotkit.value.runtimeTransport,
370
228
  () => copilotkit.value.ɵheadersGeneration,
229
+ () => copilotkit.value.credentials,
371
230
  ],
372
231
  resolveAgent,
373
232
  { immediate: true },
374
233
  );
375
234
 
376
- // Pin the resolved thread onto the current agent. AbstractAgent auto-mints a
377
- // UUID when none is given, so without this the agent would ship its own random
378
- // id in /agent/run, /agent/connect and /agent/stop. Deps are deliberately just
379
- // the agent and the thread — matching React — so status/header churn cannot
380
- // re-fire this and overwrite a thread `CopilotChat` pinned for its own chat.
381
- // `() => agent.value`, not `agent`: Vue sets `forceTrigger` when any array
382
- // watch source is a shallow ref, which would re-run this on every
383
- // `triggerRef(agent)` — i.e. every streamed message — and re-pin a thread that
384
- // `CopilotChat` may have deliberately overridden for the chat it renders. A
385
- // getter fires only when the identity actually changes.
235
+ // Pin the resolved thread onto the current agent. Deps are just the agent
236
+ // identity and the thread, so status or header churn cannot re-pin a thread
237
+ // `CopilotChat` set for the chat it renders.
386
238
  watch(
387
239
  [() => agent.value, resolvedThreadId],
388
240
  ([currentAgent, threadId]) => {
389
241
  if (!currentAgent || !threadId) return;
390
- currentAgent.threadId = threadId as string;
242
+ currentAgent.threadId = threadId;
391
243
  },
392
244
  { immediate: true },
393
245
  );
394
246
 
395
- // Keyed on `ɵheadersGeneration`, not header VALUES: a builder's returned
396
- // token can change on every resolution without a new source ever being set,
397
- // and this watcher must not re-fire on that (see #1937).
398
247
  watch(
399
- [subscriptionAgent, () => copilotkit.value.ɵheadersGeneration],
248
+ [
249
+ () => agent.value,
250
+ () => copilotkit.value.ɵheadersGeneration,
251
+ () => copilotkit.value.credentials,
252
+ ],
400
253
  ([currentAgent]) => {
401
- if (ɵisHttpAgent(currentAgent)) {
402
- copilotkit.value.applyHeadersToAgent(currentAgent);
403
- }
254
+ if (currentAgent) resolver.value.refreshRequestSettings(currentAgent);
404
255
  },
405
256
  { immediate: true },
406
257
  );
407
258
 
408
- // Subscribe through the shared `CopilotKitCore.subscribeToAgentWithOptions`
409
- // API. Core owns:
410
- // - shared leading+trailing throttle window across `onMessagesChanged`
411
- // and `onStateChanged` (parity with React)
412
- // - safeCall-guarded callbacks (errors in subscribers never poison the
413
- // agent notification loop)
414
- // - validation/fallback for invalid `throttleMs`
415
- // - `onRunErrorEvent` in the run-status callback set
416
- //
417
- // The hook only schedules a microtask-batched `triggerRef(agent)` so
418
- // multiple synchronous notifications (e.g. state + run-status firing in
419
- // the same tick) coalesce into a single Vue re-render — matching React's
420
- // `queueMicrotask`-batched forceUpdate strategy.
259
+ // Core owns throttling, safe callbacks and `throttleMs` validation; the
260
+ // re-render is microtask-batched so notifications in one tick coalesce.
421
261
  watch(
422
- [subscriptionAgent, updateFlags, hookThrottleMs, providerThrottleMs],
423
- ([a, flags], _old, onCleanup) => {
424
- const f = flags as UseAgentUpdate[];
425
- if (!a || f.length === 0) return;
426
-
427
- let active = true;
428
- let batchScheduled = false;
429
- const batchedRefresh = () => {
430
- if (!active) return;
431
- if (!batchScheduled) {
432
- batchScheduled = true;
433
- queueMicrotask(() => {
434
- batchScheduled = false;
435
- if (active) {
436
- triggerRef(agent);
437
- }
438
- });
439
- }
440
- };
441
-
442
- const handlers: SubscribeToAgentSubscriber = {};
443
-
444
- if (f.includes(UseAgentUpdate.OnMessagesChanged)) {
445
- // Messages fire immediately (no microtask indirection) so shared-
446
- // window throttling in core sees an unadorned callback. Matches
447
- // React's `handlers.onMessagesChanged = forceUpdate`.
448
- handlers.onMessagesChanged = () => {
449
- if (active) triggerRef(agent);
450
- };
451
- }
452
-
453
- if (f.includes(UseAgentUpdate.OnStateChanged)) {
454
- handlers.onStateChanged = batchedRefresh;
455
- }
456
-
457
- if (f.includes(UseAgentUpdate.OnRunStatusChanged)) {
458
- handlers.onRunInitialized = batchedRefresh;
459
- handlers.onRunFinalized = batchedRefresh;
460
- handlers.onRunFailed = batchedRefresh;
461
- // Protocol-level RUN_ERROR event (distinct from `onRunFailed`
462
- // which handles local exceptions like network errors).
463
- handlers.onRunErrorEvent = batchedRefresh;
464
- }
465
-
466
- const subscription = copilotkit.value.subscribeToAgentWithOptions(
467
- a as AbstractAgent,
468
- handlers,
469
- { throttleMs: toValue(props.throttleMs) },
262
+ [() => agent.value, updateFlags, hookThrottleMs, providerThrottleMs],
263
+ ([currentAgent, flags], _old, onCleanup) => {
264
+ if (!currentAgent) return;
265
+ onCleanup(
266
+ ɵsubscribeToAgentUpdates(copilotkit.value, currentAgent, {
267
+ updates: flags,
268
+ throttleMs: toValue(props.throttleMs),
269
+ onUpdate: () => triggerRef(agent),
270
+ }),
470
271
  );
471
-
472
- onCleanup(() => {
473
- active = false;
474
- subscription.unsubscribe();
475
- });
476
272
  },
477
273
  { immediate: true },
478
274
  );
479
275
 
480
- return { agent };
276
+ return { agent, isReady };
481
277
  }