@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.
Files changed (46) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +22 -17
  3. package/dist/chunk-CXBZ6WLZ.js +636 -0
  4. package/dist/chunk-CXBZ6WLZ.js.map +1 -0
  5. package/dist/index.d.ts +20 -24
  6. package/dist/index.js +269 -166
  7. package/dist/index.js.map +1 -1
  8. package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +82 -39
  9. package/dist/plugins/truefoundry-agent-server-adapter/index.js +3 -1
  10. package/dist/server/index.d.ts +2 -2
  11. package/dist/{types-BfiFf8O1.d.ts → types-B_z-FsDS.d.ts} +208 -10
  12. package/package.json +1 -1
  13. package/src/convertTurnMessages.ts +4 -0
  14. package/src/{private → draft}/agentSpec.ts +14 -17
  15. package/src/{private → draft}/draftSessionBridge.ts +1 -2
  16. package/src/{private → draft}/truefoundryDraftThreadListAdapter.test.ts +1 -1
  17. package/src/{private → draft}/truefoundryDraftThreadListAdapter.ts +6 -2
  18. package/src/{private → draft}/useDraftAgentSpec.ts +16 -5
  19. package/src/draftAgentConfig.test.ts +2 -1
  20. package/src/harness.temp.ts +85 -0
  21. package/src/index.ts +43 -7
  22. package/src/plugins/truefoundry-agent-server-adapter/README.md +83 -44
  23. package/src/plugins/truefoundry-agent-server-adapter/chatServer.ts +365 -0
  24. package/src/plugins/truefoundry-agent-server-adapter/cp.test.ts +444 -0
  25. package/src/plugins/truefoundry-agent-server-adapter/cp.ts +482 -0
  26. package/src/plugins/truefoundry-agent-server-adapter/createTrueFoundryAgentUIServer.ts +94 -0
  27. package/src/plugins/truefoundry-agent-server-adapter/guards.ts +1 -1
  28. package/src/plugins/truefoundry-agent-server-adapter/index.ts +20 -351
  29. package/src/plugins/truefoundry-agent-server-adapter/normalizeAgentSpec.test.ts +85 -0
  30. package/src/plugins/truefoundry-agent-server-adapter/normalizeAgentSpec.ts +84 -0
  31. package/src/plugins/truefoundry-agent-server-adapter/types.ts +7 -5
  32. package/src/server/index.ts +29 -0
  33. package/src/server/types.ts +264 -12
  34. package/src/streamTurn.test.ts +27 -27
  35. package/src/streamTurn.ts +2 -2
  36. package/src/truefoundryExtras.ts +4 -1
  37. package/src/truefoundryOwnedSessionsThreadListAdapter.ts +5 -2
  38. package/src/truefoundryThreadListAdapter.test.ts +22 -0
  39. package/src/truefoundryThreadListAdapter.ts +4 -1
  40. package/src/types.ts +1 -2
  41. package/src/useTrueFoundryAgentMessages.test.tsx +262 -2
  42. package/src/useTrueFoundryAgentMessages.ts +284 -176
  43. package/src/useTrueFoundryAgentRuntime.ts +31 -21
  44. package/dist/chunk-Q2SHKMLM.js +0 -270
  45. package/dist/chunk-Q2SHKMLM.js.map +0 -1
  46. /package/src/{private → draft}/useDraftAgentSpec.test.tsx +0 -0
@@ -1,359 +1,28 @@
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";
1
+ export {
2
+ createTrueFoundryChatServer,
3
+ type CreateTrueFoundryChatServerOptions,
4
+ type TrueFoundryChatServer
5
+ } from "./chatServer.js";
6
+
7
+ export {
8
+ createTrueFoundryAgentUIServer,
9
+ type CreateTrueFoundryAgentUIServerOptions,
10
+ type TrueFoundryAgentUIServer
11
+ } from "./createTrueFoundryAgentUIServer.js";
12
+
13
+ export {
14
+ type TfyAgentSelectorEntry, type TfyConnectorSelectorEntry, type TfyModelSelectorEntry,
15
+ type TfySkillSelectorEntry
16
+ } from "./cp.js";
25
17
 
26
18
  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
19
  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,
20
+ type RequireApprovalToolsSelectorTag, type TfyAgentSpec, type TfyCreateSessionRequest, type TfyFinishReason, type TfyListSessionsParams, type TfyMcpServerInitInfo, type TfyMcpServerMount, type TfyMcpToolInfo,
21
+ type TfyModelMessageUsage, type TfyModelParams, type TfyResponseFormat, type TfyRuntimeConfig, type TfySession, type TfySkillMount, type TfySubject, type TfySystemToolInfo, type TfyThreadState, type TfyToolInfo, type TfyTurn, type TfyTurnCancelledReason, type TfyTurnState, type TfyTurnStateDoneOutput, type ToolsSelectorItem,
22
+ type ToolsSelectorTag
52
23
  } from "./types.js";
53
24
 
54
25
  export {
55
- isTfyToolInfo,
56
- isTfySystemToolInfo,
57
- isTfyMcpToolInfo,
58
- getTfyUsage,
59
- getTfyThreadState,
60
- getTfyMcpInitServers,
26
+ getTfyMcpInitServers, getTfyThreadState, getTfyUsage, isTfyMcpToolInfo, isTfySystemToolInfo, isTfyToolInfo
61
27
  } from "./guards.js";
62
28
 
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,85 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import {
4
+ normalizeAgentSpecForGateway,
5
+ normalizeMcpMount,
6
+ normalizeSkillMount,
7
+ } from "./normalizeAgentSpec.js";
8
+
9
+ describe("normalizeMcpMount", () => {
10
+ it("passes through registry mounts", () => {
11
+ expect(
12
+ normalizeMcpMount({
13
+ type: "truefoundry-mcp-registry",
14
+ name: "g-calendar",
15
+ enableTools: ["@all"],
16
+ }),
17
+ ).toEqual({
18
+ type: "truefoundry-mcp-registry",
19
+ name: "g-calendar",
20
+ enableTools: ["@all"],
21
+ });
22
+ });
23
+
24
+ it("maps UI {id,name} catalog rows to registry mounts", () => {
25
+ expect(
26
+ normalizeMcpMount({ id: "deepwiki-mcp", name: "deepwiki-mcp" }),
27
+ ).toEqual({
28
+ type: "truefoundry-mcp-registry",
29
+ name: "deepwiki-mcp",
30
+ });
31
+ });
32
+ });
33
+
34
+ describe("normalizeSkillMount", () => {
35
+ it("passes through registry mounts", () => {
36
+ expect(
37
+ normalizeSkillMount({
38
+ type: "truefoundry-skills-registry",
39
+ fqn: "agent-skill:truefoundry/skills/web:1",
40
+ preload: false,
41
+ }),
42
+ ).toEqual({
43
+ type: "truefoundry-skills-registry",
44
+ fqn: "agent-skill:truefoundry/skills/web:1",
45
+ preload: false,
46
+ });
47
+ });
48
+
49
+ it("maps UI {id,name} rows (id = fqn from CP catalog) to registry mounts", () => {
50
+ expect(
51
+ normalizeSkillMount({
52
+ id: "agent-skill:truefoundry/skills/web:1",
53
+ name: "web",
54
+ }),
55
+ ).toEqual({
56
+ type: "truefoundry-skills-registry",
57
+ fqn: "agent-skill:truefoundry/skills/web:1",
58
+ });
59
+ });
60
+ });
61
+
62
+ describe("normalizeAgentSpecForGateway", () => {
63
+ it("rewrites UI mount rows so gateway serialization can succeed", () => {
64
+ const next = normalizeAgentSpecForGateway({
65
+ model: { name: "openai-main/gpt-4.1" },
66
+ mcpServers: [{ id: "gmail", name: "gmail" }] as never[],
67
+ skills: [
68
+ {
69
+ id: "agent-skill:truefoundry/skills/web:1",
70
+ name: "web",
71
+ },
72
+ ] as never[],
73
+ });
74
+
75
+ expect(next.mcpServers).toEqual([
76
+ { type: "truefoundry-mcp-registry", name: "gmail" },
77
+ ]);
78
+ expect(next.skills).toEqual([
79
+ {
80
+ type: "truefoundry-skills-registry",
81
+ fqn: "agent-skill:truefoundry/skills/web:1",
82
+ },
83
+ ]);
84
+ });
85
+ });
@@ -0,0 +1,84 @@
1
+ import type { TruefoundryGatewayApi } from "truefoundry-gateway-sdk";
2
+
3
+ import type { TfyAgentSpec } from "./types.js";
4
+
5
+ function isRecord(value: unknown): value is Record<string, unknown> {
6
+ return value != null && typeof value === "object" && !Array.isArray(value);
7
+ }
8
+
9
+ /**
10
+ * agent-ui-sdk DraftCompositeSelector writes catalog rows as `{ id, name }`.
11
+ * Gateway AgentSpec mounts need discriminated registry shapes — without
12
+ * `type` (and skill `fqn`), Fern serialization throws JsonError before PATCH.
13
+ *
14
+ * Our CP catalog sets skill `id` = version fqn and MCP `id` = server name.
15
+ */
16
+ export function normalizeMcpMount(
17
+ raw: unknown,
18
+ ): TruefoundryGatewayApi.McpServer {
19
+ if (!isRecord(raw)) {
20
+ throw new Error("mcpServers entry must be an object");
21
+ }
22
+ if (raw.type === "truefoundry-mcp-registry" || raw.type === "inline") {
23
+ return raw as TruefoundryGatewayApi.McpServer;
24
+ }
25
+ const name =
26
+ (typeof raw.name === "string" && raw.name !== "" ? raw.name : null) ??
27
+ (typeof raw.mcpName === "string" && raw.mcpName !== ""
28
+ ? raw.mcpName
29
+ : null) ??
30
+ (typeof raw.id === "string" && raw.id !== "" ? raw.id : null);
31
+ if (name == null) {
32
+ throw new Error(
33
+ "mcpServers entry needs name, mcpName, or id to mount as registry MCP",
34
+ );
35
+ }
36
+ return { type: "truefoundry-mcp-registry", name };
37
+ }
38
+
39
+ export function normalizeSkillMount(
40
+ raw: unknown,
41
+ ): TruefoundryGatewayApi.SkillMount {
42
+ if (!isRecord(raw)) {
43
+ throw new Error("skills entry must be an object");
44
+ }
45
+ if (raw.type === "truefoundry-skills-registry" || raw.type === "git") {
46
+ return raw as TruefoundryGatewayApi.SkillMount;
47
+ }
48
+ const fqn =
49
+ (typeof raw.fqn === "string" && raw.fqn !== "" ? raw.fqn : null) ??
50
+ (typeof raw.id === "string" && raw.id !== "" ? raw.id : null);
51
+ if (fqn == null) {
52
+ throw new Error(
53
+ "skills entry needs fqn or id to mount as registry skill",
54
+ );
55
+ }
56
+ return {
57
+ type: "truefoundry-skills-registry",
58
+ fqn,
59
+ ...(raw.preload === true ? { preload: true } : {}),
60
+ };
61
+ }
62
+
63
+ /** Rewrite UI `{id,name}` mounts so create/update draft session can serialize. */
64
+ export function normalizeAgentSpecForGateway<TSpec extends TfyAgentSpec>(
65
+ spec: TSpec,
66
+ ): TSpec {
67
+ return {
68
+ ...spec,
69
+ ...(spec.mcpServers != null
70
+ ? {
71
+ mcpServers: spec.mcpServers.map(
72
+ normalizeMcpMount,
73
+ ) as TSpec["mcpServers"],
74
+ }
75
+ : {}),
76
+ ...(spec.skills != null
77
+ ? {
78
+ skills: spec.skills.map(
79
+ normalizeSkillMount,
80
+ ) as TSpec["skills"],
81
+ }
82
+ : {}),
83
+ };
84
+ }
@@ -63,10 +63,12 @@ export type TfyMcpServerMount = RuntimeMcpServerMount & TruefoundryGatewayApi.Mc
63
63
  // AgentSpec — the concrete TrueFoundry agent definition
64
64
  // ---------------------------------------------------------------------------
65
65
 
66
- export interface TfyAgentSpec extends AgentSpec {
67
- model: TruefoundryGatewayApi.Model;
68
- skills?: TfySkillMount[];
69
- mcpServers?: TfyMcpServerMount[];
66
+ export interface TfyAgentSpec
67
+ extends AgentSpec<
68
+ TruefoundryGatewayApi.Model,
69
+ TfySkillMount,
70
+ TfyMcpServerMount
71
+ > {
70
72
  config?: TruefoundryGatewayApi.RuntimeConfig;
71
73
  responseFormat?: TruefoundryGatewayApi.ResponseFormat;
72
74
  messages?: TruefoundryGatewayApi.AgentSpecUserMessage[];
@@ -121,7 +123,7 @@ export interface TfyListSessionsParams extends ListSessionsParams {
121
123
  // Event-side types.
122
124
  //
123
125
  // These do NOT flow through AgentChatServer — its listEvents / listTurnEvents /
124
- // subscribeToTurn / prepareAndExecuteTurn signatures hardcode the runtime's
126
+ // subscribeToTurn / createTurn signatures hardcode the runtime's
125
127
  // event types with no generic to override. Hosts narrow at the point of use
126
128
  // with the guards in `guards.ts`.
127
129
  // ---------------------------------------------------------------------------
@@ -31,6 +31,35 @@ export type {
31
31
  Turn,
32
32
  AgentChatServer,
33
33
  AgentBuilderServer,
34
+ ProviderType,
35
+ ModelEntry,
36
+ ModelProviderConfigBase,
37
+ ModelProviderBase,
38
+ ModelProviderCatalogEntry,
39
+ CreateModelProviderRequest,
40
+ UpdateModelProviderRequest,
41
+ ModelCatalogServer,
42
+ ToolBase,
43
+ ConnectorAuthType,
44
+ ConnectorAuthOAuth,
45
+ ConnectorAuthApiKey,
46
+ ConnectorAuthNone,
47
+ ConnectorAuth,
48
+ ConnectorAuthPublicOAuth,
49
+ ConnectorAuthPublicApiKey,
50
+ ConnectorAuthPublicNone,
51
+ ConnectorAuthPublic,
52
+ ConnectorConfigBase,
53
+ ConnectorBase,
54
+ ConnectorCatalogEntry,
55
+ CreateConnectorRequest,
56
+ UpdateConnectorRequest,
57
+ ConnectorCatalogServer,
58
+ SkillBase,
59
+ CreateSkillRequest,
60
+ SkillCatalogServer,
61
+ CatalogServer,
62
+ AgentUIServerPort,
34
63
  } from "./types.js";
35
64
 
36
65
  export type {