@truefoundry/assistant-ui-runtime 0.1.6 → 0.1.8
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/CHANGELOG.md +23 -0
- package/README.md +22 -17
- package/dist/chunk-CXBZ6WLZ.js +636 -0
- package/dist/chunk-CXBZ6WLZ.js.map +1 -0
- package/dist/index.d.ts +20 -24
- package/dist/index.js +269 -166
- package/dist/index.js.map +1 -1
- package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +82 -39
- package/dist/plugins/truefoundry-agent-server-adapter/index.js +3 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/{types-BfiFf8O1.d.ts → types-B_z-FsDS.d.ts} +208 -10
- package/package.json +1 -1
- package/src/convertTurnMessages.ts +4 -0
- package/src/{private → draft}/agentSpec.ts +14 -17
- package/src/{private → draft}/draftSessionBridge.ts +1 -2
- package/src/{private → draft}/truefoundryDraftThreadListAdapter.test.ts +1 -1
- package/src/{private → draft}/truefoundryDraftThreadListAdapter.ts +6 -2
- package/src/{private → draft}/useDraftAgentSpec.ts +16 -5
- package/src/draftAgentConfig.test.ts +2 -1
- package/src/harness.temp.ts +85 -0
- package/src/index.ts +43 -7
- package/src/plugins/truefoundry-agent-server-adapter/README.md +83 -44
- package/src/plugins/truefoundry-agent-server-adapter/chatServer.ts +365 -0
- package/src/plugins/truefoundry-agent-server-adapter/cp.test.ts +444 -0
- package/src/plugins/truefoundry-agent-server-adapter/cp.ts +482 -0
- package/src/plugins/truefoundry-agent-server-adapter/createTrueFoundryAgentUIServer.ts +94 -0
- package/src/plugins/truefoundry-agent-server-adapter/guards.ts +1 -1
- package/src/plugins/truefoundry-agent-server-adapter/index.ts +20 -351
- package/src/plugins/truefoundry-agent-server-adapter/normalizeAgentSpec.test.ts +85 -0
- package/src/plugins/truefoundry-agent-server-adapter/normalizeAgentSpec.ts +84 -0
- package/src/plugins/truefoundry-agent-server-adapter/types.ts +7 -5
- package/src/server/index.ts +29 -0
- package/src/server/types.ts +264 -12
- package/src/streamTurn.test.ts +27 -27
- package/src/streamTurn.ts +2 -2
- package/src/truefoundryExtras.ts +4 -1
- package/src/truefoundryOwnedSessionsThreadListAdapter.ts +5 -2
- package/src/truefoundryThreadListAdapter.test.ts +22 -0
- package/src/truefoundryThreadListAdapter.ts +4 -1
- package/src/types.ts +1 -2
- package/src/useTrueFoundryAgentMessages.test.tsx +262 -2
- package/src/useTrueFoundryAgentMessages.ts +284 -176
- package/src/useTrueFoundryAgentRuntime.ts +31 -21
- package/dist/chunk-Q2SHKMLM.js +0 -270
- package/dist/chunk-Q2SHKMLM.js.map +0 -1
- /package/src/{private → draft}/useDraftAgentSpec.test.tsx +0 -0
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
mergeEventDelta
|
|
4
4
|
} from "./chunk-3A2EPLQG.js";
|
|
5
5
|
import {
|
|
6
|
+
createTrueFoundryAgentUIServer,
|
|
6
7
|
createTrueFoundryChatServer,
|
|
7
8
|
getTfyMcpInitServers,
|
|
8
9
|
getTfyThreadState,
|
|
@@ -10,7 +11,7 @@ import {
|
|
|
10
11
|
isTfyMcpToolInfo,
|
|
11
12
|
isTfySystemToolInfo,
|
|
12
13
|
isTfyToolInfo
|
|
13
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-CXBZ6WLZ.js";
|
|
14
15
|
|
|
15
16
|
// src/useTrueFoundryAgentRuntime.ts
|
|
16
17
|
import {
|
|
@@ -1533,6 +1534,7 @@ function attachRunningTurn(snapshot, runningTurn) {
|
|
|
1533
1534
|
if (runningTurn == null) {
|
|
1534
1535
|
return snapshot;
|
|
1535
1536
|
}
|
|
1537
|
+
applyUserToolResponsesToFold(snapshot.fold, runningTurn.input ?? []);
|
|
1536
1538
|
const pendingUserText = extractTurnUserText(runningTurn.input);
|
|
1537
1539
|
return replaceSessionSnapshot(snapshot, {
|
|
1538
1540
|
runningTurn,
|
|
@@ -2386,7 +2388,7 @@ function repositoryItemsFromMessages(messages) {
|
|
|
2386
2388
|
return items;
|
|
2387
2389
|
}
|
|
2388
2390
|
|
|
2389
|
-
// src/
|
|
2391
|
+
// src/draft/draftSessionBridge.ts
|
|
2390
2392
|
var DRAFT_SESSION_LAST_UPDATED_AT_HEADER = "x-tfy-session-last-updated-at";
|
|
2391
2393
|
function createDraftSessionBridge(server) {
|
|
2392
2394
|
return {
|
|
@@ -2409,7 +2411,7 @@ function createDraftSessionBridge(server) {
|
|
|
2409
2411
|
};
|
|
2410
2412
|
}
|
|
2411
2413
|
|
|
2412
|
-
// src/
|
|
2414
|
+
// src/draft/agentSpec.ts
|
|
2413
2415
|
function mergeAgentSpec(base, update) {
|
|
2414
2416
|
const { model: modelUpdate, ...rest } = update;
|
|
2415
2417
|
const next = {
|
|
@@ -2437,7 +2439,7 @@ function sessionListStartTimestamp() {
|
|
|
2437
2439
|
return start.toISOString();
|
|
2438
2440
|
}
|
|
2439
2441
|
|
|
2440
|
-
// src/
|
|
2442
|
+
// src/draft/truefoundryDraftThreadListAdapter.ts
|
|
2441
2443
|
var THREAD_LIST_PAGE_SIZE = 20;
|
|
2442
2444
|
function createTrueFoundryDraftThreadListAdapter(options) {
|
|
2443
2445
|
const { server, defaultAgentSpec, getAgentSpec } = options;
|
|
@@ -2486,7 +2488,9 @@ function createTrueFoundryDraftThreadListAdapter(options) {
|
|
|
2486
2488
|
},
|
|
2487
2489
|
async unarchive() {
|
|
2488
2490
|
},
|
|
2489
|
-
async delete() {
|
|
2491
|
+
async delete(remoteId) {
|
|
2492
|
+
if (typeof server.deleteSession !== "function") return;
|
|
2493
|
+
await server.deleteSession({ sessionId: remoteId });
|
|
2490
2494
|
},
|
|
2491
2495
|
async generateTitle() {
|
|
2492
2496
|
return new ReadableStream();
|
|
@@ -2502,6 +2506,7 @@ var trueFoundryExtras = createRuntimeExtras(
|
|
|
2502
2506
|
var EMPTY_DRAFT_EXTRAS = {
|
|
2503
2507
|
agentSpec: null,
|
|
2504
2508
|
draftSessionId: void 0,
|
|
2509
|
+
isSpecLoading: false,
|
|
2505
2510
|
isSpecSyncing: false,
|
|
2506
2511
|
specError: null,
|
|
2507
2512
|
updateAgentSpec: () => {
|
|
@@ -2566,7 +2571,9 @@ function createTrueFoundryThreadListAdapter(options) {
|
|
|
2566
2571
|
},
|
|
2567
2572
|
async unarchive() {
|
|
2568
2573
|
},
|
|
2569
|
-
async delete() {
|
|
2574
|
+
async delete(remoteId) {
|
|
2575
|
+
if (typeof server.deleteSession !== "function") return;
|
|
2576
|
+
await server.deleteSession({ sessionId: remoteId });
|
|
2570
2577
|
},
|
|
2571
2578
|
async generateTitle() {
|
|
2572
2579
|
return new ReadableStream();
|
|
@@ -2597,7 +2604,7 @@ function resolveTrueFoundryAgentRuntimeOptions(options) {
|
|
|
2597
2604
|
};
|
|
2598
2605
|
}
|
|
2599
2606
|
|
|
2600
|
-
// src/
|
|
2607
|
+
// src/draft/useDraftAgentSpec.ts
|
|
2601
2608
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2602
2609
|
var SPEC_SYNC_DEBOUNCE_MS = 400;
|
|
2603
2610
|
function useDraftAgentSpec({
|
|
@@ -2609,6 +2616,7 @@ function useDraftAgentSpec({
|
|
|
2609
2616
|
}) {
|
|
2610
2617
|
const enabled = draftBridge != null;
|
|
2611
2618
|
const [agentSpec, setAgentSpec] = useState(defaultAgentSpec);
|
|
2619
|
+
const [isSpecLoading, setIsSpecLoading] = useState(false);
|
|
2612
2620
|
const [isSpecSyncing, setIsSpecSyncing] = useState(false);
|
|
2613
2621
|
const [specError, setSpecError] = useState(null);
|
|
2614
2622
|
const agentSpecRef = useRef(agentSpec);
|
|
@@ -2649,12 +2657,14 @@ function useDraftAgentSpec({
|
|
|
2649
2657
|
setAgentSpec(defaultAgentSpec);
|
|
2650
2658
|
localDirtyRef.current = false;
|
|
2651
2659
|
setSpecError(null);
|
|
2660
|
+
setIsSpecLoading(false);
|
|
2652
2661
|
return;
|
|
2653
2662
|
}
|
|
2654
2663
|
if (loadedDraftIdRef.current === draftSessionId) {
|
|
2655
2664
|
return;
|
|
2656
2665
|
}
|
|
2657
2666
|
let cancelled = false;
|
|
2667
|
+
setIsSpecLoading(true);
|
|
2658
2668
|
void (async () => {
|
|
2659
2669
|
try {
|
|
2660
2670
|
const loaded = await draftBridge.getDraftAgentSpec(draftSessionId);
|
|
@@ -2666,19 +2676,23 @@ function useDraftAgentSpec({
|
|
|
2666
2676
|
scheduleSpecSyncRef.current?.(draftSessionId, agentSpecRef.current);
|
|
2667
2677
|
localDirtyRef.current = false;
|
|
2668
2678
|
setSpecError(null);
|
|
2679
|
+
setIsSpecLoading(false);
|
|
2669
2680
|
return;
|
|
2670
2681
|
}
|
|
2671
2682
|
setAgentSpec(loaded);
|
|
2672
2683
|
setSpecError(null);
|
|
2684
|
+
setIsSpecLoading(false);
|
|
2673
2685
|
} catch (error) {
|
|
2674
2686
|
if (!cancelled) {
|
|
2675
2687
|
onError?.(error);
|
|
2676
2688
|
setSpecError(error);
|
|
2689
|
+
setIsSpecLoading(false);
|
|
2677
2690
|
}
|
|
2678
2691
|
}
|
|
2679
2692
|
})();
|
|
2680
2693
|
return () => {
|
|
2681
2694
|
cancelled = true;
|
|
2695
|
+
setIsSpecLoading(false);
|
|
2682
2696
|
};
|
|
2683
2697
|
}, [defaultAgentSpec, draftBridge, draftSessionId, enabled, onError]);
|
|
2684
2698
|
const flushSpecSync = useCallback(
|
|
@@ -2781,6 +2795,7 @@ function useDraftAgentSpec({
|
|
|
2781
2795
|
() => ({
|
|
2782
2796
|
agentSpec: enabled ? agentSpec : null,
|
|
2783
2797
|
draftSessionId: enabled ? draftSessionId : void 0,
|
|
2798
|
+
isSpecLoading: enabled ? isSpecLoading : false,
|
|
2784
2799
|
isSpecSyncing: enabled ? isSpecSyncing : false,
|
|
2785
2800
|
specError: enabled ? specError : null,
|
|
2786
2801
|
updateAgentSpec,
|
|
@@ -2790,6 +2805,7 @@ function useDraftAgentSpec({
|
|
|
2790
2805
|
agentSpec,
|
|
2791
2806
|
draftSessionId,
|
|
2792
2807
|
enabled,
|
|
2808
|
+
isSpecLoading,
|
|
2793
2809
|
isSpecSyncing,
|
|
2794
2810
|
specError,
|
|
2795
2811
|
takeTurnHeaderTimestamp,
|
|
@@ -2873,7 +2889,7 @@ async function* streamTurnContent(server, sessionId, foldState, options, abortSi
|
|
|
2873
2889
|
turnIdNotified = true;
|
|
2874
2890
|
}
|
|
2875
2891
|
};
|
|
2876
|
-
const stream = server.
|
|
2892
|
+
const stream = server.createTurn({
|
|
2877
2893
|
sessionId,
|
|
2878
2894
|
input: buildTurnInput(options),
|
|
2879
2895
|
previousTurnId: options.previousTurnId ?? "auto",
|
|
@@ -3058,6 +3074,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3058
3074
|
server,
|
|
3059
3075
|
sessionId,
|
|
3060
3076
|
isMain,
|
|
3077
|
+
isInitialSession,
|
|
3061
3078
|
listEventsConcurrency,
|
|
3062
3079
|
onError,
|
|
3063
3080
|
initializeSession,
|
|
@@ -3066,7 +3083,9 @@ function useTrueFoundryAgentMessages({
|
|
|
3066
3083
|
}) {
|
|
3067
3084
|
const [snapshot, setSnapshot] = useState2(createEmptySessionSnapshot);
|
|
3068
3085
|
const [isRunning, setIsRunning] = useState2(false);
|
|
3069
|
-
const [isLoading, setIsLoading] = useState2(
|
|
3086
|
+
const [isLoading, setIsLoading] = useState2(
|
|
3087
|
+
sessionId != null && (isMain !== false || isInitialSession === true)
|
|
3088
|
+
);
|
|
3070
3089
|
const [isLoadingOlderHistory, setIsLoadingOlderHistory] = useState2(false);
|
|
3071
3090
|
const [loadRetryTrigger, setLoadRetryTrigger] = useState2(0);
|
|
3072
3091
|
const snapshotRef = useRef2(snapshot);
|
|
@@ -3087,6 +3106,8 @@ function useTrueFoundryAgentMessages({
|
|
|
3087
3106
|
const loadGenerationRef = useRef2(0);
|
|
3088
3107
|
const streamGenerationRef = useRef2(0);
|
|
3089
3108
|
const lazilyCreatedSessionIdRef = useRef2(void 0);
|
|
3109
|
+
const initialLoadStartedForRef = useRef2(void 0);
|
|
3110
|
+
const skipInitialPromotionLoadForRef = useRef2(void 0);
|
|
3090
3111
|
const projectOptions = useMemo2(
|
|
3091
3112
|
() => ({
|
|
3092
3113
|
getCreatedAt: (messageId, fallback) => {
|
|
@@ -3197,12 +3218,24 @@ function useTrueFoundryAgentMessages({
|
|
|
3197
3218
|
[onError]
|
|
3198
3219
|
);
|
|
3199
3220
|
const load = useCallback2(async () => {
|
|
3221
|
+
void loadRetryTrigger;
|
|
3200
3222
|
if (sessionId == null) {
|
|
3201
3223
|
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3202
3224
|
setSnapshot(createEmptySessionSnapshot());
|
|
3203
3225
|
return;
|
|
3204
3226
|
}
|
|
3205
|
-
|
|
3227
|
+
const isEarlyInitialLoad = isMain === false && isInitialSession === true && initialLoadStartedForRef.current !== sessionId;
|
|
3228
|
+
if (isMain === false) {
|
|
3229
|
+
if (!isEarlyInitialLoad) return;
|
|
3230
|
+
initialLoadStartedForRef.current = sessionId;
|
|
3231
|
+
skipInitialPromotionLoadForRef.current = sessionId;
|
|
3232
|
+
} else if (isMain === true && skipInitialPromotionLoadForRef.current === sessionId) {
|
|
3233
|
+
skipInitialPromotionLoadForRef.current = void 0;
|
|
3234
|
+
return;
|
|
3235
|
+
}
|
|
3236
|
+
if (isInitialSession === true) {
|
|
3237
|
+
initialLoadStartedForRef.current = sessionId;
|
|
3238
|
+
}
|
|
3206
3239
|
if (lazilyCreatedSessionIdRef.current != null && sessionId !== lazilyCreatedSessionIdRef.current) {
|
|
3207
3240
|
lazilyCreatedSessionIdRef.current = void 0;
|
|
3208
3241
|
}
|
|
@@ -3211,6 +3244,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3211
3244
|
}
|
|
3212
3245
|
const generation = ++loadGenerationRef.current;
|
|
3213
3246
|
++streamGenerationRef.current;
|
|
3247
|
+
setIsRunning(false);
|
|
3214
3248
|
abortControllerRef.current?.abort();
|
|
3215
3249
|
loadOlderInflightRef.current = null;
|
|
3216
3250
|
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
@@ -3257,6 +3291,10 @@ function useTrueFoundryAgentMessages({
|
|
|
3257
3291
|
}
|
|
3258
3292
|
} catch (error) {
|
|
3259
3293
|
if (generation === loadGenerationRef.current) {
|
|
3294
|
+
if (isEarlyInitialLoad) {
|
|
3295
|
+
initialLoadStartedForRef.current = void 0;
|
|
3296
|
+
skipInitialPromotionLoadForRef.current = void 0;
|
|
3297
|
+
}
|
|
3260
3298
|
onErrorRef.current?.(error);
|
|
3261
3299
|
}
|
|
3262
3300
|
throw error;
|
|
@@ -3265,134 +3303,178 @@ function useTrueFoundryAgentMessages({
|
|
|
3265
3303
|
setIsLoading(false);
|
|
3266
3304
|
}
|
|
3267
3305
|
}
|
|
3268
|
-
}, [
|
|
3306
|
+
}, [
|
|
3307
|
+
server,
|
|
3308
|
+
runStream,
|
|
3309
|
+
sessionId,
|
|
3310
|
+
loadRetryTrigger,
|
|
3311
|
+
isMain,
|
|
3312
|
+
isInitialSession
|
|
3313
|
+
]);
|
|
3269
3314
|
useEffect2(() => {
|
|
3270
3315
|
void load().catch(() => void 0);
|
|
3271
3316
|
}, [load]);
|
|
3272
3317
|
const sendTurn = useCallback2(
|
|
3273
3318
|
async (options) => {
|
|
3274
|
-
let
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3319
|
+
let gatewayTurnAccepted = false;
|
|
3320
|
+
let pendingUserWasSet = false;
|
|
3321
|
+
let runStreamStarted = false;
|
|
3322
|
+
let pendingUserTurnId;
|
|
3323
|
+
try {
|
|
3324
|
+
let activeSessionId = sessionId;
|
|
3325
|
+
if (activeSessionId == null) {
|
|
3326
|
+
if (initializeSessionRef.current == null) {
|
|
3327
|
+
throw new Error("Cannot send a turn without an active session.");
|
|
3328
|
+
}
|
|
3329
|
+
const { remoteId } = await initializeSessionRef.current();
|
|
3330
|
+
activeSessionId = remoteId;
|
|
3331
|
+
lazilyCreatedSessionIdRef.current = remoteId;
|
|
3278
3332
|
}
|
|
3279
|
-
const
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
}
|
|
3283
|
-
const conversationSessionId = await resolveActiveSessionId(
|
|
3284
|
-
activeSessionId,
|
|
3285
|
-
resolveConversationSessionIdRef.current
|
|
3286
|
-
);
|
|
3287
|
-
const turnHeaders = await getTurnHeadersRef.current?.();
|
|
3288
|
-
const streamHeaders = turnHeaders != null ? { headers: turnHeaders } : {};
|
|
3289
|
-
const isContinuation = "inputs" in options || "resumeMcpAuth" in options && options.resumeMcpAuth === true;
|
|
3290
|
-
const continuationTurnId = snapshotRef.current.activeStream?.turnId;
|
|
3291
|
-
const turnId = isContinuation && continuationTurnId != null ? continuationTurnId : generateId();
|
|
3292
|
-
const isFirstTurnInSession = "userMessage" in options && options.previousTurnId === void 0 && snapshotRef.current.turns.length === 0 && snapshotRef.current.pendingUser == null && snapshotRef.current.activeStream == null;
|
|
3293
|
-
const turnIdRef = { current: turnId };
|
|
3294
|
-
if ("inputs" in options) {
|
|
3295
|
-
applyUserToolResponsesToFold(
|
|
3296
|
-
snapshotRef.current.fold,
|
|
3297
|
-
options.inputs
|
|
3298
|
-
);
|
|
3299
|
-
}
|
|
3300
|
-
const branchBase = "userMessage" in options ? options.branchFromSnapshot : void 0;
|
|
3301
|
-
let groupRootBaseline;
|
|
3302
|
-
if (branchBase != null && "userMessage" in options) {
|
|
3303
|
-
const rootBucket = branchBase.fold.threads.get(ROOT_THREAD_ID);
|
|
3304
|
-
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
3305
|
-
const nextSnapshot = replaceSessionSnapshot(branchBase, {
|
|
3306
|
-
pendingUser: {
|
|
3307
|
-
turnId,
|
|
3308
|
-
content: options.userMessage,
|
|
3309
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
3310
|
-
},
|
|
3311
|
-
activeStream: void 0,
|
|
3312
|
-
groupRootBaseline
|
|
3313
|
-
});
|
|
3314
|
-
snapshotRef.current = nextSnapshot;
|
|
3315
|
-
setSnapshot(nextSnapshot);
|
|
3316
|
-
} else {
|
|
3317
|
-
setSnapshot(
|
|
3318
|
-
(prev) => commitActiveStream(
|
|
3319
|
-
prev,
|
|
3320
|
-
"inputs" in options ? options.inputs : void 0
|
|
3321
|
-
)
|
|
3333
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
3334
|
+
activeSessionId,
|
|
3335
|
+
resolveConversationSessionIdRef.current
|
|
3322
3336
|
);
|
|
3323
|
-
|
|
3324
|
-
|
|
3337
|
+
const turnHeaders = await getTurnHeadersRef.current?.();
|
|
3338
|
+
const streamHeaders = turnHeaders != null ? { headers: turnHeaders } : {};
|
|
3339
|
+
const isContinuation = "inputs" in options || "resumeMcpAuth" in options && options.resumeMcpAuth === true;
|
|
3340
|
+
const continuationTurnId = snapshotRef.current.activeStream?.turnId;
|
|
3341
|
+
const turnId = isContinuation && continuationTurnId != null ? continuationTurnId : generateId();
|
|
3342
|
+
const isFirstTurnInSession = "userMessage" in options && options.previousTurnId === void 0 && snapshotRef.current.turns.length === 0 && snapshotRef.current.pendingUser == null && snapshotRef.current.activeStream == null;
|
|
3343
|
+
const turnIdRef = { current: turnId };
|
|
3344
|
+
if ("inputs" in options) {
|
|
3345
|
+
applyUserToolResponsesToFold(
|
|
3346
|
+
snapshotRef.current.fold,
|
|
3347
|
+
options.inputs
|
|
3348
|
+
);
|
|
3349
|
+
}
|
|
3350
|
+
const branchBase = "userMessage" in options ? options.branchFromSnapshot : void 0;
|
|
3351
|
+
let groupRootBaseline;
|
|
3352
|
+
if (branchBase != null && "userMessage" in options) {
|
|
3353
|
+
const rootBucket = branchBase.fold.threads.get(ROOT_THREAD_ID);
|
|
3325
3354
|
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
groupRootBaseline
|
|
3335
|
-
});
|
|
3336
|
-
snapshotRef.current = next;
|
|
3337
|
-
return next;
|
|
3355
|
+
const nextSnapshot = replaceSessionSnapshot(branchBase, {
|
|
3356
|
+
pendingUser: {
|
|
3357
|
+
turnId,
|
|
3358
|
+
content: options.userMessage,
|
|
3359
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3360
|
+
},
|
|
3361
|
+
activeStream: void 0,
|
|
3362
|
+
groupRootBaseline
|
|
3338
3363
|
});
|
|
3364
|
+
snapshotRef.current = nextSnapshot;
|
|
3365
|
+
setSnapshot(nextSnapshot);
|
|
3366
|
+
pendingUserWasSet = true;
|
|
3367
|
+
pendingUserTurnId = turnId;
|
|
3339
3368
|
} else {
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
|
|
3369
|
+
setSnapshot(
|
|
3370
|
+
(prev) => commitActiveStream(
|
|
3371
|
+
prev,
|
|
3372
|
+
"inputs" in options ? options.inputs : void 0
|
|
3373
|
+
)
|
|
3374
|
+
);
|
|
3375
|
+
if ("userMessage" in options) {
|
|
3376
|
+
const rootBucket = snapshotRef.current.fold.threads.get(ROOT_THREAD_ID);
|
|
3377
|
+
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
3378
|
+
setSnapshot((prev) => {
|
|
3379
|
+
const next = replaceSessionSnapshot(prev, {
|
|
3380
|
+
pendingUser: {
|
|
3381
|
+
turnId,
|
|
3382
|
+
content: options.userMessage,
|
|
3383
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3384
|
+
},
|
|
3385
|
+
activeStream: void 0,
|
|
3386
|
+
groupRootBaseline
|
|
3387
|
+
});
|
|
3388
|
+
snapshotRef.current = next;
|
|
3389
|
+
return next;
|
|
3390
|
+
});
|
|
3391
|
+
pendingUserWasSet = true;
|
|
3392
|
+
pendingUserTurnId = turnId;
|
|
3393
|
+
} else {
|
|
3394
|
+
groupRootBaseline = snapshotRef.current.groupRootBaseline ?? computeGroupRootBaseline(snapshotRef.current.turns);
|
|
3354
3395
|
}
|
|
3355
|
-
|
|
3396
|
+
}
|
|
3397
|
+
runStreamStarted = true;
|
|
3398
|
+
await runStream(
|
|
3399
|
+
(signal) => {
|
|
3400
|
+
if ("inputs" in options) {
|
|
3401
|
+
return streamTurnContent(
|
|
3402
|
+
server,
|
|
3403
|
+
conversationSessionId,
|
|
3404
|
+
snapshotRef.current.fold,
|
|
3405
|
+
{ inputs: options.inputs, ...streamHeaders },
|
|
3406
|
+
signal,
|
|
3407
|
+
groupRootBaseline
|
|
3408
|
+
);
|
|
3409
|
+
}
|
|
3410
|
+
if ("resumeMcpAuth" in options) {
|
|
3411
|
+
return streamTurnContent(
|
|
3412
|
+
server,
|
|
3413
|
+
conversationSessionId,
|
|
3414
|
+
snapshotRef.current.fold,
|
|
3415
|
+
{ resumeMcpAuth: true, ...streamHeaders },
|
|
3416
|
+
signal,
|
|
3417
|
+
groupRootBaseline
|
|
3418
|
+
);
|
|
3419
|
+
}
|
|
3356
3420
|
return streamTurnContent(
|
|
3357
3421
|
server,
|
|
3358
3422
|
conversationSessionId,
|
|
3359
3423
|
snapshotRef.current.fold,
|
|
3360
|
-
{
|
|
3424
|
+
{
|
|
3425
|
+
userMessage: options.userMessage,
|
|
3426
|
+
...options.previousTurnId !== void 0 ? { previousTurnId: options.previousTurnId ?? "none" } : isFirstTurnInSession ? { previousTurnId: "none" } : {},
|
|
3427
|
+
...streamHeaders
|
|
3428
|
+
},
|
|
3361
3429
|
signal,
|
|
3362
|
-
groupRootBaseline
|
|
3430
|
+
groupRootBaseline,
|
|
3431
|
+
// Rename the optimistic local ID to the gateway turn ID
|
|
3432
|
+
// so that edit/retry can resolve the turn via the gateway.
|
|
3433
|
+
(gatewayTurnId) => {
|
|
3434
|
+
const oldId = turnIdRef.current;
|
|
3435
|
+
gatewayTurnAccepted = true;
|
|
3436
|
+
if (gatewayTurnId === oldId) return;
|
|
3437
|
+
turnIdRef.current = gatewayTurnId;
|
|
3438
|
+
const renamePendingUser = (prev) => {
|
|
3439
|
+
if (prev.pendingUser?.turnId !== oldId) return prev;
|
|
3440
|
+
return replaceSessionSnapshot(prev, {
|
|
3441
|
+
pendingUser: { ...prev.pendingUser, turnId: gatewayTurnId }
|
|
3442
|
+
});
|
|
3443
|
+
};
|
|
3444
|
+
snapshotRef.current = renamePendingUser(snapshotRef.current);
|
|
3445
|
+
setSnapshot(renamePendingUser);
|
|
3446
|
+
}
|
|
3363
3447
|
);
|
|
3448
|
+
},
|
|
3449
|
+
turnIdRef,
|
|
3450
|
+
isContinuation
|
|
3451
|
+
);
|
|
3452
|
+
} catch (error) {
|
|
3453
|
+
if ("userMessage" in options && !gatewayTurnAccepted) {
|
|
3454
|
+
const branchRollbackSnapshot = options.branchRollbackSnapshot;
|
|
3455
|
+
const canRestoreBranch = branchRollbackSnapshot != null && (snapshotRef.current === options.branchFromSnapshot || snapshotRef.current.pendingUser?.turnId === pendingUserTurnId);
|
|
3456
|
+
if (canRestoreBranch) {
|
|
3457
|
+
snapshotRef.current = branchRollbackSnapshot;
|
|
3458
|
+
setSnapshot(branchRollbackSnapshot);
|
|
3459
|
+
} else if (pendingUserWasSet) {
|
|
3460
|
+
const clearPendingUser = (previous) => {
|
|
3461
|
+
if (previous.pendingUser?.turnId !== pendingUserTurnId) {
|
|
3462
|
+
return previous;
|
|
3463
|
+
}
|
|
3464
|
+
return replaceSessionSnapshot(previous, {
|
|
3465
|
+
pendingUser: void 0
|
|
3466
|
+
});
|
|
3467
|
+
};
|
|
3468
|
+
snapshotRef.current = clearPendingUser(snapshotRef.current);
|
|
3469
|
+
setSnapshot(clearPendingUser);
|
|
3364
3470
|
}
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
...streamHeaders
|
|
3373
|
-
},
|
|
3374
|
-
signal,
|
|
3375
|
-
groupRootBaseline,
|
|
3376
|
-
// Rename the optimistic local ID to the gateway turn ID
|
|
3377
|
-
// so that edit/retry can resolve the turn via the gateway.
|
|
3378
|
-
(gatewayTurnId) => {
|
|
3379
|
-
const oldId = turnIdRef.current;
|
|
3380
|
-
if (gatewayTurnId === oldId) return;
|
|
3381
|
-
turnIdRef.current = gatewayTurnId;
|
|
3382
|
-
const renamePendingUser = (prev) => {
|
|
3383
|
-
if (prev.pendingUser?.turnId !== oldId) return prev;
|
|
3384
|
-
return replaceSessionSnapshot(prev, {
|
|
3385
|
-
pendingUser: { ...prev.pendingUser, turnId: gatewayTurnId }
|
|
3386
|
-
});
|
|
3387
|
-
};
|
|
3388
|
-
snapshotRef.current = renamePendingUser(snapshotRef.current);
|
|
3389
|
-
setSnapshot(renamePendingUser);
|
|
3390
|
-
}
|
|
3391
|
-
);
|
|
3392
|
-
},
|
|
3393
|
-
turnIdRef,
|
|
3394
|
-
isContinuation
|
|
3395
|
-
);
|
|
3471
|
+
options.onPreTurnFailure?.();
|
|
3472
|
+
}
|
|
3473
|
+
if (!runStreamStarted) {
|
|
3474
|
+
onErrorRef.current?.(error);
|
|
3475
|
+
}
|
|
3476
|
+
throw error;
|
|
3477
|
+
}
|
|
3396
3478
|
},
|
|
3397
3479
|
[server, runStream, sessionId]
|
|
3398
3480
|
);
|
|
@@ -3422,7 +3504,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3422
3504
|
}
|
|
3423
3505
|
const inputs = collectRequiredActionInputs(paused);
|
|
3424
3506
|
if (inputs.length > 0) {
|
|
3425
|
-
void sendTurn({ inputs }).catch((
|
|
3507
|
+
void sendTurn({ inputs }).catch(() => void 0);
|
|
3426
3508
|
}
|
|
3427
3509
|
},
|
|
3428
3510
|
[projectOptions, sendTurn]
|
|
@@ -3483,35 +3565,44 @@ function useTrueFoundryAgentMessages({
|
|
|
3483
3565
|
}, [runStream, server]);
|
|
3484
3566
|
const branchFromTurn = useCallback2(
|
|
3485
3567
|
async (turnId, userMessage) => {
|
|
3486
|
-
let
|
|
3487
|
-
|
|
3488
|
-
|
|
3568
|
+
let committed;
|
|
3569
|
+
let previousTurnId;
|
|
3570
|
+
let rewound;
|
|
3571
|
+
try {
|
|
3572
|
+
let activeSessionId = sessionId;
|
|
3573
|
+
if (activeSessionId == null) {
|
|
3574
|
+
throw new Error("Cannot branch from a turn without an active session.");
|
|
3575
|
+
}
|
|
3576
|
+
committed = commitActiveStream(snapshotRef.current);
|
|
3577
|
+
setSnapshot(committed);
|
|
3578
|
+
await cancel();
|
|
3579
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
3580
|
+
activeSessionId,
|
|
3581
|
+
resolveConversationSessionIdRef.current
|
|
3582
|
+
);
|
|
3583
|
+
previousTurnId = await resolveGatewayBranchPreviousTurnIdForTurn(
|
|
3584
|
+
server,
|
|
3585
|
+
conversationSessionId,
|
|
3586
|
+
turnId
|
|
3587
|
+
);
|
|
3588
|
+
rewound = await buildSnapshotBeforeTurn(
|
|
3589
|
+
server,
|
|
3590
|
+
conversationSessionId,
|
|
3591
|
+
turnId,
|
|
3592
|
+
listEventsConcurrency
|
|
3593
|
+
);
|
|
3594
|
+
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3595
|
+
snapshotRef.current = rewound;
|
|
3596
|
+
setSnapshot(rewound);
|
|
3597
|
+
} catch (error) {
|
|
3598
|
+
onErrorRef.current?.(error);
|
|
3599
|
+
throw error;
|
|
3489
3600
|
}
|
|
3490
|
-
const committed = commitActiveStream(snapshotRef.current);
|
|
3491
|
-
setSnapshot(committed);
|
|
3492
|
-
await cancel();
|
|
3493
|
-
const conversationSessionId = await resolveActiveSessionId(
|
|
3494
|
-
activeSessionId,
|
|
3495
|
-
resolveConversationSessionIdRef.current
|
|
3496
|
-
);
|
|
3497
|
-
const previousTurnId = await resolveGatewayBranchPreviousTurnIdForTurn(
|
|
3498
|
-
server,
|
|
3499
|
-
conversationSessionId,
|
|
3500
|
-
turnId
|
|
3501
|
-
);
|
|
3502
|
-
const rewound = await buildSnapshotBeforeTurn(
|
|
3503
|
-
server,
|
|
3504
|
-
conversationSessionId,
|
|
3505
|
-
turnId,
|
|
3506
|
-
listEventsConcurrency
|
|
3507
|
-
);
|
|
3508
|
-
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3509
|
-
snapshotRef.current = rewound;
|
|
3510
|
-
setSnapshot(rewound);
|
|
3511
3601
|
await sendTurn({
|
|
3512
3602
|
userMessage,
|
|
3513
3603
|
previousTurnId,
|
|
3514
|
-
branchFromSnapshot: rewound
|
|
3604
|
+
branchFromSnapshot: rewound,
|
|
3605
|
+
branchRollbackSnapshot: committed
|
|
3515
3606
|
});
|
|
3516
3607
|
},
|
|
3517
3608
|
[
|
|
@@ -3527,7 +3618,9 @@ function useTrueFoundryAgentMessages({
|
|
|
3527
3618
|
const committed = commitActiveStream(snapshotRef.current);
|
|
3528
3619
|
const originalInput = resolveTurnInput(committed, turnId);
|
|
3529
3620
|
if (originalInput == null) {
|
|
3530
|
-
|
|
3621
|
+
const error = new Error(`Turn ${turnId} not found in session snapshot`);
|
|
3622
|
+
onErrorRef.current?.(error);
|
|
3623
|
+
throw error;
|
|
3531
3624
|
}
|
|
3532
3625
|
const userMessage = extractTurnUserMessageContent(originalInput);
|
|
3533
3626
|
await branchFromTurn(turnId, userMessage);
|
|
@@ -3539,7 +3632,9 @@ function useTrueFoundryAgentMessages({
|
|
|
3539
3632
|
const committed = commitActiveStream(snapshotRef.current);
|
|
3540
3633
|
const originalInput = resolveTurnInput(committed, turnId);
|
|
3541
3634
|
if (originalInput == null) {
|
|
3542
|
-
|
|
3635
|
+
const error = new Error(`Turn ${turnId} not found in session snapshot`);
|
|
3636
|
+
onErrorRef.current?.(error);
|
|
3637
|
+
throw error;
|
|
3543
3638
|
}
|
|
3544
3639
|
const userMessage = buildEditedUserMessageContent(
|
|
3545
3640
|
editedText,
|
|
@@ -3638,6 +3733,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3638
3733
|
const isMain = useAuiState(
|
|
3639
3734
|
(state) => state.threads.mainThreadId === state.threadListItem.id
|
|
3640
3735
|
);
|
|
3736
|
+
const isInitialSession = sessionId != null && sessionId === options.initialSessionId;
|
|
3641
3737
|
const draftSpec = useDraftAgentSpec({
|
|
3642
3738
|
draftSessionId,
|
|
3643
3739
|
draftBridge: draftBridgeRef.current,
|
|
@@ -3683,6 +3779,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3683
3779
|
server,
|
|
3684
3780
|
sessionId,
|
|
3685
3781
|
isMain,
|
|
3782
|
+
isInitialSession,
|
|
3686
3783
|
listEventsConcurrency,
|
|
3687
3784
|
onError,
|
|
3688
3785
|
initializeSession,
|
|
@@ -3708,20 +3805,16 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3708
3805
|
const downloadSandboxFile = useCallback3(
|
|
3709
3806
|
async (path) => {
|
|
3710
3807
|
if (server.downloadSandboxFile == null) {
|
|
3711
|
-
|
|
3808
|
+
throw new Error(
|
|
3712
3809
|
"Downloading a sandbox file requires AgentChatServer.downloadSandboxFile."
|
|
3713
3810
|
);
|
|
3714
|
-
onError?.(error);
|
|
3715
|
-
throw error;
|
|
3716
3811
|
}
|
|
3717
3812
|
if (sandboxId == null) {
|
|
3718
|
-
|
|
3719
|
-
onError?.(error);
|
|
3720
|
-
throw error;
|
|
3813
|
+
throw new Error("No sandbox is available yet for this session.");
|
|
3721
3814
|
}
|
|
3722
3815
|
return await server.downloadSandboxFile(sandboxId, { path });
|
|
3723
3816
|
},
|
|
3724
|
-
[server, sandboxId
|
|
3817
|
+
[server, sandboxId]
|
|
3725
3818
|
);
|
|
3726
3819
|
const draftExtras = useMemo3(() => {
|
|
3727
3820
|
if (agent.mode !== "draft") {
|
|
@@ -3730,6 +3823,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3730
3823
|
return {
|
|
3731
3824
|
agentSpec: draftSpec.agentSpec,
|
|
3732
3825
|
draftSessionId: draftSpec.draftSessionId,
|
|
3826
|
+
isSpecLoading: draftSpec.isSpecLoading,
|
|
3733
3827
|
isSpecSyncing: draftSpec.isSpecSyncing,
|
|
3734
3828
|
specError: draftSpec.specError,
|
|
3735
3829
|
updateAgentSpec: draftSpec.updateAgentSpec
|
|
@@ -3750,9 +3844,8 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3750
3844
|
resumeMcpAuth,
|
|
3751
3845
|
downloadSandboxFile,
|
|
3752
3846
|
cancel,
|
|
3753
|
-
resetFromTurn
|
|
3754
|
-
|
|
3755
|
-
}),
|
|
3847
|
+
// resetFromTurn/branchFromTurn/sendTurn already report via onError.
|
|
3848
|
+
resetFromTurn: (turnId) => resetFromTurn(turnId).catch(() => void 0),
|
|
3756
3849
|
reload: retryLoad,
|
|
3757
3850
|
hasOlderHistory,
|
|
3758
3851
|
isLoadingOlderHistory,
|
|
@@ -3777,7 +3870,19 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3777
3870
|
await sendTurn({ resumeMcpAuth: true });
|
|
3778
3871
|
return;
|
|
3779
3872
|
}
|
|
3780
|
-
|
|
3873
|
+
const userMessage = buildUserMessageContent(message);
|
|
3874
|
+
await sendTurn({
|
|
3875
|
+
userMessage,
|
|
3876
|
+
// The composer clears before onNew runs. Restore its text only when
|
|
3877
|
+
// the turn failed before turn.created registered it in the backend.
|
|
3878
|
+
onPreTurnFailure: () => {
|
|
3879
|
+
const text = userMessageContentToText(userMessage);
|
|
3880
|
+
const composer = aui.thread().composer();
|
|
3881
|
+
if (text && !composer.getState().text.trim()) {
|
|
3882
|
+
composer.setText(text);
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
});
|
|
3781
3886
|
},
|
|
3782
3887
|
onCancel: async () => {
|
|
3783
3888
|
await cancel();
|
|
@@ -3795,12 +3900,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3795
3900
|
}
|
|
3796
3901
|
const turnId = parseTurnIdFromMessageId(sourceId);
|
|
3797
3902
|
const editedText = extractEditedText(message);
|
|
3798
|
-
|
|
3799
|
-
await editFromTurn(turnId, editedText);
|
|
3800
|
-
} catch (error) {
|
|
3801
|
-
onError?.(error);
|
|
3802
|
-
throw error;
|
|
3803
|
-
}
|
|
3903
|
+
await editFromTurn(turnId, editedText);
|
|
3804
3904
|
}
|
|
3805
3905
|
});
|
|
3806
3906
|
}
|
|
@@ -3887,7 +3987,9 @@ function createTrueFoundryOwnedSessionsThreadListAdapter(options) {
|
|
|
3887
3987
|
},
|
|
3888
3988
|
async unarchive() {
|
|
3889
3989
|
},
|
|
3890
|
-
async delete() {
|
|
3990
|
+
async delete(remoteId) {
|
|
3991
|
+
if (typeof server.deleteSession !== "function") return;
|
|
3992
|
+
await server.deleteSession({ sessionId: remoteId });
|
|
3891
3993
|
},
|
|
3892
3994
|
async generateTitle() {
|
|
3893
3995
|
return new ReadableStream();
|
|
@@ -4049,6 +4151,7 @@ export {
|
|
|
4049
4151
|
collectResponseInputs,
|
|
4050
4152
|
convertTurnsToThreadMessages,
|
|
4051
4153
|
createDraftSessionBridge,
|
|
4154
|
+
createTrueFoundryAgentUIServer,
|
|
4052
4155
|
createTrueFoundryChatServer,
|
|
4053
4156
|
createTrueFoundryDraftThreadListAdapter,
|
|
4054
4157
|
createTrueFoundryOwnedSessionsThreadListAdapter,
|