@opengeni/react 1.0.1 → 2.3.0-canary.0
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/README.md +33 -10
- package/dist/artifacts-spreadsheet.js +1 -1
- package/dist/artifacts.js +1 -1
- package/dist/browser-viewer-GXUICIAG.js +14 -0
- package/dist/{chunk-R3AZOAB5.js → chunk-4MDLEHXL.js} +9 -115
- package/dist/chunk-4MDLEHXL.js.map +1 -0
- package/dist/chunk-5YK2ZDIG.js +116 -0
- package/dist/chunk-5YK2ZDIG.js.map +1 -0
- package/dist/chunk-H5YGYNXS.js +329 -0
- package/dist/chunk-H5YGYNXS.js.map +1 -0
- package/dist/{chunk-7WCLAEFV.js → chunk-ICA6R6TW.js} +2 -2
- package/dist/{chunk-7WCLAEFV.js.map → chunk-ICA6R6TW.js.map} +1 -1
- package/dist/{chunk-IGC6A2ZI.js → chunk-JOAVA2TW.js} +589 -217
- package/dist/chunk-JOAVA2TW.js.map +1 -0
- package/dist/{chunk-Y7OEDUJ5.js → chunk-LS4POUTY.js} +1057 -426
- package/dist/chunk-LS4POUTY.js.map +1 -0
- package/dist/{chunk-5UQPNLIO.js → chunk-LTCHJ4MS.js} +9 -9
- package/dist/chunk-LTCHJ4MS.js.map +1 -0
- package/dist/{chunk-C5ZPSSS5.js → chunk-NEXLLTP4.js} +2 -1
- package/dist/{chunk-C5ZPSSS5.js.map → chunk-NEXLLTP4.js.map} +1 -1
- package/dist/chunk-QGBJ6GHG.js +2300 -0
- package/dist/chunk-QGBJ6GHG.js.map +1 -0
- package/dist/{chunk-6KLX2RH5.js → chunk-RSXJN73N.js} +365 -21
- package/dist/chunk-RSXJN73N.js.map +1 -0
- package/dist/{chunk-B6WPZSTT.js → chunk-SE4W4WQ3.js} +78 -16
- package/dist/chunk-SE4W4WQ3.js.map +1 -0
- package/dist/{chunk-MKPIAGVL.js → chunk-W6NFJXSA.js} +8 -19
- package/dist/chunk-W6NFJXSA.js.map +1 -0
- package/dist/{chunk-XBZWOM2K.js → chunk-X4A66EWZ.js} +8 -3
- package/dist/chunk-X4A66EWZ.js.map +1 -0
- package/dist/chunk-X4JAFD5R.js +3907 -0
- package/dist/chunk-X4JAFD5R.js.map +1 -0
- package/dist/{chunk-HA46CYQK.js → chunk-XXWH2JLC.js} +792 -206
- package/dist/chunk-XXWH2JLC.js.map +1 -0
- package/dist/client.d.ts +2 -2
- package/dist/components/browser-viewer.d.ts +7 -1
- package/dist/components/computer-viewer.d.ts +4 -1
- package/dist/components/enrollment-consent.d.ts +6 -3
- package/dist/components/file-browser.d.ts +7 -1
- package/dist/components/human-input-form.d.ts +1 -1
- package/dist/components/human-input-surface.d.ts +1 -1
- package/dist/components/machine-card.d.ts +4 -1
- package/dist/components/machines/machine-detail.d.ts +4 -1
- package/dist/components/machines/machine-operation-policy.d.ts +11 -0
- package/dist/components/machines-dashboard.d.ts +3 -1
- package/dist/components/markdown.d.ts +20 -1
- package/dist/components/message-timeline.d.ts +1 -1
- package/dist/components/model-policy-picker.d.ts +2 -0
- package/dist/components/pierre-file.d.ts +1 -1
- package/dist/components/sandbox-files.d.ts +8 -2
- package/dist/components/sandbox-workspace.d.ts +33 -3
- package/dist/components/session-chrome.d.ts +15 -3
- package/dist/components/workspace-dock.d.ts +6 -2
- package/dist/composer.js +5 -5
- package/dist/computer-viewer-ZOP4Q7A7.js +16 -0
- package/dist/computer-viewer-ZOP4Q7A7.js.map +1 -0
- package/dist/hooks/channel-cache.d.ts +23 -0
- package/dist/hooks/shared-machines-list.d.ts +14 -0
- package/dist/hooks/use-attached-browsers.d.ts +2 -1
- package/dist/hooks/use-channels.d.ts +1 -0
- package/dist/hooks/use-composer.d.ts +37 -9
- package/dist/hooks/use-machine-chip.d.ts +3 -3
- package/dist/hooks/use-machines.d.ts +19 -1
- package/dist/hooks/use-sandbox-files.d.ts +1 -0
- package/dist/hooks/use-session-background-commands.d.ts +14 -0
- package/dist/hooks/use-turn-queue.d.ts +12 -0
- package/dist/hooks/use-workspace-sessions.d.ts +1 -0
- package/dist/index.d.ts +7 -5
- package/dist/index.js +1096 -623
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +29 -181
- package/dist/interaction.js.map +1 -1
- package/dist/lib/interaction-errors.d.ts +3 -0
- package/dist/machines.d.ts +4 -2
- package/dist/machines.js +10 -2
- package/dist/model-policy.d.ts +1 -1
- package/dist/model-policy.js +1 -1
- package/dist/platform-activity-row-BJHUHXAT.js +169 -0
- package/dist/platform-activity-row-BJHUHXAT.js.map +1 -0
- package/dist/{queue-surface-implementation-2KVJTYXH.js → queue-surface-implementation-BSKUWHRI.js} +76 -16
- package/dist/queue-surface-implementation-BSKUWHRI.js.map +1 -0
- package/dist/realtime/realtime-control.d.ts +6 -3
- package/dist/realtime.js +36 -14
- package/dist/realtime.js.map +1 -1
- package/dist/session-ui.d.ts +1 -1
- package/dist/session-ui.js +6 -2
- package/dist/session.d.ts +2 -2
- package/dist/session.js +4 -4
- package/dist/timeline/index.d.ts +1 -1
- package/dist/timeline/platform-activity-row.d.ts +15 -0
- package/dist/timeline/screenshot-lightbox.d.ts +1 -1
- package/dist/timeline/shared.d.ts +4 -2
- package/dist/timeline/types.d.ts +50 -5
- package/dist/types/machines.d.ts +2 -2
- package/package.json +3 -3
- package/src/client.ts +12 -1
- package/src/components/artifacts/editable-spreadsheet.tsx +1 -1
- package/src/components/browser-viewer.tsx +361 -58
- package/src/components/chat-composer.tsx +1 -1
- package/src/components/composer.tsx +6 -6
- package/src/components/computer-viewer.tsx +368 -115
- package/src/components/enrollment-consent.tsx +64 -6
- package/src/components/file-browser.tsx +117 -2
- package/src/components/human-input-form.tsx +103 -59
- package/src/components/human-input-surface.tsx +1 -1
- package/src/components/machine-card.tsx +111 -0
- package/src/components/machine-input-display.ts +15 -0
- package/src/components/machines/machine-detail.tsx +47 -0
- package/src/components/machines/machine-operation-policy.tsx +179 -0
- package/src/components/machines-dashboard.tsx +6 -0
- package/src/components/markdown.tsx +174 -20
- package/src/components/message-timeline.tsx +215 -18
- package/src/components/model-policy-picker.tsx +9 -17
- package/src/components/pierre-file.tsx +1 -1
- package/src/components/queue-surface-implementation.tsx +82 -16
- package/src/components/sandbox-files.tsx +135 -19
- package/src/components/sandbox-workspace.tsx +204 -92
- package/src/components/session-chrome.tsx +415 -208
- package/src/components/session-status.tsx +1 -1
- package/src/components/user-message-body.tsx +168 -48
- package/src/components/workspace-dock.tsx +141 -175
- package/src/hooks/channel-cache.ts +104 -0
- package/src/hooks/shared-machines-list.ts +239 -0
- package/src/hooks/use-attached-browsers.ts +5 -1
- package/src/hooks/use-browser-frame-stream.ts +6 -1
- package/src/hooks/use-browser-session.ts +6 -4
- package/src/hooks/use-browser-sessions.ts +7 -1
- package/src/hooks/use-channels.ts +32 -10
- package/src/hooks/use-composer.ts +760 -291
- package/src/hooks/use-computer-frame-stream.ts +14 -9
- package/src/hooks/use-computer-session.ts +16 -14
- package/src/hooks/use-computer-sessions.ts +8 -1
- package/src/hooks/use-last-started-turn-policy.ts +1 -1
- package/src/hooks/use-machine-chip.ts +23 -6
- package/src/hooks/use-machines.ts +104 -6
- package/src/hooks/use-sandbox-files.ts +195 -140
- package/src/hooks/use-sandbox-git.ts +58 -29
- package/src/hooks/use-session-background-commands.ts +56 -0
- package/src/hooks/use-session-capabilities.ts +18 -0
- package/src/hooks/use-turn-queue.ts +111 -12
- package/src/hooks/use-workspace-sessions.ts +5 -1
- package/src/index.ts +26 -4
- package/src/lib/interaction-errors.ts +18 -0
- package/src/machines.ts +9 -1
- package/src/model-policy.ts +10 -2
- package/src/realtime/realtime-control.tsx +53 -17
- package/src/session-context.ts +1 -0
- package/src/session-ui.ts +6 -1
- package/src/session.ts +9 -1
- package/src/timeline/activity-rail.tsx +20 -75
- package/src/timeline/index.ts +4 -0
- package/src/timeline/platform-activity-row.tsx +201 -0
- package/src/timeline/projection.ts +529 -25
- package/src/timeline/screenshot-lightbox.tsx +48 -14
- package/src/timeline/shared.tsx +8 -2
- package/src/timeline/tool-renderers.tsx +104 -6
- package/src/timeline/turn-summary.tsx +6 -1
- package/src/timeline/types.ts +77 -2
- package/src/types/machines.ts +10 -0
- package/styles/compiled.css +115 -104
- package/dist/chunk-5UQPNLIO.js.map +0 -1
- package/dist/chunk-6KLX2RH5.js.map +0 -1
- package/dist/chunk-B6WPZSTT.js.map +0 -1
- package/dist/chunk-HA46CYQK.js.map +0 -1
- package/dist/chunk-IGC6A2ZI.js.map +0 -1
- package/dist/chunk-LLOLUHVG.js +0 -5937
- package/dist/chunk-LLOLUHVG.js.map +0 -1
- package/dist/chunk-MKPIAGVL.js.map +0 -1
- package/dist/chunk-R3AZOAB5.js.map +0 -1
- package/dist/chunk-XBZWOM2K.js.map +0 -1
- package/dist/chunk-Y7OEDUJ5.js.map +0 -1
- package/dist/interactive-workbench-viewers-TOHBXJEE.js +0 -15
- package/dist/queue-surface-implementation-2KVJTYXH.js.map +0 -1
- /package/dist/{interactive-workbench-viewers-TOHBXJEE.js.map → browser-viewer-GXUICIAG.js.map} +0 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-KZ73RL76.js";
|
|
4
4
|
import {
|
|
5
5
|
useEmbeddedSession
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NEXLLTP4.js";
|
|
7
7
|
|
|
8
8
|
// src/hooks/use-composer.ts
|
|
9
9
|
import {
|
|
@@ -46,6 +46,8 @@ function restoreOptimisticSendOperations(key) {
|
|
|
46
46
|
}
|
|
47
47
|
return stored.map(({ hasMcpCredentialUpdates, ...operation }) => ({
|
|
48
48
|
...operation,
|
|
49
|
+
delivery: "send",
|
|
50
|
+
destination: operation.destination === "queue" ? "queue" : "chat",
|
|
49
51
|
newerShadow: operation.newerShadow ?? { text: "", resources: [], annotations: [] },
|
|
50
52
|
state: operation.state === "sending" || operation.state === "queued" ? "sending" : operation.state,
|
|
51
53
|
outcomeUnknown: operation.state === "sending" || operation.state === "queued" ? true : operation.outcomeUnknown,
|
|
@@ -65,6 +67,14 @@ function rememberOptimisticSendOperations(key, operations) {
|
|
|
65
67
|
hasMcpCredentialUpdates: input.mcpCredentialUpdates !== void 0
|
|
66
68
|
};
|
|
67
69
|
});
|
|
70
|
+
if (stored.length === 0) {
|
|
71
|
+
optimisticSendOperations.delete(key);
|
|
72
|
+
try {
|
|
73
|
+
pendingComposerStorage()?.removeItem(optimisticSendStorageKey(key));
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
68
78
|
optimisticSendOperations.set(key, stored);
|
|
69
79
|
try {
|
|
70
80
|
pendingComposerStorage()?.setItem(optimisticSendStorageKey(key), JSON.stringify(stored));
|
|
@@ -157,7 +167,8 @@ function rememberPendingComposerOperation(key, operation) {
|
|
|
157
167
|
newerShadow: {
|
|
158
168
|
text: operation.newerShadow.text,
|
|
159
169
|
resources: [...operation.newerShadow.resources],
|
|
160
|
-
annotations: cloneAnnotations(operation.newerShadow.annotations)
|
|
170
|
+
annotations: cloneAnnotations(operation.newerShadow.annotations),
|
|
171
|
+
...operation.newerShadow.policy ? { policy: { ...operation.newerShadow.policy } } : {}
|
|
161
172
|
}
|
|
162
173
|
};
|
|
163
174
|
pendingComposerOperations.set(key, stored);
|
|
@@ -201,6 +212,18 @@ function steeringAcceptedEvent(steering, events) {
|
|
|
201
212
|
(event) => event.type === "user.message" && steering.clientEventId !== null && event.clientEventId === steering.clientEventId
|
|
202
213
|
);
|
|
203
214
|
}
|
|
215
|
+
function promptTurnIdForTrigger(triggerEventId, events) {
|
|
216
|
+
if (!triggerEventId) return null;
|
|
217
|
+
const queued = events.find((event) => {
|
|
218
|
+
if (event.type !== "turn.queued") return false;
|
|
219
|
+
const payload2 = event.payload;
|
|
220
|
+
return typeof payload2 === "object" && payload2 !== null && "triggerEventId" in payload2 && payload2.triggerEventId === triggerEventId;
|
|
221
|
+
});
|
|
222
|
+
if (!queued) return null;
|
|
223
|
+
if (queued.turnId) return queued.turnId;
|
|
224
|
+
const payload = queued.payload;
|
|
225
|
+
return typeof payload === "object" && payload !== null && "turnId" in payload && typeof payload.turnId === "string" ? payload.turnId : null;
|
|
226
|
+
}
|
|
204
227
|
function steeringSettledByEvents(steering, events) {
|
|
205
228
|
const acceptedEventId = steering.triggerEventId ?? steeringAcceptedEvent(steering, events)?.id ?? null;
|
|
206
229
|
return events.some((event) => {
|
|
@@ -212,9 +235,53 @@ function steeringSettledByEvents(steering, events) {
|
|
|
212
235
|
return typeof payload === "object" && payload !== null && "triggerEventId" in payload && payload.triggerEventId === acceptedEventId;
|
|
213
236
|
});
|
|
214
237
|
}
|
|
238
|
+
function reconcileOptimisticSendFromEvents(operation, events) {
|
|
239
|
+
const accepted = events.find(
|
|
240
|
+
(event) => event.type === "user.message" && event.clientEventId === operation.clientEventId
|
|
241
|
+
);
|
|
242
|
+
const triggerEventId = operation.triggerEventId ?? accepted?.id ?? null;
|
|
243
|
+
const turnId = operation.turnId ?? promptTurnIdForTrigger(triggerEventId, events);
|
|
244
|
+
const needsAdmissionUpdate = accepted !== void 0 && (operation.state !== "queued" || operation.triggerEventId !== triggerEventId || operation.turnId !== turnId || operation.error !== void 0 || operation.outcomeUnknown !== false);
|
|
245
|
+
const reconciled = needsAdmissionUpdate ? {
|
|
246
|
+
...operation,
|
|
247
|
+
state: "queued",
|
|
248
|
+
triggerEventId,
|
|
249
|
+
turnId,
|
|
250
|
+
error: void 0,
|
|
251
|
+
outcomeUnknown: false
|
|
252
|
+
} : operation;
|
|
253
|
+
const withdrawnFromQueue = events.some((event) => {
|
|
254
|
+
if (event.type !== "session.queue.changed" || !turnId) return false;
|
|
255
|
+
const payload = event.payload;
|
|
256
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) return false;
|
|
257
|
+
const record = payload;
|
|
258
|
+
return record.turnId === turnId && (record.operation === "edit" || record.operation === "delete");
|
|
259
|
+
});
|
|
260
|
+
return {
|
|
261
|
+
operation: reconciled,
|
|
262
|
+
admitted: accepted !== void 0,
|
|
263
|
+
// Edit/Delete atomically withdraw the queued turn. Keeping its optimistic
|
|
264
|
+
// send alive after that point lets its old `newerShadow` become the newest
|
|
265
|
+
// composer draft again when a later turn settles, duplicating submitted
|
|
266
|
+
// text. The queue mutation is the durable terminal fact for this send.
|
|
267
|
+
settled: withdrawnFromQueue || steeringSettledByEvents(
|
|
268
|
+
{
|
|
269
|
+
phase: "accepted",
|
|
270
|
+
text: reconciled.text,
|
|
271
|
+
clientEventId: reconciled.clientEventId,
|
|
272
|
+
triggerEventId: reconciled.triggerEventId ?? null,
|
|
273
|
+
turnId: reconciled.turnId ?? null
|
|
274
|
+
},
|
|
275
|
+
events
|
|
276
|
+
)
|
|
277
|
+
};
|
|
278
|
+
}
|
|
215
279
|
function useComposer(sessionId, options = {}) {
|
|
216
280
|
const { client, workspaceId, registerSessionReconciler } = useEmbeddedSession(options);
|
|
217
281
|
const durableDrafts = options.draftPersistence !== "disabled";
|
|
282
|
+
if (!durableDrafts && !options.initialPolicy) {
|
|
283
|
+
throw new Error("useComposer requires initialPolicy when draft persistence is disabled");
|
|
284
|
+
}
|
|
218
285
|
const targetKey = `${workspaceId}\0${sessionId ?? ""}\0${durableDrafts ? "durable" : "disabled"}`;
|
|
219
286
|
const pendingOperationKey = pendingComposerOperationKey(workspaceId, sessionId);
|
|
220
287
|
const initialPendingOperation = restorePendingComposerOperation(pendingOperationKey);
|
|
@@ -230,21 +297,26 @@ function useComposer(sessionId, options = {}) {
|
|
|
230
297
|
const [optimisticSends, setOptimisticSends] = useState(initialOptimisticSends);
|
|
231
298
|
const [steering, setSteering] = useState(
|
|
232
299
|
() => initialPendingOperation?.delivery === "steer" ? {
|
|
233
|
-
phase: "
|
|
300
|
+
phase: "failed",
|
|
234
301
|
text: initialPendingOperation.input.text,
|
|
235
302
|
clientEventId: initialPendingOperation.input.clientEventId ?? null,
|
|
236
303
|
triggerEventId: null,
|
|
237
|
-
turnId: null
|
|
304
|
+
turnId: null,
|
|
305
|
+
error: "Not confirmed. Retry to check the same direction change.",
|
|
306
|
+
outcomeUnknown: true
|
|
238
307
|
} : null
|
|
239
308
|
);
|
|
240
309
|
const [pausing, setPausing] = useState(false);
|
|
241
|
-
const [
|
|
310
|
+
const [acceptedControl, setAcceptedControl] = useState(null);
|
|
242
311
|
const [resuming, setResuming] = useState(false);
|
|
243
312
|
const [error, setError] = useState(null);
|
|
244
313
|
const [draft, setDraft] = useState(null);
|
|
245
314
|
const [draftLoading, setDraftLoading] = useState(Boolean(sessionId) && durableDrafts);
|
|
246
315
|
const [draftSaving, setDraftSaving] = useState(false);
|
|
247
316
|
const [draftConflict, setDraftConflict] = useState(null);
|
|
317
|
+
const [policy, setPolicy] = useState(
|
|
318
|
+
() => initialShadow?.policy ?? options.initialPolicy ?? null
|
|
319
|
+
);
|
|
248
320
|
const [restoredResources, setRestoredResources] = useState(
|
|
249
321
|
() => initialShadow?.resources ?? []
|
|
250
322
|
);
|
|
@@ -254,11 +326,15 @@ function useComposer(sessionId, options = {}) {
|
|
|
254
326
|
const optimisticCallbackIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
255
327
|
const steeringSettlementEventsRef = useRef([]);
|
|
256
328
|
const steeringRef = useRef(steering);
|
|
329
|
+
const steeringOccurredAtRef = useRef((/* @__PURE__ */ new Date()).toISOString());
|
|
257
330
|
const pendingClientEventId = useRef(
|
|
258
331
|
initialPendingOperation?.input.clientEventId ?? null
|
|
259
332
|
);
|
|
260
333
|
const valueRef = useRef(initialShadow?.text ?? "");
|
|
261
334
|
const annotationsRef = useRef(initialShadow?.annotations ?? []);
|
|
335
|
+
const policyRef = useRef(
|
|
336
|
+
initialShadow?.policy ?? options.initialPolicy ?? null
|
|
337
|
+
);
|
|
262
338
|
const draftRef = useRef(null);
|
|
263
339
|
const restoredResourcesRef = useRef(initialShadow?.resources ?? []);
|
|
264
340
|
const localEditRevision = useRef(initialShadow ? 1 : 0);
|
|
@@ -268,18 +344,21 @@ function useComposer(sessionId, options = {}) {
|
|
|
268
344
|
const saveChain = useRef(Promise.resolve());
|
|
269
345
|
const onSent = options.onSent;
|
|
270
346
|
const onSubmitted = options.onSubmitted;
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
useLayoutEffect(() => {
|
|
274
|
-
onDraftAppliedRef.current = onDraftApplied;
|
|
275
|
-
}, [onDraftApplied]);
|
|
347
|
+
const onDeliveryErrorRef = useRef(options.onDeliveryError);
|
|
348
|
+
onDeliveryErrorRef.current = options.onDeliveryError;
|
|
276
349
|
useLayoutEffect(() => {
|
|
277
350
|
steeringRef.current = steering;
|
|
278
351
|
}, [steering]);
|
|
279
352
|
const sendExtrasRef = useRef(options.sendExtras);
|
|
280
353
|
sendExtrasRef.current = options.sendExtras;
|
|
354
|
+
const sendDestinationRef = useRef(options.sendDestination);
|
|
355
|
+
sendDestinationRef.current = options.sendDestination;
|
|
281
356
|
const sendBlockedRef = useRef(options.sendBlocked);
|
|
282
357
|
sendBlockedRef.current = options.sendBlocked;
|
|
358
|
+
const effectiveControlRef = useRef(
|
|
359
|
+
acceptedControl ?? options.effectiveControl ?? null
|
|
360
|
+
);
|
|
361
|
+
effectiveControlRef.current = acceptedControl ?? options.effectiveControl ?? null;
|
|
283
362
|
const liveExtrasVersion = JSON.stringify(resolveSendExtras(options.sendExtras));
|
|
284
363
|
const targetKeyRef = useRef(targetKey);
|
|
285
364
|
useLayoutEffect(() => {
|
|
@@ -298,6 +377,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
298
377
|
localEditRevision.current = shadow ? 1 : 0;
|
|
299
378
|
valueRef.current = shadow?.text ?? "";
|
|
300
379
|
annotationsRef.current = shadow?.annotations ?? [];
|
|
380
|
+
policyRef.current = shadow?.policy ?? options.initialPolicy ?? null;
|
|
301
381
|
draftRef.current = null;
|
|
302
382
|
restoredResourcesRef.current = shadow?.resources ?? [];
|
|
303
383
|
lastSavedSignature.current = null;
|
|
@@ -305,20 +385,23 @@ function useComposer(sessionId, options = {}) {
|
|
|
305
385
|
setStateTargetKey(targetKey);
|
|
306
386
|
setValue(shadow?.text ?? "");
|
|
307
387
|
setAnnotations(shadow?.annotations ?? []);
|
|
388
|
+
setPolicy(policyRef.current);
|
|
308
389
|
setAnnotationReviewTargetId(null);
|
|
309
390
|
setSending(false);
|
|
310
391
|
setOptimisticSends(restoredOptimisticSends);
|
|
311
392
|
setSteering(
|
|
312
393
|
pendingOperationRef.current?.delivery === "steer" ? {
|
|
313
|
-
phase: "
|
|
394
|
+
phase: "failed",
|
|
314
395
|
text: pendingOperationRef.current.input.text,
|
|
315
396
|
clientEventId: pendingOperationRef.current.input.clientEventId ?? null,
|
|
316
397
|
triggerEventId: null,
|
|
317
|
-
turnId: null
|
|
398
|
+
turnId: null,
|
|
399
|
+
error: "Not confirmed. Retry to check the same direction change.",
|
|
400
|
+
outcomeUnknown: true
|
|
318
401
|
} : null
|
|
319
402
|
);
|
|
320
403
|
setPausing(false);
|
|
321
|
-
|
|
404
|
+
setAcceptedControl(null);
|
|
322
405
|
setResuming(false);
|
|
323
406
|
setError(null);
|
|
324
407
|
setDraft(null);
|
|
@@ -326,7 +409,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
326
409
|
setDraftSaving(false);
|
|
327
410
|
setDraftConflict(null);
|
|
328
411
|
setRestoredResources(shadow?.resources ?? []);
|
|
329
|
-
}, [durableDrafts, pendingOperationKey, sessionId, targetKey]);
|
|
412
|
+
}, [durableDrafts, options.initialPolicy, pendingOperationKey, sessionId, targetKey]);
|
|
330
413
|
const setOptimisticDraftShadow = useCallback(
|
|
331
414
|
(shadow) => {
|
|
332
415
|
if (optimisticSendsRef.current.length === 0) return;
|
|
@@ -335,7 +418,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
335
418
|
newerShadow: {
|
|
336
419
|
text: shadow.text,
|
|
337
420
|
resources: [...shadow.resources],
|
|
338
|
-
annotations: cloneAnnotations(shadow.annotations)
|
|
421
|
+
annotations: cloneAnnotations(shadow.annotations),
|
|
422
|
+
...shadow.policy ? { policy: { ...shadow.policy } } : {}
|
|
339
423
|
}
|
|
340
424
|
}));
|
|
341
425
|
optimisticSendsRef.current = next;
|
|
@@ -348,15 +432,18 @@ function useComposer(sessionId, options = {}) {
|
|
|
348
432
|
(next) => {
|
|
349
433
|
if (targetKeyRef.current !== targetKey) return;
|
|
350
434
|
if (!durableDrafts) {
|
|
435
|
+
const nextPolicy2 = policyFromDraft(next);
|
|
351
436
|
localEditRevision.current += 1;
|
|
352
437
|
valueRef.current = next.text;
|
|
353
438
|
annotationsRef.current = next.annotations ?? [];
|
|
439
|
+
policyRef.current = nextPolicy2;
|
|
354
440
|
restoredResourcesRef.current = next.resources;
|
|
355
441
|
draftRef.current = null;
|
|
356
442
|
lastSavedSignature.current = null;
|
|
357
443
|
setDraft(null);
|
|
358
444
|
setValue(next.text);
|
|
359
445
|
setAnnotations(next.annotations ?? []);
|
|
446
|
+
setPolicy(nextPolicy2);
|
|
360
447
|
setRestoredResources(next.resources);
|
|
361
448
|
pendingOperationRef.current = updatePendingComposerShadow(
|
|
362
449
|
pendingOperationKey,
|
|
@@ -367,7 +454,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
367
454
|
next.resources,
|
|
368
455
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
369
456
|
),
|
|
370
|
-
annotations: next.annotations ?? []
|
|
457
|
+
annotations: next.annotations ?? [],
|
|
458
|
+
policy: nextPolicy2
|
|
371
459
|
}
|
|
372
460
|
);
|
|
373
461
|
setOptimisticDraftShadow({
|
|
@@ -376,13 +464,16 @@ function useComposer(sessionId, options = {}) {
|
|
|
376
464
|
next.resources,
|
|
377
465
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
378
466
|
),
|
|
379
|
-
annotations: next.annotations ?? []
|
|
467
|
+
annotations: next.annotations ?? [],
|
|
468
|
+
policy: nextPolicy2
|
|
380
469
|
});
|
|
381
470
|
setDraftConflict(null);
|
|
382
471
|
return;
|
|
383
472
|
}
|
|
473
|
+
const nextPolicy = policyFromDraft(next);
|
|
384
474
|
valueRef.current = next.text;
|
|
385
475
|
annotationsRef.current = next.annotations ?? [];
|
|
476
|
+
policyRef.current = nextPolicy;
|
|
386
477
|
draftRef.current = next;
|
|
387
478
|
restoredResourcesRef.current = next.resources;
|
|
388
479
|
lastSavedSignature.current = draftSignature(draftPayload(next));
|
|
@@ -390,6 +481,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
390
481
|
setDraft(next);
|
|
391
482
|
setValue(next.text);
|
|
392
483
|
setAnnotations(next.annotations ?? []);
|
|
484
|
+
setPolicy(nextPolicy);
|
|
393
485
|
setRestoredResources(next.resources);
|
|
394
486
|
pendingOperationRef.current = updatePendingComposerShadow(
|
|
395
487
|
pendingOperationKey,
|
|
@@ -400,7 +492,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
400
492
|
next.resources,
|
|
401
493
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
402
494
|
),
|
|
403
|
-
annotations: next.annotations ?? []
|
|
495
|
+
annotations: next.annotations ?? [],
|
|
496
|
+
policy: nextPolicy
|
|
404
497
|
}
|
|
405
498
|
);
|
|
406
499
|
setOptimisticDraftShadow({
|
|
@@ -409,10 +502,10 @@ function useComposer(sessionId, options = {}) {
|
|
|
409
502
|
next.resources,
|
|
410
503
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
411
504
|
),
|
|
412
|
-
annotations: next.annotations ?? []
|
|
505
|
+
annotations: next.annotations ?? [],
|
|
506
|
+
policy: nextPolicy
|
|
413
507
|
});
|
|
414
508
|
setDraftConflict(null);
|
|
415
|
-
onDraftAppliedRef.current?.(next);
|
|
416
509
|
},
|
|
417
510
|
[durableDrafts, pendingOperationKey, setOptimisticDraftShadow, targetKey]
|
|
418
511
|
);
|
|
@@ -427,16 +520,17 @@ function useComposer(sessionId, options = {}) {
|
|
|
427
520
|
const readTicket = ++draftReadGeneration.current;
|
|
428
521
|
const localAtStart = localEditRevision.current;
|
|
429
522
|
const baseAtStart = draftRef.current;
|
|
430
|
-
const
|
|
431
|
-
const localSignatureAtStart = baseAtStart ? draftSignature(
|
|
523
|
+
const policyAtStart = policyRef.current;
|
|
524
|
+
const localSignatureAtStart = baseAtStart ? policyAtStart ? draftSignature(
|
|
432
525
|
composerDraftPayload(
|
|
433
526
|
baseAtStart,
|
|
434
527
|
valueRef.current,
|
|
435
528
|
restoredResourcesRef.current,
|
|
436
529
|
annotationsRef.current,
|
|
437
|
-
|
|
530
|
+
policyAtStart,
|
|
531
|
+
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
438
532
|
)
|
|
439
|
-
) : null;
|
|
533
|
+
) : null : null;
|
|
440
534
|
const localWasDirtyAtStart = localSignatureAtStart === null ? localAtStart !== 0 : localSignatureAtStart !== lastSavedSignature.current;
|
|
441
535
|
const showLoading = replaceLocal || draftRef.current === null;
|
|
442
536
|
if (showLoading) {
|
|
@@ -457,22 +551,29 @@ function useComposer(sessionId, options = {}) {
|
|
|
457
551
|
valueRef.current = shadow.text;
|
|
458
552
|
restoredResourcesRef.current = shadow.resources;
|
|
459
553
|
annotationsRef.current = shadow.annotations;
|
|
554
|
+
if (shadow.policy) policyRef.current = shadow.policy;
|
|
460
555
|
localEditRevision.current ||= 1;
|
|
461
556
|
setValue(shadow.text);
|
|
462
557
|
setRestoredResources(shadow.resources);
|
|
463
558
|
setAnnotations(shadow.annotations);
|
|
559
|
+
if (shadow.policy) setPolicy(shadow.policy);
|
|
464
560
|
} else if (replaceLocal || !localWasDirtyAtStart && localAtStart === localEditRevision.current) {
|
|
465
|
-
const
|
|
466
|
-
const pickerChangedDuringFetch = extrasNow.model !== extrasAtStart.model || extrasNow.reasoningEffort !== extrasAtStart.reasoningEffort || extrasNow.latencyMode !== extrasAtStart.latencyMode;
|
|
561
|
+
const fetchedPolicy = policyFromDraft(fetched);
|
|
467
562
|
valueRef.current = fetched.text;
|
|
468
563
|
restoredResourcesRef.current = fetched.resources;
|
|
469
564
|
annotationsRef.current = fetched.annotations ?? [];
|
|
565
|
+
policyRef.current = fetchedPolicy;
|
|
470
566
|
lastSavedSignature.current = draftSignature(draftPayload(fetched));
|
|
471
567
|
setValue(fetched.text);
|
|
472
568
|
setRestoredResources(fetched.resources);
|
|
473
569
|
setAnnotations(fetched.annotations ?? []);
|
|
474
|
-
|
|
475
|
-
|
|
570
|
+
setPolicy(fetchedPolicy);
|
|
571
|
+
} else {
|
|
572
|
+
lastSavedSignature.current = draftSignature(draftPayload(fetched));
|
|
573
|
+
if (!policyRef.current) {
|
|
574
|
+
const fetchedPolicy = policyFromDraft(fetched);
|
|
575
|
+
policyRef.current = fetchedPolicy;
|
|
576
|
+
setPolicy(fetchedPolicy);
|
|
476
577
|
}
|
|
477
578
|
}
|
|
478
579
|
}
|
|
@@ -580,23 +681,38 @@ function useComposer(sessionId, options = {}) {
|
|
|
580
681
|
setSteering(null);
|
|
581
682
|
}, [options.events, steering]);
|
|
582
683
|
useEffect(() => {
|
|
583
|
-
if (!
|
|
684
|
+
if (!acceptedControl) return;
|
|
584
685
|
const effectiveControl = options.effectiveControl;
|
|
585
|
-
if (!effectiveControl || effectiveControl.controlVersion <
|
|
686
|
+
if (!effectiveControl || effectiveControl.controlVersion < acceptedControl.controlVersion) {
|
|
586
687
|
return;
|
|
587
688
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
setControlStopping((current) => current === controlStopping ? null : current);
|
|
592
|
-
}, [controlStopping, options.effectiveControl]);
|
|
689
|
+
setAcceptedControl((current) => current === acceptedControl ? null : current);
|
|
690
|
+
}, [acceptedControl, options.effectiveControl]);
|
|
593
691
|
const currentDraftPayload = useCallback(() => {
|
|
594
692
|
if (!durableDrafts || targetKeyRef.current !== targetKey) return null;
|
|
595
693
|
const base = draftRef.current;
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
return composerDraftPayload(
|
|
694
|
+
const currentPolicy = policyRef.current;
|
|
695
|
+
if (!base || !currentPolicy) return null;
|
|
696
|
+
return composerDraftPayload(
|
|
697
|
+
base,
|
|
698
|
+
value,
|
|
699
|
+
restoredResources,
|
|
700
|
+
annotations,
|
|
701
|
+
currentPolicy,
|
|
702
|
+
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
703
|
+
);
|
|
599
704
|
}, [annotations, durableDrafts, restoredResources, targetKey, value]);
|
|
705
|
+
const adoptDraftBase = useCallback(
|
|
706
|
+
(next) => {
|
|
707
|
+
if (targetKeyRef.current !== targetKey) return;
|
|
708
|
+
draftRef.current = next;
|
|
709
|
+
setDraft(next);
|
|
710
|
+
lastSavedSignature.current = draftSignature(draftPayload(next));
|
|
711
|
+
setDraftConflict(null);
|
|
712
|
+
setError(null);
|
|
713
|
+
},
|
|
714
|
+
[targetKey]
|
|
715
|
+
);
|
|
600
716
|
const persistPayload = useCallback(
|
|
601
717
|
async (payload) => {
|
|
602
718
|
const ownedTargetKey = targetKey;
|
|
@@ -619,27 +735,11 @@ function useComposer(sessionId, options = {}) {
|
|
|
619
735
|
}
|
|
620
736
|
setDraftSaving(true);
|
|
621
737
|
try {
|
|
622
|
-
const saved = await
|
|
623
|
-
client,
|
|
624
|
-
workspaceId,
|
|
625
|
-
sessionId,
|
|
626
|
-
request,
|
|
627
|
-
onAdoptRemote: (remote) => {
|
|
628
|
-
draftRef.current = remote;
|
|
629
|
-
setDraft(remote);
|
|
630
|
-
}
|
|
631
|
-
});
|
|
738
|
+
const saved = await client.saveComposerDraft(workspaceId, sessionId, request);
|
|
632
739
|
if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
|
|
633
740
|
return;
|
|
634
741
|
}
|
|
635
|
-
|
|
636
|
-
setDraft(saved);
|
|
637
|
-
lastSavedSignature.current = draftSignature({
|
|
638
|
-
...request,
|
|
639
|
-
expectedRevision: saved.revision
|
|
640
|
-
});
|
|
641
|
-
setDraftConflict(null);
|
|
642
|
-
setError(null);
|
|
742
|
+
adoptDraftBase(saved);
|
|
643
743
|
success = true;
|
|
644
744
|
} catch (cause) {
|
|
645
745
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
@@ -657,7 +757,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
657
757
|
await saveChain.current;
|
|
658
758
|
return success;
|
|
659
759
|
},
|
|
660
|
-
[client, durableDrafts, sessionId, targetKey, workspaceId]
|
|
760
|
+
[adoptDraftBase, client, durableDrafts, sessionId, targetKey, workspaceId]
|
|
661
761
|
);
|
|
662
762
|
const replaceOptimisticSends = useCallback(
|
|
663
763
|
(update) => {
|
|
@@ -682,15 +782,40 @@ function useComposer(sessionId, options = {}) {
|
|
|
682
782
|
[onSent, replaceOptimisticSends]
|
|
683
783
|
);
|
|
684
784
|
useEffect(() => {
|
|
685
|
-
const
|
|
686
|
-
|
|
785
|
+
const events = options.events ?? [];
|
|
786
|
+
if (events.length === 0 || optimisticSendsRef.current.length === 0) return;
|
|
787
|
+
const reconciled = optimisticSendsRef.current.map(
|
|
788
|
+
(operation) => reconcileOptimisticSendFromEvents(operation, events)
|
|
789
|
+
);
|
|
790
|
+
const settledIds = new Set(
|
|
791
|
+
reconciled.filter((item) => item.settled).map((item) => item.operation.clientEventId)
|
|
687
792
|
);
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
(operation) => acceptedIds.has(operation.clientEventId)
|
|
793
|
+
const changed = reconciled.some(
|
|
794
|
+
(item, index) => item.operation !== optimisticSendsRef.current[index] && !settledIds.has(item.operation.clientEventId)
|
|
691
795
|
);
|
|
692
|
-
for (const
|
|
693
|
-
|
|
796
|
+
for (const item of reconciled) {
|
|
797
|
+
if (item.admitted && !optimisticCallbackIdsRef.current.has(item.operation.clientEventId)) {
|
|
798
|
+
optimisticCallbackIdsRef.current.add(item.operation.clientEventId);
|
|
799
|
+
onSent?.(item.operation.input.text, item.operation.input);
|
|
800
|
+
}
|
|
801
|
+
if (item.settled) markOptimisticAccepted(item.operation);
|
|
802
|
+
}
|
|
803
|
+
if (changed) {
|
|
804
|
+
replaceOptimisticSends(
|
|
805
|
+
(current) => current.map(
|
|
806
|
+
(operation) => reconciled.find((item) => item.operation.clientEventId === operation.clientEventId)?.operation ?? operation
|
|
807
|
+
).filter((operation) => !settledIds.has(operation.clientEventId))
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
if (durableDrafts && reconciled.some((item) => item.admitted)) void loadDraft(false);
|
|
811
|
+
}, [
|
|
812
|
+
durableDrafts,
|
|
813
|
+
loadDraft,
|
|
814
|
+
markOptimisticAccepted,
|
|
815
|
+
onSent,
|
|
816
|
+
options.events,
|
|
817
|
+
replaceOptimisticSends
|
|
818
|
+
]);
|
|
694
819
|
const processOptimisticSends = useCallback(() => {
|
|
695
820
|
if (!sessionId || optimisticProcessorBusyRef.current) return;
|
|
696
821
|
const currentOperations = optimisticSendsRef.current;
|
|
@@ -703,17 +828,59 @@ function useComposer(sessionId, options = {}) {
|
|
|
703
828
|
const ownedGeneration = targetGeneration.current;
|
|
704
829
|
optimisticProcessorBusyRef.current = true;
|
|
705
830
|
void (async () => {
|
|
831
|
+
let mutationFailureObserved = false;
|
|
832
|
+
const markFailed = (problem, outcomeUnknown) => {
|
|
833
|
+
if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
|
|
834
|
+
return;
|
|
835
|
+
}
|
|
836
|
+
replaceOptimisticSends(
|
|
837
|
+
(current) => current.map(
|
|
838
|
+
(candidate) => candidate.clientEventId === operation.clientEventId ? {
|
|
839
|
+
...candidate,
|
|
840
|
+
state: "failed",
|
|
841
|
+
error: problem.message,
|
|
842
|
+
outcomeUnknown
|
|
843
|
+
} : candidate
|
|
844
|
+
)
|
|
845
|
+
);
|
|
846
|
+
};
|
|
706
847
|
try {
|
|
707
848
|
if (operation.outcomeUnknown) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
849
|
+
let events;
|
|
850
|
+
try {
|
|
851
|
+
events = await client.listEvents(workspaceId, sessionId, {
|
|
852
|
+
includeTypes: [
|
|
853
|
+
"user.message",
|
|
854
|
+
"turn.queued",
|
|
855
|
+
"turn.started",
|
|
856
|
+
"turn.completed",
|
|
857
|
+
"turn.failed",
|
|
858
|
+
"turn.cancelled",
|
|
859
|
+
"turn.superseded"
|
|
860
|
+
],
|
|
861
|
+
limit: 250,
|
|
862
|
+
payloadMode: "full"
|
|
863
|
+
});
|
|
864
|
+
} catch (cause) {
|
|
865
|
+
markFailed(asError(cause), true);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
const reconciled = reconcileOptimisticSendFromEvents(operation, events);
|
|
869
|
+
if (reconciled.admitted) {
|
|
870
|
+
if (durableDrafts) await loadDraft(false);
|
|
871
|
+
if (reconciled.settled) {
|
|
872
|
+
markOptimisticAccepted(reconciled.operation);
|
|
873
|
+
} else {
|
|
874
|
+
replaceOptimisticSends(
|
|
875
|
+
(current) => current.map(
|
|
876
|
+
(candidate) => candidate.clientEventId === operation.clientEventId ? reconciled.operation : candidate
|
|
877
|
+
)
|
|
878
|
+
);
|
|
879
|
+
if (!optimisticCallbackIdsRef.current.has(operation.clientEventId)) {
|
|
880
|
+
optimisticCallbackIdsRef.current.add(operation.clientEventId);
|
|
881
|
+
onSent?.(reconciled.operation.input.text, reconciled.operation.input);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
717
884
|
return;
|
|
718
885
|
}
|
|
719
886
|
if (!operation.canRetry) {
|
|
@@ -736,16 +903,58 @@ function useComposer(sessionId, options = {}) {
|
|
|
736
903
|
...operation.input,
|
|
737
904
|
...expectedDraftRevision !== void 0 ? { expectedDraftRevision } : {}
|
|
738
905
|
};
|
|
739
|
-
|
|
906
|
+
let acceptedResult = null;
|
|
907
|
+
let acceptedEvent = null;
|
|
908
|
+
if (durableDrafts) {
|
|
909
|
+
if (!operation.draftPayload || expectedDraftRevision === void 0) {
|
|
910
|
+
throw new Error("The durable composer draft is not ready for delivery.");
|
|
911
|
+
}
|
|
912
|
+
const result = await client.submitComposerDraft(workspaceId, sessionId, {
|
|
913
|
+
text: operation.draftPayload.text,
|
|
914
|
+
annotations: operation.draftPayload.annotations,
|
|
915
|
+
resources: operation.draftPayload.resources,
|
|
916
|
+
model: operation.draftPayload.model,
|
|
917
|
+
reasoningEffort: operation.draftPayload.reasoningEffort,
|
|
918
|
+
latencyMode: operation.draftPayload.latencyMode,
|
|
919
|
+
expectedDraftRevision,
|
|
920
|
+
clientEventId: operation.clientEventId,
|
|
921
|
+
delivery: "send",
|
|
922
|
+
...wireInput.controlEtag ? { controlEtag: wireInput.controlEtag } : {},
|
|
923
|
+
...wireInput.modelContext ? { modelContext: wireInput.modelContext } : {},
|
|
924
|
+
...wireInput.mcpCredentialUpdates ? { mcpCredentialUpdates: wireInput.mcpCredentialUpdates } : {},
|
|
925
|
+
...wireInput.connectionAuthorities ? { connectionAuthorities: wireInput.connectionAuthorities } : {},
|
|
926
|
+
...wireInput.personalResourceAttachment ? { personalResourceAttachment: wireInput.personalResourceAttachment } : {}
|
|
927
|
+
}).catch((cause) => {
|
|
928
|
+
mutationFailureObserved = true;
|
|
929
|
+
throw cause;
|
|
930
|
+
});
|
|
931
|
+
acceptedResult = result;
|
|
932
|
+
adoptDraftBase(result.draft);
|
|
933
|
+
} else {
|
|
934
|
+
acceptedEvent = await client.sendMessage(workspaceId, sessionId, wireInput).catch((cause) => {
|
|
935
|
+
mutationFailureObserved = true;
|
|
936
|
+
throw cause;
|
|
937
|
+
});
|
|
938
|
+
}
|
|
740
939
|
if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
|
|
741
940
|
return;
|
|
742
941
|
}
|
|
743
|
-
|
|
942
|
+
const acceptedDestination = acceptedResult?.routing === "queued_for_execution" ? "queue" : acceptedResult?.routing === "accepted_for_execution" ? "chat" : operation.destination;
|
|
943
|
+
if (options.events === void 0 && acceptedDestination === "chat") {
|
|
744
944
|
markOptimisticAccepted({ ...operation, input: wireInput });
|
|
745
945
|
} else {
|
|
746
946
|
replaceOptimisticSends(
|
|
747
947
|
(current) => current.map(
|
|
748
|
-
(candidate) => candidate.clientEventId === operation.clientEventId ? {
|
|
948
|
+
(candidate) => candidate.clientEventId === operation.clientEventId ? {
|
|
949
|
+
...candidate,
|
|
950
|
+
input: wireInput,
|
|
951
|
+
destination: acceptedDestination,
|
|
952
|
+
turnId: acceptedResult?.turn.id ?? candidate.turnId,
|
|
953
|
+
triggerEventId: acceptedResult?.accepted.id ?? acceptedEvent?.id ?? candidate.triggerEventId,
|
|
954
|
+
appliedQueueVersion: acceptedResult?.receipt?.appliedQueueVersion ?? candidate.appliedQueueVersion,
|
|
955
|
+
state: "queued",
|
|
956
|
+
error: void 0
|
|
957
|
+
} : candidate
|
|
749
958
|
)
|
|
750
959
|
);
|
|
751
960
|
}
|
|
@@ -753,36 +962,17 @@ function useComposer(sessionId, options = {}) {
|
|
|
753
962
|
optimisticCallbackIdsRef.current.add(operation.clientEventId);
|
|
754
963
|
onSent?.(wireInput.text, wireInput);
|
|
755
964
|
}
|
|
756
|
-
if (durableDrafts && draftRef.current) {
|
|
757
|
-
const cleared = {
|
|
758
|
-
...draftRef.current,
|
|
759
|
-
revision: 0,
|
|
760
|
-
text: "",
|
|
761
|
-
resources: [],
|
|
762
|
-
annotations: [],
|
|
763
|
-
sourceTurnId: null,
|
|
764
|
-
sourceTurnVersion: null,
|
|
765
|
-
updatedAt: null
|
|
766
|
-
};
|
|
767
|
-
draftRef.current = cleared;
|
|
768
|
-
setDraft(cleared);
|
|
769
|
-
lastSavedSignature.current = draftSignature(draftPayload(cleared));
|
|
770
|
-
}
|
|
771
965
|
} catch (cause) {
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
(candidate) => candidate.clientEventId === operation.clientEventId ? {
|
|
778
|
-
...candidate,
|
|
779
|
-
state: "failed",
|
|
780
|
-
error: problem.message,
|
|
781
|
-
outcomeUnknown
|
|
782
|
-
} : candidate
|
|
783
|
-
)
|
|
784
|
-
);
|
|
966
|
+
const current = optimisticSendsRef.current.find(
|
|
967
|
+
(candidate) => candidate.clientEventId === operation.clientEventId
|
|
968
|
+
);
|
|
969
|
+
if (!current || current.state === "queued" && current.outcomeUnknown === false) {
|
|
970
|
+
return;
|
|
785
971
|
}
|
|
972
|
+
const problem = asError(cause);
|
|
973
|
+
onDeliveryErrorRef.current?.(problem, operation.input, "send");
|
|
974
|
+
const outcomeUnknown = operation.outcomeUnknown && !mutationFailureObserved ? true : isOutcomeUnknownError(cause);
|
|
975
|
+
markFailed(problem, outcomeUnknown);
|
|
786
976
|
} finally {
|
|
787
977
|
optimisticProcessorBusyRef.current = false;
|
|
788
978
|
if (targetKeyRef.current === ownedTargetKey) {
|
|
@@ -791,9 +981,11 @@ function useComposer(sessionId, options = {}) {
|
|
|
791
981
|
}
|
|
792
982
|
})();
|
|
793
983
|
}, [
|
|
984
|
+
adoptDraftBase,
|
|
794
985
|
client,
|
|
795
986
|
durableDrafts,
|
|
796
987
|
markOptimisticAccepted,
|
|
988
|
+
loadDraft,
|
|
797
989
|
onSent,
|
|
798
990
|
options.events,
|
|
799
991
|
persistPayload,
|
|
@@ -814,9 +1006,10 @@ function useComposer(sessionId, options = {}) {
|
|
|
814
1006
|
restoredResourcesRef.current,
|
|
815
1007
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
816
1008
|
),
|
|
817
|
-
annotations: annotationsRef.current
|
|
1009
|
+
annotations: annotationsRef.current,
|
|
1010
|
+
...policyRef.current ? { policy: policyRef.current } : {}
|
|
818
1011
|
};
|
|
819
|
-
if (pending.newerShadow.text !== shadow.text || JSON.stringify(pending.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(pending.newerShadow.annotations) !== JSON.stringify(shadow.annotations)) {
|
|
1012
|
+
if (pending.newerShadow.text !== shadow.text || JSON.stringify(pending.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(pending.newerShadow.annotations) !== JSON.stringify(shadow.annotations) || JSON.stringify(pending.newerShadow.policy) !== JSON.stringify(shadow.policy)) {
|
|
820
1013
|
pendingOperationRef.current = updatePendingComposerShadow(
|
|
821
1014
|
pendingOperationKey,
|
|
822
1015
|
pending,
|
|
@@ -833,9 +1026,10 @@ function useComposer(sessionId, options = {}) {
|
|
|
833
1026
|
restoredResourcesRef.current,
|
|
834
1027
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
835
1028
|
),
|
|
836
|
-
annotations: annotationsRef.current
|
|
1029
|
+
annotations: annotationsRef.current,
|
|
1030
|
+
...policyRef.current ? { policy: policyRef.current } : {}
|
|
837
1031
|
};
|
|
838
|
-
if (optimistic.newerShadow.text !== shadow.text || JSON.stringify(optimistic.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(optimistic.newerShadow.annotations) !== JSON.stringify(shadow.annotations)) {
|
|
1032
|
+
if (optimistic.newerShadow.text !== shadow.text || JSON.stringify(optimistic.newerShadow.resources) !== JSON.stringify(shadow.resources) || JSON.stringify(optimistic.newerShadow.annotations) !== JSON.stringify(shadow.annotations) || JSON.stringify(optimistic.newerShadow.policy) !== JSON.stringify(shadow.policy)) {
|
|
839
1033
|
setOptimisticDraftShadow(shadow);
|
|
840
1034
|
}
|
|
841
1035
|
}
|
|
@@ -875,12 +1069,13 @@ function useComposer(sessionId, options = {}) {
|
|
|
875
1069
|
const rawText = explicit ?? draftAtSend;
|
|
876
1070
|
const hasText = rawText.trim().length > 0;
|
|
877
1071
|
const hasAnnotations = annotationsAtSend.length > 0;
|
|
1072
|
+
const currentPolicy = policyRef.current;
|
|
878
1073
|
const annotationsComplete2 = annotationsAtSend.every(
|
|
879
1074
|
(annotation) => annotation.note.trim().length > 0
|
|
880
1075
|
);
|
|
881
1076
|
const extras = pending ? {} : resolveSendExtras(sendExtrasRef.current);
|
|
882
1077
|
const hasResources = restoredResources.length > 0 || (extras.resources?.length ?? 0) > 0;
|
|
883
|
-
if (!pending && (!annotationsComplete2 || !hasText && !hasResources && !hasAnnotations) || !sessionId || sending || sendBlockedRef.current?.() === true || targetKeyRef.current !== ownedTargetKey) {
|
|
1078
|
+
if (!pending && (!annotationsComplete2 || !hasText && !hasResources && !hasAnnotations) || !sessionId || !currentPolicy || sending || sendBlockedRef.current?.() === true || targetKeyRef.current !== ownedTargetKey) {
|
|
884
1079
|
return false;
|
|
885
1080
|
}
|
|
886
1081
|
const clearPending = () => {
|
|
@@ -894,22 +1089,6 @@ function useComposer(sessionId, options = {}) {
|
|
|
894
1089
|
const draftWasUnchanged = valueRef.current === operation.draftAtSend;
|
|
895
1090
|
const resourcesWereUnchanged = JSON.stringify(restoredResourcesRef.current) === JSON.stringify(operation.resourcesAtSend);
|
|
896
1091
|
const annotationsWereUnchanged = JSON.stringify(annotationsRef.current) === JSON.stringify(operation.annotationsAtSend);
|
|
897
|
-
const previousDraft = draftRef.current;
|
|
898
|
-
if (previousDraft) {
|
|
899
|
-
const cleared = {
|
|
900
|
-
...previousDraft,
|
|
901
|
-
revision: 0,
|
|
902
|
-
text: "",
|
|
903
|
-
resources: [],
|
|
904
|
-
annotations: [],
|
|
905
|
-
sourceTurnId: null,
|
|
906
|
-
sourceTurnVersion: null,
|
|
907
|
-
updatedAt: null
|
|
908
|
-
};
|
|
909
|
-
draftRef.current = cleared;
|
|
910
|
-
setDraft(cleared);
|
|
911
|
-
lastSavedSignature.current = draftSignature(draftPayload(cleared));
|
|
912
|
-
}
|
|
913
1092
|
if (resourcesWereUnchanged) {
|
|
914
1093
|
restoredResourcesRef.current = [];
|
|
915
1094
|
setRestoredResources([]);
|
|
@@ -926,6 +1105,30 @@ function useComposer(sessionId, options = {}) {
|
|
|
926
1105
|
onSent?.(operation.input.text, operation.input);
|
|
927
1106
|
};
|
|
928
1107
|
const deliver = async (operation) => {
|
|
1108
|
+
if (durableDrafts) {
|
|
1109
|
+
const input = operation.input;
|
|
1110
|
+
if (input.expectedDraftRevision === void 0 || input.clientEventId === void 0 || input.model === void 0 || input.reasoningEffort === void 0 || input.latencyMode === void 0) {
|
|
1111
|
+
throw new Error("The durable composer draft is not ready for delivery.");
|
|
1112
|
+
}
|
|
1113
|
+
const result = await client.submitComposerDraft(workspaceId, sessionId, {
|
|
1114
|
+
text: input.text,
|
|
1115
|
+
annotations: input.annotations ?? [],
|
|
1116
|
+
resources: input.resources ?? [],
|
|
1117
|
+
model: input.model,
|
|
1118
|
+
reasoningEffort: input.reasoningEffort,
|
|
1119
|
+
latencyMode: input.latencyMode,
|
|
1120
|
+
expectedDraftRevision: input.expectedDraftRevision,
|
|
1121
|
+
clientEventId: input.clientEventId,
|
|
1122
|
+
delivery: operation.delivery,
|
|
1123
|
+
...input.controlEtag ? { controlEtag: input.controlEtag } : {},
|
|
1124
|
+
...input.modelContext ? { modelContext: input.modelContext } : {},
|
|
1125
|
+
...input.mcpCredentialUpdates ? { mcpCredentialUpdates: input.mcpCredentialUpdates } : {},
|
|
1126
|
+
...input.connectionAuthorities ? { connectionAuthorities: input.connectionAuthorities } : {},
|
|
1127
|
+
...input.personalResourceAttachment ? { personalResourceAttachment: input.personalResourceAttachment } : {}
|
|
1128
|
+
});
|
|
1129
|
+
adoptDraftBase(result.draft);
|
|
1130
|
+
return result;
|
|
1131
|
+
}
|
|
929
1132
|
if (operation.delivery === "steer") {
|
|
930
1133
|
return await client.steerMessage(workspaceId, sessionId, operation.input);
|
|
931
1134
|
}
|
|
@@ -933,6 +1136,9 @@ function useComposer(sessionId, options = {}) {
|
|
|
933
1136
|
return null;
|
|
934
1137
|
};
|
|
935
1138
|
if (delivery === "steer") {
|
|
1139
|
+
if (steeringRef.current?.clientEventId !== pending?.input.clientEventId) {
|
|
1140
|
+
steeringOccurredAtRef.current = (/* @__PURE__ */ new Date()).toISOString();
|
|
1141
|
+
}
|
|
936
1142
|
setSteering({
|
|
937
1143
|
phase: "submitting",
|
|
938
1144
|
text: rawText,
|
|
@@ -957,7 +1163,20 @@ function useComposer(sessionId, options = {}) {
|
|
|
957
1163
|
) ?? null;
|
|
958
1164
|
} catch (cause) {
|
|
959
1165
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
960
|
-
|
|
1166
|
+
const problem = asError(cause);
|
|
1167
|
+
setError(problem);
|
|
1168
|
+
if (pending.delivery === "steer") {
|
|
1169
|
+
keepSteering = true;
|
|
1170
|
+
setSteering({
|
|
1171
|
+
phase: "failed",
|
|
1172
|
+
text: pending.input.text,
|
|
1173
|
+
clientEventId: pending.input.clientEventId ?? null,
|
|
1174
|
+
triggerEventId: null,
|
|
1175
|
+
turnId: null,
|
|
1176
|
+
error: "Not confirmed. Retry.",
|
|
1177
|
+
outcomeUnknown: true
|
|
1178
|
+
});
|
|
1179
|
+
}
|
|
961
1180
|
}
|
|
962
1181
|
return false;
|
|
963
1182
|
}
|
|
@@ -965,6 +1184,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
965
1184
|
return false;
|
|
966
1185
|
}
|
|
967
1186
|
if (acceptedEvent) {
|
|
1187
|
+
if (durableDrafts) await loadDraft(false);
|
|
968
1188
|
if (pending.delivery === "steer") {
|
|
969
1189
|
keepSteering = true;
|
|
970
1190
|
setSteering({
|
|
@@ -1000,9 +1220,26 @@ function useComposer(sessionId, options = {}) {
|
|
|
1000
1220
|
});
|
|
1001
1221
|
}
|
|
1002
1222
|
} catch (cause) {
|
|
1003
|
-
|
|
1223
|
+
const problem = asError(cause);
|
|
1224
|
+
const outcomeUnknown = isOutcomeUnknownError(cause);
|
|
1225
|
+
onDeliveryErrorRef.current?.(problem, pending.input, pending.delivery);
|
|
1226
|
+
if (!outcomeUnknown) {
|
|
1227
|
+
clearPending();
|
|
1228
|
+
keepSteering = false;
|
|
1229
|
+
} else if (pending.delivery === "steer") {
|
|
1230
|
+
keepSteering = true;
|
|
1231
|
+
setSteering({
|
|
1232
|
+
phase: "failed",
|
|
1233
|
+
text: pending.input.text,
|
|
1234
|
+
clientEventId: pending.input.clientEventId ?? null,
|
|
1235
|
+
triggerEventId: null,
|
|
1236
|
+
turnId: null,
|
|
1237
|
+
error: "Not confirmed. Retry.",
|
|
1238
|
+
outcomeUnknown: true
|
|
1239
|
+
});
|
|
1240
|
+
}
|
|
1004
1241
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
1005
|
-
setError(
|
|
1242
|
+
setError(problem);
|
|
1006
1243
|
}
|
|
1007
1244
|
return false;
|
|
1008
1245
|
}
|
|
@@ -1020,8 +1257,10 @@ function useComposer(sessionId, options = {}) {
|
|
|
1020
1257
|
return false;
|
|
1021
1258
|
}
|
|
1022
1259
|
pendingClientEventId.current ??= generateClientEventId();
|
|
1260
|
+
const effectiveControl = effectiveControlRef.current;
|
|
1023
1261
|
const input = composeSendInput(sendText, pendingClientEventId.current, extras, {
|
|
1024
|
-
...
|
|
1262
|
+
...currentPolicy,
|
|
1263
|
+
...effectiveControl?.controlEtag ? { controlEtag: effectiveControl.controlEtag } : {},
|
|
1025
1264
|
...durableDrafts && draftRef.current ? { expectedDraftRevision: draftRef.current.revision } : {},
|
|
1026
1265
|
resources: mergeResources(restoredResources, extras.resources ?? []),
|
|
1027
1266
|
annotations: cloneAnnotations(annotationsAtSend)
|
|
@@ -1035,7 +1274,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
1035
1274
|
newerShadow: {
|
|
1036
1275
|
text: draftAtSend,
|
|
1037
1276
|
resources: mergeResources(restoredResources, extras.resources ?? []),
|
|
1038
|
-
annotations: cloneAnnotations(annotationsAtSend)
|
|
1277
|
+
annotations: cloneAnnotations(annotationsAtSend),
|
|
1278
|
+
policy: currentPolicy
|
|
1039
1279
|
},
|
|
1040
1280
|
clearDraftOnAccept: explicit === void 0,
|
|
1041
1281
|
canRetry: true
|
|
@@ -1065,10 +1305,20 @@ function useComposer(sessionId, options = {}) {
|
|
|
1065
1305
|
});
|
|
1066
1306
|
}
|
|
1067
1307
|
} catch (cause) {
|
|
1308
|
+
onDeliveryErrorRef.current?.(asError(cause), operation.input, operation.delivery);
|
|
1068
1309
|
if (!isOutcomeUnknownError(cause)) {
|
|
1069
1310
|
clearPending();
|
|
1070
1311
|
} else if (delivery === "steer") {
|
|
1071
1312
|
keepSteering = true;
|
|
1313
|
+
setSteering({
|
|
1314
|
+
phase: "failed",
|
|
1315
|
+
text: operation.input.text,
|
|
1316
|
+
clientEventId: operation.input.clientEventId ?? null,
|
|
1317
|
+
triggerEventId: null,
|
|
1318
|
+
turnId: null,
|
|
1319
|
+
error: "Not confirmed. Retry.",
|
|
1320
|
+
outcomeUnknown: true
|
|
1321
|
+
});
|
|
1072
1322
|
}
|
|
1073
1323
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
1074
1324
|
setError(asError(cause));
|
|
@@ -1092,15 +1342,16 @@ function useComposer(sessionId, options = {}) {
|
|
|
1092
1342
|
currentDraftPayload,
|
|
1093
1343
|
durableDrafts,
|
|
1094
1344
|
onSent,
|
|
1095
|
-
options.effectiveControl?.controlEtag,
|
|
1096
1345
|
persistPayload,
|
|
1097
1346
|
restoredResources,
|
|
1098
1347
|
annotations,
|
|
1348
|
+
adoptDraftBase,
|
|
1099
1349
|
sending,
|
|
1100
1350
|
sessionId,
|
|
1101
1351
|
targetKey,
|
|
1102
1352
|
value,
|
|
1103
|
-
workspaceId
|
|
1353
|
+
workspaceId,
|
|
1354
|
+
loadDraft
|
|
1104
1355
|
]
|
|
1105
1356
|
);
|
|
1106
1357
|
const send = useCallback(
|
|
@@ -1110,6 +1361,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
1110
1361
|
}
|
|
1111
1362
|
const rawText = explicit ?? valueRef.current;
|
|
1112
1363
|
const annotationsAtSend = cloneAnnotations(annotationsRef.current);
|
|
1364
|
+
const currentPolicy = policyRef.current;
|
|
1113
1365
|
const hasText = rawText.trim().length > 0;
|
|
1114
1366
|
const hasAnnotations = annotationsAtSend.length > 0;
|
|
1115
1367
|
const annotationsComplete2 = annotationsAtSend.every(
|
|
@@ -1117,19 +1369,26 @@ function useComposer(sessionId, options = {}) {
|
|
|
1117
1369
|
);
|
|
1118
1370
|
const extras = resolveSendExtras(sendExtrasRef.current);
|
|
1119
1371
|
const resources = mergeResources(restoredResourcesRef.current, extras.resources ?? []);
|
|
1120
|
-
if (!sessionId || sending || !annotationsComplete2 || !hasText && !hasAnnotations && resources.length === 0 || sendBlockedRef.current?.() === true || targetKeyRef.current !== targetKey) {
|
|
1372
|
+
if (!sessionId || !currentPolicy || sending || !annotationsComplete2 || !hasText && !hasAnnotations && resources.length === 0 || sendBlockedRef.current?.() === true || targetKeyRef.current !== targetKey) {
|
|
1121
1373
|
return false;
|
|
1122
1374
|
}
|
|
1123
1375
|
const sendText = hasText ? rawText : hasAnnotations ? "" : FILE_ONLY_MESSAGE_TEXT;
|
|
1124
1376
|
const clientEventId = generateClientEventId();
|
|
1377
|
+
const effectiveControl = effectiveControlRef.current;
|
|
1125
1378
|
const input = composeSendInput(sendText, clientEventId, extras, {
|
|
1126
|
-
...
|
|
1379
|
+
...currentPolicy,
|
|
1380
|
+
...effectiveControl?.controlEtag ? { controlEtag: effectiveControl.controlEtag } : {},
|
|
1127
1381
|
resources,
|
|
1128
1382
|
annotations: annotationsAtSend
|
|
1129
1383
|
});
|
|
1130
1384
|
const currentPayload = currentDraftPayload();
|
|
1385
|
+
const hasEarlierUnsettledSend = optimisticSendsRef.current.some(
|
|
1386
|
+
(candidate) => candidate.state !== "failed" || candidate.outcomeUnknown === true
|
|
1387
|
+
);
|
|
1131
1388
|
const operation = {
|
|
1132
1389
|
clientEventId,
|
|
1390
|
+
delivery: "send",
|
|
1391
|
+
destination: effectiveControl?.state === "paused" || hasEarlierUnsettledSend ? "queue" : sendDestinationRef.current?.() ?? "chat",
|
|
1133
1392
|
text: sendText,
|
|
1134
1393
|
annotations: annotationsAtSend,
|
|
1135
1394
|
resources,
|
|
@@ -1140,7 +1399,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
1140
1399
|
newerShadow: {
|
|
1141
1400
|
text: explicit === void 0 ? "" : valueRef.current,
|
|
1142
1401
|
resources: explicit === void 0 ? [] : [...restoredResourcesRef.current],
|
|
1143
|
-
annotations: explicit === void 0 ? [] : cloneAnnotations(annotationsRef.current)
|
|
1402
|
+
annotations: explicit === void 0 ? [] : cloneAnnotations(annotationsRef.current),
|
|
1403
|
+
policy: currentPolicy
|
|
1144
1404
|
},
|
|
1145
1405
|
canRetry: true
|
|
1146
1406
|
};
|
|
@@ -1164,7 +1424,6 @@ function useComposer(sessionId, options = {}) {
|
|
|
1164
1424
|
currentDraftPayload,
|
|
1165
1425
|
dispatch,
|
|
1166
1426
|
onSubmitted,
|
|
1167
|
-
options.effectiveControl?.controlEtag,
|
|
1168
1427
|
processOptimisticSends,
|
|
1169
1428
|
replaceOptimisticSends,
|
|
1170
1429
|
sending,
|
|
@@ -1175,6 +1434,12 @@ function useComposer(sessionId, options = {}) {
|
|
|
1175
1434
|
const steer = useCallback(async (text) => await dispatch("steer", text), [dispatch]);
|
|
1176
1435
|
const retryOptimisticMessage = useCallback(
|
|
1177
1436
|
(clientEventId) => {
|
|
1437
|
+
if (sendBlockedRef.current?.() === true) return;
|
|
1438
|
+
const currentSteering = steeringRef.current;
|
|
1439
|
+
if (currentSteering?.phase === "failed" && currentSteering.clientEventId === clientEventId) {
|
|
1440
|
+
void dispatch("steer");
|
|
1441
|
+
return;
|
|
1442
|
+
}
|
|
1178
1443
|
replaceOptimisticSends(
|
|
1179
1444
|
(current) => current.map((operation) => {
|
|
1180
1445
|
if (operation.clientEventId !== clientEventId || operation.state !== "failed") {
|
|
@@ -1184,22 +1449,27 @@ function useComposer(sessionId, options = {}) {
|
|
|
1184
1449
|
return { ...operation, state: "sending", error: void 0 };
|
|
1185
1450
|
}
|
|
1186
1451
|
const nextClientEventId = generateClientEventId();
|
|
1187
|
-
const
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1452
|
+
const currentPersonalResourceAttachment = resolveSendExtras(
|
|
1453
|
+
sendExtrasRef.current
|
|
1454
|
+
).personalResourceAttachment;
|
|
1455
|
+
const retryInput = composeSendInput(
|
|
1456
|
+
operation.text,
|
|
1457
|
+
nextClientEventId,
|
|
1458
|
+
{
|
|
1459
|
+
...operation.input,
|
|
1460
|
+
...currentPersonalResourceAttachment ? { personalResourceAttachment: currentPersonalResourceAttachment } : {}
|
|
1461
|
+
},
|
|
1462
|
+
{
|
|
1463
|
+
...effectiveControlRef.current?.controlEtag ? { controlEtag: effectiveControlRef.current.controlEtag } : {},
|
|
1464
|
+
resources: operation.resources,
|
|
1465
|
+
annotations: operation.annotations
|
|
1466
|
+
}
|
|
1467
|
+
);
|
|
1193
1468
|
return {
|
|
1194
1469
|
...operation,
|
|
1195
1470
|
clientEventId: nextClientEventId,
|
|
1196
1471
|
input: retryInput,
|
|
1197
|
-
draftPayload: operation.draftPayload
|
|
1198
|
-
...operation.draftPayload,
|
|
1199
|
-
model: retryExtras.model ?? operation.draftPayload.model,
|
|
1200
|
-
reasoningEffort: retryExtras.reasoningEffort ?? operation.draftPayload.reasoningEffort,
|
|
1201
|
-
latencyMode: retryExtras.latencyMode ?? operation.draftPayload.latencyMode
|
|
1202
|
-
} : null,
|
|
1472
|
+
draftPayload: operation.draftPayload,
|
|
1203
1473
|
occurredAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1204
1474
|
state: "sending",
|
|
1205
1475
|
error: void 0,
|
|
@@ -1210,15 +1480,23 @@ function useComposer(sessionId, options = {}) {
|
|
|
1210
1480
|
);
|
|
1211
1481
|
queueMicrotask(processOptimisticSends);
|
|
1212
1482
|
},
|
|
1213
|
-
[
|
|
1483
|
+
[dispatch, processOptimisticSends, replaceOptimisticSends]
|
|
1214
1484
|
);
|
|
1215
1485
|
const removeOptimisticMessage = useCallback(
|
|
1216
1486
|
(clientEventId) => {
|
|
1487
|
+
if (steeringRef.current?.clientEventId === clientEventId) {
|
|
1488
|
+
pendingOperationRef.current = null;
|
|
1489
|
+
pendingClientEventId.current = null;
|
|
1490
|
+
forgetPendingComposerOperation(pendingComposerOperationKey(workspaceId, sessionId));
|
|
1491
|
+
setSteering(null);
|
|
1492
|
+
setError(null);
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1217
1495
|
replaceOptimisticSends(
|
|
1218
1496
|
(current) => current.filter((operation) => operation.clientEventId !== clientEventId)
|
|
1219
1497
|
);
|
|
1220
1498
|
},
|
|
1221
|
-
[replaceOptimisticSends]
|
|
1499
|
+
[replaceOptimisticSends, sessionId, workspaceId]
|
|
1222
1500
|
);
|
|
1223
1501
|
const hasReadyResources = restoredResources.length > 0 || (resolveSendExtras(sendExtrasRef.current).resources?.length ?? 0) > 0;
|
|
1224
1502
|
const hasPendingOperation = pendingOperationRef.current !== null;
|
|
@@ -1233,17 +1511,17 @@ function useComposer(sessionId, options = {}) {
|
|
|
1233
1511
|
setPausing(true);
|
|
1234
1512
|
setError(null);
|
|
1235
1513
|
try {
|
|
1236
|
-
const
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1514
|
+
const clientEventId = generateClientEventId();
|
|
1515
|
+
const effectiveControl = effectiveControlRef.current;
|
|
1516
|
+
const result = await replayOutcomeUnknown(
|
|
1517
|
+
() => client.pauseSession(workspaceId, sessionId, {
|
|
1518
|
+
clientEventId,
|
|
1519
|
+
...reason !== void 0 ? { reason } : {},
|
|
1520
|
+
...effectiveControl?.controlEtag ? { expectedControlEtag: effectiveControl.controlEtag } : {}
|
|
1521
|
+
})
|
|
1522
|
+
);
|
|
1240
1523
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
1241
|
-
|
|
1242
|
-
result.interruptionCount > 0 && result.effectiveControl.state === "paused" && result.effectiveControl.settlement !== null ? {
|
|
1243
|
-
controlVersion: result.effectiveControl.controlVersion,
|
|
1244
|
-
controlEtag: result.effectiveControl.controlEtag
|
|
1245
|
-
} : null
|
|
1246
|
-
);
|
|
1524
|
+
setAcceptedControl(result.effectiveControl);
|
|
1247
1525
|
}
|
|
1248
1526
|
} catch (cause) {
|
|
1249
1527
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
@@ -1255,7 +1533,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
1255
1533
|
}
|
|
1256
1534
|
}
|
|
1257
1535
|
},
|
|
1258
|
-
[client, workspaceId, sessionId, pausing,
|
|
1536
|
+
[client, workspaceId, sessionId, pausing, targetKey]
|
|
1259
1537
|
);
|
|
1260
1538
|
const resume = useCallback(
|
|
1261
1539
|
async (reason) => {
|
|
@@ -1265,10 +1543,18 @@ function useComposer(sessionId, options = {}) {
|
|
|
1265
1543
|
setResuming(true);
|
|
1266
1544
|
setError(null);
|
|
1267
1545
|
try {
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1546
|
+
const clientEventId = generateClientEventId();
|
|
1547
|
+
const effectiveControl = effectiveControlRef.current;
|
|
1548
|
+
const result = await replayOutcomeUnknown(
|
|
1549
|
+
() => client.resumeSession(workspaceId, sessionId, {
|
|
1550
|
+
clientEventId,
|
|
1551
|
+
...reason !== void 0 ? { reason } : {},
|
|
1552
|
+
...effectiveControl?.controlEtag ? { expectedControlEtag: effectiveControl.controlEtag } : {}
|
|
1553
|
+
})
|
|
1554
|
+
);
|
|
1555
|
+
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
1556
|
+
setAcceptedControl(result.effectiveControl);
|
|
1557
|
+
}
|
|
1272
1558
|
} catch (cause) {
|
|
1273
1559
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
1274
1560
|
setError(cause instanceof Error ? cause : new Error(String(cause)));
|
|
@@ -1279,7 +1565,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
1279
1565
|
}
|
|
1280
1566
|
}
|
|
1281
1567
|
},
|
|
1282
|
-
[client, workspaceId, sessionId, resuming,
|
|
1568
|
+
[client, workspaceId, sessionId, resuming, targetKey]
|
|
1283
1569
|
);
|
|
1284
1570
|
const resumeScope = useCallback(
|
|
1285
1571
|
async (option) => {
|
|
@@ -1290,7 +1576,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
1290
1576
|
setError(null);
|
|
1291
1577
|
try {
|
|
1292
1578
|
if (option.scope === "workspace") {
|
|
1293
|
-
const workspaceBlocker =
|
|
1579
|
+
const workspaceBlocker = effectiveControlRef.current?.blockers.find(
|
|
1294
1580
|
(blocker) => blocker.kind === "workspace"
|
|
1295
1581
|
);
|
|
1296
1582
|
if (!client.setWorkspaceInferenceState) {
|
|
@@ -1298,23 +1584,38 @@ function useComposer(sessionId, options = {}) {
|
|
|
1298
1584
|
"@opengeni/react: workspace-scoped resume requires setWorkspaceInferenceState."
|
|
1299
1585
|
);
|
|
1300
1586
|
}
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1587
|
+
const clientEventId = generateClientEventId();
|
|
1588
|
+
await replayOutcomeUnknown(
|
|
1589
|
+
() => client.setWorkspaceInferenceState(workspaceId, {
|
|
1590
|
+
action: "resume",
|
|
1591
|
+
clientEventId,
|
|
1592
|
+
...workspaceBlocker ? { expectedRevision: workspaceBlocker.revision } : {}
|
|
1593
|
+
})
|
|
1594
|
+
);
|
|
1306
1595
|
} else if (option.scope === "session" && option.targetId) {
|
|
1307
1596
|
const target = await client.getQueue(workspaceId, option.targetId);
|
|
1308
1597
|
if (targetKeyRef.current !== ownedTargetKey || targetGeneration.current !== ownedGeneration) {
|
|
1309
1598
|
return;
|
|
1310
1599
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1600
|
+
const clientEventId = generateClientEventId();
|
|
1601
|
+
await replayOutcomeUnknown(
|
|
1602
|
+
() => client.resumeSession(workspaceId, option.targetId, {
|
|
1603
|
+
clientEventId,
|
|
1604
|
+
expectedControlEtag: target.effectiveControl.controlEtag
|
|
1605
|
+
})
|
|
1606
|
+
);
|
|
1314
1607
|
} else {
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1608
|
+
const clientEventId = generateClientEventId();
|
|
1609
|
+
const effectiveControl = effectiveControlRef.current;
|
|
1610
|
+
const result = await replayOutcomeUnknown(
|
|
1611
|
+
() => client.resumeSession(workspaceId, sessionId, {
|
|
1612
|
+
clientEventId,
|
|
1613
|
+
...effectiveControl?.controlEtag ? { expectedControlEtag: effectiveControl.controlEtag } : {}
|
|
1614
|
+
})
|
|
1615
|
+
);
|
|
1616
|
+
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
1617
|
+
setAcceptedControl(result.effectiveControl);
|
|
1618
|
+
}
|
|
1318
1619
|
}
|
|
1319
1620
|
} catch (cause) {
|
|
1320
1621
|
if (targetKeyRef.current === ownedTargetKey && targetGeneration.current === ownedGeneration) {
|
|
@@ -1326,7 +1627,7 @@ function useComposer(sessionId, options = {}) {
|
|
|
1326
1627
|
}
|
|
1327
1628
|
}
|
|
1328
1629
|
},
|
|
1329
|
-
[client,
|
|
1630
|
+
[client, resuming, sessionId, targetKey, workspaceId]
|
|
1330
1631
|
);
|
|
1331
1632
|
const updateValue = useCallback(
|
|
1332
1633
|
(next) => {
|
|
@@ -1342,7 +1643,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
1342
1643
|
restoredResourcesRef.current,
|
|
1343
1644
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
1344
1645
|
),
|
|
1345
|
-
annotations: annotationsRef.current
|
|
1646
|
+
annotations: annotationsRef.current,
|
|
1647
|
+
policy: policyRef.current ?? void 0
|
|
1346
1648
|
}
|
|
1347
1649
|
);
|
|
1348
1650
|
setOptimisticDraftShadow({
|
|
@@ -1351,7 +1653,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
1351
1653
|
restoredResourcesRef.current,
|
|
1352
1654
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
1353
1655
|
),
|
|
1354
|
-
annotations: annotationsRef.current
|
|
1656
|
+
annotations: annotationsRef.current,
|
|
1657
|
+
policy: policyRef.current ?? void 0
|
|
1355
1658
|
});
|
|
1356
1659
|
setValue(next);
|
|
1357
1660
|
},
|
|
@@ -1371,7 +1674,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
1371
1674
|
restoredResourcesRef.current,
|
|
1372
1675
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
1373
1676
|
),
|
|
1374
|
-
annotations: next
|
|
1677
|
+
annotations: next,
|
|
1678
|
+
policy: policyRef.current ?? void 0
|
|
1375
1679
|
}
|
|
1376
1680
|
);
|
|
1377
1681
|
setOptimisticDraftShadow({
|
|
@@ -1380,7 +1684,8 @@ function useComposer(sessionId, options = {}) {
|
|
|
1380
1684
|
restoredResourcesRef.current,
|
|
1381
1685
|
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
1382
1686
|
),
|
|
1383
|
-
annotations: next
|
|
1687
|
+
annotations: next,
|
|
1688
|
+
policy: policyRef.current ?? void 0
|
|
1384
1689
|
});
|
|
1385
1690
|
setAnnotations(next);
|
|
1386
1691
|
setAnnotationReviewTargetId(reviewTargetId);
|
|
@@ -1417,6 +1722,51 @@ function useComposer(sessionId, options = {}) {
|
|
|
1417
1722
|
const clearAnnotationReviewTarget = useCallback(() => {
|
|
1418
1723
|
setAnnotationReviewTargetId(null);
|
|
1419
1724
|
}, []);
|
|
1725
|
+
const updatePolicy = useCallback(
|
|
1726
|
+
(next) => {
|
|
1727
|
+
if (targetKeyRef.current !== targetKey) return;
|
|
1728
|
+
localEditRevision.current += 1;
|
|
1729
|
+
policyRef.current = next;
|
|
1730
|
+
const shadow = {
|
|
1731
|
+
text: valueRef.current,
|
|
1732
|
+
resources: mergeResources(
|
|
1733
|
+
restoredResourcesRef.current,
|
|
1734
|
+
resolveSendExtras(sendExtrasRef.current).resources ?? []
|
|
1735
|
+
),
|
|
1736
|
+
annotations: annotationsRef.current,
|
|
1737
|
+
policy: next
|
|
1738
|
+
};
|
|
1739
|
+
pendingOperationRef.current = updatePendingComposerShadow(
|
|
1740
|
+
pendingOperationKey,
|
|
1741
|
+
pendingOperationRef.current,
|
|
1742
|
+
shadow
|
|
1743
|
+
);
|
|
1744
|
+
setOptimisticDraftShadow(shadow);
|
|
1745
|
+
setPolicy(next);
|
|
1746
|
+
},
|
|
1747
|
+
[pendingOperationKey, setOptimisticDraftShadow, targetKey]
|
|
1748
|
+
);
|
|
1749
|
+
const updateModel = useCallback(
|
|
1750
|
+
(model) => {
|
|
1751
|
+
const current = policyRef.current;
|
|
1752
|
+
if (current) updatePolicy({ ...current, model });
|
|
1753
|
+
},
|
|
1754
|
+
[updatePolicy]
|
|
1755
|
+
);
|
|
1756
|
+
const updateReasoningEffort = useCallback(
|
|
1757
|
+
(reasoningEffort) => {
|
|
1758
|
+
const current = policyRef.current;
|
|
1759
|
+
if (current) updatePolicy({ ...current, reasoningEffort });
|
|
1760
|
+
},
|
|
1761
|
+
[updatePolicy]
|
|
1762
|
+
);
|
|
1763
|
+
const updateLatencyMode = useCallback(
|
|
1764
|
+
(latencyMode) => {
|
|
1765
|
+
const current = policyRef.current;
|
|
1766
|
+
if (current) updatePolicy({ ...current, latencyMode });
|
|
1767
|
+
},
|
|
1768
|
+
[updatePolicy]
|
|
1769
|
+
);
|
|
1420
1770
|
const removeRestoredResource = useCallback(
|
|
1421
1771
|
(index) => {
|
|
1422
1772
|
if (targetKeyRef.current !== targetKey) return;
|
|
@@ -1429,13 +1779,15 @@ function useComposer(sessionId, options = {}) {
|
|
|
1429
1779
|
{
|
|
1430
1780
|
text: valueRef.current,
|
|
1431
1781
|
resources: mergeResources(next, resolveSendExtras(sendExtrasRef.current).resources ?? []),
|
|
1432
|
-
annotations: annotationsRef.current
|
|
1782
|
+
annotations: annotationsRef.current,
|
|
1783
|
+
policy: policyRef.current ?? void 0
|
|
1433
1784
|
}
|
|
1434
1785
|
);
|
|
1435
1786
|
setOptimisticDraftShadow({
|
|
1436
1787
|
text: valueRef.current,
|
|
1437
1788
|
resources: mergeResources(next, resolveSendExtras(sendExtrasRef.current).resources ?? []),
|
|
1438
|
-
annotations: annotationsRef.current
|
|
1789
|
+
annotations: annotationsRef.current,
|
|
1790
|
+
policy: policyRef.current ?? void 0
|
|
1439
1791
|
});
|
|
1440
1792
|
setRestoredResources(next);
|
|
1441
1793
|
},
|
|
@@ -1480,6 +1832,27 @@ function useComposer(sessionId, options = {}) {
|
|
|
1480
1832
|
);
|
|
1481
1833
|
const identityMatches = stateTargetKey === targetKey;
|
|
1482
1834
|
const visibleSteering = identityMatches ? steering : null;
|
|
1835
|
+
const visibleOptimisticMessages = identityMatches ? [
|
|
1836
|
+
...optimisticSends.map(
|
|
1837
|
+
({ input: _input, draftPayload: _payload, canRetry: _retry, ...item }) => item
|
|
1838
|
+
),
|
|
1839
|
+
...visibleSteering?.clientEventId ? [
|
|
1840
|
+
{
|
|
1841
|
+
clientEventId: visibleSteering.clientEventId,
|
|
1842
|
+
delivery: "steer",
|
|
1843
|
+
destination: "chat",
|
|
1844
|
+
text: visibleSteering.text,
|
|
1845
|
+
annotations: pendingOperationRef.current?.delivery === "steer" ? pendingOperationRef.current.annotationsAtSend : [],
|
|
1846
|
+
resources: pendingOperationRef.current?.delivery === "steer" ? pendingOperationRef.current.resourcesAtSend : [],
|
|
1847
|
+
occurredAt: steeringOccurredAtRef.current,
|
|
1848
|
+
state: visibleSteering.phase === "submitting" ? "sending" : visibleSteering.phase === "failed" ? "failed" : "queued",
|
|
1849
|
+
turnId: visibleSteering.turnId,
|
|
1850
|
+
triggerEventId: visibleSteering.triggerEventId,
|
|
1851
|
+
...visibleSteering.error ? { error: visibleSteering.error } : {},
|
|
1852
|
+
...visibleSteering.outcomeUnknown !== void 0 ? { outcomeUnknown: visibleSteering.outcomeUnknown } : {}
|
|
1853
|
+
}
|
|
1854
|
+
] : []
|
|
1855
|
+
] : [];
|
|
1483
1856
|
const reloadDraft = useCallback(async () => await loadDraft(true), [loadDraft]);
|
|
1484
1857
|
const clearError = useCallback(() => {
|
|
1485
1858
|
if (targetKeyRef.current !== targetKey) return;
|
|
@@ -1497,26 +1870,29 @@ function useComposer(sessionId, options = {}) {
|
|
|
1497
1870
|
clearAnnotationReviewTarget,
|
|
1498
1871
|
hasDraftContent,
|
|
1499
1872
|
send,
|
|
1500
|
-
optimisticMessages:
|
|
1501
|
-
({ input: _input, draftPayload: _payload, canRetry: _retry, ...item }) => item
|
|
1502
|
-
) : [],
|
|
1873
|
+
optimisticMessages: visibleOptimisticMessages,
|
|
1503
1874
|
retryOptimisticMessage,
|
|
1504
1875
|
removeOptimisticMessage,
|
|
1505
1876
|
steer,
|
|
1506
1877
|
steering: visibleSteering,
|
|
1507
|
-
stoppingAttempt: identityMatches ?
|
|
1878
|
+
stoppingAttempt: identityMatches ? visibleSteering?.phase === "accepted" && visibleSteering.stoppingPreviousAttempt === true ? "previous" : null : null,
|
|
1508
1879
|
sending: identityMatches ? sending : false,
|
|
1509
|
-
canSend: identityMatches && Boolean(sessionId) && !sending && sendBlockedRef.current?.() !== true && annotationsComplete && (hasPendingOperation || value.trim().length > 0 || hasReadyResources || annotations.length > 0),
|
|
1880
|
+
canSend: identityMatches && Boolean(sessionId) && !sending && !draftLoading && policy !== null && sendBlockedRef.current?.() !== true && annotationsComplete && (hasPendingOperation || value.trim().length > 0 || hasReadyResources || annotations.length > 0),
|
|
1510
1881
|
pause,
|
|
1511
1882
|
pausing: identityMatches ? pausing : false,
|
|
1512
1883
|
resume,
|
|
1513
1884
|
resumeScope,
|
|
1514
1885
|
resuming: identityMatches ? resuming : false,
|
|
1886
|
+
effectiveControl: identityMatches ? effectiveControlRef.current : null,
|
|
1515
1887
|
draft: identityMatches ? draft : null,
|
|
1516
1888
|
draftRevision: identityMatches ? draft?.revision ?? 0 : 0,
|
|
1517
1889
|
draftLoading: identityMatches ? draftLoading : Boolean(sessionId) && durableDrafts,
|
|
1518
1890
|
draftSaving: identityMatches ? draftSaving : false,
|
|
1519
1891
|
draftConflict: identityMatches ? draftConflict : null,
|
|
1892
|
+
policy: identityMatches ? policy : null,
|
|
1893
|
+
setModel: updateModel,
|
|
1894
|
+
setReasoningEffort: updateReasoningEffort,
|
|
1895
|
+
setLatencyMode: updateLatencyMode,
|
|
1520
1896
|
draftPersistence: durableDrafts ? "durable" : "disabled",
|
|
1521
1897
|
applyDraft,
|
|
1522
1898
|
reloadDraft,
|
|
@@ -1552,31 +1928,20 @@ function generateClientEventId() {
|
|
|
1552
1928
|
function isOutcomeUnknownError(cause) {
|
|
1553
1929
|
return typeof cause === "object" && cause !== null && cause.outcomeUnknown === true;
|
|
1554
1930
|
}
|
|
1931
|
+
async function replayOutcomeUnknown(command) {
|
|
1932
|
+
try {
|
|
1933
|
+
return await command();
|
|
1934
|
+
} catch (cause) {
|
|
1935
|
+
if (!isOutcomeUnknownError(cause)) throw cause;
|
|
1936
|
+
return await command();
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1555
1939
|
function asError(cause) {
|
|
1556
1940
|
return cause instanceof Error ? cause : new Error(String(cause));
|
|
1557
1941
|
}
|
|
1558
1942
|
function isDraftConflictError(error) {
|
|
1559
1943
|
const apiError = error;
|
|
1560
|
-
|
|
1561
|
-
const code = apiError.code;
|
|
1562
|
-
if (code === void 0 || code === "DRAFT_CHANGED" || code === "conflict" || code === "idempotency_conflict") {
|
|
1563
|
-
return true;
|
|
1564
|
-
}
|
|
1565
|
-
return /draft changed/i.test(error.message);
|
|
1566
|
-
}
|
|
1567
|
-
async function saveComposerDraftWithStaleRetry(input) {
|
|
1568
|
-
try {
|
|
1569
|
-
return await input.client.saveComposerDraft(input.workspaceId, input.sessionId, input.request);
|
|
1570
|
-
} catch (cause) {
|
|
1571
|
-
const problem = asError(cause);
|
|
1572
|
-
if (!isDraftConflictError(problem)) throw problem;
|
|
1573
|
-
const remote = await input.client.getComposerDraft(input.workspaceId, input.sessionId);
|
|
1574
|
-
input.onAdoptRemote(remote);
|
|
1575
|
-
return await input.client.saveComposerDraft(input.workspaceId, input.sessionId, {
|
|
1576
|
-
...input.request,
|
|
1577
|
-
expectedRevision: remote.revision
|
|
1578
|
-
});
|
|
1579
|
-
}
|
|
1944
|
+
return apiError.status === 409 && apiError.outcomeUnknown !== true && apiError.code === "DRAFT_CHANGED";
|
|
1580
1945
|
}
|
|
1581
1946
|
function draftPayload(draft) {
|
|
1582
1947
|
return {
|
|
@@ -1586,18 +1951,25 @@ function draftPayload(draft) {
|
|
|
1586
1951
|
annotations: draft.annotations ?? [],
|
|
1587
1952
|
model: draft.model,
|
|
1588
1953
|
reasoningEffort: draft.reasoningEffort,
|
|
1589
|
-
latencyMode: draft.latencyMode
|
|
1954
|
+
latencyMode: draft.latencyMode
|
|
1955
|
+
};
|
|
1956
|
+
}
|
|
1957
|
+
function policyFromDraft(draft) {
|
|
1958
|
+
return {
|
|
1959
|
+
model: draft.model,
|
|
1960
|
+
reasoningEffort: draft.reasoningEffort,
|
|
1961
|
+
latencyMode: draft.latencyMode
|
|
1590
1962
|
};
|
|
1591
1963
|
}
|
|
1592
|
-
function composerDraftPayload(base, text, restoredResources, annotations,
|
|
1964
|
+
function composerDraftPayload(base, text, restoredResources, annotations, policy, additionalResources) {
|
|
1593
1965
|
return {
|
|
1594
1966
|
expectedRevision: base.revision,
|
|
1595
1967
|
text,
|
|
1596
|
-
resources: mergeResources(restoredResources,
|
|
1968
|
+
resources: mergeResources(restoredResources, additionalResources),
|
|
1597
1969
|
annotations,
|
|
1598
|
-
model:
|
|
1599
|
-
reasoningEffort:
|
|
1600
|
-
latencyMode:
|
|
1970
|
+
model: policy.model,
|
|
1971
|
+
reasoningEffort: policy.reasoningEffort,
|
|
1972
|
+
latencyMode: policy.latencyMode
|
|
1601
1973
|
};
|
|
1602
1974
|
}
|
|
1603
1975
|
function draftSignature(payload) {
|
|
@@ -1621,4 +1993,4 @@ export {
|
|
|
1621
1993
|
shouldSubmitOnKey,
|
|
1622
1994
|
shouldSteerOnKey
|
|
1623
1995
|
};
|
|
1624
|
-
//# sourceMappingURL=chunk-
|
|
1996
|
+
//# sourceMappingURL=chunk-JOAVA2TW.js.map
|