@assistant-ui/react-ag-ui 0.0.47 → 0.0.49

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 (41) hide show
  1. package/dist/agUiExtras.d.ts +1 -1
  2. package/dist/agUiExtras.d.ts.map +1 -1
  3. package/dist/agUiExtras.js +1 -1
  4. package/dist/agUiExtras.js.map +1 -1
  5. package/dist/hooks.d.ts +6 -1
  6. package/dist/hooks.d.ts.map +1 -1
  7. package/dist/hooks.js +10 -1
  8. package/dist/hooks.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +2 -2
  11. package/dist/runtime/AgUiThreadRuntimeCore.d.ts +3 -0
  12. package/dist/runtime/AgUiThreadRuntimeCore.d.ts.map +1 -1
  13. package/dist/runtime/AgUiThreadRuntimeCore.js +78 -16
  14. package/dist/runtime/AgUiThreadRuntimeCore.js.map +1 -1
  15. package/dist/runtime/adapter/conversions.d.ts.map +1 -1
  16. package/dist/runtime/adapter/conversions.js +63 -1
  17. package/dist/runtime/adapter/conversions.js.map +1 -1
  18. package/dist/runtime/adapter/run-aggregator.d.ts +6 -1
  19. package/dist/runtime/adapter/run-aggregator.d.ts.map +1 -1
  20. package/dist/runtime/adapter/run-aggregator.js +57 -1
  21. package/dist/runtime/adapter/run-aggregator.js.map +1 -1
  22. package/dist/runtime/event-parser.js +5 -2
  23. package/dist/runtime/event-parser.js.map +1 -1
  24. package/dist/runtime/mcp-tool-result.d.ts.map +1 -1
  25. package/dist/runtime/mcp-tool-result.js +6 -3
  26. package/dist/runtime/mcp-tool-result.js.map +1 -1
  27. package/dist/runtime/types.d.ts +3 -0
  28. package/dist/runtime/types.d.ts.map +1 -1
  29. package/dist/useAgUiRuntime.js +2 -1
  30. package/dist/useAgUiRuntime.js.map +1 -1
  31. package/package.json +5 -4
  32. package/src/agUiExtras.ts +1 -1
  33. package/src/hooks.ts +14 -0
  34. package/src/index.ts +1 -0
  35. package/src/runtime/AgUiThreadRuntimeCore.ts +132 -16
  36. package/src/runtime/adapter/conversions.ts +107 -1
  37. package/src/runtime/adapter/run-aggregator.ts +82 -0
  38. package/src/runtime/event-parser.ts +12 -5
  39. package/src/runtime/mcp-tool-result.ts +8 -6
  40. package/src/runtime/types.ts +3 -0
  41. package/src/useAgUiRuntime.ts +1 -0
@@ -1,6 +1,6 @@
1
1
  import { AgUiRuntimeExtras } from "./runtime/types.js";
2
2
  //#region src/agUiExtras.d.ts
3
- declare const agUiExtras: import("@assistant-ui/core/internal").RuntimeExtras<AgUiRuntimeExtras>;
3
+ declare const agUiExtras: import("@assistant-ui/core/react").RuntimeExtras<AgUiRuntimeExtras>;
4
4
  //#endregion
5
5
  export { agUiExtras };
6
6
  //# sourceMappingURL=agUiExtras.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agUiExtras.d.ts","names":[],"sources":["../src/agUiExtras.ts"],"mappings":";;cAGa,kDAAU,cAAA"}
1
+ {"version":3,"file":"agUiExtras.d.ts","names":[],"sources":["../src/agUiExtras.ts"],"mappings":";;cAGa,+CAAU,cAAA"}
@@ -1,4 +1,4 @@
1
- import { createRuntimeExtras } from "@assistant-ui/core/internal";
1
+ import { createRuntimeExtras } from "@assistant-ui/core/react";
2
2
  //#region src/agUiExtras.ts
3
3
  const agUiExtras = createRuntimeExtras("useAgUiRuntime");
4
4
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"agUiExtras.js","names":[],"sources":["../src/agUiExtras.ts"],"sourcesContent":["import { createRuntimeExtras } from \"@assistant-ui/core/internal\";\nimport type { AgUiRuntimeExtras } from \"./runtime/types\";\n\nexport const agUiExtras =\n createRuntimeExtras<AgUiRuntimeExtras>(\"useAgUiRuntime\");\n"],"mappings":";;AAGA,MAAa,aACX,oBAAuC,gBAAgB"}
1
+ {"version":3,"file":"agUiExtras.js","names":[],"sources":["../src/agUiExtras.ts"],"sourcesContent":["import { createRuntimeExtras } from \"@assistant-ui/core/react\";\nimport type { AgUiRuntimeExtras } from \"./runtime/types\";\n\nexport const agUiExtras =\n createRuntimeExtras<AgUiRuntimeExtras>(\"useAgUiRuntime\");\n"],"mappings":";;AAGA,MAAa,aACX,oBAAuC,gBAAgB"}
package/dist/hooks.d.ts CHANGED
@@ -7,6 +7,11 @@ import { ReadonlyJSONValue } from "assistant-stream/utils";
7
7
  * array when no interrupts are pending, so consumers can `.map` without a guard.
8
8
  */
9
9
  declare const useAgUiInterrupts: () => readonly AgUiInterrupt[];
10
+ /**
11
+ * Returns a stable function that sends an A2UI action back to the agent and
12
+ * resumes the run.
13
+ */
14
+ declare const useAgUiSendA2uiAction: () => (action: Record<string, unknown>) => void;
10
15
  /**
11
16
  * Returns a function that submits responses (each `resolved` or `cancelled`)
12
17
  * for the pending AG-UI interrupts and resumes the run.
@@ -29,5 +34,5 @@ declare const useAgUiSteerAway: () => (message: CreateAppendMessage, responses?:
29
34
  declare const useAgUiState: <TState = ReadonlyJSONValue>() => TState | undefined;
30
35
  declare const useAgUiSetState: <TState = ReadonlyJSONValue>() => (next: TState | ((prev: TState | undefined) => TState)) => void;
31
36
  //#endregion
32
- export { useAgUiInterrupts, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
37
+ export { useAgUiInterrupts, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
33
38
  //# sourceMappingURL=hooks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;;;;;;cAca,kCAAiC;;;;;cAOjC,wCAEH,oBAAoB,sBAAoB;;;;;;;;;;;;;;cAiBrC,yBAGT,SAAS,qBACT,qBAAqB,sBACpB;cAGQ,eAAgB,SAAS,wBAClC;cAIS,kBAAmB,SAAS,yBAE/B,MAAM,WAAW,MAAM,uBAAuB"}
1
+ {"version":3,"file":"hooks.d.ts","names":[],"sources":["../src/hooks.ts"],"mappings":";;;;;;;;cAea,kCAAiC;;;;;cAOjC,8BAAqB,QAGrB;;;;;cAUA,wCAEH,oBAAoB,sBAAoB;;;;;;;;;;;;;;cAiBrC,yBAGT,SAAS,qBACT,qBAAqB,sBACpB;cAGQ,eAAgB,SAAS,wBAClC;cAIS,kBAAmB,SAAS,yBAE/B,MAAM,WAAW,MAAM,uBAAuB"}
package/dist/hooks.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { agUiExtras } from "./agUiExtras.js";
3
+ import { useCallback } from "react";
3
4
  import { useAui } from "@assistant-ui/store";
4
5
  //#region src/hooks.ts
5
6
  const EMPTY_INTERRUPTS = [];
@@ -9,6 +10,14 @@ const EMPTY_INTERRUPTS = [];
9
10
  */
10
11
  const useAgUiInterrupts = () => agUiExtras.use((e) => e.interrupts, EMPTY_INTERRUPTS);
11
12
  /**
13
+ * Returns a stable function that sends an A2UI action back to the agent and
14
+ * resumes the run.
15
+ */
16
+ const useAgUiSendA2uiAction = () => {
17
+ const aui = useAui();
18
+ return useCallback((action) => agUiExtras.get(aui).sendA2uiAction(action), [aui]);
19
+ };
20
+ /**
12
21
  * Returns a function that submits responses (each `resolved` or `cancelled`)
13
22
  * for the pending AG-UI interrupts and resumes the run.
14
23
  */
@@ -39,6 +48,6 @@ const useAgUiSetState = () => {
39
48
  return (next) => agUiExtras.get(aui).setState(next);
40
49
  };
41
50
  //#endregion
42
- export { useAgUiInterrupts, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
51
+ export { useAgUiInterrupts, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
43
52
 
44
53
  //# sourceMappingURL=hooks.js.map
package/dist/hooks.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.js","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport { useAui } from \"@assistant-ui/store\";\nimport type { CreateAppendMessage } from \"@assistant-ui/core\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport { agUiExtras } from \"./agUiExtras\";\nimport type { AgUiInterrupt, AgUiResumeEntry } from \"./runtime/types\";\n\nconst EMPTY_INTERRUPTS: readonly AgUiInterrupt[] = [];\n\n/**\n * Read the pending AG-UI interrupts on the current thread. Returns an empty\n * array when no interrupts are pending, so consumers can `.map` without a guard.\n */\nexport const useAgUiInterrupts = (): readonly AgUiInterrupt[] =>\n agUiExtras.use((e) => e.interrupts, EMPTY_INTERRUPTS);\n\n/**\n * Returns a function that submits responses (each `resolved` or `cancelled`)\n * for the pending AG-UI interrupts and resumes the run.\n */\nexport const useAgUiSubmitInterruptResponses = () => {\n const aui = useAui();\n return (responses: readonly AgUiResumeEntry[]): Promise<void> =>\n agUiExtras.get(aui).submitInterruptResponses(responses);\n};\n\n/**\n * Returns a function that discards the pending AG-UI interrupts or pending\n * client-side tool calls and appends the given user message, starting a fresh\n * run. Use this when the user sends a new message instead of resolving them:\n * every open interrupt is reported to the agent as cancelled, and every\n * unresolved client-side tool call receives an error result. The message\n * accepts a plain string or a partial `AppendMessage` (the parent defaults to\n * the current head). Pass `responses` to override the status of specific\n * interrupts; the rest still default to cancelled. `responses` throws when\n * tool calls rather than interrupts are pending. Unlike the\n * `autoCancelPendingToolCalls` runtime option, this hook cancels regardless\n * of that option's value.\n */\nexport const useAgUiSteerAway = () => {\n const aui = useAui();\n return (\n message: CreateAppendMessage,\n responses?: readonly AgUiResumeEntry[],\n ): Promise<void> => agUiExtras.get(aui).steerAway(message, responses);\n};\n\nexport const useAgUiState = <TState = ReadonlyJSONValue>():\n | TState\n | undefined =>\n agUiExtras.use((e) => e.state as TState | undefined, undefined);\n\nexport const useAgUiSetState = <TState = ReadonlyJSONValue>() => {\n const aui = useAui();\n return (next: TState | ((prev: TState | undefined) => TState)): void =>\n agUiExtras\n .get(aui)\n .setState(\n next as\n | ReadonlyJSONValue\n | ((prev: ReadonlyJSONValue | undefined) => ReadonlyJSONValue),\n );\n};\n"],"mappings":";;;;AAQA,MAAM,mBAA6C,CAAC;;;;;AAMpD,MAAa,0BACX,WAAW,KAAK,MAAM,EAAE,YAAY,gBAAgB;;;;;AAMtD,MAAa,wCAAwC;CACnD,MAAM,MAAM,OAAO;CACnB,QAAQ,cACN,WAAW,IAAI,GAAG,CAAC,CAAC,yBAAyB,SAAS;AAC1D;;;;;;;;;;;;;;AAeA,MAAa,yBAAyB;CACpC,MAAM,MAAM,OAAO;CACnB,QACE,SACA,cACkB,WAAW,IAAI,GAAG,CAAC,CAAC,UAAU,SAAS,SAAS;AACtE;AAEA,MAAa,qBAGX,WAAW,KAAK,MAAM,EAAE,OAA6B,KAAA,CAAS;AAEhE,MAAa,wBAAoD;CAC/D,MAAM,MAAM,OAAO;CACnB,QAAQ,SACN,WACG,IAAI,GAAG,CAAC,CACR,SACC,IAGF;AACN"}
1
+ {"version":3,"file":"hooks.js","names":[],"sources":["../src/hooks.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback } from \"react\";\nimport { useAui } from \"@assistant-ui/store\";\nimport type { CreateAppendMessage } from \"@assistant-ui/core\";\nimport type { ReadonlyJSONValue } from \"assistant-stream/utils\";\nimport { agUiExtras } from \"./agUiExtras\";\nimport type { AgUiInterrupt, AgUiResumeEntry } from \"./runtime/types\";\n\nconst EMPTY_INTERRUPTS: readonly AgUiInterrupt[] = [];\n\n/**\n * Read the pending AG-UI interrupts on the current thread. Returns an empty\n * array when no interrupts are pending, so consumers can `.map` without a guard.\n */\nexport const useAgUiInterrupts = (): readonly AgUiInterrupt[] =>\n agUiExtras.use((e) => e.interrupts, EMPTY_INTERRUPTS);\n\n/**\n * Returns a stable function that sends an A2UI action back to the agent and\n * resumes the run.\n */\nexport const useAgUiSendA2uiAction = () => {\n const aui = useAui();\n return useCallback(\n (action: Record<string, unknown>): void =>\n agUiExtras.get(aui).sendA2uiAction(action),\n [aui],\n );\n};\n\n/**\n * Returns a function that submits responses (each `resolved` or `cancelled`)\n * for the pending AG-UI interrupts and resumes the run.\n */\nexport const useAgUiSubmitInterruptResponses = () => {\n const aui = useAui();\n return (responses: readonly AgUiResumeEntry[]): Promise<void> =>\n agUiExtras.get(aui).submitInterruptResponses(responses);\n};\n\n/**\n * Returns a function that discards the pending AG-UI interrupts or pending\n * client-side tool calls and appends the given user message, starting a fresh\n * run. Use this when the user sends a new message instead of resolving them:\n * every open interrupt is reported to the agent as cancelled, and every\n * unresolved client-side tool call receives an error result. The message\n * accepts a plain string or a partial `AppendMessage` (the parent defaults to\n * the current head). Pass `responses` to override the status of specific\n * interrupts; the rest still default to cancelled. `responses` throws when\n * tool calls rather than interrupts are pending. Unlike the\n * `autoCancelPendingToolCalls` runtime option, this hook cancels regardless\n * of that option's value.\n */\nexport const useAgUiSteerAway = () => {\n const aui = useAui();\n return (\n message: CreateAppendMessage,\n responses?: readonly AgUiResumeEntry[],\n ): Promise<void> => agUiExtras.get(aui).steerAway(message, responses);\n};\n\nexport const useAgUiState = <TState = ReadonlyJSONValue>():\n | TState\n | undefined =>\n agUiExtras.use((e) => e.state as TState | undefined, undefined);\n\nexport const useAgUiSetState = <TState = ReadonlyJSONValue>() => {\n const aui = useAui();\n return (next: TState | ((prev: TState | undefined) => TState)): void =>\n agUiExtras\n .get(aui)\n .setState(\n next as\n | ReadonlyJSONValue\n | ((prev: ReadonlyJSONValue | undefined) => ReadonlyJSONValue),\n );\n};\n"],"mappings":";;;;;AASA,MAAM,mBAA6C,CAAC;;;;;AAMpD,MAAa,0BACX,WAAW,KAAK,MAAM,EAAE,YAAY,gBAAgB;;;;;AAMtD,MAAa,8BAA8B;CACzC,MAAM,MAAM,OAAO;CACnB,OAAO,aACJ,WACC,WAAW,IAAI,GAAG,CAAC,CAAC,eAAe,MAAM,GAC3C,CAAC,GAAG,CACN;AACF;;;;;AAMA,MAAa,wCAAwC;CACnD,MAAM,MAAM,OAAO;CACnB,QAAQ,cACN,WAAW,IAAI,GAAG,CAAC,CAAC,yBAAyB,SAAS;AAC1D;;;;;;;;;;;;;;AAeA,MAAa,yBAAyB;CACpC,MAAM,MAAM,OAAO;CACnB,QACE,SACA,cACkB,WAAW,IAAI,GAAG,CAAC,CAAC,UAAU,SAAS,SAAS;AACtE;AAEA,MAAa,qBAGX,WAAW,KAAK,MAAM,EAAE,OAA6B,KAAA,CAAS;AAEhE,MAAa,wBAAoD;CAC/D,MAAM,MAAM,OAAO;CACnB,QAAQ,SACN,WACG,IAAI,GAAG,CAAC,CACR,SACC,IAGF;AACN"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { AgUiInterrupt, AgUiInterruptReason, AgUiResumeEntry, AgUiRunFinishedOutcome, UseAgUiRuntimeAdapters, UseAgUiRuntimeOptions, UseAgUiThreadListAdapter } from "./runtime/types.js";
2
- import { useAgUiInterrupts, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses } from "./hooks.js";
2
+ import { useAgUiInterrupts, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses } from "./hooks.js";
3
3
  import { AgUiAssistantRuntime, useAgUiRuntime } from "./useAgUiRuntime.js";
4
4
  import { FromAgUiMessagesOptions, fromAgUiMessages } from "./runtime/adapter/conversions.js";
5
- export { type AgUiAssistantRuntime, type AgUiInterrupt, type AgUiInterruptReason, type AgUiResumeEntry, type AgUiRunFinishedOutcome, type FromAgUiMessagesOptions, type UseAgUiRuntimeAdapters, type UseAgUiRuntimeOptions, type UseAgUiThreadListAdapter, fromAgUiMessages, useAgUiInterrupts, useAgUiRuntime, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
5
+ export { type AgUiAssistantRuntime, type AgUiInterrupt, type AgUiInterruptReason, type AgUiResumeEntry, type AgUiRunFinishedOutcome, type FromAgUiMessagesOptions, type UseAgUiRuntimeAdapters, type UseAgUiRuntimeOptions, type UseAgUiThreadListAdapter, fromAgUiMessages, useAgUiInterrupts, useAgUiRuntime, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { useAgUiInterrupts, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses } from "./hooks.js";
1
+ import { useAgUiInterrupts, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses } from "./hooks.js";
2
2
  import { fromAgUiMessages } from "./runtime/adapter/conversions.js";
3
3
  import { useAgUiRuntime } from "./useAgUiRuntime.js";
4
- export { fromAgUiMessages, useAgUiInterrupts, useAgUiRuntime, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
4
+ export { fromAgUiMessages, useAgUiInterrupts, useAgUiRuntime, useAgUiSendA2uiAction, useAgUiSetState, useAgUiState, useAgUiSteerAway, useAgUiSubmitInterruptResponses };
@@ -44,6 +44,8 @@ declare class AgUiThreadRuntimeCore {
44
44
  private _isLoading;
45
45
  private _loadPromise;
46
46
  private pendingResumeMessageId;
47
+ private pendingA2uiResume;
48
+ private pendingA2uiAction;
47
49
  constructor(options: CoreOptions);
48
50
  updateOptions(options: Omit<CoreOptions, "notifyUpdate">): void;
49
51
  attachRuntime(runtime: AssistantRuntime): void;
@@ -93,6 +95,7 @@ declare class AgUiThreadRuntimeCore {
93
95
  findMessageIdForToolCall(toolCallId: string): string | undefined;
94
96
  private cancelUnresolvedToolCalls;
95
97
  addToolResult(options: AddToolResultOptions): void;
98
+ sendA2uiAction(action: Record<string, unknown>): void;
96
99
  private maybeResumeAfterToolResults;
97
100
  private maybeCompleteAfterToolResults;
98
101
  private startResumeRun;
@@ -1 +1 @@
1
- {"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;KAsDK,YAAY,YAAY;KACxB,gBACH,SAAS,wBACN,eAAe;KACf;EACH;EACA;EACA,WAAW;EACX,SAAS;;KAGN;EACH,OAAO;EACP,QAAQ;EACR;EACA;EACA,WAAW,OAAO;EAClB;EACA,UAAU;EACV;;cAKW;UACH;UACA;UACA;UACA;UACA;UACA;mBACS;UAET;mBACS;UACT;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;mBACA;UACT;UACA;UACA;EAEI,YAAA,SAAS;EAYrB,cAAc,SAAS,KAAK;EAW5B,cAAc,SAAS;EAIvB;EAIA,wBAAwB;EAIxB,wBAAwB;UAmBhB;UAQA;UAUA;UAIA;UAQA;UAQA;UAMA;UAKA;UAKA;UAKA;EAYR,YAAY;EAIZ;MAII;EAIJ,mBAAmB;EA2Cb,OAAO,SAAS,gBAAgB;UAW9B;UAQA;EAiBF,KAAK,SAAS,gBAAgB;EAI9B,OACJ,yBACA;IAAU,YAAY;MACrB;EAMG,UAAU;EAKV,OAAO,QAAQ,kBAAkB;EAUjC,kBAAkB,mBAAmB,kBAAkB;UAwBrD;UAOA;EAgBR;IACE;IACA,qBAAqB;;EAavB;IACE;IACA;;EAcI,yBACJ,oBAAoB,oBACnB;EAoDG,UACJ,SAAS,qBACT,qBAAqB,oBACpB;UAyCK;UAkBA;UAiCA;UA0BA;EA+BR,yBAAyB;UAkBjB;EAiBR,cAAc,SAAS;UA4Bf;UAYA;UA6BA;EAMR,sBAAsB,mBAAmB;UAgDjC;EAgER,kBAAkB,OAAO;EAKzB,SACE,MACI,sBACE,MAAM,kCAAkC;EAOhD;UAKc;UAkJA;UAyDN;UA6BA;UAqBA;UAKA;UAOA;UAuBA;UA2CA;UAiDA;UA4BA;UA6BA;UA4DA;UA2EA;UA8DA;UAwBA;UAQA;UAIA;UAKA;UAIA;UAQA;UAWA"}
1
+ {"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;KAsDK,YAAY,YAAY;KACxB,gBACH,SAAS,wBACN,eAAe;KACf;EACH;EACA;EACA,WAAW;EACX,SAAS;;KAGN;EACH,OAAO;EACP,QAAQ;EACR;EACA;EACA,WAAW,OAAO;EAClB;EACA,UAAU;EACV;;cAKW;UACH;UACA;UACA;UACA;UACA;UACA;mBACS;UAET;mBACS;UACT;UACA;UACA;UACA;UACA;UACA;UACA;mBACS;mBACA;UACT;UACA;UACA;UACA;UACA;EAEI,YAAA,SAAS;EAYrB,cAAc,SAAS,KAAK;EAW5B,cAAc,SAAS;EAIvB;EAIA,wBAAwB;EAIxB,wBAAwB;UAmBhB;UAQA;UAUA;UAIA;UAQA;UAQA;UAMA;UAKA;UAKA;UAKA;EAYR,YAAY;EAIZ;MAII;EAIJ,mBAAmB;EA2Cb,OAAO,SAAS,gBAAgB;UAW9B;UAQA;EAiBF,KAAK,SAAS,gBAAgB;EAI9B,OACJ,yBACA;IAAU,YAAY;MACrB;EAMG,UAAU;EAKV,OAAO,QAAQ,kBAAkB;EAUjC,kBAAkB,mBAAmB,kBAAkB;UAwBrD;UAOA;EAgBR;IACE;IACA,qBAAqB;;EAavB;IACE;IACA;;EAcI,yBACJ,oBAAoB,oBACnB;EAoDG,UACJ,SAAS,qBACT,qBAAqB,oBACpB;UAyCK;UAkBA;UAiCA;UA0BA;EA+BR,yBAAyB;UAkBjB;EAiBR,cAAc,SAAS;EAyBvB,eAAe,QAAQ;UA4Bf;UAYA;UA6BA;EAMR,sBAAsB,mBAAmB;UAkDjC;EAgER,kBAAkB,OAAO;EAKzB,SACE,MACI,sBACE,MAAM,kCAAkC;EAOhD;UAKc;UAoMA;UA2DN;UAkCA;UAqBA;UAKA;UAOA;UAyBA;UA2CA;UAiDA;UA4BA;UA6BA;UAgEA;UA2EA;UA8DA;UAgDA;UAQA;UAIA;UAKA;UAIA;UAQA;UAWA"}
@@ -3,8 +3,8 @@ import { readMcpAppResourceUri } from "./mcp-tool-result.js";
3
3
  import { AG_UI_METADATA_NAMESPACE, RunAggregator, isPlainObject, tryParseJSON } from "./adapter/run-aggregator.js";
4
4
  import { fromAgUiMessages, toAgUiMessages, toAgUiTools } from "./adapter/conversions.js";
5
5
  import { createAgUiSubscriber } from "./adapter/subscriber.js";
6
- import { MessageRepository } from "@assistant-ui/core/internal";
7
6
  import { fromThreadMessageLike, generateId, isMcpAppUri } from "@assistant-ui/core";
7
+ import { MessageRepository } from "@assistant-ui/core/internal";
8
8
  import jsonpatch from "fast-json-patch";
9
9
  //#region src/runtime/AgUiThreadRuntimeCore.ts
10
10
  const optimisticPrefix = "__optimistic__";
@@ -38,6 +38,8 @@ var AgUiThreadRuntimeCore = class {
38
38
  _isLoading = false;
39
39
  _loadPromise;
40
40
  pendingResumeMessageId = null;
41
+ pendingA2uiResume = false;
42
+ pendingA2uiAction;
41
43
  constructor(options) {
42
44
  this.agent = options.agent;
43
45
  this.logger = options.logger;
@@ -424,6 +426,24 @@ var AgUiThreadRuntimeCore = class {
424
426
  this.notifyUpdate();
425
427
  this.maybeResumeAfterToolResults(options.messageId);
426
428
  }
429
+ sendA2uiAction(action) {
430
+ this.assertNoPendingInterrupts();
431
+ this.maybeAutoCancelPendingToolCalls();
432
+ const parentId = this.repository.headId;
433
+ if (parentId === null) {
434
+ this.logger.debug("[agui] sendA2uiAction: no messages to resume, dropping action");
435
+ return;
436
+ }
437
+ const userAction = { ...action };
438
+ delete userAction.type;
439
+ if (!("timestamp" in userAction)) userAction.timestamp = (/* @__PURE__ */ new Date()).toISOString();
440
+ this.pendingA2uiAction = userAction;
441
+ if (this.isRunningFlag) {
442
+ this.pendingA2uiResume = true;
443
+ return;
444
+ }
445
+ this.startResumeRun(parentId);
446
+ }
427
447
  maybeResumeAfterToolResults(messageId) {
428
448
  if (!this.maybeCompleteAfterToolResults(messageId)) return;
429
449
  if (this.isRunningFlag) {
@@ -455,6 +475,8 @@ var AgUiThreadRuntimeCore = class {
455
475
  });
456
476
  }
457
477
  applyExternalMessages(messages) {
478
+ this.pendingA2uiResume = false;
479
+ this.pendingA2uiAction = void 0;
458
480
  this.assistantHistoryParents.clear();
459
481
  if (messages.length === 0) this.clearRepository();
460
482
  else {
@@ -564,16 +586,21 @@ var AgUiThreadRuntimeCore = class {
564
586
  this.pendingError = null;
565
587
  const assistantParentId = parent ? parentId : this.repository.headId;
566
588
  let assistantMessageId;
567
- const ensureAssistant = () => {
568
- if (assistantMessageId) return assistantMessageId;
569
- const created = this.insertAssistantPlaceholder(assistantParentId ?? null);
589
+ let assistantCollided = false;
590
+ const ensureAssistant = (allowRecreate = false) => {
591
+ const cached = assistantMessageId;
592
+ if (cached !== void 0 && this.tryGetMessage(cached)) return cached;
593
+ if (cached !== void 0 && (assistantCollided || !allowRecreate)) return cached;
594
+ const parentId = cached === void 0 && assistantParentId && this.hasMessage(assistantParentId) ? assistantParentId : this.repository.headId;
595
+ const created = this.insertAssistantPlaceholder(parentId, cached);
570
596
  assistantMessageId = created;
571
- this.markPendingAssistantHistory(created, assistantParentId ?? null);
597
+ this.markPendingAssistantHistory(created, parentId);
572
598
  return created;
573
599
  };
574
600
  if (shouldEagerlyInsertAssistant) ensureAssistant();
575
601
  const applyUpdate = (update) => {
576
- const resolved = this.updateAssistantMessage(ensureAssistant(), update);
602
+ const hasContent = Array.isArray(update.content) && update.content.length > 0;
603
+ const resolved = this.updateAssistantMessage(ensureAssistant(hasContent), update);
577
604
  if (resolved !== assistantMessageId) assistantMessageId = resolved;
578
605
  };
579
606
  const aggregator = new RunAggregator({
@@ -581,12 +608,13 @@ var AgUiThreadRuntimeCore = class {
581
608
  logger: this.logger,
582
609
  emit: applyUpdate,
583
610
  onServerMessageId: (serverId) => {
584
- const placeholder = ensureAssistant();
611
+ const placeholder = ensureAssistant(true);
585
612
  if (placeholder === serverId) return;
586
613
  if (this.reassignAssistantId(placeholder, serverId)) assistantMessageId = serverId;
614
+ else assistantCollided = true;
587
615
  }
588
616
  });
589
- const dispatch = (event) => this.handleEvent(aggregator, event);
617
+ const dispatch = (event) => this.handleEvent(aggregator, event, assistantMessageId);
590
618
  const abortController = new AbortController();
591
619
  const abortSignal = abortController.signal;
592
620
  this.abortController = abortController;
@@ -653,15 +681,37 @@ var AgUiThreadRuntimeCore = class {
653
681
  const err = this.pendingError;
654
682
  this.pendingError = null;
655
683
  this.pendingResumeMessageId = null;
684
+ this.pendingA2uiResume = false;
685
+ this.pendingA2uiAction = void 0;
656
686
  throw err;
657
687
  }
658
688
  if (this.pendingResumeMessageId !== null) {
659
689
  const resumeMessageId = this.pendingResumeMessageId;
660
690
  this.pendingResumeMessageId = null;
661
691
  if (!abortSignal.aborted) this.startResumeRun(resumeMessageId);
692
+ else this.pendingA2uiAction = void 0;
693
+ }
694
+ if (this.pendingA2uiResume) {
695
+ this.pendingA2uiResume = false;
696
+ if (!abortSignal.aborted && this.pendingA2uiAction !== void 0) {
697
+ if (this.getPendingInterrupts()) {
698
+ this.pendingA2uiAction = void 0;
699
+ this.logger.debug("[agui] sendA2uiAction: pending interrupts, dropping action");
700
+ return;
701
+ }
702
+ this.maybeAutoCancelPendingToolCalls();
703
+ const parentId = this.repository.headId;
704
+ if (parentId !== null) this.startResumeRun(parentId);
705
+ else {
706
+ this.pendingA2uiAction = void 0;
707
+ this.logger.debug("[agui] sendA2uiAction: no messages to resume, dropping action");
708
+ }
709
+ } else this.pendingA2uiAction = void 0;
662
710
  }
663
711
  }
664
712
  async consumeResumeStream(stream, ctx) {
713
+ this.pendingA2uiAction = void 0;
714
+ this.pendingA2uiResume = false;
665
715
  const assistantId = ctx.ensureAssistant();
666
716
  const currentId = () => ctx.getAssistantMessageId() ?? assistantId;
667
717
  const options = {
@@ -706,7 +756,7 @@ var AgUiThreadRuntimeCore = class {
706
756
  const threadId = this.agent.threadId || "main";
707
757
  const messages = toAgUiMessages(historyMessages ?? this.repository.getMessages());
708
758
  const context = this.runtime?.thread.getModelContext();
709
- return {
759
+ const input = {
710
760
  threadId,
711
761
  runId,
712
762
  state: this.stateSnapshot ?? null,
@@ -719,10 +769,13 @@ var AgUiThreadRuntimeCore = class {
719
769
  forwardedProps: {
720
770
  ...context?.callSettings ?? {},
721
771
  ...context?.config ?? {},
722
- ...runConfig?.custom ? { runConfig: runConfig.custom } : {}
772
+ ...runConfig?.custom ? { runConfig: runConfig.custom } : {},
773
+ ...this.pendingA2uiAction ? { a2uiAction: { userAction: this.pendingA2uiAction } } : {}
723
774
  },
724
775
  ...resume !== void 0 ? { resume } : {}
725
776
  };
777
+ this.pendingA2uiAction = void 0;
778
+ return input;
726
779
  }
727
780
  installResumeShim() {
728
781
  const agent = this.agent;
@@ -747,8 +800,7 @@ var AgUiThreadRuntimeCore = class {
747
800
  if (this.abortController === controller) this.abortController = null;
748
801
  this.setRunning(false);
749
802
  }
750
- insertAssistantPlaceholder(parentId) {
751
- const id = generateOptimisticId();
803
+ insertAssistantPlaceholder(parentId, id = generateOptimisticId()) {
752
804
  const assistant = {
753
805
  id,
754
806
  role: "assistant",
@@ -760,7 +812,7 @@ var AgUiThreadRuntimeCore = class {
760
812
  unstable_annotations: [],
761
813
  unstable_data: [],
762
814
  steps: [],
763
- isOptimistic: true,
815
+ isOptimistic: isOptimisticId(id),
764
816
  custom: {}
765
817
  }
766
818
  };
@@ -863,7 +915,7 @@ var AgUiThreadRuntimeCore = class {
863
915
  } : current.custom
864
916
  };
865
917
  }
866
- handleEvent(aggregator, event) {
918
+ handleEvent(aggregator, event, activeAssistantId) {
867
919
  switch (event.type) {
868
920
  case "STATE_SNAPSHOT":
869
921
  this.stateSnapshot = event.snapshot;
@@ -881,7 +933,7 @@ var AgUiThreadRuntimeCore = class {
881
933
  }
882
934
  return;
883
935
  case "MESSAGES_SNAPSHOT":
884
- this.importMessagesSnapshot(event.messages);
936
+ this.importMessagesSnapshot(event.messages, activeAssistantId);
885
937
  return;
886
938
  case "TOOL_CALL_RESULT":
887
939
  if (!aggregator.hasToolCall(event.toolCallId)) {
@@ -986,8 +1038,10 @@ var AgUiThreadRuntimeCore = class {
986
1038
  this.notifyUpdate();
987
1039
  this.maybeCompleteAfterToolResults(messageId);
988
1040
  }
989
- importMessagesSnapshot(rawMessages) {
1041
+ importMessagesSnapshot(rawMessages, activeAssistantId) {
990
1042
  try {
1043
+ const activeMessage = activeAssistantId ? this.tryGetMessage(activeAssistantId)?.message : void 0;
1044
+ const activeAssistant = activeMessage?.role === "assistant" ? activeMessage : void 0;
991
1045
  const normalized = fromAgUiMessages(rawMessages, { showThinking: this.showThinking });
992
1046
  const converted = [];
993
1047
  for (const message of normalized) try {
@@ -995,7 +1049,15 @@ var AgUiThreadRuntimeCore = class {
995
1049
  } catch (error) {
996
1050
  this.logger.error?.("[agui] failed to import message from snapshot", error);
997
1051
  }
1052
+ const snapshotHeadId = converted.at(-1)?.id ?? null;
1053
+ const snapshotContainsActiveAssistant = converted.some((message) => message.id === activeAssistant?.id);
1054
+ const preservesActiveAssistant = activeAssistant !== void 0 && !snapshotContainsActiveAssistant && (activeAssistant.metadata.isOptimistic !== true || converted.at(-1)?.role !== "assistant");
1055
+ if (preservesActiveAssistant) converted.push(activeAssistant);
998
1056
  this.applyExternalMessages(converted);
1057
+ if (preservesActiveAssistant) {
1058
+ this.recordedHistoryIds.delete(activeAssistant.id);
1059
+ this.markPendingAssistantHistory(activeAssistant.id, snapshotHeadId);
1060
+ }
999
1061
  } catch (error) {
1000
1062
  this.logger.error?.("[agui] failed to import messages snapshot", error);
1001
1063
  }