@assistant-ui/react-ag-ui 0.0.56 → 0.0.57

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.
@@ -32,8 +32,7 @@ declare class AgUiThreadRuntimeCore {
32
32
  private readonly notifyUpdate;
33
33
  private readonly reportedErrors;
34
34
  private runtime;
35
- private readonly repository;
36
- private exportedRepository;
35
+ private readonly session;
37
36
  private isRunningFlag;
38
37
  private abortController;
39
38
  private activeRunAgent;
@@ -47,6 +46,7 @@ declare class AgUiThreadRuntimeCore {
47
46
  private readonly historyWrites;
48
47
  private _isLoading;
49
48
  private _loadPromise;
49
+ private _loadRequested;
50
50
  private pendingResumeMessageId;
51
51
  private pendingA2uiResume;
52
52
  private pendingA2uiAction;
@@ -56,16 +56,6 @@ declare class AgUiThreadRuntimeCore {
56
56
  detachRuntime(): void;
57
57
  getMessages(): readonly ThreadMessage[];
58
58
  getMessageRepository(): ExportedMessageRepository;
59
- private tryGetMessage;
60
- private tryGetMessages;
61
- private hasMessage;
62
- private addOrUpdateMessage;
63
- private deleteMessage;
64
- private tryDeleteMessage;
65
- private switchToBranch;
66
- private resetRepositoryHead;
67
- private clearRepository;
68
- private updateMessage;
69
59
  getState(): ReadonlyJSONValue | undefined;
70
60
  isRunning(): boolean;
71
61
  get isLoading(): boolean;
@@ -121,7 +111,6 @@ declare class AgUiThreadRuntimeCore {
121
111
  private maybeCompleteAfterToolResults;
122
112
  private startResumeRun;
123
113
  applyExternalMessages(messages: readonly ThreadMessage[]): void;
124
- private applyExternalMessageRepository;
125
114
  loadExternalState(state: ReadonlyJSONValue): void;
126
115
  setState(next: ReadonlyJSONValue | ((prev: ReadonlyJSONValue | undefined) => ReadonlyJSONValue)): void;
127
116
  resetState(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;KA2EK,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;;cAuDW;UACH;UACA;UACA;UACA;UACA;UACA;mBACS;mBACA;UAET;mBACS;UACT;UACA;UACA;UAGA;UACA;UACA;UACA;UACA;mBACS;mBACA;mBACA;mBACA;UACT;UACA;UACA;UACA;UACA;EAEI,YAAA,SAAS;EAYrB,cAAc,SAAS,KAAK;EAW5B,cAAc,SAAS;EAIvB;EAOA,wBAAwB;EAIxB,wBAAwB;UAmBhB;UAQA;UAUA;UAIA;UAQA;UAQA;UAMA;UAKA;UAKA;UAKA;EAYR,YAAY;EAIZ;MAII;EAIJ,mBAAmB;EA6Cb,OAAO,SAAS,gBAAgB;UAW9B;UAQA;EAiBF,KAAK,SAAS,gBAAgB;EAI9B,OACJ,yBACA;IAAU,YAAY;MACrB;EAMG,UAAU;EAcV,OAAO,QAAQ,kBAAkB;EAUjC,kBAAkB,mBAAmB,kBAAkB;UAwBrD;UAOA;EAgBR;IACE;IACA,qBAAqB;;EAavB;IACE;IACA;;EAcI,yBACJ,oBAAoB,oBACnB;;;;;;;UAuCW;;;;;;;;EAed,YAAY;UAYJ;EAwBF,sBACJ,SAAS,+BACR;EAoEG,UACJ,SAAS,qBACT,qBAAqB,oBACpB;UAyCK;UAkBA;UAiCA;UA0BA;EAmCR,yBAAyB;UAkBjB;EAiBR,cAAc,SAAS;EAyBvB,eAAe,QAAQ;UA4Bf;UAYA;UA6BA;EAUR,sBAAsB,mBAAmB;UAkDjC;EAiER,kBAAkB,OAAO;EAKzB,SACE,MACI,sBACE,MAAM,kCAAkC;EAOhD;UAKc;UAoOA;UA2DN;UAkCA;UAqBA;UAKA;UAQA;UAyBA;UAkEA;UAiDA;UA4BA;UA6BA;UAgEA;UA2EA;UA8DA;UAuDA;UAQA;UAIA;UAKA;UAMA;UAQA;UAsDA;UAqBA"}
1
+ {"version":3,"file":"AgUiThreadRuntimeCore.d.ts","names":[],"sources":["../../src/runtime/AgUiThreadRuntimeCore.ts"],"mappings":";;;;;;KA8EK,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;;cAoCW;UACH;UACA;UACA;UACA;UACA;UACA;mBACS;mBACA;UAET;mBACS;UAgBT;UACA;UAGA;UACA;UACA;UACA;UACA;mBACS;mBACA;mBACA;mBACA;UACT;UACA;UACA;UACA;UACA;UACA;EAEI,YAAA,SAAS;EAYrB,cAAc,SAAS,KAAK;EAsB5B,cAAc,SAAS;EAIvB;EAOA,wBAAwB;EAIxB,wBAAwB;EAIxB,YAAY;EAIZ;MAII;EAIJ,mBAAmB;EAsDb,OAAO,SAAS,gBAAgB;UAW9B;UAQA;EAiBF,KAAK,SAAS,gBAAgB;EAI9B,OACJ,yBACA;IAAU,YAAY;MACrB;EAMG,UAAU;EAcV,OAAO,QAAQ,kBAAkB;EAUjC,kBAAkB,mBAAmB,kBAAkB;UAwBrD;UAOA;EAgBR;IACE;IACA,qBAAqB;;EAavB;IACE;IACA;;EAcI,yBACJ,oBAAoB,oBACnB;;;;;;;UAuCW;;;;;;;;EAed,YAAY;UAYJ;EAwBF,sBACJ,SAAS,+BACR;EAsEG,UACJ,SAAS,qBACT,qBAAqB,oBACpB;UAyCK;UAkBA;UAiCA;UA0BA;EAmCR,yBAAyB;UAkBjB;EAiBR,cAAc,SAAS;EAyBvB,eAAe,QAAQ;UA4Bf;UAYA;UA6BA;EAUR,sBAAsB,mBAAmB;EAkDzC,kBAAkB,OAAO;EAKzB,SACE,MACI,sBACE,MAAM,kCAAkC;EAOhD;UAKc;UAyPA;UA2DN;UAkCA;UAqBA;UAKA;UAQA;UAyBA;UAkEA;UAiDA;UA4BA;UA6BA;UAgEA;UA2EA;UA8DA;UAuDA;UAQA;UAIA;UAKA;UAMA;UAQA;UAsDA;UAqBA"}
@@ -5,7 +5,7 @@ import { AG_UI_METADATA_NAMESPACE, RunAggregator, isPlainObject, tryParseJSON }
5
5
  import { fromAgUiMessages, toAgUiMessages, toAgUiTools } from "./adapter/conversions.js";
6
6
  import { createAgUiSubscriber } from "./adapter/subscriber.js";
7
7
  import { fromThreadMessageLike, generateId, isMcpAppUri } from "@assistant-ui/core";
8
- import { MessageRepository } from "@assistant-ui/core/internal";
8
+ import { createMessageRepositorySession, invokeUserCallback } from "@assistant-ui/core/internal";
9
9
  import jsonpatch from "fast-json-patch";
10
10
  //#region src/runtime/AgUiThreadRuntimeCore.ts
11
11
  const optimisticPrefix = "__optimistic__";
@@ -17,19 +17,8 @@ const FALLBACK_USER_STATUS = {
17
17
  type: "complete",
18
18
  reason: "unknown"
19
19
  };
20
- const reportCallbackError = (name, error) => {
21
- console.error(`[react-ag-ui] ${name} callback threw an error`, error);
22
- };
23
20
  const invokeRuntimeCallback = (name, callback, ...args) => {
24
- if (!callback) return;
25
- try {
26
- const result = callback(...args);
27
- if (result !== null && (typeof result === "object" || typeof result === "function") && "then" in result && typeof result.then === "function") Promise.resolve(result).catch((error) => {
28
- reportCallbackError(name, error);
29
- });
30
- } catch (error) {
31
- reportCallbackError(name, error);
32
- }
21
+ invokeUserCallback("react-ag-ui", name, callback, ...args);
33
22
  };
34
23
  const mergeAgUiNamespace = (current, incoming) => {
35
24
  const merged = {
@@ -54,8 +43,20 @@ var AgUiThreadRuntimeCore = class {
54
43
  notifyUpdate;
55
44
  reportedErrors = /* @__PURE__ */ new WeakSet();
56
45
  runtime;
57
- repository = new MessageRepository();
58
- exportedRepository;
46
+ session = createMessageRepositorySession({ decorateExport: (exported, repository) => {
47
+ let parentId = null;
48
+ for (const message of repository.getMessages()) {
49
+ if (message.metadata.isOptimistic) exported.messages.push({
50
+ parentId,
51
+ message
52
+ });
53
+ parentId = message.id;
54
+ }
55
+ return {
56
+ ...exported,
57
+ headId: repository.headId
58
+ };
59
+ } });
59
60
  isRunningFlag = false;
60
61
  abortController = null;
61
62
  activeRunAgent = null;
@@ -69,6 +70,7 @@ var AgUiThreadRuntimeCore = class {
69
70
  historyWrites = /* @__PURE__ */ new Map();
70
71
  _isLoading = false;
71
72
  _loadPromise;
73
+ _loadRequested = false;
72
74
  pendingResumeMessageId = null;
73
75
  pendingA2uiResume = false;
74
76
  pendingA2uiAction;
@@ -90,8 +92,10 @@ var AgUiThreadRuntimeCore = class {
90
92
  this.autoCancelPendingToolCalls = options.autoCancelPendingToolCalls;
91
93
  this.onError = options.onError;
92
94
  this.onCancel = options.onCancel;
95
+ const previousHistory = this.history;
93
96
  this.history = options.history;
94
97
  this.installResumeShim();
98
+ if (this._loadRequested && !this._loadPromise && !previousHistory && options.history && this.session.getMessages().length === 0) this.__internal_load();
95
99
  }
96
100
  attachRuntime(runtime) {
97
101
  this.runtime = runtime;
@@ -103,74 +107,10 @@ var AgUiThreadRuntimeCore = class {
103
107
  });
104
108
  }
105
109
  getMessages() {
106
- return this.repository.getMessages();
110
+ return this.session.getMessages();
107
111
  }
108
112
  getMessageRepository() {
109
- if (this.exportedRepository) return this.exportedRepository;
110
- const exportedRepository = this.repository.export();
111
- let parentId = null;
112
- for (const message of this.repository.getMessages()) {
113
- if (message.metadata.isOptimistic) exportedRepository.messages.push({
114
- parentId,
115
- message
116
- });
117
- parentId = message.id;
118
- }
119
- this.exportedRepository = {
120
- ...exportedRepository,
121
- headId: this.repository.headId
122
- };
123
- return this.exportedRepository;
124
- }
125
- tryGetMessage(messageId) {
126
- try {
127
- return this.repository.getMessage(messageId);
128
- } catch {
129
- return;
130
- }
131
- }
132
- tryGetMessages(messageId) {
133
- try {
134
- return this.repository.getMessages(messageId);
135
- } catch {
136
- return;
137
- }
138
- }
139
- hasMessage(messageId) {
140
- return this.tryGetMessage(messageId) !== void 0;
141
- }
142
- addOrUpdateMessage(parentId, message) {
143
- this.repository.addOrUpdateMessage(parentId, message);
144
- this.exportedRepository = void 0;
145
- }
146
- deleteMessage(messageId, replacementId) {
147
- this.repository.deleteMessage(messageId, replacementId);
148
- this.exportedRepository = void 0;
149
- }
150
- tryDeleteMessage(messageId) {
151
- if (!this.hasMessage(messageId)) return false;
152
- this.deleteMessage(messageId);
153
- return true;
154
- }
155
- switchToBranch(messageId) {
156
- this.repository.switchToBranch(messageId);
157
- this.exportedRepository = void 0;
158
- }
159
- resetRepositoryHead(messageId) {
160
- this.repository.resetHead(messageId);
161
- this.exportedRepository = void 0;
162
- }
163
- clearRepository() {
164
- this.repository.clear();
165
- this.exportedRepository = void 0;
166
- }
167
- updateMessage(messageId, updater) {
168
- const item = this.tryGetMessage(messageId);
169
- if (!item) return false;
170
- const message = updater(item.message);
171
- if (message === item.message) return false;
172
- this.addOrUpdateMessage(item.parentId, message);
173
- return true;
113
+ return this.session.export();
174
114
  }
175
115
  getState() {
176
116
  return this.stateSnapshot;
@@ -182,15 +122,22 @@ var AgUiThreadRuntimeCore = class {
182
122
  return this._isLoading;
183
123
  }
184
124
  __internal_load() {
125
+ this._loadRequested = true;
185
126
  if (this._loadPromise) return this._loadPromise;
186
- const promise = this.history?.load() ?? Promise.resolve(null);
127
+ if (!this.history) return Promise.resolve();
128
+ const promise = this.history.load();
187
129
  this._isLoading = true;
188
130
  this._loadPromise = promise.then(async (repo) => {
189
131
  if (!repo) return;
190
- this.applyExternalMessageRepository(repo);
132
+ this.session.applyExternalMessageRepository(repo);
133
+ this.assistantHistoryParents.clear();
134
+ this.snapshotHistoryIds.clear();
135
+ this.persistedHistoryIds.clear();
136
+ for (const { message } of repo.messages) this.persistedHistoryIds.add(message.id);
137
+ this.notifyUpdate();
191
138
  if (repo.state !== void 0) this.loadExternalState(repo.state);
192
139
  if (repo.unstable_resume) {
193
- const parentId = repo.headId ?? this.repository.headId;
140
+ const parentId = repo.headId ?? this.session.headId;
194
141
  const resumeStream = this.history?.resume?.bind(this.history);
195
142
  await this.startRun(parentId, this.lastRunConfig, void 0, resumeStream);
196
143
  }
@@ -222,11 +169,11 @@ var AgUiThreadRuntimeCore = class {
222
169
  this.maybeCompleteAfterToolResults(pending.messageId);
223
170
  }
224
171
  appendEntry(message) {
225
- if (message.sourceId) this.tryDeleteMessage(message.sourceId);
172
+ if (message.sourceId) this.session.tryDeleteMessage(message.sourceId);
226
173
  const threadMessage = this.toThreadMessage(message);
227
- const parentId = message.parentId === null ? null : message.parentId && this.hasMessage(message.parentId) ? message.parentId : this.repository.headId;
228
- this.addOrUpdateMessage(parentId, threadMessage);
229
- this.switchToBranch(threadMessage.id);
174
+ const parentId = message.parentId === null ? null : message.parentId && this.session.hasMessage(message.parentId) ? message.parentId : this.session.headId;
175
+ this.session.addOrUpdateMessage(parentId, threadMessage);
176
+ this.session.switchToBranch(threadMessage.id);
230
177
  this.notifyUpdate();
231
178
  this.recordHistoryEntry(parentId, threadMessage);
232
179
  return threadMessage.id;
@@ -345,10 +292,10 @@ var AgUiThreadRuntimeCore = class {
345
292
  async respondToToolApproval(options) {
346
293
  const pending = this.getPendingInterrupts();
347
294
  if (!pending) throw new Error("[agui] respondToToolApproval: no pending interrupts on this thread");
348
- const gatedMessage = this.tryGetMessage(pending.messageId)?.message;
295
+ const gatedMessage = this.session.tryGetMessage(pending.messageId)?.message;
349
296
  if (![...projectAgUiToolApprovals(pending.interrupts, new Set((gatedMessage?.content ?? []).filter((part) => part.type === "tool-call").map((part) => part.toolCallId))).values()].some((approval) => approval.id === options.approvalId)) throw new Error(`[agui] respondToToolApproval: no pending tool-call interrupt for approval id "${options.approvalId}"`);
350
297
  this.assertInterruptsAnswerable("respondToToolApproval", pending.interrupts);
351
- if (!this.updateMessage(pending.messageId, (message) => {
298
+ if (!this.session.updateMessage(pending.messageId, (message) => {
352
299
  if (message.role !== "assistant") return message;
353
300
  const assistant = message;
354
301
  const content = withToolApprovalDecision(assistant.content, options);
@@ -359,7 +306,7 @@ var AgUiThreadRuntimeCore = class {
359
306
  };
360
307
  })) throw new Error(`[agui] respondToToolApproval: approval "${options.approvalId}" is already decided`);
361
308
  this.notifyUpdate();
362
- const assistant = this.tryGetMessage(pending.messageId)?.message;
309
+ const assistant = this.session.tryGetMessage(pending.messageId)?.message;
363
310
  if (!assistant) return;
364
311
  const resume = buildToolApprovalResume(assistant.content, pending.interrupts);
365
312
  if (!resume) return;
@@ -412,7 +359,7 @@ var AgUiThreadRuntimeCore = class {
412
359
  toAppendMessage(message) {
413
360
  if (typeof message === "string") return {
414
361
  createdAt: /* @__PURE__ */ new Date(),
415
- parentId: this.repository.headId,
362
+ parentId: this.session.headId,
416
363
  sourceId: null,
417
364
  runConfig: {},
418
365
  role: "user",
@@ -425,7 +372,7 @@ var AgUiThreadRuntimeCore = class {
425
372
  };
426
373
  return {
427
374
  createdAt: message.createdAt ?? /* @__PURE__ */ new Date(),
428
- parentId: message.parentId ?? this.repository.headId,
375
+ parentId: message.parentId ?? this.session.headId,
429
376
  sourceId: message.sourceId ?? null,
430
377
  role: message.role ?? "user",
431
378
  content: message.content,
@@ -436,7 +383,7 @@ var AgUiThreadRuntimeCore = class {
436
383
  };
437
384
  }
438
385
  clearPendingInterrupts(messageId, resume) {
439
- if (this.updateMessage(messageId, (message) => {
386
+ if (this.session.updateMessage(messageId, (message) => {
440
387
  if (message.role !== "assistant") return message;
441
388
  const assistant = message;
442
389
  if (assistant.status?.type !== "requires-action" || assistant.status.reason !== "interrupt") return assistant;
@@ -473,7 +420,7 @@ var AgUiThreadRuntimeCore = class {
473
420
  return fallbackMessageId;
474
421
  }
475
422
  cancelUnresolvedToolCalls(messageId) {
476
- if (this.updateMessage(messageId, (message) => {
423
+ if (this.session.updateMessage(messageId, (message) => {
477
424
  if (message.role !== "assistant") return message;
478
425
  const assistant = message;
479
426
  const content = assistant.content.map((part) => {
@@ -491,7 +438,7 @@ var AgUiThreadRuntimeCore = class {
491
438
  })) this.notifyUpdate();
492
439
  }
493
440
  addToolResult(options) {
494
- if (!this.updateMessage(options.messageId, (message) => {
441
+ if (!this.session.updateMessage(options.messageId, (message) => {
495
442
  if (message.role !== "assistant") return message;
496
443
  const assistant = message;
497
444
  let matchedToolCall = false;
@@ -517,7 +464,7 @@ var AgUiThreadRuntimeCore = class {
517
464
  sendA2uiAction(action) {
518
465
  this.assertNoPendingInterrupts();
519
466
  this.maybeAutoCancelPendingToolCalls();
520
- const parentId = this.repository.headId;
467
+ const parentId = this.session.headId;
521
468
  if (parentId === null) {
522
469
  this.logger.debug("[agui] sendA2uiAction: no messages to resume, dropping action");
523
470
  return;
@@ -541,12 +488,12 @@ var AgUiThreadRuntimeCore = class {
541
488
  this.startResumeRun(messageId);
542
489
  }
543
490
  maybeCompleteAfterToolResults(messageId) {
544
- const message = this.tryGetMessage(messageId)?.message;
491
+ const message = this.session.tryGetMessage(messageId)?.message;
545
492
  if (!message || message.role !== "assistant") return false;
546
493
  const assistant = message;
547
494
  if (assistant.status?.type !== "requires-action" || assistant.status.reason !== "tool-calls") return false;
548
495
  if (!assistant.content.every((part) => part.type !== "tool-call" || isResolvedToolCall(part))) return false;
549
- if (!this.updateMessage(messageId, (current) => current.role === "assistant" ? {
496
+ if (!this.session.updateMessage(messageId, (current) => current.role === "assistant" ? {
550
497
  ...current,
551
498
  status: {
552
499
  type: "complete",
@@ -566,7 +513,7 @@ var AgUiThreadRuntimeCore = class {
566
513
  this.pendingA2uiResume = false;
567
514
  this.pendingA2uiAction = void 0;
568
515
  this.assistantHistoryParents.clear();
569
- if (messages.length === 0) this.clearRepository();
516
+ if (messages.length === 0) this.session.clear();
570
517
  else {
571
518
  let expectedParentId = null;
572
519
  let lastAppliedId = null;
@@ -575,85 +522,34 @@ var AgUiThreadRuntimeCore = class {
575
522
  for (const message of messages) {
576
523
  if (seen.has(message.id)) continue;
577
524
  seen.add(message.id);
578
- const existing = this.tryGetMessage(message.id);
525
+ const existing = this.session.tryGetMessage(message.id);
579
526
  if (existing && existing.parentId !== expectedParentId) {
580
527
  hardReplace = true;
581
528
  break;
582
529
  }
583
- this.addOrUpdateMessage(expectedParentId, message);
530
+ this.session.addOrUpdateMessage(expectedParentId, message);
584
531
  expectedParentId = message.id;
585
532
  lastAppliedId = message.id;
586
533
  }
587
534
  if (hardReplace) {
588
- this.clearRepository();
535
+ this.session.clear();
589
536
  expectedParentId = null;
590
537
  lastAppliedId = null;
591
538
  seen.clear();
592
539
  for (const message of messages) {
593
540
  if (seen.has(message.id)) continue;
594
541
  seen.add(message.id);
595
- this.addOrUpdateMessage(expectedParentId, message);
542
+ this.session.addOrUpdateMessage(expectedParentId, message);
596
543
  expectedParentId = message.id;
597
544
  lastAppliedId = message.id;
598
545
  }
599
546
  }
600
- this.resetRepositoryHead(lastAppliedId);
547
+ this.session.resetHead(lastAppliedId);
601
548
  }
602
549
  this.snapshotHistoryIds.clear();
603
550
  for (const { message } of this.getMessageRepository().messages) this.snapshotHistoryIds.add(message.id);
604
551
  this.notifyUpdate();
605
552
  }
606
- applyExternalMessageRepository(loaded) {
607
- const headId = loaded.headId ?? loaded.messages.at(-1)?.message.id ?? null;
608
- const ids = /* @__PURE__ */ new Set();
609
- let degenerate = false;
610
- for (const { message } of loaded.messages) {
611
- if (ids.has(message.id)) {
612
- degenerate = true;
613
- break;
614
- }
615
- ids.add(message.id);
616
- }
617
- if (headId !== null && !ids.has(headId)) degenerate = true;
618
- if (!degenerate) {
619
- this.clearRepository();
620
- let pending = [...loaded.messages];
621
- const importedIds = /* @__PURE__ */ new Set();
622
- while (pending.length > 0) {
623
- const unresolved = [];
624
- let progressed = false;
625
- for (const item of pending) {
626
- if (item.parentId !== null && !importedIds.has(item.parentId)) {
627
- unresolved.push(item);
628
- continue;
629
- }
630
- this.addOrUpdateMessage(item.parentId, item.message);
631
- importedIds.add(item.message.id);
632
- progressed = true;
633
- }
634
- if (!progressed) {
635
- degenerate = true;
636
- break;
637
- }
638
- pending = unresolved;
639
- }
640
- }
641
- if (degenerate) {
642
- this.clearRepository();
643
- let previousId = null;
644
- for (const { message } of loaded.messages) {
645
- const existing = this.tryGetMessage(message.id);
646
- this.addOrUpdateMessage(existing ? existing.parentId : previousId, message);
647
- previousId = message.id;
648
- }
649
- this.resetRepositoryHead(previousId);
650
- } else this.resetRepositoryHead(headId);
651
- this.assistantHistoryParents.clear();
652
- this.snapshotHistoryIds.clear();
653
- this.persistedHistoryIds.clear();
654
- for (const { message } of loaded.messages) this.persistedHistoryIds.add(message.id);
655
- this.notifyUpdate();
656
- }
657
553
  loadExternalState(state) {
658
554
  this.stateSnapshot = state;
659
555
  this.notifyUpdate();
@@ -669,20 +565,20 @@ var AgUiThreadRuntimeCore = class {
669
565
  async startRun(parentId, runConfig, resume, resumeStream) {
670
566
  const normalizedRunConfig = runConfig ?? {};
671
567
  this.lastRunConfig = normalizedRunConfig;
672
- const parent = parentId === null ? void 0 : this.tryGetMessage(parentId);
673
- const shouldEagerlyInsertAssistant = parentId !== null && parent !== void 0 && parentId !== this.repository.headId;
674
- const historicalMessages = [...shouldEagerlyInsertAssistant ? this.tryGetMessages(parentId) ?? this.repository.getMessages() : this.repository.getMessages()];
568
+ const parent = parentId === null ? void 0 : this.session.tryGetMessage(parentId);
569
+ const shouldEagerlyInsertAssistant = parentId !== null && parent !== void 0 && parentId !== this.session.headId;
570
+ const historicalMessages = [...shouldEagerlyInsertAssistant ? this.session.tryGetMessages(parentId) ?? this.session.getMessages() : this.session.getMessages()];
675
571
  const runStartMessageIds = new Set(this.getMessageRepository().messages.map(({ message }) => message.id));
676
572
  this.pendingError = null;
677
- const assistantParentId = parent ? parentId : this.repository.headId;
573
+ const assistantParentId = parent ? parentId : this.session.headId;
678
574
  let assistantMessageId;
679
575
  let assistantCollided = false;
680
576
  const ensureAssistant = (allowRecreate = false) => {
681
577
  const cached = assistantMessageId;
682
- if (cached !== void 0 && this.tryGetMessage(cached)) return cached;
578
+ if (cached !== void 0 && this.session.tryGetMessage(cached)) return cached;
683
579
  if (cached !== void 0 && (assistantCollided || !allowRecreate)) return cached;
684
- const repositoryHeadId = this.repository.headId;
685
- const parentId = (cached === void 0 || shouldEagerlyInsertAssistant && (repositoryHeadId === null || runStartMessageIds.has(repositoryHeadId))) && assistantParentId && this.hasMessage(assistantParentId) ? assistantParentId : repositoryHeadId;
580
+ const repositoryHeadId = this.session.headId;
581
+ const parentId = (cached === void 0 || shouldEagerlyInsertAssistant && (repositoryHeadId === null || runStartMessageIds.has(repositoryHeadId))) && assistantParentId && this.session.hasMessage(assistantParentId) ? assistantParentId : repositoryHeadId;
686
582
  const created = this.insertAssistantPlaceholder(parentId, cached);
687
583
  assistantMessageId = created;
688
584
  this.markPendingAssistantHistory(created, parentId);
@@ -694,23 +590,40 @@ var AgUiThreadRuntimeCore = class {
694
590
  const resolved = this.updateAssistantMessage(ensureAssistant(hasStreamContent), update);
695
591
  if (resolved !== assistantMessageId) assistantMessageId = resolved;
696
592
  };
593
+ const adoptServerMessageId = (serverId, startNewMessage) => {
594
+ if (startNewMessage && assistantMessageId !== void 0) {
595
+ applyUpdate({ status: {
596
+ type: "complete",
597
+ reason: "unknown"
598
+ } });
599
+ const previousId = assistantMessageId;
600
+ assistantMessageId = void 0;
601
+ if (this.session.tryGetMessage(previousId)) {
602
+ const created = this.insertAssistantPlaceholder(previousId);
603
+ assistantMessageId = created;
604
+ this.markPendingAssistantHistory(created, previousId);
605
+ }
606
+ }
607
+ const placeholder = ensureAssistant(true);
608
+ if (placeholder === serverId) return;
609
+ const reassigned = this.reassignAssistantId(placeholder, serverId);
610
+ const adoptsVisibleCollision = !reassigned && !runStartMessageIds.has(serverId) && this.session.headId === serverId;
611
+ if (reassigned || adoptsVisibleCollision) {
612
+ assistantMessageId = serverId;
613
+ if (adoptsVisibleCollision) {
614
+ const parentId = this.session.tryGetMessage(serverId)?.parentId ?? null;
615
+ this.markPendingAssistantHistory(serverId, parentId);
616
+ }
617
+ } else assistantCollided = true;
618
+ };
697
619
  const aggregator = new RunAggregator({
698
620
  showThinking: this.showThinking,
699
621
  logger: this.logger,
700
622
  emit: applyUpdate,
701
623
  onServerMessageId: (serverId) => {
702
- const placeholder = ensureAssistant(true);
703
- if (placeholder === serverId) return;
704
- const reassigned = this.reassignAssistantId(placeholder, serverId);
705
- const adoptsVisibleCollision = !reassigned && !runStartMessageIds.has(serverId) && this.repository.headId === serverId;
706
- if (reassigned || adoptsVisibleCollision) {
707
- assistantMessageId = serverId;
708
- if (adoptsVisibleCollision) {
709
- const parentId = this.tryGetMessage(serverId)?.parentId ?? null;
710
- this.markPendingAssistantHistory(serverId, parentId);
711
- }
712
- } else assistantCollided = true;
713
- }
624
+ adoptServerMessageId(serverId, false);
625
+ },
626
+ onTextMessageStart: (serverId) => adoptServerMessageId(serverId, true)
714
627
  });
715
628
  const dispatch = (event) => this.handleEvent(aggregator, event, assistantMessageId);
716
629
  const abortController = new AbortController();
@@ -802,7 +715,7 @@ var AgUiThreadRuntimeCore = class {
802
715
  return;
803
716
  }
804
717
  this.maybeAutoCancelPendingToolCalls();
805
- const parentId = this.repository.headId;
718
+ const parentId = this.session.headId;
806
719
  if (parentId !== null) this.startResumeRun(parentId);
807
720
  else {
808
721
  this.pendingA2uiAction = void 0;
@@ -825,7 +738,7 @@ var AgUiThreadRuntimeCore = class {
825
738
  unstable_threadId: ctx.threadId,
826
739
  unstable_parentId: ctx.parentId,
827
740
  unstable_getMessage: () => {
828
- const message = this.tryGetMessage(currentId())?.message;
741
+ const message = this.session.tryGetMessage(currentId())?.message;
829
742
  if (!message) throw new Error("[agui] resume stream requested the assistant message before it existed");
830
743
  return message;
831
744
  }
@@ -848,7 +761,7 @@ var AgUiThreadRuntimeCore = class {
848
761
  return;
849
762
  }
850
763
  if (ctx.abortSignal.aborted) return;
851
- const current = this.tryGetMessage(currentId())?.message;
764
+ const current = this.session.tryGetMessage(currentId())?.message;
852
765
  if (!current || current.status?.type === "running") ctx.applyUpdate({ status: {
853
766
  type: "complete",
854
767
  reason: "unknown"
@@ -856,7 +769,7 @@ var AgUiThreadRuntimeCore = class {
856
769
  }
857
770
  buildRunInput(runId, runConfig, historyMessages, resume) {
858
771
  const threadId = this.agent.threadId || "main";
859
- const messages = toAgUiMessages(historyMessages ?? this.repository.getMessages());
772
+ const messages = toAgUiMessages(historyMessages ?? this.session.getMessages());
860
773
  const context = this.runtime?.thread.getModelContext();
861
774
  const input = {
862
775
  threadId,
@@ -921,31 +834,31 @@ var AgUiThreadRuntimeCore = class {
921
834
  custom: {}
922
835
  }
923
836
  };
924
- this.addOrUpdateMessage(parentId ?? this.repository.headId, assistant);
925
- this.switchToBranch(id);
837
+ this.session.addOrUpdateMessage(parentId ?? this.session.headId, assistant);
838
+ this.session.switchToBranch(id);
926
839
  this.notifyUpdate();
927
840
  return id;
928
841
  }
929
842
  reassignAssistantId(oldId, newId) {
930
843
  if (oldId === newId) return true;
931
- const oldItem = this.tryGetMessage(oldId);
844
+ const oldItem = this.session.tryGetMessage(oldId);
932
845
  if (!oldItem) return false;
933
- const collidesWithExisting = this.hasMessage(newId);
846
+ const collidesWithExisting = this.session.hasMessage(newId);
934
847
  if (collidesWithExisting) {
935
848
  this.logger.debug?.("[agui] reassignAssistantId: server id already present in messages or repository, dropping placeholder", {
936
849
  oldId,
937
850
  newId
938
851
  });
939
- this.deleteMessage(oldId, oldItem.parentId ?? null);
852
+ this.session.deleteMessage(oldId, oldItem.parentId ?? null);
940
853
  } else {
941
854
  const { isOptimistic: _, ...metadata } = oldItem.message.metadata;
942
- this.addOrUpdateMessage(oldItem.parentId, {
855
+ this.session.addOrUpdateMessage(oldItem.parentId, {
943
856
  ...oldItem.message,
944
857
  id: newId,
945
858
  metadata
946
859
  });
947
- this.switchToBranch(newId);
948
- this.tryDeleteMessage(oldId);
860
+ this.session.switchToBranch(newId);
861
+ this.session.tryDeleteMessage(oldId);
949
862
  }
950
863
  const pendingParent = this.assistantHistoryParents.get(oldId);
951
864
  if (pendingParent !== void 0) {
@@ -976,7 +889,7 @@ var AgUiThreadRuntimeCore = class {
976
889
  }
977
890
  updateAssistantMessage(messageId, update) {
978
891
  let latestStatus;
979
- if (!this.updateMessage(messageId, (message) => {
892
+ if (!this.session.updateMessage(messageId, (message) => {
980
893
  if (message.role !== "assistant") return message;
981
894
  const assistant = message;
982
895
  const metadata = update.metadata ? this.mergeAssistantMetadata(assistant.metadata, update.metadata) : assistant.metadata;
@@ -1078,7 +991,7 @@ var AgUiThreadRuntimeCore = class {
1078
991
  }
1079
992
  }
1080
993
  applyCrossRunToolResult(messageId, event) {
1081
- if (!this.updateMessage(messageId, (message) => {
994
+ if (!this.session.updateMessage(messageId, (message) => {
1082
995
  if (message.role !== "assistant") return message;
1083
996
  const assistant = message;
1084
997
  const mcpAppUri = readMcpAppResourceUri(event.mcpResult?._meta);
@@ -1123,7 +1036,7 @@ var AgUiThreadRuntimeCore = class {
1123
1036
  const serverHash = event.content["serverHash"];
1124
1037
  const appServerId = typeof serverId === "string" && serverId.length > 0 ? serverId : typeof serverHash === "string" && serverHash.length > 0 ? serverHash : void 0;
1125
1038
  const result = event.content["result"];
1126
- if (!this.updateMessage(messageId, (message) => {
1039
+ if (!this.session.updateMessage(messageId, (message) => {
1127
1040
  if (message.role !== "assistant") return message;
1128
1041
  const assistant = message;
1129
1042
  let matchedToolCall = false;
@@ -1157,7 +1070,7 @@ var AgUiThreadRuntimeCore = class {
1157
1070
  }
1158
1071
  importMessagesSnapshot(rawMessages, activeAssistantId) {
1159
1072
  try {
1160
- const activeMessage = activeAssistantId ? this.tryGetMessage(activeAssistantId)?.message : void 0;
1073
+ const activeMessage = activeAssistantId ? this.session.tryGetMessage(activeAssistantId)?.message : void 0;
1161
1074
  const activeAssistant = activeMessage?.role === "assistant" ? activeMessage : void 0;
1162
1075
  const normalized = fromAgUiMessages(rawMessages, { showThinking: this.showThinking });
1163
1076
  const converted = [];
@@ -1171,7 +1084,7 @@ var AgUiThreadRuntimeCore = class {
1171
1084
  if (preservesActiveAssistant) converted.push(activeAssistant);
1172
1085
  this.applyExternalMessages(converted);
1173
1086
  if (activeAssistant !== void 0) {
1174
- const activeItem = this.tryGetMessage(activeAssistant.id);
1087
+ const activeItem = this.session.tryGetMessage(activeAssistant.id);
1175
1088
  if (activeItem) {
1176
1089
  if (preservesActiveAssistant) this.snapshotHistoryIds.delete(activeAssistant.id);
1177
1090
  this.markPendingAssistantHistory(activeAssistant.id, activeItem.parentId);
@@ -1205,7 +1118,7 @@ var AgUiThreadRuntimeCore = class {
1205
1118
  if (!history) return;
1206
1119
  const parentId = this.assistantHistoryParents.get(messageId);
1207
1120
  if (parentId === void 0) return;
1208
- const message = this.tryGetMessage(messageId)?.message;
1121
+ const message = this.session.tryGetMessage(messageId)?.message;
1209
1122
  if (!message || message.role !== "assistant") return;
1210
1123
  if (!this.isPersistableStatus(message.status)) return;
1211
1124
  const wasPersisted = this.persistedHistoryIds.has(messageId);