@truefoundry/assistant-ui-runtime 0.1.7 → 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 +19 -15
- package/dist/chunk-CXBZ6WLZ.js +636 -0
- package/dist/chunk-CXBZ6WLZ.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +14 -5
- package/dist/index.js.map +1 -1
- package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +81 -35
- package/dist/plugins/truefoundry-agent-server-adapter/index.js +3 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/{types-DbNsU075.d.ts → types-B_z-FsDS.d.ts} +32 -21
- package/package.json +1 -1
- package/src/convertTurnMessages.ts +4 -0
- package/src/draft/truefoundryDraftThreadListAdapter.ts +4 -1
- package/src/harness.temp.ts +85 -0
- package/src/index.ts +13 -0
- 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 -391
- 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 +1 -1
- package/src/server/index.ts +6 -0
- package/src/server/types.ts +30 -23
- package/src/streamTurn.test.ts +27 -27
- package/src/streamTurn.ts +2 -2
- package/src/truefoundryOwnedSessionsThreadListAdapter.ts +4 -1
- package/src/truefoundryThreadListAdapter.test.ts +22 -0
- package/src/truefoundryThreadListAdapter.ts +4 -1
- package/src/useTrueFoundryAgentMessages.test.tsx +1 -1
- package/dist/chunk-SQDOTGP2.js +0 -292
- package/dist/chunk-SQDOTGP2.js.map +0 -1
package/src/server/types.ts
CHANGED
|
@@ -249,7 +249,7 @@ export interface AgentChatServer<
|
|
|
249
249
|
getSession(req: { sessionId: string }): Promise<TSession>;
|
|
250
250
|
updateSession(req: TUpdate): Promise<TSession>;
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
createTurn(req: {
|
|
253
253
|
sessionId: string;
|
|
254
254
|
input?: TurnInputItem[];
|
|
255
255
|
previousTurnId?: PreviousTurnIdInput;
|
|
@@ -407,31 +407,33 @@ export interface ToolBase {
|
|
|
407
407
|
name: string;
|
|
408
408
|
}
|
|
409
409
|
|
|
410
|
-
/**
|
|
411
|
-
|
|
412
|
-
* Stays `string` so hosts can widen (same pattern as `ProviderType`).
|
|
413
|
-
*/
|
|
414
|
-
export type ConnectorAuthType = string;
|
|
410
|
+
/** Strict auth type id. Hosts widen branches via intersection + re-union. */
|
|
411
|
+
export type ConnectorAuthType = "oauth" | "apiKey" | "none";
|
|
415
412
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
export interface ConnectorAuth<TType extends ConnectorAuthType = ConnectorAuthType> {
|
|
421
|
-
type: TType;
|
|
413
|
+
// Write (create/update) — export branches so hosts can intersect extras
|
|
414
|
+
export type ConnectorAuthOAuth = { type: "oauth"; authUrl?: string };
|
|
415
|
+
export type ConnectorAuthApiKey = {
|
|
416
|
+
type: "apiKey";
|
|
422
417
|
apiKey?: string;
|
|
423
418
|
headerName?: string;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
419
|
+
};
|
|
420
|
+
export type ConnectorAuthNone = { type: "none" };
|
|
421
|
+
export type ConnectorAuth =
|
|
422
|
+
| ConnectorAuthOAuth
|
|
423
|
+
| ConnectorAuthApiKey
|
|
424
|
+
| ConnectorAuthNone;
|
|
425
|
+
|
|
426
|
+
// Public (list/detail) — no secrets; oauth requires authUrl
|
|
427
|
+
export type ConnectorAuthPublicOAuth = { type: "oauth"; authUrl: string };
|
|
428
|
+
export type ConnectorAuthPublicApiKey = {
|
|
429
|
+
type: "apiKey";
|
|
433
430
|
headerName?: string;
|
|
434
|
-
}
|
|
431
|
+
};
|
|
432
|
+
export type ConnectorAuthPublicNone = { type: "none" };
|
|
433
|
+
export type ConnectorAuthPublic =
|
|
434
|
+
| ConnectorAuthPublicOAuth
|
|
435
|
+
| ConnectorAuthPublicApiKey
|
|
436
|
+
| ConnectorAuthPublicNone;
|
|
435
437
|
|
|
436
438
|
/**
|
|
437
439
|
* MCP / connector create-edit config. Host extends for extra fields, etc.
|
|
@@ -457,6 +459,8 @@ export interface ConnectorBase<
|
|
|
457
459
|
description: string;
|
|
458
460
|
url: string;
|
|
459
461
|
auth: TAuth;
|
|
462
|
+
/** When true, UI should not show Disconnect. */
|
|
463
|
+
requiresAuth: boolean;
|
|
460
464
|
authenticated: boolean;
|
|
461
465
|
tools: TTool[];
|
|
462
466
|
}
|
|
@@ -500,7 +504,10 @@ export interface ConnectorCatalogServer<
|
|
|
500
504
|
createConnector(req: TCreate): Promise<TConnector>;
|
|
501
505
|
/** Full replace update keyed by connector `id`. */
|
|
502
506
|
updateConnector(req: TUpdate): Promise<TConnector>;
|
|
503
|
-
/**
|
|
507
|
+
/**
|
|
508
|
+
* Start connector auth (e.g. OAuth).
|
|
509
|
+
* For oauth, the returned connector's `auth.authUrl` is the authorize URL.
|
|
510
|
+
*/
|
|
504
511
|
authenticateConnector(req: { id: string }): Promise<TConnector>;
|
|
505
512
|
/** Clear connector auth. */
|
|
506
513
|
disconnectConnector(req: { id: string }): Promise<TConnector>;
|
package/src/streamTurn.test.ts
CHANGED
|
@@ -33,7 +33,7 @@ describe("streamTurn", () => {
|
|
|
33
33
|
describe("streamTurnContent", () => {
|
|
34
34
|
it("prepares a user turn and yields folded stream updates", async () => {
|
|
35
35
|
const foldState = new PeerThreadFoldState();
|
|
36
|
-
const
|
|
36
|
+
const createTurn = vi.fn(async function* () {
|
|
37
37
|
yield streamData(1, {
|
|
38
38
|
type: "model.message",
|
|
39
39
|
createdAt,
|
|
@@ -43,7 +43,7 @@ describe("streamTurn", () => {
|
|
|
43
43
|
});
|
|
44
44
|
});
|
|
45
45
|
const server = mockServer({
|
|
46
|
-
|
|
46
|
+
createTurn,
|
|
47
47
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -57,7 +57,7 @@ describe("streamTurn", () => {
|
|
|
57
57
|
),
|
|
58
58
|
);
|
|
59
59
|
|
|
60
|
-
expect(
|
|
60
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
61
61
|
sessionId: SESSION_ID,
|
|
62
62
|
input: [{ type: "user.message", content: "hello" }],
|
|
63
63
|
previousTurnId: "auto",
|
|
@@ -68,7 +68,7 @@ describe("streamTurn", () => {
|
|
|
68
68
|
]);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
it("passes required-action inputs through
|
|
71
|
+
it("passes required-action inputs through createTurn", async () => {
|
|
72
72
|
const inputs = [
|
|
73
73
|
{
|
|
74
74
|
type: "user.tool_approval" as const,
|
|
@@ -83,9 +83,9 @@ describe("streamTurn", () => {
|
|
|
83
83
|
content: "A",
|
|
84
84
|
},
|
|
85
85
|
];
|
|
86
|
-
const
|
|
86
|
+
const createTurn = vi.fn(async function* () {});
|
|
87
87
|
const server = mockServer({
|
|
88
|
-
|
|
88
|
+
createTurn,
|
|
89
89
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
90
90
|
});
|
|
91
91
|
|
|
@@ -99,7 +99,7 @@ describe("streamTurn", () => {
|
|
|
99
99
|
),
|
|
100
100
|
);
|
|
101
101
|
|
|
102
|
-
expect(
|
|
102
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
103
103
|
sessionId: SESSION_ID,
|
|
104
104
|
input: inputs,
|
|
105
105
|
previousTurnId: "auto",
|
|
@@ -108,9 +108,9 @@ describe("streamTurn", () => {
|
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
it("uses empty input when resuming after MCP auth", async () => {
|
|
111
|
-
const
|
|
111
|
+
const createTurn = vi.fn(async function* () {});
|
|
112
112
|
const server = mockServer({
|
|
113
|
-
|
|
113
|
+
createTurn,
|
|
114
114
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
115
115
|
});
|
|
116
116
|
|
|
@@ -124,7 +124,7 @@ describe("streamTurn", () => {
|
|
|
124
124
|
),
|
|
125
125
|
);
|
|
126
126
|
|
|
127
|
-
expect(
|
|
127
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
128
128
|
sessionId: SESSION_ID,
|
|
129
129
|
input: [],
|
|
130
130
|
previousTurnId: "auto",
|
|
@@ -133,9 +133,9 @@ describe("streamTurn", () => {
|
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
it("forwards an explicit previousTurnId when branching", async () => {
|
|
136
|
-
const
|
|
136
|
+
const createTurn = vi.fn(async function* () {});
|
|
137
137
|
const server = mockServer({
|
|
138
|
-
|
|
138
|
+
createTurn,
|
|
139
139
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
140
140
|
});
|
|
141
141
|
|
|
@@ -149,7 +149,7 @@ describe("streamTurn", () => {
|
|
|
149
149
|
),
|
|
150
150
|
);
|
|
151
151
|
|
|
152
|
-
expect(
|
|
152
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
153
153
|
sessionId: SESSION_ID,
|
|
154
154
|
input: [{ type: "user.message", content: "edited" }],
|
|
155
155
|
previousTurnId: "turn-a",
|
|
@@ -158,9 +158,9 @@ describe("streamTurn", () => {
|
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
it("forwards previousTurnId \"none\" when branching from root", async () => {
|
|
161
|
-
const
|
|
161
|
+
const createTurn = vi.fn(async function* () {});
|
|
162
162
|
const server = mockServer({
|
|
163
|
-
|
|
163
|
+
createTurn,
|
|
164
164
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
165
165
|
});
|
|
166
166
|
|
|
@@ -174,7 +174,7 @@ describe("streamTurn", () => {
|
|
|
174
174
|
),
|
|
175
175
|
);
|
|
176
176
|
|
|
177
|
-
expect(
|
|
177
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
178
178
|
sessionId: SESSION_ID,
|
|
179
179
|
input: [{ type: "user.message", content: "first" }],
|
|
180
180
|
previousTurnId: "none",
|
|
@@ -183,9 +183,9 @@ describe("streamTurn", () => {
|
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
it("returns early and cancels the session when already aborted", async () => {
|
|
186
|
-
const
|
|
186
|
+
const createTurn = vi.fn(async function* () {});
|
|
187
187
|
const cancelSession = vi.fn().mockResolvedValue(undefined);
|
|
188
|
-
const server = mockServer({
|
|
188
|
+
const server = mockServer({ createTurn, cancelSession });
|
|
189
189
|
const abortController = new AbortController();
|
|
190
190
|
abortController.abort();
|
|
191
191
|
|
|
@@ -200,14 +200,14 @@ describe("streamTurn", () => {
|
|
|
200
200
|
);
|
|
201
201
|
|
|
202
202
|
expect(cancelSession).toHaveBeenCalledWith({ sessionId: SESSION_ID });
|
|
203
|
-
expect(
|
|
203
|
+
expect(createTurn).not.toHaveBeenCalled();
|
|
204
204
|
expect(updates).toEqual([]);
|
|
205
205
|
});
|
|
206
206
|
|
|
207
|
-
it("forwards headers to
|
|
208
|
-
const
|
|
207
|
+
it("forwards headers to createTurn", async () => {
|
|
208
|
+
const createTurn = vi.fn(async function* () {});
|
|
209
209
|
const server = mockServer({
|
|
210
|
-
|
|
210
|
+
createTurn,
|
|
211
211
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
212
212
|
});
|
|
213
213
|
const abortSignal = new AbortController().signal;
|
|
@@ -227,7 +227,7 @@ describe("streamTurn", () => {
|
|
|
227
227
|
),
|
|
228
228
|
);
|
|
229
229
|
|
|
230
|
-
expect(
|
|
230
|
+
expect(createTurn).toHaveBeenCalledWith({
|
|
231
231
|
sessionId: SESSION_ID,
|
|
232
232
|
input: [{ type: "user.message", content: "hello" }],
|
|
233
233
|
previousTurnId: "auto",
|
|
@@ -240,7 +240,7 @@ describe("streamTurn", () => {
|
|
|
240
240
|
|
|
241
241
|
it("notifies gateway turn id when turn.done errors with no content yields", async () => {
|
|
242
242
|
const gatewayTurnId = "01ky6mqzmczwt6ssyd5r02gjjc";
|
|
243
|
-
const
|
|
243
|
+
const createTurn = vi.fn(async function* () {
|
|
244
244
|
yield streamData(1, {
|
|
245
245
|
type: "turn.created",
|
|
246
246
|
createdAt,
|
|
@@ -261,7 +261,7 @@ describe("streamTurn", () => {
|
|
|
261
261
|
});
|
|
262
262
|
});
|
|
263
263
|
const server = mockServer({
|
|
264
|
-
|
|
264
|
+
createTurn,
|
|
265
265
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
266
266
|
});
|
|
267
267
|
const onTurnIdAvailable = vi.fn();
|
|
@@ -285,7 +285,7 @@ describe("streamTurn", () => {
|
|
|
285
285
|
});
|
|
286
286
|
|
|
287
287
|
it("does not notify when an error stream never emits turn.created", async () => {
|
|
288
|
-
const
|
|
288
|
+
const createTurn = vi.fn(async function* () {
|
|
289
289
|
yield streamData(1, {
|
|
290
290
|
type: "turn.done",
|
|
291
291
|
createdAt,
|
|
@@ -298,7 +298,7 @@ describe("streamTurn", () => {
|
|
|
298
298
|
});
|
|
299
299
|
});
|
|
300
300
|
const server = mockServer({
|
|
301
|
-
|
|
301
|
+
createTurn,
|
|
302
302
|
cancelSession: vi.fn().mockResolvedValue(undefined),
|
|
303
303
|
});
|
|
304
304
|
const onTurnIdAvailable = vi.fn();
|
package/src/streamTurn.ts
CHANGED
|
@@ -18,7 +18,7 @@ export type StreamTurnOptions = {
|
|
|
18
18
|
resumeMcpAuth?: boolean;
|
|
19
19
|
inputs?: RequiredActionInput[];
|
|
20
20
|
/**
|
|
21
|
-
* Branch anchor for
|
|
21
|
+
* Branch anchor for createTurn. Omit for `"auto"`. Pass `"none"` for a fresh
|
|
22
22
|
* root turn.
|
|
23
23
|
*/
|
|
24
24
|
previousTurnId?: PreviousTurnIdInput;
|
|
@@ -79,7 +79,7 @@ export async function* streamTurnContent(
|
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
-
const stream: AsyncIterable<TurnStreamData> = server.
|
|
82
|
+
const stream: AsyncIterable<TurnStreamData> = server.createTurn({
|
|
83
83
|
sessionId,
|
|
84
84
|
input: buildTurnInput(options),
|
|
85
85
|
previousTurnId: options.previousTurnId ?? "auto",
|
|
@@ -63,7 +63,10 @@ export function createTrueFoundryOwnedSessionsThreadListAdapter(options: {
|
|
|
63
63
|
async rename() {},
|
|
64
64
|
async archive() {},
|
|
65
65
|
async unarchive() {},
|
|
66
|
-
async delete() {
|
|
66
|
+
async delete(remoteId) {
|
|
67
|
+
if (typeof server.deleteSession !== "function") return;
|
|
68
|
+
await server.deleteSession({ sessionId: remoteId });
|
|
69
|
+
},
|
|
67
70
|
|
|
68
71
|
async generateTitle() {
|
|
69
72
|
return new ReadableStream();
|
|
@@ -98,4 +98,26 @@ describe("createTrueFoundryThreadListAdapter", () => {
|
|
|
98
98
|
|
|
99
99
|
expect(result.nextCursor).toBeUndefined();
|
|
100
100
|
});
|
|
101
|
+
|
|
102
|
+
it("delete calls server.deleteSession when implemented", async () => {
|
|
103
|
+
const deleteSession = vi.fn().mockResolvedValue(undefined);
|
|
104
|
+
const server = mockServer({ deleteSession });
|
|
105
|
+
const adapter = createTrueFoundryThreadListAdapter({
|
|
106
|
+
server,
|
|
107
|
+
agentName: "my-agent",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await adapter.delete("s1");
|
|
111
|
+
|
|
112
|
+
expect(deleteSession).toHaveBeenCalledWith({ sessionId: "s1" });
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("delete is a no-op when server.deleteSession is missing", async () => {
|
|
116
|
+
const adapter = createTrueFoundryThreadListAdapter({
|
|
117
|
+
server: mockServer({}),
|
|
118
|
+
agentName: "my-agent",
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
await expect(adapter.delete("s1")).resolves.toBeUndefined();
|
|
122
|
+
});
|
|
101
123
|
});
|
|
@@ -50,7 +50,10 @@ export function createTrueFoundryThreadListAdapter(options: {
|
|
|
50
50
|
async rename() {},
|
|
51
51
|
async archive() {},
|
|
52
52
|
async unarchive() {},
|
|
53
|
-
async delete() {
|
|
53
|
+
async delete(remoteId) {
|
|
54
|
+
if (typeof server.deleteSession !== "function") return;
|
|
55
|
+
await server.deleteSession({ sessionId: remoteId });
|
|
56
|
+
},
|
|
54
57
|
|
|
55
58
|
async generateTitle() {
|
|
56
59
|
return new ReadableStream();
|
|
@@ -994,7 +994,7 @@ describe("useTrueFoundryAgentMessages", () => {
|
|
|
994
994
|
});
|
|
995
995
|
|
|
996
996
|
describe("batched resume invariant", () => {
|
|
997
|
-
it("issues exactly one
|
|
997
|
+
it("issues exactly one createTurn input batch across root and sub-agent threads", async () => {
|
|
998
998
|
vi.mocked(loadSessionSnapshot).mockResolvedValue(
|
|
999
999
|
snapshotWithAssistantMessage(assistantMessageWithMultiThreadPendingActions()),
|
|
1000
1000
|
);
|
package/dist/chunk-SQDOTGP2.js
DELETED
|
@@ -1,292 +0,0 @@
|
|
|
1
|
-
// src/plugins/truefoundry-agent-server-adapter/index.ts
|
|
2
|
-
import { AgentSessionClient } from "truefoundry-gateway-sdk/agents";
|
|
3
|
-
import { PrivateAgentSessionClient } from "truefoundry-gateway-sdk/agents/private";
|
|
4
|
-
|
|
5
|
-
// src/plugins/truefoundry-agent-server-adapter/guards.ts
|
|
6
|
-
function isRecord(value) {
|
|
7
|
-
return typeof value === "object" && value !== null;
|
|
8
|
-
}
|
|
9
|
-
function hasNumbers(value, keys) {
|
|
10
|
-
return isRecord(value) && keys.every((key) => typeof value[key] === "number");
|
|
11
|
-
}
|
|
12
|
-
function isTfySystemToolInfo(toolInfo) {
|
|
13
|
-
return isRecord(toolInfo) && toolInfo.type === "truefoundry-system" && typeof toolInfo.name === "string";
|
|
14
|
-
}
|
|
15
|
-
function isTfyMcpToolInfo(toolInfo) {
|
|
16
|
-
return isRecord(toolInfo) && toolInfo.type === "mcp" && typeof toolInfo.name === "string" && typeof toolInfo.serverId === "string" && typeof toolInfo.serverName === "string";
|
|
17
|
-
}
|
|
18
|
-
function isTfyToolInfo(toolInfo) {
|
|
19
|
-
return isTfySystemToolInfo(toolInfo) || isTfyMcpToolInfo(toolInfo);
|
|
20
|
-
}
|
|
21
|
-
var USAGE_BREAKDOWN_KEYS = [
|
|
22
|
-
"harness",
|
|
23
|
-
"skills",
|
|
24
|
-
"instructions",
|
|
25
|
-
"toolDefinitions",
|
|
26
|
-
"messages"
|
|
27
|
-
];
|
|
28
|
-
function getTfyUsage(source) {
|
|
29
|
-
const usage = source?.usage;
|
|
30
|
-
if (!hasNumbers(usage, ["inputTokens", "outputTokens"])) {
|
|
31
|
-
return void 0;
|
|
32
|
-
}
|
|
33
|
-
if (!hasNumbers(usage.inputTokensBreakdown, USAGE_BREAKDOWN_KEYS)) {
|
|
34
|
-
return void 0;
|
|
35
|
-
}
|
|
36
|
-
return usage;
|
|
37
|
-
}
|
|
38
|
-
function getTfyThreadState(event) {
|
|
39
|
-
const state = event?.state;
|
|
40
|
-
if (!isRecord(state)) {
|
|
41
|
-
return void 0;
|
|
42
|
-
}
|
|
43
|
-
if (state.status === "done" && isRecord(state.output)) {
|
|
44
|
-
return state;
|
|
45
|
-
}
|
|
46
|
-
if (state.status === "error" && typeof state.error === "string") {
|
|
47
|
-
return state;
|
|
48
|
-
}
|
|
49
|
-
return void 0;
|
|
50
|
-
}
|
|
51
|
-
function getTfyMcpInitServers(event) {
|
|
52
|
-
const servers = event?.mcpServers;
|
|
53
|
-
if (!Array.isArray(servers)) {
|
|
54
|
-
return void 0;
|
|
55
|
-
}
|
|
56
|
-
const valid = servers.every(
|
|
57
|
-
(server) => isRecord(server) && typeof server.id === "string" && typeof server.name === "string"
|
|
58
|
-
);
|
|
59
|
-
return valid ? servers : void 0;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// src/plugins/truefoundry-agent-server-adapter/index.ts
|
|
63
|
-
function isNotFound(error) {
|
|
64
|
-
return typeof error === "object" && error !== null && error.statusCode === 404;
|
|
65
|
-
}
|
|
66
|
-
function isDraft(session) {
|
|
67
|
-
return session.type === "session/draft";
|
|
68
|
-
}
|
|
69
|
-
function toSession(raw) {
|
|
70
|
-
const mutable = isDraft(raw);
|
|
71
|
-
return {
|
|
72
|
-
id: raw.id,
|
|
73
|
-
title: raw.title,
|
|
74
|
-
agentName: raw.agentName,
|
|
75
|
-
...mutable ? { agentSpec: raw.agentSpec } : {},
|
|
76
|
-
isMutable: mutable,
|
|
77
|
-
createdBySubject: raw.createdBySubject,
|
|
78
|
-
createdAt: raw.createdAt,
|
|
79
|
-
updatedAt: raw.updatedAt
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
function toTurn(raw) {
|
|
83
|
-
return {
|
|
84
|
-
id: raw.id,
|
|
85
|
-
sessionId: raw.sessionId,
|
|
86
|
-
previousTurnId: raw.previousTurnId,
|
|
87
|
-
input: raw.input,
|
|
88
|
-
state: raw.state,
|
|
89
|
-
createdBySubject: raw.createdBySubject,
|
|
90
|
-
createdAt: raw.createdAt
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
async function toListResult(page, map) {
|
|
94
|
-
const nextPageToken = page.response?.pagination?.nextPageToken;
|
|
95
|
-
return {
|
|
96
|
-
data: page.data.map(map),
|
|
97
|
-
...nextPageToken != null && nextPageToken !== "" ? { nextPageToken } : {}
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
function createTrueFoundryChatServer(opts) {
|
|
101
|
-
const gatewayOpts = { apiKey: opts.apiKey, baseUrl: opts.baseUrl };
|
|
102
|
-
const client = opts.client ?? new AgentSessionClient(gatewayOpts);
|
|
103
|
-
const privateClient = opts.privateClient ?? new PrivateAgentSessionClient(gatewayOpts);
|
|
104
|
-
const sessionTypeCache = /* @__PURE__ */ new Map();
|
|
105
|
-
const sessionTypeProbes = /* @__PURE__ */ new Map();
|
|
106
|
-
function cacheSessionType(session) {
|
|
107
|
-
sessionTypeCache.set(session.id, session.isMutable);
|
|
108
|
-
}
|
|
109
|
-
async function probeSessionType(sessionId) {
|
|
110
|
-
const inflight = sessionTypeProbes.get(sessionId);
|
|
111
|
-
if (inflight != null) {
|
|
112
|
-
return inflight;
|
|
113
|
-
}
|
|
114
|
-
const probe = (async () => {
|
|
115
|
-
try {
|
|
116
|
-
await privateClient.getDraftSession({ draftSessionId: sessionId });
|
|
117
|
-
return true;
|
|
118
|
-
} catch (error) {
|
|
119
|
-
if (!isNotFound(error)) {
|
|
120
|
-
throw error;
|
|
121
|
-
}
|
|
122
|
-
await client.getSession({ sessionId });
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
})();
|
|
126
|
-
sessionTypeProbes.set(sessionId, probe);
|
|
127
|
-
try {
|
|
128
|
-
const isMutable = await probe;
|
|
129
|
-
sessionTypeCache.set(sessionId, isMutable);
|
|
130
|
-
return isMutable;
|
|
131
|
-
} finally {
|
|
132
|
-
sessionTypeProbes.delete(sessionId);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
async function getSessionObj(sessionId) {
|
|
136
|
-
const isMutable = sessionTypeCache.get(sessionId) ?? await probeSessionType(sessionId);
|
|
137
|
-
return isMutable ? privateClient.getDraftSession({ draftSessionId: sessionId }) : client.getSession({ sessionId });
|
|
138
|
-
}
|
|
139
|
-
const server = {
|
|
140
|
-
async createSession(req) {
|
|
141
|
-
if (req.agentSpec != null) {
|
|
142
|
-
const draft = await privateClient.createDraftSession({
|
|
143
|
-
agentSpec: req.agentSpec,
|
|
144
|
-
...req.agentName != null ? { agentName: req.agentName } : {},
|
|
145
|
-
...req.tfyMetadata != null ? { tfyMetadata: req.tfyMetadata } : {}
|
|
146
|
-
});
|
|
147
|
-
const session = toSession(draft);
|
|
148
|
-
cacheSessionType(session);
|
|
149
|
-
return session;
|
|
150
|
-
}
|
|
151
|
-
if (req.agentName != null) {
|
|
152
|
-
const named = await client.createSession({
|
|
153
|
-
agentName: req.agentName,
|
|
154
|
-
...req.tfyMetadata != null ? { tfyMetadata: req.tfyMetadata } : {}
|
|
155
|
-
});
|
|
156
|
-
const session = toSession(named);
|
|
157
|
-
cacheSessionType(session);
|
|
158
|
-
return session;
|
|
159
|
-
}
|
|
160
|
-
throw new Error("createSession requires agentName and/or agentSpec");
|
|
161
|
-
},
|
|
162
|
-
async listSessions(req) {
|
|
163
|
-
const page = await privateClient.listOwnedSessions({
|
|
164
|
-
limit: req?.limit,
|
|
165
|
-
order: req?.order,
|
|
166
|
-
pageToken: req?.pageToken,
|
|
167
|
-
startTimestamp: req?.startTimestamp,
|
|
168
|
-
endTimestamp: req?.endTimestamp,
|
|
169
|
-
...req?.agentName != null ? { agentName: req.agentName } : {}
|
|
170
|
-
});
|
|
171
|
-
const result = await toListResult(page, (s) => toSession(s));
|
|
172
|
-
for (const session of result.data) {
|
|
173
|
-
cacheSessionType(session);
|
|
174
|
-
}
|
|
175
|
-
return result;
|
|
176
|
-
},
|
|
177
|
-
async getSession({ sessionId }) {
|
|
178
|
-
const raw = await getSessionObj(sessionId);
|
|
179
|
-
const session = toSession(raw);
|
|
180
|
-
cacheSessionType(session);
|
|
181
|
-
return session;
|
|
182
|
-
},
|
|
183
|
-
async updateSession(req) {
|
|
184
|
-
const raw = await getSessionObj(req.sessionId);
|
|
185
|
-
if (!isDraft(raw)) {
|
|
186
|
-
throw new Error(
|
|
187
|
-
"updateSession: session is not mutable (isMutable=false)"
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
if (req.agentSpec != null) {
|
|
191
|
-
await raw.update({ agentSpec: req.agentSpec });
|
|
192
|
-
}
|
|
193
|
-
return toSession(raw);
|
|
194
|
-
},
|
|
195
|
-
prepareAndExecuteTurn(req) {
|
|
196
|
-
return (async function* () {
|
|
197
|
-
const session = await getSessionObj(req.sessionId);
|
|
198
|
-
const prepared = session.prepareTurn({
|
|
199
|
-
input: req.input,
|
|
200
|
-
previousTurnId: req.previousTurnId ?? "auto"
|
|
201
|
-
});
|
|
202
|
-
yield* prepared.execute(
|
|
203
|
-
{ stream: true },
|
|
204
|
-
{
|
|
205
|
-
...req.abortSignal != null ? { abortSignal: req.abortSignal } : {},
|
|
206
|
-
...req.headers != null ? { headers: req.headers } : {}
|
|
207
|
-
}
|
|
208
|
-
);
|
|
209
|
-
})();
|
|
210
|
-
},
|
|
211
|
-
async cancelSession({ sessionId }) {
|
|
212
|
-
await (await getSessionObj(sessionId)).cancel();
|
|
213
|
-
},
|
|
214
|
-
async deleteSession({ sessionId }) {
|
|
215
|
-
if (opts.deleteSession == null) {
|
|
216
|
-
throw new Error(
|
|
217
|
-
"deleteSession is not on the gateway SDK. Pass deleteSession to createTrueFoundryChatServer."
|
|
218
|
-
);
|
|
219
|
-
}
|
|
220
|
-
await opts.deleteSession({ sessionId });
|
|
221
|
-
},
|
|
222
|
-
// The runtime's signature offers `order`, but the gateway's listTurns
|
|
223
|
-
// takes no such param — forwarding it silently did nothing.
|
|
224
|
-
async listTurns({ sessionId, limit, pageToken }) {
|
|
225
|
-
const raw = await getSessionObj(sessionId);
|
|
226
|
-
const page = await raw.listTurns({
|
|
227
|
-
...limit != null ? { limit } : {},
|
|
228
|
-
...pageToken != null ? { pageToken } : {}
|
|
229
|
-
});
|
|
230
|
-
return toListResult(page, (turn) => toTurn(turn));
|
|
231
|
-
},
|
|
232
|
-
async getTurn({ sessionId, turnId }) {
|
|
233
|
-
const raw = await getSessionObj(sessionId);
|
|
234
|
-
return toTurn(await raw.getTurn({ turnId }));
|
|
235
|
-
},
|
|
236
|
-
async listEvents({ sessionId, pageToken, lastTurnId, limit }) {
|
|
237
|
-
const raw = await getSessionObj(sessionId);
|
|
238
|
-
const page = await raw.listEvents({
|
|
239
|
-
...limit != null ? { limit } : {},
|
|
240
|
-
...pageToken != null ? { pageToken } : {},
|
|
241
|
-
...lastTurnId != null ? { lastTurnId } : {}
|
|
242
|
-
});
|
|
243
|
-
return toListResult(
|
|
244
|
-
page,
|
|
245
|
-
(item) => item
|
|
246
|
-
);
|
|
247
|
-
},
|
|
248
|
-
async listTurnEvents({ sessionId, turnId, limit, pageToken, order }) {
|
|
249
|
-
const raw = await getSessionObj(sessionId);
|
|
250
|
-
const turn = await raw.getTurn({ turnId });
|
|
251
|
-
const page = await turn.listEvents({
|
|
252
|
-
...limit != null ? { limit } : {},
|
|
253
|
-
...pageToken != null ? { pageToken } : {},
|
|
254
|
-
...order != null ? { order } : {}
|
|
255
|
-
});
|
|
256
|
-
return toListResult(page, (event) => event);
|
|
257
|
-
},
|
|
258
|
-
async *subscribeToTurn({
|
|
259
|
-
sessionId,
|
|
260
|
-
turnId,
|
|
261
|
-
afterSequenceNumber,
|
|
262
|
-
abortSignal
|
|
263
|
-
}) {
|
|
264
|
-
const raw = await getSessionObj(sessionId);
|
|
265
|
-
const turn = await raw.getTurn({ turnId });
|
|
266
|
-
yield* turn.stream(
|
|
267
|
-
afterSequenceNumber != null ? { afterSequenceNumber } : {},
|
|
268
|
-
abortSignal != null ? { abortSignal } : {}
|
|
269
|
-
);
|
|
270
|
-
},
|
|
271
|
-
async downloadSandboxFile(sandboxId, req) {
|
|
272
|
-
const response = await privateClient.downloadSandboxFile(
|
|
273
|
-
sandboxId,
|
|
274
|
-
req
|
|
275
|
-
);
|
|
276
|
-
return await response.blob();
|
|
277
|
-
},
|
|
278
|
-
getGatewayClients: () => ({ client, privateClient })
|
|
279
|
-
};
|
|
280
|
-
return server;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
export {
|
|
284
|
-
isTfySystemToolInfo,
|
|
285
|
-
isTfyMcpToolInfo,
|
|
286
|
-
isTfyToolInfo,
|
|
287
|
-
getTfyUsage,
|
|
288
|
-
getTfyThreadState,
|
|
289
|
-
getTfyMcpInitServers,
|
|
290
|
-
createTrueFoundryChatServer
|
|
291
|
-
};
|
|
292
|
-
//# sourceMappingURL=chunk-SQDOTGP2.js.map
|