@agents24/react 0.2.26 → 0.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compatibility.json +3 -3
- package/dist/assistant-preview.d.ts +18 -0
- package/dist/index.js +93 -3
- package/dist/index.js.map +1 -1
- package/dist/state.d.ts +2 -0
- package/package.json +2 -2
package/compatibility.json
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Ephemeral display only: these fragments never enter stored messages or replay cursors. */
|
|
2
|
+
import type { AssistantPreview } from "@agents24/client/protocol";
|
|
3
|
+
import type { RuntimeEvent } from "@agents24/client";
|
|
4
|
+
import type { ChatMessage } from "./model";
|
|
5
|
+
export type AssistantPreviewState = {
|
|
6
|
+
runId: string;
|
|
7
|
+
key: string;
|
|
8
|
+
segmentId: string;
|
|
9
|
+
committed: number;
|
|
10
|
+
dispatchId: string;
|
|
11
|
+
generation: number;
|
|
12
|
+
chunks: Record<number, string>;
|
|
13
|
+
retired: string[];
|
|
14
|
+
};
|
|
15
|
+
export declare function acceptAssistantPreview(current: AssistantPreviewState | null | undefined, frame: AssistantPreview | null): AssistantPreviewState | null;
|
|
16
|
+
export declare function commitAssistantPreview(current: AssistantPreviewState | null | undefined, event: RuntimeEvent): AssistantPreviewState | null;
|
|
17
|
+
export declare function previewText(state: AssistantPreviewState | null | undefined): string;
|
|
18
|
+
export declare function messagesWithAssistantPreview(messages: ChatMessage[], state: AssistantPreviewState | null | undefined): ChatMessage[];
|
package/dist/index.js
CHANGED
|
@@ -637,6 +637,79 @@ function createRuntimeEventFrameBuffer(apply, scheduleFrame) {
|
|
|
637
637
|
};
|
|
638
638
|
}
|
|
639
639
|
|
|
640
|
+
// src/assistant-preview.ts
|
|
641
|
+
var keyOf = (frame) => `${frame.dispatch_id}:${frame.generation}:${frame.segment_id}`;
|
|
642
|
+
function acceptAssistantPreview(current, frame) {
|
|
643
|
+
if (!frame) return current ? { ...current, chunks: {} } : null;
|
|
644
|
+
const key = keyOf(frame);
|
|
645
|
+
if (current?.runId === frame.run_id && current.dispatchId === frame.dispatch_id && current.generation > frame.generation) return current;
|
|
646
|
+
if (current?.runId === frame.run_id && current.retired.includes(key)) return current;
|
|
647
|
+
const state = current?.runId === frame.run_id && current.key === key ? current : {
|
|
648
|
+
runId: frame.run_id,
|
|
649
|
+
dispatchId: frame.dispatch_id,
|
|
650
|
+
generation: frame.generation,
|
|
651
|
+
key,
|
|
652
|
+
segmentId: frame.segment_id,
|
|
653
|
+
committed: -1,
|
|
654
|
+
chunks: {},
|
|
655
|
+
retired: current?.runId === frame.run_id ? [...current.retired, current.key].slice(-8) : []
|
|
656
|
+
};
|
|
657
|
+
if (frame.chunk_index <= state.committed || Object.keys(state.chunks).length >= 32 || Object.values(state.chunks).reduce((size, text2) => size + text2.length, 0) + frame.text.length > 65536) return state;
|
|
658
|
+
return { ...state, chunks: { ...state.chunks, [frame.chunk_index]: frame.text } };
|
|
659
|
+
}
|
|
660
|
+
function commitAssistantPreview(current, event) {
|
|
661
|
+
if (event.event === "run.accepted" && current && current.runId !== event.run_id) return null;
|
|
662
|
+
if (current && current.runId !== event.run_id) return current;
|
|
663
|
+
if (["assistant.completed", "run.completed", "run.failed", "run.cancelled", "run.waiting", "run.interrupted", "run.paused", "run.snapshot"].includes(event.event)) return null;
|
|
664
|
+
const ack = event.payload.preview_ack;
|
|
665
|
+
if (event.event !== "assistant.delta" || !ack || typeof ack.dispatch_id !== "string" || typeof ack.segment_id !== "string" || !Number.isSafeInteger(ack.generation) || !Number.isSafeInteger(ack.chunk_index)) return current || null;
|
|
666
|
+
const key = keyOf(ack);
|
|
667
|
+
if (current && current.key !== key) return current;
|
|
668
|
+
const committed = Math.max(current?.committed ?? -1, ack.chunk_index);
|
|
669
|
+
return {
|
|
670
|
+
runId: event.run_id,
|
|
671
|
+
dispatchId: ack.dispatch_id,
|
|
672
|
+
generation: ack.generation,
|
|
673
|
+
key,
|
|
674
|
+
segmentId: ack.segment_id,
|
|
675
|
+
committed,
|
|
676
|
+
retired: current?.retired || [],
|
|
677
|
+
chunks: Object.fromEntries(Object.entries(current?.chunks || {}).filter(([index]) => Number(index) > committed))
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
function previewText(state) {
|
|
681
|
+
if (!state) return "";
|
|
682
|
+
let text2 = "";
|
|
683
|
+
for (let index = state.committed + 1; Object.hasOwn(state.chunks, index); index++) text2 += state.chunks[index];
|
|
684
|
+
return text2;
|
|
685
|
+
}
|
|
686
|
+
function messagesWithAssistantPreview(messages, state) {
|
|
687
|
+
const tail = previewText(state);
|
|
688
|
+
if (!state || !tail) return messages;
|
|
689
|
+
let index = -1;
|
|
690
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
691
|
+
if (messages[i].role === "assistant" && messages[i].runId === state.runId && !messages[i].isFinal) {
|
|
692
|
+
index = i;
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
const base = index < 0 ? {
|
|
697
|
+
id: `preview-${state.runId}`,
|
|
698
|
+
role: "assistant",
|
|
699
|
+
runId: state.runId,
|
|
700
|
+
content: "",
|
|
701
|
+
parts: [],
|
|
702
|
+
createdAt: /* @__PURE__ */ new Date(0),
|
|
703
|
+
isFinal: false
|
|
704
|
+
} : messages[index];
|
|
705
|
+
const parts = [...base.parts];
|
|
706
|
+
const last = parts[parts.length - 1];
|
|
707
|
+
if (last?.type === "text") parts[parts.length - 1] = { ...last, text: last.text + tail };
|
|
708
|
+
else parts.push({ id: `preview-${state.segmentId}`, type: "text", kind: "text", text: tail });
|
|
709
|
+
const rendered = { ...base, content: base.content + tail, parts };
|
|
710
|
+
return index < 0 ? [...messages, rendered] : messages.map((message, i) => i === index ? rendered : message);
|
|
711
|
+
}
|
|
712
|
+
|
|
640
713
|
// src/hitl-resolution.ts
|
|
641
714
|
function applyHitlResolution(messages, receipt) {
|
|
642
715
|
return messages.map((message) => message.runId !== receipt.run_id ? message : {
|
|
@@ -869,6 +942,11 @@ function reconcileModelTurnParts(parts, event) {
|
|
|
869
942
|
return active ? upsertResponseBlockParts(next, [active]) : next;
|
|
870
943
|
}
|
|
871
944
|
function applyRuntimeEvent(state, event) {
|
|
945
|
+
const next = applyCanonicalRuntimeEvent(state, event);
|
|
946
|
+
if (!state.assistantPreview && !event.payload.preview_ack) return next;
|
|
947
|
+
return { ...next, assistantPreview: commitAssistantPreview(state.assistantPreview, event) };
|
|
948
|
+
}
|
|
949
|
+
function applyCanonicalRuntimeEvent(state, event) {
|
|
872
950
|
if (state.activeRunId && event.run_id && event.run_id !== state.activeRunId) {
|
|
873
951
|
const previous = state.messages.find((message) => message.role === "assistant" && message.runId === event.run_id);
|
|
874
952
|
if (event.event !== "run.accepted") {
|
|
@@ -2130,6 +2208,12 @@ function useAgentChat(options = {}) {
|
|
|
2130
2208
|
}
|
|
2131
2209
|
}
|
|
2132
2210
|
}, [clearOperationError, client, detach, failOperation, pageSize, queue.hydrate, runtime, update, invalidateThreadOpen, ownOperation, captureFeedbackRead]);
|
|
2211
|
+
const consumePreview = React8.useCallback((frame) => {
|
|
2212
|
+
update((current) => {
|
|
2213
|
+
if (frame && current.activeRunId && current.activeRunId !== frame.run_id) return current;
|
|
2214
|
+
return { ...current, assistantPreview: acceptAssistantPreview(current.assistantPreview, frame) };
|
|
2215
|
+
});
|
|
2216
|
+
}, [update]);
|
|
2133
2217
|
const consumeEvent = React8.useCallback((event) => {
|
|
2134
2218
|
const timing = continuationTiming.current.get(event.run_id);
|
|
2135
2219
|
if (timing && !timing.attached) {
|
|
@@ -2158,7 +2242,9 @@ function useAgentChat(options = {}) {
|
|
|
2158
2242
|
clearOperationError("attach_run");
|
|
2159
2243
|
update((current) => ({ ...current, activeRunId: runId, runState: "reconnecting", error: null }));
|
|
2160
2244
|
try {
|
|
2161
|
-
const result = await client.runs.attach({ runId, cursor,
|
|
2245
|
+
const result = await client.runs.attach({ runId, cursor, onPreview: (frame) => {
|
|
2246
|
+
if (isCurrent()) consumePreview(frame);
|
|
2247
|
+
}, leaseSeconds: 60, signal: controller.signal }, (event) => {
|
|
2162
2248
|
if (isCurrent()) consumeEvent(event);
|
|
2163
2249
|
});
|
|
2164
2250
|
if (!isCurrent()) return;
|
|
@@ -2174,7 +2260,7 @@ function useAgentChat(options = {}) {
|
|
|
2174
2260
|
} finally {
|
|
2175
2261
|
if (streamControllerRef.current === controller) streamControllerRef.current = null;
|
|
2176
2262
|
}
|
|
2177
|
-
}, [clearOperationError, client, consumeEvent, eventBuffer, failOperation, refreshMessages, runtime, update, ownOperation]);
|
|
2263
|
+
}, [clearOperationError, client, consumeEvent, consumePreview, eventBuffer, failOperation, refreshMessages, runtime, update, ownOperation]);
|
|
2178
2264
|
attachRunRef.current = attachRun;
|
|
2179
2265
|
const submit = React8.useCallback(async (input) => {
|
|
2180
2266
|
if (!input.text.trim() && !input.attachmentIds?.length && !input.uploads?.length) return;
|
|
@@ -2285,6 +2371,9 @@ function useAgentChat(options = {}) {
|
|
|
2285
2371
|
}));
|
|
2286
2372
|
}
|
|
2287
2373
|
const result = await client.chat.stream({
|
|
2374
|
+
onPreview: (frame) => {
|
|
2375
|
+
if (isCurrent()) consumePreview(frame);
|
|
2376
|
+
},
|
|
2288
2377
|
leaseSeconds: 60,
|
|
2289
2378
|
clientSubmissionId: ticket.client_submission_id,
|
|
2290
2379
|
input: input.text.trim(),
|
|
@@ -2336,7 +2425,7 @@ function useAgentChat(options = {}) {
|
|
|
2336
2425
|
} catch (error) {
|
|
2337
2426
|
if (submissionOwner() || !isAbortLike(error)) throw error;
|
|
2338
2427
|
}
|
|
2339
|
-
}, [clearOperationError, client, consumeEvent, detach, eventBuffer, failOperation, invalidateThreadOpen, queue.submit, refreshMessages, refreshThreads, runtime, update, ownOperation]);
|
|
2428
|
+
}, [clearOperationError, client, consumeEvent, consumePreview, detach, eventBuffer, failOperation, invalidateThreadOpen, queue.submit, refreshMessages, refreshThreads, runtime, update, ownOperation]);
|
|
2340
2429
|
const { steer, editPendingMessage, steerPendingMessage, removePendingMessage, resumeQueue } = useAgentChatQueueActions({
|
|
2341
2430
|
queue,
|
|
2342
2431
|
stateRef,
|
|
@@ -2563,6 +2652,7 @@ function useAgentChat(options = {}) {
|
|
|
2563
2652
|
const hasMoreThreads = threadTotal === void 0 ? state.threads.length >= threadPageSize : state.threads.length < threadTotal;
|
|
2564
2653
|
return {
|
|
2565
2654
|
...state,
|
|
2655
|
+
messages: messagesWithAssistantPreview(state.messages, state.assistantPreview),
|
|
2566
2656
|
activeThread,
|
|
2567
2657
|
pendingMessages,
|
|
2568
2658
|
messageQueue,
|