@truefoundry/assistant-ui-runtime 0.1.5 → 0.1.6

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.
Files changed (70) hide show
  1. package/README.md +198 -401
  2. package/dist/chunk-3A2EPLQG.js +93 -0
  3. package/dist/chunk-3A2EPLQG.js.map +1 -0
  4. package/dist/chunk-Q2SHKMLM.js +270 -0
  5. package/dist/chunk-Q2SHKMLM.js.map +1 -0
  6. package/dist/index.d.ts +24 -29
  7. package/dist/index.js +264 -237
  8. package/dist/index.js.map +1 -1
  9. package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +162 -0
  10. package/dist/plugins/truefoundry-agent-server-adapter/index.js +19 -0
  11. package/dist/plugins/truefoundry-agent-server-adapter/index.js.map +1 -0
  12. package/dist/server/index.d.ts +17 -0
  13. package/dist/server/index.js +9 -0
  14. package/dist/server/index.js.map +1 -0
  15. package/dist/types-BfiFf8O1.d.ts +468 -0
  16. package/package.json +19 -6
  17. package/src/askUserQuestion.ts +3 -3
  18. package/src/buildEditedUserMessageContent.test.ts +2 -2
  19. package/src/collectPending.ts +1 -1
  20. package/src/convertTurnMessages.test.ts +141 -196
  21. package/src/convertTurnMessages.ts +130 -76
  22. package/src/createSubAgent.ts +1 -1
  23. package/src/draftAgentConfig.test.ts +26 -29
  24. package/src/extractTurnUserText.ts +1 -1
  25. package/src/foldPeerThreads.test.ts +1 -1
  26. package/src/foldPeerThreads.ts +3 -2
  27. package/src/index.ts +80 -4
  28. package/src/listPages.ts +21 -0
  29. package/src/loadSessionSnapshot.test.ts +9 -8
  30. package/src/loadSessionSnapshot.ts +9 -14
  31. package/src/mcpAuth.ts +6 -3
  32. package/src/messageCustomMetadata.ts +1 -1
  33. package/src/modelMessageContent.ts +1 -1
  34. package/src/modelMessageImageContent.test.ts +1 -1
  35. package/src/modelMessageImageContent.ts +7 -6
  36. package/src/plugins/truefoundry-agent-server-adapter/README.md +178 -0
  37. package/src/plugins/truefoundry-agent-server-adapter/guards.test.ts +113 -0
  38. package/src/plugins/truefoundry-agent-server-adapter/guards.ts +130 -0
  39. package/src/plugins/truefoundry-agent-server-adapter/index.ts +359 -0
  40. package/src/plugins/truefoundry-agent-server-adapter/types.ts +135 -0
  41. package/src/plugins/truefoundry-agent-server-adapter/types.typecheck.ts +164 -0
  42. package/src/private/agentSpec.ts +8 -3
  43. package/src/private/draftSessionBridge.ts +14 -13
  44. package/src/private/truefoundryDraftThreadListAdapter.test.ts +44 -49
  45. package/src/private/truefoundryDraftThreadListAdapter.ts +22 -16
  46. package/src/requiredActionInputs.ts +1 -1
  47. package/src/requiredActionsFromActiveUpdate.test.ts +1 -1
  48. package/src/server/eventUtils.ts +120 -0
  49. package/src/server/events.ts +246 -0
  50. package/src/server/index.ts +66 -0
  51. package/src/server/types.ts +319 -0
  52. package/src/sessionSnapshot.ts +1 -1
  53. package/src/sessions.ts +5 -21
  54. package/src/streamTurn.test.ts +172 -155
  55. package/src/streamTurn.ts +51 -48
  56. package/src/toolApproval.ts +4 -4
  57. package/src/toolResponse.ts +4 -4
  58. package/src/truefoundryExtras.ts +1 -1
  59. package/src/truefoundryOwnedSessionsThreadListAdapter.test.ts +26 -29
  60. package/src/truefoundryOwnedSessionsThreadListAdapter.ts +18 -23
  61. package/src/truefoundryThreadListAdapter.test.ts +16 -18
  62. package/src/truefoundryThreadListAdapter.ts +7 -7
  63. package/src/turnEventHelpers.ts +1 -1
  64. package/src/types.ts +2 -16
  65. package/src/useTrueFoundryAgentMessages.test.tsx +38 -70
  66. package/src/useTrueFoundryAgentMessages.ts +32 -44
  67. package/src/useTrueFoundryAgentRuntime.ts +11 -28
  68. package/src/private/bindDraftAgentSession.test.ts +0 -54
  69. package/src/private/bindDraftAgentSession.ts +0 -28
  70. package/src/private/getGatewayFromPrivateClient.ts +0 -13
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Point-of-use narrowing for the event half of the gateway protocol.
3
+ *
4
+ * `AgentChatServer` hardcodes the runtime's event types on listEvents,
5
+ * listTurnEvents, subscribeToTurn and prepareAndExecuteTurn — there is no
6
+ * generic to override them from here. So instead of typing those channels,
7
+ * hosts call these guards on the values they receive.
8
+ *
9
+ * They validate rather than cast: this data comes off the network, and the
10
+ * runtime types the relevant fields as `unknown` precisely because nothing
11
+ * has checked them yet.
12
+ */
13
+
14
+ import type {
15
+ TfyMcpServerInitInfo,
16
+ TfyMcpToolInfo,
17
+ TfyModelMessageUsage,
18
+ TfySystemToolInfo,
19
+ TfyThreadState,
20
+ TfyToolInfo,
21
+ } from "./types.js";
22
+
23
+ function isRecord(value: unknown): value is Record<string, unknown> {
24
+ return typeof value === "object" && value !== null;
25
+ }
26
+
27
+ function hasNumbers<K extends string>(
28
+ value: unknown,
29
+ keys: readonly K[],
30
+ ): value is Record<string, unknown> & Record<K, number> {
31
+ return isRecord(value) && keys.every((key) => typeof value[key] === "number");
32
+ }
33
+
34
+ /**
35
+ * Identifies built-in tools such as `ask_user_question` and `create_sub_agent`.
36
+ * Note `toolInfo` is legitimately absent on streamed deltas, so callers must
37
+ * keep their `function.name` fallback rather than treating absence as an error.
38
+ */
39
+ export function isTfySystemToolInfo(
40
+ toolInfo: unknown,
41
+ ): toolInfo is TfySystemToolInfo {
42
+ return (
43
+ isRecord(toolInfo) &&
44
+ toolInfo.type === "truefoundry-system" &&
45
+ typeof toolInfo.name === "string"
46
+ );
47
+ }
48
+
49
+ /** Carries `serverId` / `serverName`, so the UI can attribute a call to its MCP server. */
50
+ export function isTfyMcpToolInfo(toolInfo: unknown): toolInfo is TfyMcpToolInfo {
51
+ return (
52
+ isRecord(toolInfo) &&
53
+ toolInfo.type === "mcp" &&
54
+ typeof toolInfo.name === "string" &&
55
+ typeof toolInfo.serverId === "string" &&
56
+ typeof toolInfo.serverName === "string"
57
+ );
58
+ }
59
+
60
+ export function isTfyToolInfo(toolInfo: unknown): toolInfo is TfyToolInfo {
61
+ return isTfySystemToolInfo(toolInfo) || isTfyMcpToolInfo(toolInfo);
62
+ }
63
+
64
+ const USAGE_BREAKDOWN_KEYS = [
65
+ "harness",
66
+ "skills",
67
+ "instructions",
68
+ "toolDefinitions",
69
+ "messages",
70
+ ] as const;
71
+
72
+ /**
73
+ * Token usage including the TrueFoundry-specific `inputTokensBreakdown`, which
74
+ * attributes input tokens across harness, skills, instructions, tool
75
+ * definitions and messages.
76
+ */
77
+ export function getTfyUsage(
78
+ source: { usage?: unknown } | null | undefined,
79
+ ): TfyModelMessageUsage | undefined {
80
+ const usage = source?.usage;
81
+ if (!hasNumbers(usage, ["inputTokens", "outputTokens"])) {
82
+ return undefined;
83
+ }
84
+ if (!hasNumbers(usage.inputTokensBreakdown, USAGE_BREAKDOWN_KEYS)) {
85
+ return undefined;
86
+ }
87
+ return usage as unknown as TfyModelMessageUsage;
88
+ }
89
+
90
+ /**
91
+ * Completion state of a sub-agent thread. The runtime types `thread.done`'s
92
+ * `state` as `unknown`, so a sub-agent that errored is otherwise
93
+ * indistinguishable from one that succeeded.
94
+ */
95
+ export function getTfyThreadState(
96
+ event: { state?: unknown } | null | undefined,
97
+ ): TfyThreadState | undefined {
98
+ const state = event?.state;
99
+ if (!isRecord(state)) {
100
+ return undefined;
101
+ }
102
+ if (state.status === "done" && isRecord(state.output)) {
103
+ return state as unknown as TfyThreadState;
104
+ }
105
+ if (state.status === "error" && typeof state.error === "string") {
106
+ return state as unknown as TfyThreadState;
107
+ }
108
+ return undefined;
109
+ }
110
+
111
+ /**
112
+ * Servers from an `mcp.initialize` event, including each one's `transportType`.
113
+ * The runtime models this event with an index signature, so the array is
114
+ * `unknown` until checked.
115
+ */
116
+ export function getTfyMcpInitServers(
117
+ event: { mcpServers?: unknown } | null | undefined,
118
+ ): TfyMcpServerInitInfo[] | undefined {
119
+ const servers = event?.mcpServers;
120
+ if (!Array.isArray(servers)) {
121
+ return undefined;
122
+ }
123
+ const valid = servers.every(
124
+ (server) =>
125
+ isRecord(server) &&
126
+ typeof server.id === "string" &&
127
+ typeof server.name === "string",
128
+ );
129
+ return valid ? (servers as TfyMcpServerInitInfo[]) : undefined;
130
+ }
@@ -0,0 +1,359 @@
1
+ import { AgentSessionClient } from "truefoundry-gateway-sdk/agents";
2
+ import type { AgentSession } from "truefoundry-gateway-sdk/agents";
3
+ import { PrivateAgentSessionClient } from "truefoundry-gateway-sdk/agents/private";
4
+ import type { AgentDraftSession } from "truefoundry-gateway-sdk/agents/private";
5
+ import type {
6
+ AgentChatServer,
7
+ ListResult,
8
+ TurnInputItem,
9
+ PreviousTurnIdInput,
10
+ UpdateSessionRequest,
11
+ } from "../../server/types.js";
12
+ import type {
13
+ SessionEventItem,
14
+ TurnEvent,
15
+ TurnStreamData,
16
+ } from "../../server/events.js";
17
+ import type {
18
+ TfyAgentSpec,
19
+ TfyCreateSessionRequest,
20
+ TfyListSessionsParams,
21
+ TfySession,
22
+ TfyTurn,
23
+ TfyTurnState,
24
+ } from "./types.js";
25
+
26
+ export {
27
+ type TfyAgentSpec,
28
+ type TfySkillMount,
29
+ type TfyMcpServerMount,
30
+ type TfyModelParams,
31
+ type TfyRuntimeConfig,
32
+ type TfyResponseFormat,
33
+ type TfySubject,
34
+ type ToolsSelectorItem,
35
+ type ToolsSelectorTag,
36
+ type RequireApprovalToolSelectorItem,
37
+ type RequireApprovalToolsSelectorTag,
38
+ type TfyTurn,
39
+ type TfyTurnState,
40
+ type TfyTurnCancelledReason,
41
+ type TfyTurnStateDoneOutput,
42
+ type TfySession,
43
+ type TfyCreateSessionRequest,
44
+ type TfyListSessionsParams,
45
+ type TfyToolInfo,
46
+ type TfySystemToolInfo,
47
+ type TfyMcpToolInfo,
48
+ type TfyModelMessageUsage,
49
+ type TfyFinishReason,
50
+ type TfyThreadState,
51
+ type TfyMcpServerInitInfo,
52
+ } from "./types.js";
53
+
54
+ export {
55
+ isTfyToolInfo,
56
+ isTfySystemToolInfo,
57
+ isTfyMcpToolInfo,
58
+ getTfyUsage,
59
+ getTfyThreadState,
60
+ getTfyMcpInitServers,
61
+ } from "./guards.js";
62
+
63
+ type GwSession = AgentSession | AgentDraftSession;
64
+
65
+ export type CreateTrueFoundryChatServerOptions = {
66
+ apiKey: string;
67
+ baseUrl: string;
68
+ /** Optional override — otherwise constructed from apiKey/baseUrl. */
69
+ client?: AgentSessionClient;
70
+ privateClient?: PrivateAgentSessionClient;
71
+ deleteSession?: (req: { sessionId: string }) => Promise<void>;
72
+ };
73
+
74
+ /**
75
+ * Only the spec is generic. Session/Turn/list-params are the concrete Tfy*
76
+ * types because the adapter builds them as fixed object literals — a generic
77
+ * there would type fields that nothing ever populates. The spec is safe: the
78
+ * gateway SDK serializes with `unrecognizedObjectKeys: "passthrough"`, so
79
+ * host-added spec fields survive the round trip.
80
+ */
81
+ export type TrueFoundryChatServer<TSpec extends TfyAgentSpec = TfyAgentSpec> =
82
+ AgentChatServer<
83
+ TSpec,
84
+ TfySession<TSpec>,
85
+ TfyCreateSessionRequest<TSpec>,
86
+ TfyListSessionsParams,
87
+ UpdateSessionRequest<TSpec>,
88
+ TfyTurn
89
+ > & {
90
+ /** Escape hatch for hosts that still need raw gateway clients. */
91
+ getGatewayClients(): {
92
+ client: AgentSessionClient;
93
+ privateClient: PrivateAgentSessionClient;
94
+ };
95
+ };
96
+
97
+ function isDraft(session: GwSession): session is AgentDraftSession {
98
+ return (session as AgentDraftSession).type === "session/draft";
99
+ }
100
+
101
+ function toSession<TSpec extends TfyAgentSpec>(raw: GwSession): TfySession<TSpec> {
102
+ const mutable = isDraft(raw);
103
+ return {
104
+ id: raw.id,
105
+ title: raw.title,
106
+ agentName: raw.agentName,
107
+ ...(mutable ? { agentSpec: raw.agentSpec as TSpec } : {}),
108
+ isMutable: mutable,
109
+ createdBySubject: raw.createdBySubject,
110
+ createdAt: raw.createdAt,
111
+ updatedAt: raw.updatedAt,
112
+ };
113
+ }
114
+
115
+ function toTurn(raw: {
116
+ id: string;
117
+ sessionId: string;
118
+ previousTurnId?: string | null;
119
+ input?: TurnInputItem[];
120
+ state: unknown;
121
+ createdBySubject: TfyTurn["createdBySubject"];
122
+ createdAt: string;
123
+ }): TfyTurn {
124
+ return {
125
+ id: raw.id,
126
+ sessionId: raw.sessionId,
127
+ previousTurnId: raw.previousTurnId,
128
+ input: raw.input,
129
+ state: raw.state as TfyTurnState,
130
+ createdBySubject: raw.createdBySubject,
131
+ createdAt: raw.createdAt,
132
+ };
133
+ }
134
+
135
+ async function toListResult<TIn, TOut>(
136
+ page: {
137
+ data: TIn[];
138
+ response?: { pagination?: { nextPageToken?: string } };
139
+ hasNextPage?: () => boolean;
140
+ },
141
+ map: (item: TIn) => TOut,
142
+ ): Promise<ListResult<TOut>> {
143
+ const nextPageToken = page.response?.pagination?.nextPageToken;
144
+ return {
145
+ data: page.data.map(map),
146
+ ...(nextPageToken != null && nextPageToken !== ""
147
+ ? { nextPageToken }
148
+ : {}),
149
+ };
150
+ }
151
+
152
+ /**
153
+ * Wraps TrueFoundry gateway clients into a flat `AgentChatServer`.
154
+ * Named vs draft routing is fully internal — an in-memory session-type cache
155
+ * (populated by createSession/listSessions) determines which gateway client
156
+ * to call. No try/catch fallback, no double network calls.
157
+ */
158
+ export function createTrueFoundryChatServer<
159
+ TSpec extends TfyAgentSpec = TfyAgentSpec,
160
+ >(
161
+ opts: CreateTrueFoundryChatServerOptions,
162
+ ): TrueFoundryChatServer<TSpec> {
163
+ const gatewayOpts = { apiKey: opts.apiKey, baseUrl: opts.baseUrl };
164
+ const client = opts.client ?? new AgentSessionClient(gatewayOpts);
165
+ const privateClient =
166
+ opts.privateClient ?? new PrivateAgentSessionClient(gatewayOpts);
167
+
168
+ const sessionTypeCache = new Map<string, boolean>();
169
+
170
+ function cacheSessionType(session: {
171
+ id: string;
172
+ isMutable: boolean;
173
+ }): void {
174
+ sessionTypeCache.set(session.id, session.isMutable);
175
+ }
176
+
177
+ function getSessionObj(sessionId: string): Promise<GwSession> {
178
+ const isMutable = sessionTypeCache.get(sessionId);
179
+ if (isMutable === true) {
180
+ return privateClient.getDraftSession({ draftSessionId: sessionId });
181
+ }
182
+ if (isMutable === false) {
183
+ return client.getSession({ sessionId });
184
+ }
185
+ throw new Error(
186
+ `Cannot resolve session "${sessionId}": session type not cached. ` +
187
+ `Ensure createSession or listSessions was called first.`,
188
+ );
189
+ }
190
+
191
+ const server: TrueFoundryChatServer<TSpec> = {
192
+ async createSession(req) {
193
+ if (req.agentSpec != null) {
194
+ const draft = await privateClient.createDraftSession({
195
+ agentSpec: req.agentSpec,
196
+ ...(req.agentName != null ? { agentName: req.agentName } : {}),
197
+ ...(req.tfyMetadata != null
198
+ ? { tfyMetadata: req.tfyMetadata }
199
+ : {}),
200
+ });
201
+ const session = toSession<TSpec>(draft);
202
+ cacheSessionType(session);
203
+ return session;
204
+ }
205
+ if (req.agentName != null) {
206
+ const named = await client.createSession({
207
+ agentName: req.agentName,
208
+ ...(req.tfyMetadata != null
209
+ ? { tfyMetadata: req.tfyMetadata }
210
+ : {}),
211
+ });
212
+ const session = toSession<TSpec>(named);
213
+ cacheSessionType(session);
214
+ return session;
215
+ }
216
+ throw new Error("createSession requires agentName and/or agentSpec");
217
+ },
218
+
219
+ async listSessions(req) {
220
+ const page = await privateClient.listOwnedSessions({
221
+ limit: req?.limit,
222
+ order: req?.order,
223
+ pageToken: req?.pageToken,
224
+ startTimestamp: req?.startTimestamp,
225
+ endTimestamp: req?.endTimestamp,
226
+ ...(req?.agentName != null ? { agentName: req.agentName } : {}),
227
+ });
228
+ const result = await toListResult(page, (s) => toSession<TSpec>(s));
229
+ for (const session of result.data) {
230
+ cacheSessionType(session);
231
+ }
232
+ return result;
233
+ },
234
+
235
+ async getSession({ sessionId }) {
236
+ const raw = await getSessionObj(sessionId);
237
+ const session = toSession<TSpec>(raw);
238
+ cacheSessionType(session);
239
+ return session;
240
+ },
241
+
242
+ async updateSession(req) {
243
+ const raw = await getSessionObj(req.sessionId);
244
+ if (!isDraft(raw)) {
245
+ throw new Error(
246
+ "updateSession: session is not mutable (isMutable=false)",
247
+ );
248
+ }
249
+ if (req.agentSpec != null) {
250
+ await raw.update({ agentSpec: req.agentSpec });
251
+ }
252
+ return toSession<TSpec>(raw);
253
+ },
254
+
255
+ prepareAndExecuteTurn(req: {
256
+ sessionId: string;
257
+ input?: TurnInputItem[];
258
+ previousTurnId?: PreviousTurnIdInput;
259
+ abortSignal?: AbortSignal;
260
+ headers?: Record<string, string>;
261
+ }): AsyncIterable<TurnStreamData> {
262
+ return (async function* () {
263
+ const session = await getSessionObj(req.sessionId);
264
+ const prepared = session.prepareTurn({
265
+ input: req.input,
266
+ previousTurnId: req.previousTurnId ?? "auto",
267
+ });
268
+ yield* prepared.execute(
269
+ { stream: true },
270
+ {
271
+ ...(req.abortSignal != null
272
+ ? { abortSignal: req.abortSignal }
273
+ : {}),
274
+ ...(req.headers != null ? { headers: req.headers } : {}),
275
+ },
276
+ ) as AsyncIterable<TurnStreamData>;
277
+ })();
278
+ },
279
+
280
+ async cancelSession({ sessionId }) {
281
+ await (await getSessionObj(sessionId)).cancel();
282
+ },
283
+
284
+ async deleteSession({ sessionId }) {
285
+ if (opts.deleteSession == null) {
286
+ throw new Error(
287
+ "deleteSession is not on the gateway SDK. Pass deleteSession to createTrueFoundryChatServer.",
288
+ );
289
+ }
290
+ await opts.deleteSession({ sessionId });
291
+ },
292
+
293
+ // The runtime's signature offers `order`, but the gateway's listTurns
294
+ // takes no such param — forwarding it silently did nothing.
295
+ async listTurns({ sessionId, limit, pageToken }) {
296
+ const raw = await getSessionObj(sessionId);
297
+ const page = await raw.listTurns({
298
+ ...(limit != null ? { limit } : {}),
299
+ ...(pageToken != null ? { pageToken } : {}),
300
+ });
301
+ return toListResult(page, (turn) => toTurn(turn));
302
+ },
303
+
304
+ async getTurn({ sessionId, turnId }) {
305
+ const raw = await getSessionObj(sessionId);
306
+ return toTurn(await raw.getTurn({ turnId }));
307
+ },
308
+
309
+ async listEvents({ sessionId, pageToken, lastTurnId, limit }) {
310
+ const raw = await getSessionObj(sessionId);
311
+ const page = await raw.listEvents({
312
+ ...(limit != null ? { limit } : {}),
313
+ ...(pageToken != null ? { pageToken } : {}),
314
+ ...(lastTurnId != null ? { lastTurnId } : {}),
315
+ });
316
+ return toListResult(
317
+ page,
318
+ (item) => item as SessionEventItem,
319
+ );
320
+ },
321
+
322
+ async listTurnEvents({ sessionId, turnId, limit, pageToken, order }) {
323
+ const raw = await getSessionObj(sessionId);
324
+ const turn = await raw.getTurn({ turnId });
325
+ const page = await turn.listEvents({
326
+ ...(limit != null ? { limit } : {}),
327
+ ...(pageToken != null ? { pageToken } : {}),
328
+ ...(order != null ? { order } : {}),
329
+ });
330
+ return toListResult(page, (event) => event as TurnEvent);
331
+ },
332
+
333
+ async *subscribeToTurn({
334
+ sessionId,
335
+ turnId,
336
+ afterSequenceNumber,
337
+ abortSignal,
338
+ }) {
339
+ const raw = await getSessionObj(sessionId);
340
+ const turn = await raw.getTurn({ turnId });
341
+ yield* turn.stream(
342
+ afterSequenceNumber != null ? { afterSequenceNumber } : {},
343
+ abortSignal != null ? { abortSignal } : {},
344
+ ) as AsyncIterable<TurnStreamData>;
345
+ },
346
+
347
+ async downloadSandboxFile(sandboxId, req) {
348
+ const response = await privateClient.downloadSandboxFile(
349
+ sandboxId,
350
+ req,
351
+ );
352
+ return await response.blob();
353
+ },
354
+
355
+ getGatewayClients: () => ({ client, privateClient }),
356
+ };
357
+
358
+ return server;
359
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * TrueFoundry-specific type extensions over the runtime's generic bases.
3
+ *
4
+ * The runtime defines minimal bases (SkillMount = {id,name}, McpServerMount =
5
+ * {id,name}, AgentSpec.config = unknown, etc.) that hosts extend via generics.
6
+ *
7
+ * This file builds the concrete TrueFoundry types by:
8
+ * - Importing the runtime's AgentSpec as the base to extend.
9
+ * - Importing concrete sub-types from the gateway SDK namespace rather than
10
+ * re-defining them — they're purely gateway concepts.
11
+ * - Composing a TfyAgentSpec that satisfies both the runtime's
12
+ * `TSpec extends AgentSpec` constraint and the gateway SDK's AgentSpec shape.
13
+ */
14
+
15
+ import type {
16
+ AgentSpec,
17
+ CreateSessionRequest,
18
+ ListSessionsParams,
19
+ Session,
20
+ Turn,
21
+ TurnState,
22
+ } from "../../server/types.js";
23
+ import type { TruefoundryGatewayApi } from "truefoundry-gateway-sdk";
24
+
25
+ // ---------------------------------------------------------------------------
26
+ // Re-exports — gateway sub-types surfaced for host convenience
27
+ // ---------------------------------------------------------------------------
28
+
29
+ export type TfyRuntimeConfig = TruefoundryGatewayApi.RuntimeConfig;
30
+ export type TfyResponseFormat = TruefoundryGatewayApi.ResponseFormat;
31
+ export type TfyModelParams = TruefoundryGatewayApi.ModelParams;
32
+ export type TfySubject = TruefoundryGatewayApi.Subject;
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // Tool selector helpers (mirrors gateway SDK enum values)
36
+ // ---------------------------------------------------------------------------
37
+
38
+ export type ToolsSelectorTag = "@all" | "@read-only";
39
+ export type RequireApprovalToolsSelectorTag = "@all" | "@write" | "@destructive";
40
+ export type ToolsSelectorItem = ToolsSelectorTag | string;
41
+ export type RequireApprovalToolSelectorItem = RequireApprovalToolsSelectorTag | string;
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Runtime mount bases — derived from AgentSpec, which the runtime does export
45
+ // (SkillMount / McpServerMount themselves are not part of its public API).
46
+ // ---------------------------------------------------------------------------
47
+
48
+ type RuntimeSkillMount = NonNullable<NonNullable<AgentSpec["skills"]>[number]>;
49
+ type RuntimeMcpServerMount = NonNullable<NonNullable<AgentSpec["mcpServers"]>[number]>;
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Mounts — runtime base + gateway fields (fqn, type, url, tool selectors)
53
+ // ---------------------------------------------------------------------------
54
+
55
+ // Both gateway types are unions (git vs registry source, inline vs registry
56
+ // server), so these must be intersections — an interface cannot `extends` a
57
+ // union, and doing so silently degrades to the runtime base under skipLibCheck.
58
+ export type TfySkillMount = RuntimeSkillMount & TruefoundryGatewayApi.SkillMount;
59
+
60
+ export type TfyMcpServerMount = RuntimeMcpServerMount & TruefoundryGatewayApi.McpServer;
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // AgentSpec — the concrete TrueFoundry agent definition
64
+ // ---------------------------------------------------------------------------
65
+
66
+ export interface TfyAgentSpec extends AgentSpec {
67
+ model: TruefoundryGatewayApi.Model;
68
+ skills?: TfySkillMount[];
69
+ mcpServers?: TfyMcpServerMount[];
70
+ config?: TruefoundryGatewayApi.RuntimeConfig;
71
+ responseFormat?: TruefoundryGatewayApi.ResponseFormat;
72
+ messages?: TruefoundryGatewayApi.AgentSpecUserMessage[];
73
+ }
74
+
75
+ // ---------------------------------------------------------------------------
76
+ // Turn — runtime base narrowed to the gateway's concrete state shapes
77
+ // ---------------------------------------------------------------------------
78
+
79
+ export type TfyTurnCancelledReason = TruefoundryGatewayApi.TurnStateCancelledReason;
80
+ export type TfyTurnStateDoneOutput = TruefoundryGatewayApi.TurnStateDoneOutput;
81
+
82
+ type RuntimeTurnStateDone = Extract<TurnState, { status: "done" }>;
83
+ type RuntimeTurnStateCancelled = Extract<TurnState, { status: "cancelled" }>;
84
+
85
+ /**
86
+ * The runtime types `output` as `unknown` and `reason` as bare `string`. The
87
+ * gateway sends a model message and one of four reasons — `cancelled-for-next-turn`
88
+ * in particular is routine and should not render like a failure.
89
+ */
90
+ export type TfyTurnState =
91
+ | Exclude<TurnState, { status: "done" | "cancelled" }>
92
+ | (Omit<RuntimeTurnStateDone, "output"> & { output?: TfyTurnStateDoneOutput })
93
+ | (Omit<RuntimeTurnStateCancelled, "reason"> & { reason: TfyTurnCancelledReason });
94
+
95
+ export interface TfyTurn extends Turn {
96
+ state: TfyTurnState;
97
+ createdBySubject: TfySubject;
98
+ }
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // Session and request params — runtime bases + gateway-only fields
102
+ // ---------------------------------------------------------------------------
103
+
104
+ export interface TfySession<TSpec extends TfyAgentSpec = TfyAgentSpec>
105
+ extends Session<TSpec> {
106
+ createdBySubject: TfySubject;
107
+ }
108
+
109
+ export interface TfyCreateSessionRequest<TSpec extends TfyAgentSpec = TfyAgentSpec>
110
+ extends CreateSessionRequest<TSpec> {
111
+ /** Sent as `x-tfy-metadata`, persisted server-side as `request_metadata`. */
112
+ tfyMetadata?: string;
113
+ }
114
+
115
+ export interface TfyListSessionsParams extends ListSessionsParams {
116
+ /** Inclusive upper bound on `createdAt` (ISO-8601). */
117
+ endTimestamp?: string;
118
+ }
119
+
120
+ // ---------------------------------------------------------------------------
121
+ // Event-side types.
122
+ //
123
+ // These do NOT flow through AgentChatServer — its listEvents / listTurnEvents /
124
+ // subscribeToTurn / prepareAndExecuteTurn signatures hardcode the runtime's
125
+ // event types with no generic to override. Hosts narrow at the point of use
126
+ // with the guards in `guards.ts`.
127
+ // ---------------------------------------------------------------------------
128
+
129
+ export type TfyToolInfo = TruefoundryGatewayApi.ToolInfo;
130
+ export type TfySystemToolInfo = TruefoundryGatewayApi.TrueFoundrySystemToolInfo;
131
+ export type TfyMcpToolInfo = TruefoundryGatewayApi.McpToolInfo;
132
+ export type TfyModelMessageUsage = TruefoundryGatewayApi.ModelMessageUsage;
133
+ export type TfyFinishReason = TruefoundryGatewayApi.FinishReason;
134
+ export type TfyThreadState = TruefoundryGatewayApi.ThreadState;
135
+ export type TfyMcpServerInitInfo = TruefoundryGatewayApi.McpServerInitInfo;