@truefoundry/assistant-ui-runtime 0.1.6-rc.0 → 0.1.7
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 +193 -579
- package/dist/chunk-3A2EPLQG.js +93 -0
- package/dist/chunk-3A2EPLQG.js.map +1 -0
- package/dist/chunk-SQDOTGP2.js +292 -0
- package/dist/chunk-SQDOTGP2.js.map +1 -0
- package/dist/index.d.ts +24 -36
- package/dist/index.js +276 -249
- package/dist/index.js.map +1 -1
- package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +134 -5
- package/dist/plugins/truefoundry-agent-server-adapter/index.js +16 -195
- package/dist/plugins/truefoundry-agent-server-adapter/index.js.map +1 -1
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.js +9 -0
- package/dist/server/index.js.map +1 -0
- package/dist/{types-VUBzoJT2.d.ts → types-DbNsU075.d.ts} +212 -19
- package/package.json +10 -5
- 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 +2 -1
- package/src/{private → draft}/useDraftAgentSpec.ts +16 -5
- package/src/draftAgentConfig.test.ts +2 -1
- package/src/index.ts +71 -7
- package/src/plugins/truefoundry-agent-server-adapter/README.md +178 -0
- package/src/plugins/truefoundry-agent-server-adapter/guards.test.ts +113 -0
- package/src/plugins/truefoundry-agent-server-adapter/guards.ts +130 -0
- package/src/plugins/truefoundry-agent-server-adapter/index.ts +154 -40
- package/src/plugins/truefoundry-agent-server-adapter/types.ts +137 -0
- package/src/plugins/truefoundry-agent-server-adapter/types.typecheck.ts +164 -0
- package/src/server/index.ts +23 -0
- package/src/server/types.ts +272 -21
- package/src/truefoundryExtras.ts +4 -1
- package/src/truefoundryOwnedSessionsThreadListAdapter.ts +1 -1
- package/src/types.ts +1 -2
- package/src/useTrueFoundryAgentMessages.test.tsx +261 -1
- package/src/useTrueFoundryAgentMessages.ts +284 -176
- package/src/useTrueFoundryAgentRuntime.ts +31 -21
- /package/src/{private → draft}/useDraftAgentSpec.test.tsx +0 -0
package/dist/index.js
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isEventDelta,
|
|
3
|
+
mergeEventDelta
|
|
4
|
+
} from "./chunk-3A2EPLQG.js";
|
|
5
|
+
import {
|
|
6
|
+
createTrueFoundryChatServer,
|
|
7
|
+
getTfyMcpInitServers,
|
|
8
|
+
getTfyThreadState,
|
|
9
|
+
getTfyUsage,
|
|
10
|
+
isTfyMcpToolInfo,
|
|
11
|
+
isTfySystemToolInfo,
|
|
12
|
+
isTfyToolInfo
|
|
13
|
+
} from "./chunk-SQDOTGP2.js";
|
|
14
|
+
|
|
1
15
|
// src/useTrueFoundryAgentRuntime.ts
|
|
2
16
|
import {
|
|
3
17
|
pickExternalStoreSharedOptions
|
|
@@ -251,94 +265,6 @@ function toTrueFoundryApprovalInputs(message, response, defaultThreadId = ROOT_T
|
|
|
251
265
|
return collectApprovalInputs(updated, defaultThreadId);
|
|
252
266
|
}
|
|
253
267
|
|
|
254
|
-
// src/server/eventUtils.ts
|
|
255
|
-
function isEventDelta(event) {
|
|
256
|
-
return typeof event.type === "string" && event.type.endsWith(".delta");
|
|
257
|
-
}
|
|
258
|
-
function mergeEventDelta(base, delta) {
|
|
259
|
-
if (base.id !== delta.id) {
|
|
260
|
-
throw new Error(
|
|
261
|
-
`Cannot merge delta into a different event: base id "${base.id}" != delta id "${delta.id}".`
|
|
262
|
-
);
|
|
263
|
-
}
|
|
264
|
-
if (delta.type === "model.message.delta" && base.type === "model.message") {
|
|
265
|
-
mergeModelMessageDelta(base, delta);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
function asToolInfo(value) {
|
|
269
|
-
if (value == null || typeof value !== "object") {
|
|
270
|
-
return void 0;
|
|
271
|
-
}
|
|
272
|
-
return value;
|
|
273
|
-
}
|
|
274
|
-
function mergeModelMessageDelta(base, delta) {
|
|
275
|
-
if (delta.content) {
|
|
276
|
-
if (base.content === void 0 || base.content === null || typeof base.content === "string") {
|
|
277
|
-
base.content = (base.content ?? "") + delta.content;
|
|
278
|
-
} else {
|
|
279
|
-
const last = base.content[base.content.length - 1];
|
|
280
|
-
if (last && last.type === "text") {
|
|
281
|
-
last.text += delta.content;
|
|
282
|
-
} else {
|
|
283
|
-
base.content.push({ type: "text", text: delta.content });
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
if (delta.refusal) {
|
|
288
|
-
base.refusal = (base.refusal ?? "") + delta.refusal;
|
|
289
|
-
}
|
|
290
|
-
if (delta.toolCalls) {
|
|
291
|
-
base.toolCalls ??= [];
|
|
292
|
-
for (const d of delta.toolCalls) {
|
|
293
|
-
let tc = base.toolCalls[d.index];
|
|
294
|
-
if (tc === void 0) {
|
|
295
|
-
const toolInfo2 = asToolInfo(d.toolInfo);
|
|
296
|
-
tc = {
|
|
297
|
-
id: d.id ?? "",
|
|
298
|
-
type: d.type ?? "function",
|
|
299
|
-
function: {
|
|
300
|
-
name: d.function?.name ?? "",
|
|
301
|
-
arguments: ""
|
|
302
|
-
},
|
|
303
|
-
...toolInfo2 != null ? { toolInfo: toolInfo2 } : {}
|
|
304
|
-
};
|
|
305
|
-
base.toolCalls[d.index] = tc;
|
|
306
|
-
}
|
|
307
|
-
if (d.id) {
|
|
308
|
-
tc.id = d.id;
|
|
309
|
-
}
|
|
310
|
-
if (d.type) {
|
|
311
|
-
tc.type = d.type;
|
|
312
|
-
}
|
|
313
|
-
if (d.function?.name) {
|
|
314
|
-
tc.function.name = d.function.name;
|
|
315
|
-
}
|
|
316
|
-
if (d.function?.arguments) {
|
|
317
|
-
tc.function.arguments += d.function.arguments;
|
|
318
|
-
}
|
|
319
|
-
const toolInfo = asToolInfo(d.toolInfo);
|
|
320
|
-
if (toolInfo != null) {
|
|
321
|
-
tc.toolInfo = toolInfo;
|
|
322
|
-
}
|
|
323
|
-
if (d.providerSpecificFields) {
|
|
324
|
-
tc.providerSpecificFields = {
|
|
325
|
-
...tc.providerSpecificFields ?? {},
|
|
326
|
-
...d.providerSpecificFields
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
if (delta.finishReason) {
|
|
332
|
-
base.finishReason = delta.finishReason;
|
|
333
|
-
}
|
|
334
|
-
if (delta.reasoningContent) {
|
|
335
|
-
base.reasoningContent = (base.reasoningContent ?? "") + delta.reasoningContent;
|
|
336
|
-
}
|
|
337
|
-
if (delta.usage) {
|
|
338
|
-
base.usage = delta.usage;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
268
|
// src/askUserQuestion.ts
|
|
343
269
|
function parseAskUserQuestionArgs(argsText) {
|
|
344
270
|
if (!argsText) {
|
|
@@ -2460,7 +2386,7 @@ function repositoryItemsFromMessages(messages) {
|
|
|
2460
2386
|
return items;
|
|
2461
2387
|
}
|
|
2462
2388
|
|
|
2463
|
-
// src/
|
|
2389
|
+
// src/draft/draftSessionBridge.ts
|
|
2464
2390
|
var DRAFT_SESSION_LAST_UPDATED_AT_HEADER = "x-tfy-session-last-updated-at";
|
|
2465
2391
|
function createDraftSessionBridge(server) {
|
|
2466
2392
|
return {
|
|
@@ -2483,7 +2409,7 @@ function createDraftSessionBridge(server) {
|
|
|
2483
2409
|
};
|
|
2484
2410
|
}
|
|
2485
2411
|
|
|
2486
|
-
// src/
|
|
2412
|
+
// src/draft/agentSpec.ts
|
|
2487
2413
|
function mergeAgentSpec(base, update) {
|
|
2488
2414
|
const { model: modelUpdate, ...rest } = update;
|
|
2489
2415
|
const next = {
|
|
@@ -2511,7 +2437,7 @@ function sessionListStartTimestamp() {
|
|
|
2511
2437
|
return start.toISOString();
|
|
2512
2438
|
}
|
|
2513
2439
|
|
|
2514
|
-
// src/
|
|
2440
|
+
// src/draft/truefoundryDraftThreadListAdapter.ts
|
|
2515
2441
|
var THREAD_LIST_PAGE_SIZE = 20;
|
|
2516
2442
|
function createTrueFoundryDraftThreadListAdapter(options) {
|
|
2517
2443
|
const { server, defaultAgentSpec, getAgentSpec } = options;
|
|
@@ -2576,6 +2502,7 @@ var trueFoundryExtras = createRuntimeExtras(
|
|
|
2576
2502
|
var EMPTY_DRAFT_EXTRAS = {
|
|
2577
2503
|
agentSpec: null,
|
|
2578
2504
|
draftSessionId: void 0,
|
|
2505
|
+
isSpecLoading: false,
|
|
2579
2506
|
isSpecSyncing: false,
|
|
2580
2507
|
specError: null,
|
|
2581
2508
|
updateAgentSpec: () => {
|
|
@@ -2671,7 +2598,7 @@ function resolveTrueFoundryAgentRuntimeOptions(options) {
|
|
|
2671
2598
|
};
|
|
2672
2599
|
}
|
|
2673
2600
|
|
|
2674
|
-
// src/
|
|
2601
|
+
// src/draft/useDraftAgentSpec.ts
|
|
2675
2602
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2676
2603
|
var SPEC_SYNC_DEBOUNCE_MS = 400;
|
|
2677
2604
|
function useDraftAgentSpec({
|
|
@@ -2683,6 +2610,7 @@ function useDraftAgentSpec({
|
|
|
2683
2610
|
}) {
|
|
2684
2611
|
const enabled = draftBridge != null;
|
|
2685
2612
|
const [agentSpec, setAgentSpec] = useState(defaultAgentSpec);
|
|
2613
|
+
const [isSpecLoading, setIsSpecLoading] = useState(false);
|
|
2686
2614
|
const [isSpecSyncing, setIsSpecSyncing] = useState(false);
|
|
2687
2615
|
const [specError, setSpecError] = useState(null);
|
|
2688
2616
|
const agentSpecRef = useRef(agentSpec);
|
|
@@ -2723,12 +2651,14 @@ function useDraftAgentSpec({
|
|
|
2723
2651
|
setAgentSpec(defaultAgentSpec);
|
|
2724
2652
|
localDirtyRef.current = false;
|
|
2725
2653
|
setSpecError(null);
|
|
2654
|
+
setIsSpecLoading(false);
|
|
2726
2655
|
return;
|
|
2727
2656
|
}
|
|
2728
2657
|
if (loadedDraftIdRef.current === draftSessionId) {
|
|
2729
2658
|
return;
|
|
2730
2659
|
}
|
|
2731
2660
|
let cancelled = false;
|
|
2661
|
+
setIsSpecLoading(true);
|
|
2732
2662
|
void (async () => {
|
|
2733
2663
|
try {
|
|
2734
2664
|
const loaded = await draftBridge.getDraftAgentSpec(draftSessionId);
|
|
@@ -2740,19 +2670,23 @@ function useDraftAgentSpec({
|
|
|
2740
2670
|
scheduleSpecSyncRef.current?.(draftSessionId, agentSpecRef.current);
|
|
2741
2671
|
localDirtyRef.current = false;
|
|
2742
2672
|
setSpecError(null);
|
|
2673
|
+
setIsSpecLoading(false);
|
|
2743
2674
|
return;
|
|
2744
2675
|
}
|
|
2745
2676
|
setAgentSpec(loaded);
|
|
2746
2677
|
setSpecError(null);
|
|
2678
|
+
setIsSpecLoading(false);
|
|
2747
2679
|
} catch (error) {
|
|
2748
2680
|
if (!cancelled) {
|
|
2749
2681
|
onError?.(error);
|
|
2750
2682
|
setSpecError(error);
|
|
2683
|
+
setIsSpecLoading(false);
|
|
2751
2684
|
}
|
|
2752
2685
|
}
|
|
2753
2686
|
})();
|
|
2754
2687
|
return () => {
|
|
2755
2688
|
cancelled = true;
|
|
2689
|
+
setIsSpecLoading(false);
|
|
2756
2690
|
};
|
|
2757
2691
|
}, [defaultAgentSpec, draftBridge, draftSessionId, enabled, onError]);
|
|
2758
2692
|
const flushSpecSync = useCallback(
|
|
@@ -2855,6 +2789,7 @@ function useDraftAgentSpec({
|
|
|
2855
2789
|
() => ({
|
|
2856
2790
|
agentSpec: enabled ? agentSpec : null,
|
|
2857
2791
|
draftSessionId: enabled ? draftSessionId : void 0,
|
|
2792
|
+
isSpecLoading: enabled ? isSpecLoading : false,
|
|
2858
2793
|
isSpecSyncing: enabled ? isSpecSyncing : false,
|
|
2859
2794
|
specError: enabled ? specError : null,
|
|
2860
2795
|
updateAgentSpec,
|
|
@@ -2864,6 +2799,7 @@ function useDraftAgentSpec({
|
|
|
2864
2799
|
agentSpec,
|
|
2865
2800
|
draftSessionId,
|
|
2866
2801
|
enabled,
|
|
2802
|
+
isSpecLoading,
|
|
2867
2803
|
isSpecSyncing,
|
|
2868
2804
|
specError,
|
|
2869
2805
|
takeTurnHeaderTimestamp,
|
|
@@ -3132,6 +3068,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3132
3068
|
server,
|
|
3133
3069
|
sessionId,
|
|
3134
3070
|
isMain,
|
|
3071
|
+
isInitialSession,
|
|
3135
3072
|
listEventsConcurrency,
|
|
3136
3073
|
onError,
|
|
3137
3074
|
initializeSession,
|
|
@@ -3140,7 +3077,9 @@ function useTrueFoundryAgentMessages({
|
|
|
3140
3077
|
}) {
|
|
3141
3078
|
const [snapshot, setSnapshot] = useState2(createEmptySessionSnapshot);
|
|
3142
3079
|
const [isRunning, setIsRunning] = useState2(false);
|
|
3143
|
-
const [isLoading, setIsLoading] = useState2(
|
|
3080
|
+
const [isLoading, setIsLoading] = useState2(
|
|
3081
|
+
sessionId != null && (isMain !== false || isInitialSession === true)
|
|
3082
|
+
);
|
|
3144
3083
|
const [isLoadingOlderHistory, setIsLoadingOlderHistory] = useState2(false);
|
|
3145
3084
|
const [loadRetryTrigger, setLoadRetryTrigger] = useState2(0);
|
|
3146
3085
|
const snapshotRef = useRef2(snapshot);
|
|
@@ -3161,6 +3100,8 @@ function useTrueFoundryAgentMessages({
|
|
|
3161
3100
|
const loadGenerationRef = useRef2(0);
|
|
3162
3101
|
const streamGenerationRef = useRef2(0);
|
|
3163
3102
|
const lazilyCreatedSessionIdRef = useRef2(void 0);
|
|
3103
|
+
const initialLoadStartedForRef = useRef2(void 0);
|
|
3104
|
+
const skipInitialPromotionLoadForRef = useRef2(void 0);
|
|
3164
3105
|
const projectOptions = useMemo2(
|
|
3165
3106
|
() => ({
|
|
3166
3107
|
getCreatedAt: (messageId, fallback) => {
|
|
@@ -3271,12 +3212,24 @@ function useTrueFoundryAgentMessages({
|
|
|
3271
3212
|
[onError]
|
|
3272
3213
|
);
|
|
3273
3214
|
const load = useCallback2(async () => {
|
|
3215
|
+
void loadRetryTrigger;
|
|
3274
3216
|
if (sessionId == null) {
|
|
3275
3217
|
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3276
3218
|
setSnapshot(createEmptySessionSnapshot());
|
|
3277
3219
|
return;
|
|
3278
3220
|
}
|
|
3279
|
-
|
|
3221
|
+
const isEarlyInitialLoad = isMain === false && isInitialSession === true && initialLoadStartedForRef.current !== sessionId;
|
|
3222
|
+
if (isMain === false) {
|
|
3223
|
+
if (!isEarlyInitialLoad) return;
|
|
3224
|
+
initialLoadStartedForRef.current = sessionId;
|
|
3225
|
+
skipInitialPromotionLoadForRef.current = sessionId;
|
|
3226
|
+
} else if (isMain === true && skipInitialPromotionLoadForRef.current === sessionId) {
|
|
3227
|
+
skipInitialPromotionLoadForRef.current = void 0;
|
|
3228
|
+
return;
|
|
3229
|
+
}
|
|
3230
|
+
if (isInitialSession === true) {
|
|
3231
|
+
initialLoadStartedForRef.current = sessionId;
|
|
3232
|
+
}
|
|
3280
3233
|
if (lazilyCreatedSessionIdRef.current != null && sessionId !== lazilyCreatedSessionIdRef.current) {
|
|
3281
3234
|
lazilyCreatedSessionIdRef.current = void 0;
|
|
3282
3235
|
}
|
|
@@ -3285,6 +3238,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3285
3238
|
}
|
|
3286
3239
|
const generation = ++loadGenerationRef.current;
|
|
3287
3240
|
++streamGenerationRef.current;
|
|
3241
|
+
setIsRunning(false);
|
|
3288
3242
|
abortControllerRef.current?.abort();
|
|
3289
3243
|
loadOlderInflightRef.current = null;
|
|
3290
3244
|
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
@@ -3331,6 +3285,10 @@ function useTrueFoundryAgentMessages({
|
|
|
3331
3285
|
}
|
|
3332
3286
|
} catch (error) {
|
|
3333
3287
|
if (generation === loadGenerationRef.current) {
|
|
3288
|
+
if (isEarlyInitialLoad) {
|
|
3289
|
+
initialLoadStartedForRef.current = void 0;
|
|
3290
|
+
skipInitialPromotionLoadForRef.current = void 0;
|
|
3291
|
+
}
|
|
3334
3292
|
onErrorRef.current?.(error);
|
|
3335
3293
|
}
|
|
3336
3294
|
throw error;
|
|
@@ -3339,134 +3297,178 @@ function useTrueFoundryAgentMessages({
|
|
|
3339
3297
|
setIsLoading(false);
|
|
3340
3298
|
}
|
|
3341
3299
|
}
|
|
3342
|
-
}, [
|
|
3300
|
+
}, [
|
|
3301
|
+
server,
|
|
3302
|
+
runStream,
|
|
3303
|
+
sessionId,
|
|
3304
|
+
loadRetryTrigger,
|
|
3305
|
+
isMain,
|
|
3306
|
+
isInitialSession
|
|
3307
|
+
]);
|
|
3343
3308
|
useEffect2(() => {
|
|
3344
3309
|
void load().catch(() => void 0);
|
|
3345
3310
|
}, [load]);
|
|
3346
3311
|
const sendTurn = useCallback2(
|
|
3347
3312
|
async (options) => {
|
|
3348
|
-
let
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3313
|
+
let gatewayTurnAccepted = false;
|
|
3314
|
+
let pendingUserWasSet = false;
|
|
3315
|
+
let runStreamStarted = false;
|
|
3316
|
+
let pendingUserTurnId;
|
|
3317
|
+
try {
|
|
3318
|
+
let activeSessionId = sessionId;
|
|
3319
|
+
if (activeSessionId == null) {
|
|
3320
|
+
if (initializeSessionRef.current == null) {
|
|
3321
|
+
throw new Error("Cannot send a turn without an active session.");
|
|
3322
|
+
}
|
|
3323
|
+
const { remoteId } = await initializeSessionRef.current();
|
|
3324
|
+
activeSessionId = remoteId;
|
|
3325
|
+
lazilyCreatedSessionIdRef.current = remoteId;
|
|
3352
3326
|
}
|
|
3353
|
-
const
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
}
|
|
3357
|
-
const conversationSessionId = await resolveActiveSessionId(
|
|
3358
|
-
activeSessionId,
|
|
3359
|
-
resolveConversationSessionIdRef.current
|
|
3360
|
-
);
|
|
3361
|
-
const turnHeaders = await getTurnHeadersRef.current?.();
|
|
3362
|
-
const streamHeaders = turnHeaders != null ? { headers: turnHeaders } : {};
|
|
3363
|
-
const isContinuation = "inputs" in options || "resumeMcpAuth" in options && options.resumeMcpAuth === true;
|
|
3364
|
-
const continuationTurnId = snapshotRef.current.activeStream?.turnId;
|
|
3365
|
-
const turnId = isContinuation && continuationTurnId != null ? continuationTurnId : generateId();
|
|
3366
|
-
const isFirstTurnInSession = "userMessage" in options && options.previousTurnId === void 0 && snapshotRef.current.turns.length === 0 && snapshotRef.current.pendingUser == null && snapshotRef.current.activeStream == null;
|
|
3367
|
-
const turnIdRef = { current: turnId };
|
|
3368
|
-
if ("inputs" in options) {
|
|
3369
|
-
applyUserToolResponsesToFold(
|
|
3370
|
-
snapshotRef.current.fold,
|
|
3371
|
-
options.inputs
|
|
3372
|
-
);
|
|
3373
|
-
}
|
|
3374
|
-
const branchBase = "userMessage" in options ? options.branchFromSnapshot : void 0;
|
|
3375
|
-
let groupRootBaseline;
|
|
3376
|
-
if (branchBase != null && "userMessage" in options) {
|
|
3377
|
-
const rootBucket = branchBase.fold.threads.get(ROOT_THREAD_ID);
|
|
3378
|
-
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
3379
|
-
const nextSnapshot = replaceSessionSnapshot(branchBase, {
|
|
3380
|
-
pendingUser: {
|
|
3381
|
-
turnId,
|
|
3382
|
-
content: options.userMessage,
|
|
3383
|
-
createdAt: /* @__PURE__ */ new Date()
|
|
3384
|
-
},
|
|
3385
|
-
activeStream: void 0,
|
|
3386
|
-
groupRootBaseline
|
|
3387
|
-
});
|
|
3388
|
-
snapshotRef.current = nextSnapshot;
|
|
3389
|
-
setSnapshot(nextSnapshot);
|
|
3390
|
-
} else {
|
|
3391
|
-
setSnapshot(
|
|
3392
|
-
(prev) => commitActiveStream(
|
|
3393
|
-
prev,
|
|
3394
|
-
"inputs" in options ? options.inputs : void 0
|
|
3395
|
-
)
|
|
3327
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
3328
|
+
activeSessionId,
|
|
3329
|
+
resolveConversationSessionIdRef.current
|
|
3396
3330
|
);
|
|
3397
|
-
|
|
3398
|
-
|
|
3331
|
+
const turnHeaders = await getTurnHeadersRef.current?.();
|
|
3332
|
+
const streamHeaders = turnHeaders != null ? { headers: turnHeaders } : {};
|
|
3333
|
+
const isContinuation = "inputs" in options || "resumeMcpAuth" in options && options.resumeMcpAuth === true;
|
|
3334
|
+
const continuationTurnId = snapshotRef.current.activeStream?.turnId;
|
|
3335
|
+
const turnId = isContinuation && continuationTurnId != null ? continuationTurnId : generateId();
|
|
3336
|
+
const isFirstTurnInSession = "userMessage" in options && options.previousTurnId === void 0 && snapshotRef.current.turns.length === 0 && snapshotRef.current.pendingUser == null && snapshotRef.current.activeStream == null;
|
|
3337
|
+
const turnIdRef = { current: turnId };
|
|
3338
|
+
if ("inputs" in options) {
|
|
3339
|
+
applyUserToolResponsesToFold(
|
|
3340
|
+
snapshotRef.current.fold,
|
|
3341
|
+
options.inputs
|
|
3342
|
+
);
|
|
3343
|
+
}
|
|
3344
|
+
const branchBase = "userMessage" in options ? options.branchFromSnapshot : void 0;
|
|
3345
|
+
let groupRootBaseline;
|
|
3346
|
+
if (branchBase != null && "userMessage" in options) {
|
|
3347
|
+
const rootBucket = branchBase.fold.threads.get(ROOT_THREAD_ID);
|
|
3399
3348
|
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
groupRootBaseline
|
|
3409
|
-
});
|
|
3410
|
-
snapshotRef.current = next;
|
|
3411
|
-
return next;
|
|
3349
|
+
const nextSnapshot = replaceSessionSnapshot(branchBase, {
|
|
3350
|
+
pendingUser: {
|
|
3351
|
+
turnId,
|
|
3352
|
+
content: options.userMessage,
|
|
3353
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3354
|
+
},
|
|
3355
|
+
activeStream: void 0,
|
|
3356
|
+
groupRootBaseline
|
|
3412
3357
|
});
|
|
3358
|
+
snapshotRef.current = nextSnapshot;
|
|
3359
|
+
setSnapshot(nextSnapshot);
|
|
3360
|
+
pendingUserWasSet = true;
|
|
3361
|
+
pendingUserTurnId = turnId;
|
|
3413
3362
|
} else {
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3363
|
+
setSnapshot(
|
|
3364
|
+
(prev) => commitActiveStream(
|
|
3365
|
+
prev,
|
|
3366
|
+
"inputs" in options ? options.inputs : void 0
|
|
3367
|
+
)
|
|
3368
|
+
);
|
|
3369
|
+
if ("userMessage" in options) {
|
|
3370
|
+
const rootBucket = snapshotRef.current.fold.threads.get(ROOT_THREAD_ID);
|
|
3371
|
+
groupRootBaseline = [...rootBucket?.modelMessageIds ?? []];
|
|
3372
|
+
setSnapshot((prev) => {
|
|
3373
|
+
const next = replaceSessionSnapshot(prev, {
|
|
3374
|
+
pendingUser: {
|
|
3375
|
+
turnId,
|
|
3376
|
+
content: options.userMessage,
|
|
3377
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
3378
|
+
},
|
|
3379
|
+
activeStream: void 0,
|
|
3380
|
+
groupRootBaseline
|
|
3381
|
+
});
|
|
3382
|
+
snapshotRef.current = next;
|
|
3383
|
+
return next;
|
|
3384
|
+
});
|
|
3385
|
+
pendingUserWasSet = true;
|
|
3386
|
+
pendingUserTurnId = turnId;
|
|
3387
|
+
} else {
|
|
3388
|
+
groupRootBaseline = snapshotRef.current.groupRootBaseline ?? computeGroupRootBaseline(snapshotRef.current.turns);
|
|
3428
3389
|
}
|
|
3429
|
-
|
|
3390
|
+
}
|
|
3391
|
+
runStreamStarted = true;
|
|
3392
|
+
await runStream(
|
|
3393
|
+
(signal) => {
|
|
3394
|
+
if ("inputs" in options) {
|
|
3395
|
+
return streamTurnContent(
|
|
3396
|
+
server,
|
|
3397
|
+
conversationSessionId,
|
|
3398
|
+
snapshotRef.current.fold,
|
|
3399
|
+
{ inputs: options.inputs, ...streamHeaders },
|
|
3400
|
+
signal,
|
|
3401
|
+
groupRootBaseline
|
|
3402
|
+
);
|
|
3403
|
+
}
|
|
3404
|
+
if ("resumeMcpAuth" in options) {
|
|
3405
|
+
return streamTurnContent(
|
|
3406
|
+
server,
|
|
3407
|
+
conversationSessionId,
|
|
3408
|
+
snapshotRef.current.fold,
|
|
3409
|
+
{ resumeMcpAuth: true, ...streamHeaders },
|
|
3410
|
+
signal,
|
|
3411
|
+
groupRootBaseline
|
|
3412
|
+
);
|
|
3413
|
+
}
|
|
3430
3414
|
return streamTurnContent(
|
|
3431
3415
|
server,
|
|
3432
3416
|
conversationSessionId,
|
|
3433
3417
|
snapshotRef.current.fold,
|
|
3434
|
-
{
|
|
3418
|
+
{
|
|
3419
|
+
userMessage: options.userMessage,
|
|
3420
|
+
...options.previousTurnId !== void 0 ? { previousTurnId: options.previousTurnId ?? "none" } : isFirstTurnInSession ? { previousTurnId: "none" } : {},
|
|
3421
|
+
...streamHeaders
|
|
3422
|
+
},
|
|
3435
3423
|
signal,
|
|
3436
|
-
groupRootBaseline
|
|
3424
|
+
groupRootBaseline,
|
|
3425
|
+
// Rename the optimistic local ID to the gateway turn ID
|
|
3426
|
+
// so that edit/retry can resolve the turn via the gateway.
|
|
3427
|
+
(gatewayTurnId) => {
|
|
3428
|
+
const oldId = turnIdRef.current;
|
|
3429
|
+
gatewayTurnAccepted = true;
|
|
3430
|
+
if (gatewayTurnId === oldId) return;
|
|
3431
|
+
turnIdRef.current = gatewayTurnId;
|
|
3432
|
+
const renamePendingUser = (prev) => {
|
|
3433
|
+
if (prev.pendingUser?.turnId !== oldId) return prev;
|
|
3434
|
+
return replaceSessionSnapshot(prev, {
|
|
3435
|
+
pendingUser: { ...prev.pendingUser, turnId: gatewayTurnId }
|
|
3436
|
+
});
|
|
3437
|
+
};
|
|
3438
|
+
snapshotRef.current = renamePendingUser(snapshotRef.current);
|
|
3439
|
+
setSnapshot(renamePendingUser);
|
|
3440
|
+
}
|
|
3437
3441
|
);
|
|
3442
|
+
},
|
|
3443
|
+
turnIdRef,
|
|
3444
|
+
isContinuation
|
|
3445
|
+
);
|
|
3446
|
+
} catch (error) {
|
|
3447
|
+
if ("userMessage" in options && !gatewayTurnAccepted) {
|
|
3448
|
+
const branchRollbackSnapshot = options.branchRollbackSnapshot;
|
|
3449
|
+
const canRestoreBranch = branchRollbackSnapshot != null && (snapshotRef.current === options.branchFromSnapshot || snapshotRef.current.pendingUser?.turnId === pendingUserTurnId);
|
|
3450
|
+
if (canRestoreBranch) {
|
|
3451
|
+
snapshotRef.current = branchRollbackSnapshot;
|
|
3452
|
+
setSnapshot(branchRollbackSnapshot);
|
|
3453
|
+
} else if (pendingUserWasSet) {
|
|
3454
|
+
const clearPendingUser = (previous) => {
|
|
3455
|
+
if (previous.pendingUser?.turnId !== pendingUserTurnId) {
|
|
3456
|
+
return previous;
|
|
3457
|
+
}
|
|
3458
|
+
return replaceSessionSnapshot(previous, {
|
|
3459
|
+
pendingUser: void 0
|
|
3460
|
+
});
|
|
3461
|
+
};
|
|
3462
|
+
snapshotRef.current = clearPendingUser(snapshotRef.current);
|
|
3463
|
+
setSnapshot(clearPendingUser);
|
|
3438
3464
|
}
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
...streamHeaders
|
|
3447
|
-
},
|
|
3448
|
-
signal,
|
|
3449
|
-
groupRootBaseline,
|
|
3450
|
-
// Rename the optimistic local ID to the gateway turn ID
|
|
3451
|
-
// so that edit/retry can resolve the turn via the gateway.
|
|
3452
|
-
(gatewayTurnId) => {
|
|
3453
|
-
const oldId = turnIdRef.current;
|
|
3454
|
-
if (gatewayTurnId === oldId) return;
|
|
3455
|
-
turnIdRef.current = gatewayTurnId;
|
|
3456
|
-
const renamePendingUser = (prev) => {
|
|
3457
|
-
if (prev.pendingUser?.turnId !== oldId) return prev;
|
|
3458
|
-
return replaceSessionSnapshot(prev, {
|
|
3459
|
-
pendingUser: { ...prev.pendingUser, turnId: gatewayTurnId }
|
|
3460
|
-
});
|
|
3461
|
-
};
|
|
3462
|
-
snapshotRef.current = renamePendingUser(snapshotRef.current);
|
|
3463
|
-
setSnapshot(renamePendingUser);
|
|
3464
|
-
}
|
|
3465
|
-
);
|
|
3466
|
-
},
|
|
3467
|
-
turnIdRef,
|
|
3468
|
-
isContinuation
|
|
3469
|
-
);
|
|
3465
|
+
options.onPreTurnFailure?.();
|
|
3466
|
+
}
|
|
3467
|
+
if (!runStreamStarted) {
|
|
3468
|
+
onErrorRef.current?.(error);
|
|
3469
|
+
}
|
|
3470
|
+
throw error;
|
|
3471
|
+
}
|
|
3470
3472
|
},
|
|
3471
3473
|
[server, runStream, sessionId]
|
|
3472
3474
|
);
|
|
@@ -3496,7 +3498,7 @@ function useTrueFoundryAgentMessages({
|
|
|
3496
3498
|
}
|
|
3497
3499
|
const inputs = collectRequiredActionInputs(paused);
|
|
3498
3500
|
if (inputs.length > 0) {
|
|
3499
|
-
void sendTurn({ inputs }).catch((
|
|
3501
|
+
void sendTurn({ inputs }).catch(() => void 0);
|
|
3500
3502
|
}
|
|
3501
3503
|
},
|
|
3502
3504
|
[projectOptions, sendTurn]
|
|
@@ -3557,35 +3559,44 @@ function useTrueFoundryAgentMessages({
|
|
|
3557
3559
|
}, [runStream, server]);
|
|
3558
3560
|
const branchFromTurn = useCallback2(
|
|
3559
3561
|
async (turnId, userMessage) => {
|
|
3560
|
-
let
|
|
3561
|
-
|
|
3562
|
-
|
|
3562
|
+
let committed;
|
|
3563
|
+
let previousTurnId;
|
|
3564
|
+
let rewound;
|
|
3565
|
+
try {
|
|
3566
|
+
let activeSessionId = sessionId;
|
|
3567
|
+
if (activeSessionId == null) {
|
|
3568
|
+
throw new Error("Cannot branch from a turn without an active session.");
|
|
3569
|
+
}
|
|
3570
|
+
committed = commitActiveStream(snapshotRef.current);
|
|
3571
|
+
setSnapshot(committed);
|
|
3572
|
+
await cancel();
|
|
3573
|
+
const conversationSessionId = await resolveActiveSessionId(
|
|
3574
|
+
activeSessionId,
|
|
3575
|
+
resolveConversationSessionIdRef.current
|
|
3576
|
+
);
|
|
3577
|
+
previousTurnId = await resolveGatewayBranchPreviousTurnIdForTurn(
|
|
3578
|
+
server,
|
|
3579
|
+
conversationSessionId,
|
|
3580
|
+
turnId
|
|
3581
|
+
);
|
|
3582
|
+
rewound = await buildSnapshotBeforeTurn(
|
|
3583
|
+
server,
|
|
3584
|
+
conversationSessionId,
|
|
3585
|
+
turnId,
|
|
3586
|
+
listEventsConcurrency
|
|
3587
|
+
);
|
|
3588
|
+
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3589
|
+
snapshotRef.current = rewound;
|
|
3590
|
+
setSnapshot(rewound);
|
|
3591
|
+
} catch (error) {
|
|
3592
|
+
onErrorRef.current?.(error);
|
|
3593
|
+
throw error;
|
|
3563
3594
|
}
|
|
3564
|
-
const committed = commitActiveStream(snapshotRef.current);
|
|
3565
|
-
setSnapshot(committed);
|
|
3566
|
-
await cancel();
|
|
3567
|
-
const conversationSessionId = await resolveActiveSessionId(
|
|
3568
|
-
activeSessionId,
|
|
3569
|
-
resolveConversationSessionIdRef.current
|
|
3570
|
-
);
|
|
3571
|
-
const previousTurnId = await resolveGatewayBranchPreviousTurnIdForTurn(
|
|
3572
|
-
server,
|
|
3573
|
-
conversationSessionId,
|
|
3574
|
-
turnId
|
|
3575
|
-
);
|
|
3576
|
-
const rewound = await buildSnapshotBeforeTurn(
|
|
3577
|
-
server,
|
|
3578
|
-
conversationSessionId,
|
|
3579
|
-
turnId,
|
|
3580
|
-
listEventsConcurrency
|
|
3581
|
-
);
|
|
3582
|
-
createdAtByMessageIdRef.current = /* @__PURE__ */ new Map();
|
|
3583
|
-
snapshotRef.current = rewound;
|
|
3584
|
-
setSnapshot(rewound);
|
|
3585
3595
|
await sendTurn({
|
|
3586
3596
|
userMessage,
|
|
3587
3597
|
previousTurnId,
|
|
3588
|
-
branchFromSnapshot: rewound
|
|
3598
|
+
branchFromSnapshot: rewound,
|
|
3599
|
+
branchRollbackSnapshot: committed
|
|
3589
3600
|
});
|
|
3590
3601
|
},
|
|
3591
3602
|
[
|
|
@@ -3601,7 +3612,9 @@ function useTrueFoundryAgentMessages({
|
|
|
3601
3612
|
const committed = commitActiveStream(snapshotRef.current);
|
|
3602
3613
|
const originalInput = resolveTurnInput(committed, turnId);
|
|
3603
3614
|
if (originalInput == null) {
|
|
3604
|
-
|
|
3615
|
+
const error = new Error(`Turn ${turnId} not found in session snapshot`);
|
|
3616
|
+
onErrorRef.current?.(error);
|
|
3617
|
+
throw error;
|
|
3605
3618
|
}
|
|
3606
3619
|
const userMessage = extractTurnUserMessageContent(originalInput);
|
|
3607
3620
|
await branchFromTurn(turnId, userMessage);
|
|
@@ -3613,7 +3626,9 @@ function useTrueFoundryAgentMessages({
|
|
|
3613
3626
|
const committed = commitActiveStream(snapshotRef.current);
|
|
3614
3627
|
const originalInput = resolveTurnInput(committed, turnId);
|
|
3615
3628
|
if (originalInput == null) {
|
|
3616
|
-
|
|
3629
|
+
const error = new Error(`Turn ${turnId} not found in session snapshot`);
|
|
3630
|
+
onErrorRef.current?.(error);
|
|
3631
|
+
throw error;
|
|
3617
3632
|
}
|
|
3618
3633
|
const userMessage = buildEditedUserMessageContent(
|
|
3619
3634
|
editedText,
|
|
@@ -3712,6 +3727,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3712
3727
|
const isMain = useAuiState(
|
|
3713
3728
|
(state) => state.threads.mainThreadId === state.threadListItem.id
|
|
3714
3729
|
);
|
|
3730
|
+
const isInitialSession = sessionId != null && sessionId === options.initialSessionId;
|
|
3715
3731
|
const draftSpec = useDraftAgentSpec({
|
|
3716
3732
|
draftSessionId,
|
|
3717
3733
|
draftBridge: draftBridgeRef.current,
|
|
@@ -3757,6 +3773,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3757
3773
|
server,
|
|
3758
3774
|
sessionId,
|
|
3759
3775
|
isMain,
|
|
3776
|
+
isInitialSession,
|
|
3760
3777
|
listEventsConcurrency,
|
|
3761
3778
|
onError,
|
|
3762
3779
|
initializeSession,
|
|
@@ -3782,20 +3799,16 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3782
3799
|
const downloadSandboxFile = useCallback3(
|
|
3783
3800
|
async (path) => {
|
|
3784
3801
|
if (server.downloadSandboxFile == null) {
|
|
3785
|
-
|
|
3802
|
+
throw new Error(
|
|
3786
3803
|
"Downloading a sandbox file requires AgentChatServer.downloadSandboxFile."
|
|
3787
3804
|
);
|
|
3788
|
-
onError?.(error);
|
|
3789
|
-
throw error;
|
|
3790
3805
|
}
|
|
3791
3806
|
if (sandboxId == null) {
|
|
3792
|
-
|
|
3793
|
-
onError?.(error);
|
|
3794
|
-
throw error;
|
|
3807
|
+
throw new Error("No sandbox is available yet for this session.");
|
|
3795
3808
|
}
|
|
3796
3809
|
return await server.downloadSandboxFile(sandboxId, { path });
|
|
3797
3810
|
},
|
|
3798
|
-
[server, sandboxId
|
|
3811
|
+
[server, sandboxId]
|
|
3799
3812
|
);
|
|
3800
3813
|
const draftExtras = useMemo3(() => {
|
|
3801
3814
|
if (agent.mode !== "draft") {
|
|
@@ -3804,6 +3817,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3804
3817
|
return {
|
|
3805
3818
|
agentSpec: draftSpec.agentSpec,
|
|
3806
3819
|
draftSessionId: draftSpec.draftSessionId,
|
|
3820
|
+
isSpecLoading: draftSpec.isSpecLoading,
|
|
3807
3821
|
isSpecSyncing: draftSpec.isSpecSyncing,
|
|
3808
3822
|
specError: draftSpec.specError,
|
|
3809
3823
|
updateAgentSpec: draftSpec.updateAgentSpec
|
|
@@ -3824,9 +3838,8 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3824
3838
|
resumeMcpAuth,
|
|
3825
3839
|
downloadSandboxFile,
|
|
3826
3840
|
cancel,
|
|
3827
|
-
resetFromTurn
|
|
3828
|
-
|
|
3829
|
-
}),
|
|
3841
|
+
// resetFromTurn/branchFromTurn/sendTurn already report via onError.
|
|
3842
|
+
resetFromTurn: (turnId) => resetFromTurn(turnId).catch(() => void 0),
|
|
3830
3843
|
reload: retryLoad,
|
|
3831
3844
|
hasOlderHistory,
|
|
3832
3845
|
isLoadingOlderHistory,
|
|
@@ -3851,7 +3864,19 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3851
3864
|
await sendTurn({ resumeMcpAuth: true });
|
|
3852
3865
|
return;
|
|
3853
3866
|
}
|
|
3854
|
-
|
|
3867
|
+
const userMessage = buildUserMessageContent(message);
|
|
3868
|
+
await sendTurn({
|
|
3869
|
+
userMessage,
|
|
3870
|
+
// The composer clears before onNew runs. Restore its text only when
|
|
3871
|
+
// the turn failed before turn.created registered it in the backend.
|
|
3872
|
+
onPreTurnFailure: () => {
|
|
3873
|
+
const text = userMessageContentToText(userMessage);
|
|
3874
|
+
const composer = aui.thread().composer();
|
|
3875
|
+
if (text && !composer.getState().text.trim()) {
|
|
3876
|
+
composer.setText(text);
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
});
|
|
3855
3880
|
},
|
|
3856
3881
|
onCancel: async () => {
|
|
3857
3882
|
await cancel();
|
|
@@ -3869,12 +3894,7 @@ function useTrueFoundryAgentRuntimeImpl(options, pendingAgentSpecRef) {
|
|
|
3869
3894
|
}
|
|
3870
3895
|
const turnId = parseTurnIdFromMessageId(sourceId);
|
|
3871
3896
|
const editedText = extractEditedText(message);
|
|
3872
|
-
|
|
3873
|
-
await editFromTurn(turnId, editedText);
|
|
3874
|
-
} catch (error) {
|
|
3875
|
-
onError?.(error);
|
|
3876
|
-
throw error;
|
|
3877
|
-
}
|
|
3897
|
+
await editFromTurn(turnId, editedText);
|
|
3878
3898
|
}
|
|
3879
3899
|
});
|
|
3880
3900
|
}
|
|
@@ -4123,14 +4143,21 @@ export {
|
|
|
4123
4143
|
collectResponseInputs,
|
|
4124
4144
|
convertTurnsToThreadMessages,
|
|
4125
4145
|
createDraftSessionBridge,
|
|
4146
|
+
createTrueFoundryChatServer,
|
|
4126
4147
|
createTrueFoundryDraftThreadListAdapter,
|
|
4127
4148
|
createTrueFoundryOwnedSessionsThreadListAdapter,
|
|
4128
4149
|
createTrueFoundryThreadListAdapter,
|
|
4129
4150
|
draftSessionTitle,
|
|
4130
4151
|
findPausedAssistantMessage,
|
|
4131
4152
|
getSession,
|
|
4153
|
+
getTfyMcpInitServers,
|
|
4154
|
+
getTfyThreadState,
|
|
4155
|
+
getTfyUsage,
|
|
4132
4156
|
getTurnMessageContent,
|
|
4133
4157
|
isEventDelta,
|
|
4158
|
+
isTfyMcpToolInfo,
|
|
4159
|
+
isTfySystemToolInfo,
|
|
4160
|
+
isTfyToolInfo,
|
|
4134
4161
|
mergeAgentSpec,
|
|
4135
4162
|
mergeEventDelta,
|
|
4136
4163
|
messageHasPendingApprovals,
|