@truefoundry/assistant-ui-runtime 0.1.10-rc.1 → 0.1.10

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 CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.10
4
+
5
+ ### Breaking
6
+
7
+ - **`ListSessionsParams.agentName` → `agentId`**
8
+ Thread-list adapters and the TFY chat server forward the optional filter as `agentId`. Hosts that previously keyed list filters by name should pass that same value as `agentId` (or via `listSessionsAgentId` on the runtime / adapters).
9
+
10
+ - **Draft thread list no longer filters `isMutable` client-side**
11
+ `createTrueFoundryDraftThreadListAdapter.list` returns every session from `listSessions`. Title named (immutable) rows with `title → agentName → id`, not the draft model name.
12
+
13
+ ### Added
14
+
15
+ - **`listSessionsAgentId?: string`** on `useTrueFoundryAgentRuntime` and all three thread-list adapters (`createTrueFoundryThreadListAdapter`, `createTrueFoundryDraftThreadListAdapter`, `createTrueFoundryOwnedSessionsThreadListAdapter`). Omit to list all chats; set to filter `listSessions({ agentId })`.
16
+ - **`AgentSelectorEntry.agentId?` / `agentSpec?`** — CP `normalizeAgents` fills these from agent id + `latestVersionDetails.manifest` so hosts can offer Edit when a published spec is present.
17
+ - **`agentSpecFromCpManifest` / `toCamelCaseDeep`** — map CP AgentManifest (snake_case) → FE `TfyAgentSpec` for Edit seeding, preserving agent `config` and mount `enableTools` / `preload` / `config`.
18
+ - **`sessionDisplayTitle` / `sessionToThreadMetadata`** — shared session → thread-list metadata helpers; named sessions expose `custom.agentName` when present.
19
+
20
+ ### Fixed
21
+
22
+ - **Edit → Save round-trip** — catalog mounts from CP keep runtime fields; `normalizeMcpMount` / `normalizeSkillMount` forward `enableTools`, `preload`, and `config` so save no longer defaults MCP tools to `@all`, forces skill `preload: false`, or drops config.
23
+ - **Untitled named sessions in draft history** — mixed lists use `sessionDisplayTitle` so immutable rows fall back to `agentName` / `id` instead of `defaultAgentSpec.model.name`.
24
+
25
+ ### Changed
26
+
27
+ - Bump `@assistant-ui/core` to `^0.2.22` and `@assistant-ui/store` to `^0.2.21`.
28
+
3
29
  ## 0.1.9
4
30
 
5
31
  ### Added
@@ -19,7 +19,13 @@ function normalizeMcpMount(raw) {
19
19
  "mcpServers entry needs name, mcpName, or id to mount as registry MCP"
20
20
  );
21
21
  }
22
- return { type: "truefoundry-mcp-registry", name };
22
+ return {
23
+ type: "truefoundry-mcp-registry",
24
+ name,
25
+ ...Array.isArray(raw.enableTools) ? { enableTools: raw.enableTools } : {},
26
+ ...typeof raw.preload === "boolean" ? { preload: raw.preload } : {},
27
+ ...raw.config != null ? { config: raw.config } : {}
28
+ };
23
29
  }
24
30
  function normalizeSkillMount(raw) {
25
31
  if (!isRecord(raw)) {
@@ -37,7 +43,8 @@ function normalizeSkillMount(raw) {
37
43
  return {
38
44
  type: "truefoundry-skills-registry",
39
45
  fqn,
40
- ...raw.preload === true ? { preload: true } : {}
46
+ ...typeof raw.preload === "boolean" ? { preload: raw.preload } : {},
47
+ ...raw.config != null ? { config: raw.config } : {}
41
48
  };
42
49
  }
43
50
  function normalizeAgentSpecForGateway(spec) {
@@ -163,7 +170,7 @@ function createTrueFoundryChatServer(opts) {
163
170
  pageToken: req?.pageToken,
164
171
  startTimestamp: req?.startTimestamp,
165
172
  endTimestamp: req?.endTimestamp,
166
- ...req?.agentName != null ? { agentName: req.agentName } : {}
173
+ ...req?.agentId != null ? { agentName: req.agentId } : {}
167
174
  });
168
175
  const result = await toListResult(page, (s) => toSession(s));
169
176
  for (const session of result.data) {
@@ -430,12 +437,86 @@ async function listMcpServers(opts) {
430
437
  const raw = await cpFetch(opts, "/api/svc/v1/mcp-servers");
431
438
  return normalizeMcpServers(raw);
432
439
  }
440
+ function isRecord2(value) {
441
+ return value != null && typeof value === "object" && !Array.isArray(value);
442
+ }
443
+ function snakeToCamelKey(key) {
444
+ return key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
445
+ }
446
+ function toCamelCaseDeep(value) {
447
+ if (Array.isArray(value)) {
448
+ return value.map(toCamelCaseDeep);
449
+ }
450
+ if (isRecord2(value)) {
451
+ const out = {};
452
+ for (const [k, v] of Object.entries(value)) {
453
+ out[snakeToCamelKey(k)] = toCamelCaseDeep(v);
454
+ }
455
+ return out;
456
+ }
457
+ return value;
458
+ }
459
+ function agentSpecFromCpManifest(manifest) {
460
+ if (!isRecord2(manifest)) return void 0;
461
+ const modelRaw = manifest.model;
462
+ if (!isRecord2(modelRaw) || typeof modelRaw.name !== "string" || modelRaw.name === "") {
463
+ return void 0;
464
+ }
465
+ const model = toCamelCaseDeep(modelRaw);
466
+ const skills = [];
467
+ if (Array.isArray(manifest.skills)) {
468
+ for (const row of manifest.skills) {
469
+ if (!isRecord2(row)) continue;
470
+ const fqn = typeof row.fqn === "string" && row.fqn !== "" ? row.fqn : typeof row.id === "string" && row.id !== "" ? row.id : null;
471
+ if (fqn == null) continue;
472
+ const camel = toCamelCaseDeep(row);
473
+ const name = typeof camel.name === "string" && camel.name !== "" ? camel.name : fqn;
474
+ skills.push({
475
+ id: fqn,
476
+ name,
477
+ ...typeof camel.preload === "boolean" ? { preload: camel.preload } : {},
478
+ ...camel.config != null ? { config: camel.config } : {}
479
+ });
480
+ }
481
+ }
482
+ const mcpServers = [];
483
+ const mcpRaw = Array.isArray(manifest.mcp_servers) ? manifest.mcp_servers : Array.isArray(manifest.mcpServers) ? manifest.mcpServers : [];
484
+ for (const row of mcpRaw) {
485
+ if (!isRecord2(row)) continue;
486
+ const camel = toCamelCaseDeep(row);
487
+ const name = typeof camel.name === "string" && camel.name !== "" ? camel.name : typeof camel.id === "string" && camel.id !== "" ? camel.id : null;
488
+ if (name == null) continue;
489
+ mcpServers.push({
490
+ id: name,
491
+ name,
492
+ ...Array.isArray(camel.enableTools) ? { enableTools: camel.enableTools } : {},
493
+ ...typeof camel.preload === "boolean" ? { preload: camel.preload } : {},
494
+ ...camel.config != null ? { config: camel.config } : {}
495
+ });
496
+ }
497
+ const configRaw = manifest.config;
498
+ const config = configRaw != null ? toCamelCaseDeep(configRaw) : void 0;
499
+ return {
500
+ model,
501
+ ...typeof manifest.instructions === "string" ? { instructions: manifest.instructions } : {},
502
+ ...config != null ? { config } : {},
503
+ ...skills.length > 0 ? { skills } : {},
504
+ ...mcpServers.length > 0 ? { mcpServers } : {}
505
+ };
506
+ }
433
507
  function normalizeAgents(raw) {
434
508
  const data = raw != null && typeof raw === "object" && Array.isArray(raw.data) ? raw.data : [];
435
509
  const out = [];
436
510
  for (const row of data) {
437
511
  if (row.name == null || row.name === "") continue;
438
- out.push({ name: row.name });
512
+ const manifest = row.latestVersionDetails?.manifest ?? row.manifest;
513
+ const agentSpec = agentSpecFromCpManifest(manifest);
514
+ const agentId = typeof row.id === "string" && row.id !== "" ? row.id : row.name;
515
+ out.push({
516
+ name: row.name,
517
+ agentId,
518
+ ...agentSpec != null ? { agentSpec } : {}
519
+ });
439
520
  }
440
521
  return out;
441
522
  }
@@ -568,17 +649,17 @@ async function createTrueFoundryAgentUIServer(opts) {
568
649
  }
569
650
 
570
651
  // src/plugins/truefoundry-agent-server-adapter/guards.ts
571
- function isRecord2(value) {
652
+ function isRecord3(value) {
572
653
  return typeof value === "object" && value !== null;
573
654
  }
574
655
  function hasNumbers(value, keys) {
575
- return isRecord2(value) && keys.every((key) => typeof value[key] === "number");
656
+ return isRecord3(value) && keys.every((key) => typeof value[key] === "number");
576
657
  }
577
658
  function isTfySystemToolInfo(toolInfo) {
578
- return isRecord2(toolInfo) && toolInfo.type === "truefoundry-system" && typeof toolInfo.name === "string";
659
+ return isRecord3(toolInfo) && toolInfo.type === "truefoundry-system" && typeof toolInfo.name === "string";
579
660
  }
580
661
  function isTfyMcpToolInfo(toolInfo) {
581
- return isRecord2(toolInfo) && toolInfo.type === "mcp" && typeof toolInfo.name === "string" && typeof toolInfo.serverId === "string" && typeof toolInfo.serverName === "string";
662
+ return isRecord3(toolInfo) && toolInfo.type === "mcp" && typeof toolInfo.name === "string" && typeof toolInfo.serverId === "string" && typeof toolInfo.serverName === "string";
582
663
  }
583
664
  function isTfyToolInfo(toolInfo) {
584
665
  return isTfySystemToolInfo(toolInfo) || isTfyMcpToolInfo(toolInfo);
@@ -602,10 +683,10 @@ function getTfyUsage(source) {
602
683
  }
603
684
  function getTfyThreadState(event) {
604
685
  const state = event?.state;
605
- if (!isRecord2(state)) {
686
+ if (!isRecord3(state)) {
606
687
  return void 0;
607
688
  }
608
- if (state.status === "done" && isRecord2(state.output)) {
689
+ if (state.status === "done" && isRecord3(state.output)) {
609
690
  return state;
610
691
  }
611
692
  if (state.status === "error" && typeof state.error === "string") {
@@ -619,7 +700,7 @@ function getTfyMcpInitServers(event) {
619
700
  return void 0;
620
701
  }
621
702
  const valid = servers.every(
622
- (server) => isRecord2(server) && typeof server.id === "string" && typeof server.name === "string"
703
+ (server) => isRecord3(server) && typeof server.id === "string" && typeof server.name === "string"
623
704
  );
624
705
  return valid ? servers : void 0;
625
706
  }
@@ -634,4 +715,4 @@ export {
634
715
  getTfyThreadState,
635
716
  getTfyMcpInitServers
636
717
  };
637
- //# sourceMappingURL=chunk-BRPTG6VA.js.map
718
+ //# sourceMappingURL=chunk-6ZOGBD7E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/plugins/truefoundry-agent-server-adapter/chatServer.ts","../src/plugins/truefoundry-agent-server-adapter/normalizeAgentSpec.ts","../src/plugins/truefoundry-agent-server-adapter/cp.ts","../src/plugins/truefoundry-agent-server-adapter/createTrueFoundryAgentUIServer.ts","../src/plugins/truefoundry-agent-server-adapter/guards.ts"],"sourcesContent":["import { AgentSessionClient } from \"truefoundry-gateway-sdk/agents\";\nimport type { AgentSession } from \"truefoundry-gateway-sdk/agents\";\nimport { PrivateAgentSessionClient } from \"truefoundry-gateway-sdk/agents/private\";\nimport type { AgentDraftSession } from \"truefoundry-gateway-sdk/agents/private\";\nimport type {\n AgentChatServer,\n ListResult,\n TurnInputItem,\n PreviousTurnIdInput,\n UpdateSessionRequest,\n} from \"../../server/types.js\";\nimport type {\n SessionEventItem,\n TurnEvent,\n TurnStreamData,\n} from \"../../server/events.js\";\nimport { normalizeAgentSpecForGateway } from \"./normalizeAgentSpec.js\";\nimport type {\n TfyAgentSpec,\n TfyCreateSessionRequest,\n TfyListSessionsParams,\n TfySession,\n TfyTurn,\n TfyTurnState,\n} from \"./types.js\";\n\ntype GwSession = AgentSession | AgentDraftSession;\n\nexport type CreateTrueFoundryChatServerOptions = {\n apiKey: string;\n baseUrl: string;\n /** Optional override — otherwise constructed from apiKey/baseUrl. */\n client?: AgentSessionClient;\n privateClient?: PrivateAgentSessionClient;\n deleteSession?: (req: { sessionId: string }) => Promise<void>;\n};\n\n/**\n * Only the spec is generic. Session/Turn/list-params are the concrete Tfy*\n * types because the adapter builds them as fixed object literals — a generic\n * there would type fields that nothing ever populates. The spec is safe: the\n * gateway SDK serializes with `unrecognizedObjectKeys: \"passthrough\"`, so\n * host-added spec fields survive the round trip.\n */\nexport type TrueFoundryChatServer<TSpec extends TfyAgentSpec = TfyAgentSpec> =\n AgentChatServer<\n TSpec,\n TfySession<TSpec>,\n TfyCreateSessionRequest<TSpec>,\n TfyListSessionsParams,\n UpdateSessionRequest<TSpec>,\n TfyTurn\n > & {\n /** Escape hatch for hosts that still need raw gateway clients. */\n getGatewayClients(): {\n client: AgentSessionClient;\n privateClient: PrivateAgentSessionClient;\n };\n };\n\n/** Gateway SDK errors carry the HTTP status as `statusCode`. */\nfunction isNotFound(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n (error as { statusCode?: unknown }).statusCode === 404\n );\n}\n\nfunction isDraft(session: GwSession): session is AgentDraftSession {\n return (session as AgentDraftSession).type === \"session/draft\";\n}\n\nfunction toSession<TSpec extends TfyAgentSpec>(raw: GwSession): TfySession<TSpec> {\n const mutable = isDraft(raw);\n return {\n id: raw.id,\n title: raw.title,\n agentName: raw.agentName,\n ...(mutable ? { agentSpec: raw.agentSpec as TSpec } : {}),\n isMutable: mutable,\n createdBySubject: raw.createdBySubject,\n createdAt: raw.createdAt,\n updatedAt: raw.updatedAt,\n };\n}\n\nfunction toTurn(raw: {\n id: string;\n sessionId: string;\n previousTurnId?: string | null;\n input?: TurnInputItem[];\n state: unknown;\n createdBySubject: TfyTurn[\"createdBySubject\"];\n createdAt: string;\n}): TfyTurn {\n return {\n id: raw.id,\n sessionId: raw.sessionId,\n previousTurnId: raw.previousTurnId,\n input: raw.input,\n state: raw.state as TfyTurnState,\n createdBySubject: raw.createdBySubject,\n createdAt: raw.createdAt,\n };\n}\n\nasync function toListResult<TIn, TOut>(\n page: {\n data: TIn[];\n response?: { pagination?: { nextPageToken?: string } };\n hasNextPage?: () => boolean;\n },\n map: (item: TIn) => TOut,\n): Promise<ListResult<TOut>> {\n const nextPageToken = page.response?.pagination?.nextPageToken;\n return {\n data: page.data.map(map),\n ...(nextPageToken != null && nextPageToken !== \"\"\n ? { nextPageToken }\n : {}),\n };\n}\n\n/**\n * Wraps TrueFoundry gateway clients into a flat `AgentChatServer`.\n * Named vs draft routing is fully internal — an in-memory session-type cache\n * (populated by createSession/listSessions) determines which gateway client\n * to call, falling back to a one-time probe for ids seen only in a URL.\n */\nexport function createTrueFoundryChatServer<\n TSpec extends TfyAgentSpec = TfyAgentSpec,\n>(\n opts: CreateTrueFoundryChatServerOptions,\n): TrueFoundryChatServer<TSpec> {\n const gatewayOpts = { apiKey: opts.apiKey, baseUrl: opts.baseUrl };\n const client = opts.client ?? new AgentSessionClient(gatewayOpts);\n const privateClient =\n opts.privateClient ?? new PrivateAgentSessionClient(gatewayOpts);\n\n const sessionTypeCache = new Map<string, boolean>();\n const sessionTypeProbes = new Map<string, Promise<boolean>>();\n\n function cacheSessionType(session: {\n id: string;\n isMutable: boolean;\n }): void {\n sessionTypeCache.set(session.id, session.isMutable);\n }\n\n /**\n * Resolving a session id straight from a URL (page reload / shared link)\n * reaches the gateway before createSession or listSessions has cached the\n * type, so discover it by probing the draft endpoint and falling back to\n * the conversation endpoint. Concurrent callers share one probe.\n */\n async function probeSessionType(sessionId: string): Promise<boolean> {\n const inflight = sessionTypeProbes.get(sessionId);\n if (inflight != null) {\n return inflight;\n }\n const probe = (async () => {\n try {\n await privateClient.getDraftSession({ draftSessionId: sessionId });\n return true;\n } catch (error) {\n // Only a miss proves the id isn't a draft. Auth or transient\n // failures would otherwise be retried as a conversation session\n // and mislabel a real draft as named.\n if (!isNotFound(error)) {\n throw error;\n }\n await client.getSession({ sessionId });\n return false;\n }\n })();\n sessionTypeProbes.set(sessionId, probe);\n try {\n const isMutable = await probe;\n sessionTypeCache.set(sessionId, isMutable);\n return isMutable;\n } finally {\n sessionTypeProbes.delete(sessionId);\n }\n }\n\n async function getSessionObj(sessionId: string): Promise<GwSession> {\n const isMutable =\n sessionTypeCache.get(sessionId) ?? (await probeSessionType(sessionId));\n return isMutable\n ? privateClient.getDraftSession({ draftSessionId: sessionId })\n : client.getSession({ sessionId });\n }\n\n const server: TrueFoundryChatServer<TSpec> = {\n async createSession(req) {\n if (req.agentSpec != null) {\n const draft = await privateClient.createDraftSession({\n agentSpec: normalizeAgentSpecForGateway(req.agentSpec),\n ...(req.agentName != null ? { agentName: req.agentName } : {}),\n ...(req.tfyMetadata != null\n ? { tfyMetadata: req.tfyMetadata }\n : {}),\n });\n const session = toSession<TSpec>(draft);\n cacheSessionType(session);\n return session;\n }\n if (req.agentName != null) {\n const named = await client.createSession({\n agentName: req.agentName,\n ...(req.tfyMetadata != null\n ? { tfyMetadata: req.tfyMetadata }\n : {}),\n });\n const session = toSession<TSpec>(named);\n cacheSessionType(session);\n return session;\n }\n throw new Error(\"createSession requires agentName and/or agentSpec\");\n },\n\n async listSessions(req) {\n const page = await privateClient.listOwnedSessions({\n limit: req?.limit,\n order: req?.order,\n pageToken: req?.pageToken,\n startTimestamp: req?.startTimestamp,\n endTimestamp: req?.endTimestamp,\n ...(req?.agentId != null ? { agentName: req.agentId } : {}),\n });\n const result = await toListResult(page, (s) => toSession<TSpec>(s));\n for (const session of result.data) {\n cacheSessionType(session);\n }\n return result;\n },\n\n async getSession({ sessionId }) {\n const raw = await getSessionObj(sessionId);\n const session = toSession<TSpec>(raw);\n cacheSessionType(session);\n return session;\n },\n\n async updateSession(req) {\n const raw = await getSessionObj(req.sessionId);\n if (!isDraft(raw)) {\n throw new Error(\n \"updateSession: session is not mutable (isMutable=false)\",\n );\n }\n if (req.agentSpec != null) {\n await raw.update({\n agentSpec: normalizeAgentSpecForGateway(req.agentSpec),\n });\n }\n return toSession<TSpec>(raw);\n },\n\n createTurn(req: {\n sessionId: string;\n input?: TurnInputItem[];\n previousTurnId?: PreviousTurnIdInput;\n abortSignal?: AbortSignal;\n headers?: Record<string, string>;\n }): AsyncIterable<TurnStreamData> {\n return (async function* () {\n const session = await getSessionObj(req.sessionId);\n const prepared = session.prepareTurn({\n input: req.input,\n previousTurnId: req.previousTurnId ?? \"auto\",\n });\n yield* prepared.execute(\n { stream: true },\n {\n ...(req.abortSignal != null\n ? { abortSignal: req.abortSignal }\n : {}),\n ...(req.headers != null ? { headers: req.headers } : {}),\n },\n ) as AsyncIterable<TurnStreamData>;\n })();\n },\n\n async cancelSession({ sessionId }) {\n await (await getSessionObj(sessionId)).cancel();\n },\n\n async deleteSession({ sessionId }) {\n if (opts.deleteSession == null) {\n throw new Error(\n \"deleteSession is not on the gateway SDK. Pass deleteSession to createTrueFoundryChatServer.\",\n );\n }\n await opts.deleteSession({ sessionId });\n },\n\n // The runtime's signature offers `order`, but the gateway's listTurns\n // takes no such param — forwarding it silently did nothing.\n async listTurns({ sessionId, limit, pageToken }) {\n const raw = await getSessionObj(sessionId);\n const page = await raw.listTurns({\n ...(limit != null ? { limit } : {}),\n ...(pageToken != null ? { pageToken } : {}),\n });\n return toListResult(page, (turn) => toTurn(turn));\n },\n\n async getTurn({ sessionId, turnId }) {\n const raw = await getSessionObj(sessionId);\n return toTurn(await raw.getTurn({ turnId }));\n },\n\n async listEvents({ sessionId, pageToken, lastTurnId, limit }) {\n const raw = await getSessionObj(sessionId);\n const page = await raw.listEvents({\n ...(limit != null ? { limit } : {}),\n ...(pageToken != null ? { pageToken } : {}),\n ...(lastTurnId != null ? { lastTurnId } : {}),\n });\n return toListResult(\n page,\n (item) => item as SessionEventItem,\n );\n },\n\n async listTurnEvents({ sessionId, turnId, limit, pageToken, order }) {\n const raw = await getSessionObj(sessionId);\n const turn = await raw.getTurn({ turnId });\n const page = await turn.listEvents({\n ...(limit != null ? { limit } : {}),\n ...(pageToken != null ? { pageToken } : {}),\n ...(order != null ? { order } : {}),\n });\n return toListResult(page, (event) => event as TurnEvent);\n },\n\n async *subscribeToTurn({\n sessionId,\n turnId,\n afterSequenceNumber,\n abortSignal,\n }) {\n const raw = await getSessionObj(sessionId);\n const turn = await raw.getTurn({ turnId });\n yield* turn.stream(\n afterSequenceNumber != null ? { afterSequenceNumber } : {},\n abortSignal != null ? { abortSignal } : {},\n ) as AsyncIterable<TurnStreamData>;\n },\n\n // The gateway addresses sandboxes directly, so the turn is carried for hosts that need it\n // but is not part of this route.\n async downloadSandboxFile({ sandboxId, path }) {\n const response = await privateClient.downloadSandboxFile(sandboxId, {\n path,\n });\n return await response.blob();\n },\n\n getGatewayClients: () => ({ client, privateClient }),\n };\n\n return server;\n}\n","import type { TruefoundryGatewayApi } from \"truefoundry-gateway-sdk\";\n\nimport type { TfyAgentSpec } from \"./types.js\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * agent-ui-sdk DraftCompositeSelector writes catalog rows as `{ id, name }`.\n * Gateway AgentSpec mounts need discriminated registry shapes — without\n * `type` (and skill `fqn`), Fern serialization throws JsonError before PATCH.\n *\n * Our CP catalog sets skill `id` = version fqn and MCP `id` = server name.\n */\nexport function normalizeMcpMount(\n raw: unknown,\n): TruefoundryGatewayApi.McpServer {\n if (!isRecord(raw)) {\n throw new Error(\"mcpServers entry must be an object\");\n }\n if (raw.type === \"truefoundry-mcp-registry\" || raw.type === \"inline\") {\n return raw as unknown as TruefoundryGatewayApi.McpServer;\n }\n const name =\n (typeof raw.name === \"string\" && raw.name !== \"\" ? raw.name : null) ??\n (typeof raw.mcpName === \"string\" && raw.mcpName !== \"\"\n ? raw.mcpName\n : null) ??\n (typeof raw.id === \"string\" && raw.id !== \"\" ? raw.id : null);\n if (name == null) {\n throw new Error(\n \"mcpServers entry needs name, mcpName, or id to mount as registry MCP\",\n );\n }\n return {\n type: \"truefoundry-mcp-registry\",\n name,\n ...(Array.isArray(raw.enableTools) ? { enableTools: raw.enableTools } : {}),\n ...(typeof raw.preload === \"boolean\" ? { preload: raw.preload } : {}),\n ...(raw.config != null ? { config: raw.config } : {}),\n } as unknown as TruefoundryGatewayApi.McpServer;\n}\n\nexport function normalizeSkillMount(\n raw: unknown,\n): TruefoundryGatewayApi.SkillMount {\n if (!isRecord(raw)) {\n throw new Error(\"skills entry must be an object\");\n }\n if (raw.type === \"truefoundry-skills-registry\" || raw.type === \"git\") {\n return raw as unknown as TruefoundryGatewayApi.SkillMount;\n }\n const fqn =\n (typeof raw.fqn === \"string\" && raw.fqn !== \"\" ? raw.fqn : null) ??\n (typeof raw.id === \"string\" && raw.id !== \"\" ? raw.id : null);\n if (fqn == null) {\n throw new Error(\n \"skills entry needs fqn or id to mount as registry skill\",\n );\n }\n return {\n type: \"truefoundry-skills-registry\",\n fqn,\n ...(typeof raw.preload === \"boolean\" ? { preload: raw.preload } : {}),\n ...(raw.config != null ? { config: raw.config } : {}),\n } as unknown as TruefoundryGatewayApi.SkillMount;\n}\n\n/** Rewrite UI `{id,name}` mounts so create/update draft session can serialize. */\nexport function normalizeAgentSpecForGateway<TSpec extends TfyAgentSpec>(\n spec: TSpec,\n): TSpec {\n return {\n ...spec,\n ...(spec.mcpServers != null\n ? {\n mcpServers: spec.mcpServers.map(\n normalizeMcpMount,\n ) as TSpec[\"mcpServers\"],\n }\n : {}),\n ...(spec.skills != null\n ? {\n skills: spec.skills.map(\n normalizeSkillMount,\n ) as TSpec[\"skills\"],\n }\n : {}),\n };\n}\n","/**\n * Control Plane HTTP for builder catalog lists + gateway URL resolution.\n *\n * Wire shapes are host/CP contracts (not Fern / gateway SDK). Paths match\n * ai.tf cpApi usage — expect drift; keep normalizers defensive.\n */\n\nimport type {\n AgentSelectorEntry,\n ConnectorSelectorEntry,\n ModelSelectorEntry,\n SearchAgentSelectorParams,\n SkillSelectorEntry,\n} from \"../../server/types.js\";\nimport { normalizeAgentSpecForGateway } from \"./normalizeAgentSpec.js\";\nimport type { TfyAgentSpec } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Selector rows — FE base + TFY mount fields\n// ---------------------------------------------------------------------------\n\nexport interface TfyModelSelectorEntry extends ModelSelectorEntry {\n /** Write into AgentSpec.model.name (model_fqn). */\n apiModel: string;\n modelId: string;\n providerAccount?: string;\n id?: string;\n}\n\nexport interface TfySkillSelectorEntry extends SkillSelectorEntry {\n /** Version FQN — mount as RegisteredSkillMount.fqn. */\n fqn: string;\n}\n\nexport interface TfyConnectorSelectorEntry extends ConnectorSelectorEntry {\n /** Mount as RegisteredMcpServer.name. */\n mcpName: string;\n serverId?: string | null;\n authenticated?: boolean;\n}\n\nexport type TfyAgentSelectorEntry = AgentSelectorEntry;\n\nexport type CpCredentials = {\n apiKey: string;\n cpURL: string;\n};\n\n// ---------------------------------------------------------------------------\n// HTTP\n// ---------------------------------------------------------------------------\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\nexport async function cpFetch<T>(\n opts: CpCredentials,\n path: string,\n init?: RequestInit,\n): Promise<T> {\n const url = `${trimSlash(opts.cpURL)}${path.startsWith(\"/\") ? path : `/${path}`}`;\n const res = await fetch(url, {\n ...init,\n headers: {\n Authorization: `Bearer ${opts.apiKey}`,\n Accept: \"application/json\",\n ...(init?.headers ?? {}),\n },\n });\n if (!res.ok) {\n throw new Error(`CP ${res.status} ${res.statusText}: ${path}`);\n }\n return (await res.json()) as T;\n}\n\n// ---------------------------------------------------------------------------\n// Gateway URL resolve\n// ---------------------------------------------------------------------------\n\n/**\n * Real CP `/api/svc/v1/session` is flat `{ user, env, ... }` (no `data` wrapper).\n * `env.LLM_GATEWAY_URL` is a prefix like `/api/llm`; tenant is appended:\n * `{cpURL}{LLM_GATEWAY_URL}/{tenantName}` → e.g. `…/api/llm/truefoundry`.\n */\ntype SessionResponse = {\n user?: {\n tenantName?: string;\n };\n env?: {\n TENANT_NAME?: string;\n LLM_GATEWAY_URL?: string;\n };\n /** Legacy / alternate wrap — keep for safety. */\n data?: {\n user?: {\n tenantName?: string;\n };\n };\n};\n\nfunction joinCpPath(cpURL: string, path: string): string {\n const base = trimSlash(cpURL);\n const p = path.startsWith(\"/\") ? path : `/${path}`;\n return `${base}${p}`;\n}\n\n/**\n * Resolve gateway base URL.\n * - `gatewayURL` set → use it (no /session).\n * - else GET /api/svc/v1/session →\n * `{cpURL}{env.LLM_GATEWAY_URL ?? \"/api/llm\"}/{tenantName}`.\n * - session HTTP failure or missing tenantName → throw (no silent public fallback).\n */\nexport async function resolveGatewayURL(opts: {\n apiKey: string;\n cpURL: string;\n gatewayURL?: string;\n}): Promise<string> {\n if (opts.gatewayURL != null && opts.gatewayURL !== \"\") {\n return opts.gatewayURL;\n }\n\n const session = await cpFetch<SessionResponse>(opts, \"/api/svc/v1/session\");\n const tenantName =\n session.user?.tenantName ??\n session.env?.TENANT_NAME ??\n session.data?.user?.tenantName;\n if (tenantName == null || tenantName === \"\") {\n throw new Error(\n \"resolveGatewayURL: /api/svc/v1/session did not return user.tenantName\",\n );\n }\n\n const llmPrefix = trimSlash(session.env?.LLM_GATEWAY_URL ?? \"/api/llm\");\n return joinCpPath(opts.cpURL, `${llmPrefix}/${tenantName}`);\n}\n\n// ---------------------------------------------------------------------------\n// Models\n// ---------------------------------------------------------------------------\n\ntype RawEnabledModel = {\n id?: string;\n name?: string;\n provider?: string;\n provider_account_name?: string;\n model_id?: string;\n model_fqn?: string;\n types?: string[];\n};\n\nfunction isChatModel(row: RawEnabledModel): boolean {\n const types = row.types;\n if (types == null || types.length === 0) return true;\n return types.includes(\"chat\");\n}\n\nfunction toModelEntry(row: RawEnabledModel): TfyModelSelectorEntry | null {\n if (!isChatModel(row)) return null;\n const apiModel = row.model_fqn ?? row.id;\n const name = row.name;\n if (apiModel == null || apiModel === \"\" || name == null || name === \"\") {\n return null;\n }\n const provider = row.provider ?? \"unknown\";\n const modelId = row.model_id ?? name;\n return {\n name,\n provider,\n apiModel,\n modelId,\n ...(row.provider_account_name != null\n ? { providerAccount: row.provider_account_name }\n : {}),\n id: apiModel,\n };\n}\n\n/**\n * Flatten enabled-models payload.\n * Nested: provider → account → models[].\n * Virtual: top-level account → models[] (array values that look like model rows).\n */\nexport function normalizeEnabledModels(raw: unknown): TfyModelSelectorEntry[] {\n if (raw == null || typeof raw !== \"object\" || Array.isArray(raw)) {\n return [];\n }\n const out: TfyModelSelectorEntry[] = [];\n const seen = new Set<string>();\n\n function pushRow(row: RawEnabledModel): void {\n const entry = toModelEntry(row);\n if (entry == null || seen.has(entry.apiModel)) return;\n seen.add(entry.apiModel);\n out.push(entry);\n }\n\n for (const level1 of Object.values(raw as Record<string, unknown>)) {\n if (Array.isArray(level1)) {\n // virtual-model style: account → models[]\n for (const row of level1) {\n if (row != null && typeof row === \"object\") {\n pushRow(row as RawEnabledModel);\n }\n }\n continue;\n }\n if (level1 == null || typeof level1 !== \"object\") continue;\n for (const level2 of Object.values(level1 as Record<string, unknown>)) {\n if (!Array.isArray(level2)) continue;\n for (const row of level2) {\n if (row != null && typeof row === \"object\") {\n pushRow(row as RawEnabledModel);\n }\n }\n }\n }\n return out;\n}\n\nexport async function listEnabledModels(\n opts: CpCredentials,\n): Promise<TfyModelSelectorEntry[]> {\n const raw = await cpFetch<unknown>(\n opts,\n \"/api/svc/v1/llm-gateway/model/enabled\",\n );\n return normalizeEnabledModels(raw);\n}\n\n// ---------------------------------------------------------------------------\n// Skills\n// ---------------------------------------------------------------------------\n\ntype RawAgentSkill = {\n id?: string;\n name?: string;\n fqn?: string;\n latest_version?: {\n id?: string;\n fqn?: string;\n manifest?: {\n ml_repo?: string;\n source?: { description?: string };\n };\n };\n};\n\nexport function normalizeAgentSkills(raw: unknown): TfySkillSelectorEntry[] {\n const data =\n raw != null &&\n typeof raw === \"object\" &&\n Array.isArray((raw as { data?: unknown }).data)\n ? ((raw as { data: RawAgentSkill[] }).data)\n : [];\n const out: TfySkillSelectorEntry[] = [];\n for (const row of data) {\n const fqn = row.latest_version?.fqn;\n const name = row.name;\n if (fqn == null || fqn === \"\" || name == null || name === \"\") continue;\n const description = row.latest_version?.manifest?.source?.description;\n out.push({\n id: fqn,\n name,\n fqn,\n ...(description != null ? { description } : {}),\n });\n }\n return out;\n}\n\nexport async function listAgentSkills(\n opts: CpCredentials,\n): Promise<TfySkillSelectorEntry[]> {\n const raw = await cpFetch<unknown>(\n opts,\n \"/api/ml/v1/agent-skills?include_empty_agent_skills=false\",\n );\n return normalizeAgentSkills(raw);\n}\n\n// ---------------------------------------------------------------------------\n// MCP\n// ---------------------------------------------------------------------------\n\ntype RawMcpServer = {\n id?: string;\n name?: string;\n fqn?: string;\n manifest?: {\n description?: string;\n url?: string;\n auth_data?: { type?: string; auth_level?: string };\n };\n authStatus?: { status?: string };\n};\n\nexport function normalizeMcpServers(raw: unknown): TfyConnectorSelectorEntry[] {\n const data =\n raw != null &&\n typeof raw === \"object\" &&\n Array.isArray((raw as { data?: unknown }).data)\n ? ((raw as { data: RawMcpServer[] }).data)\n : [];\n const out: TfyConnectorSelectorEntry[] = [];\n const seen = new Set<string>();\n for (const row of data) {\n const mcpName = row.name;\n if (mcpName == null || mcpName === \"\" || seen.has(mcpName)) continue;\n seen.add(mcpName);\n const description = row.manifest?.description;\n const authenticated = row.authStatus?.status === \"authenticated\";\n out.push({\n id: mcpName,\n name: mcpName,\n mcpName,\n ...(description != null ? { description } : {}),\n ...(row.id != null ? { serverId: row.id } : { serverId: null }),\n authenticated,\n });\n }\n return out;\n}\n\nexport async function listMcpServers(\n opts: CpCredentials,\n): Promise<TfyConnectorSelectorEntry[]> {\n const raw = await cpFetch<unknown>(opts, \"/api/svc/v1/mcp-servers\");\n return normalizeMcpServers(raw);\n}\n\n// ---------------------------------------------------------------------------\n// Agents\n// ---------------------------------------------------------------------------\n\ntype RawAgent = {\n id?: string;\n name?: string;\n latestVersionDetails?: {\n manifest?: unknown;\n };\n /** Defensive: some payloads nest manifest at the top level. */\n manifest?: unknown;\n};\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction snakeToCamelKey(key: string): string {\n return key.replace(/_([a-z])/g, (_, letter: string) => letter.toUpperCase());\n}\n\n/** Deep snake_case → camelCase (inverse of {@link toSnakeCaseDeep}). */\nexport function toCamelCaseDeep(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(toCamelCaseDeep);\n }\n if (isRecord(value)) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n out[snakeToCamelKey(k)] = toCamelCaseDeep(v);\n }\n return out;\n }\n return value;\n}\n\n/**\n * Map a CP AgentManifest (snake_case wire) → FE AgentSpec for Edit seeding.\n * Skills/MCP keep `{ id, name }` for draft pickers plus runtime fields\n * (`enableTools`, `preload`, `config`) so Edit → Save does not widen tool\n * access or wipe settings. Gateway registry shapes are restored on save via\n * normalizeAgentSpecForGateway.\n */\nexport function agentSpecFromCpManifest(manifest: unknown): TfyAgentSpec | undefined {\n if (!isRecord(manifest)) return undefined;\n const modelRaw = manifest.model;\n if (!isRecord(modelRaw) || typeof modelRaw.name !== \"string\" || modelRaw.name === \"\") {\n return undefined;\n }\n const model = toCamelCaseDeep(modelRaw) as TfyAgentSpec[\"model\"];\n\n // Catalog-shaped mounts (`id`/`name` + runtime fields). Not yet gateway\n // registry unions — normalizeAgentSpecForGateway restores those on save.\n const skills: Array<Record<string, unknown>> = [];\n if (Array.isArray(manifest.skills)) {\n for (const row of manifest.skills) {\n if (!isRecord(row)) continue;\n const fqn =\n typeof row.fqn === \"string\" && row.fqn !== \"\"\n ? row.fqn\n : typeof row.id === \"string\" && row.id !== \"\"\n ? row.id\n : null;\n if (fqn == null) continue;\n const camel = toCamelCaseDeep(row) as Record<string, unknown>;\n const name =\n typeof camel.name === \"string\" && camel.name !== \"\"\n ? camel.name\n : fqn;\n skills.push({\n id: fqn,\n name,\n ...(typeof camel.preload === \"boolean\"\n ? { preload: camel.preload }\n : {}),\n ...(camel.config != null ? { config: camel.config } : {}),\n });\n }\n }\n\n const mcpServers: Array<Record<string, unknown>> = [];\n const mcpRaw = Array.isArray(manifest.mcp_servers)\n ? manifest.mcp_servers\n : Array.isArray(manifest.mcpServers)\n ? manifest.mcpServers\n : [];\n for (const row of mcpRaw) {\n if (!isRecord(row)) continue;\n const camel = toCamelCaseDeep(row) as Record<string, unknown>;\n const name =\n typeof camel.name === \"string\" && camel.name !== \"\"\n ? camel.name\n : typeof camel.id === \"string\" && camel.id !== \"\"\n ? camel.id\n : null;\n if (name == null) continue;\n mcpServers.push({\n id: name,\n name,\n ...(Array.isArray(camel.enableTools)\n ? { enableTools: camel.enableTools }\n : {}),\n ...(typeof camel.preload === \"boolean\"\n ? { preload: camel.preload }\n : {}),\n ...(camel.config != null ? { config: camel.config } : {}),\n });\n }\n\n const configRaw = manifest.config;\n const config =\n configRaw != null ? (toCamelCaseDeep(configRaw) as TfyAgentSpec[\"config\"]) : undefined;\n\n return {\n model,\n ...(typeof manifest.instructions === \"string\"\n ? { instructions: manifest.instructions }\n : {}),\n ...(config != null ? { config } : {}),\n ...(skills.length > 0 ? { skills } : {}),\n ...(mcpServers.length > 0 ? { mcpServers } : {}),\n } as TfyAgentSpec;\n}\n\nexport function normalizeAgents(raw: unknown): TfyAgentSelectorEntry[] {\n const data =\n raw != null &&\n typeof raw === \"object\" &&\n Array.isArray((raw as { data?: unknown }).data)\n ? ((raw as { data: RawAgent[] }).data)\n : [];\n const out: TfyAgentSelectorEntry[] = [];\n for (const row of data) {\n if (row.name == null || row.name === \"\") continue;\n const manifest = row.latestVersionDetails?.manifest ?? row.manifest;\n const agentSpec = agentSpecFromCpManifest(manifest);\n const agentId =\n typeof row.id === \"string\" && row.id !== \"\" ? row.id : row.name;\n out.push({\n name: row.name,\n agentId,\n ...(agentSpec != null ? { agentSpec } : {}),\n });\n }\n return out;\n}\n\nexport async function listAgents(\n opts: CpCredentials,\n req?: SearchAgentSelectorParams,\n): Promise<TfyAgentSelectorEntry[]> {\n const limit = req?.limit ?? 50;\n const offset = req?.offset ?? 0;\n const namePrefix = req?.query ?? \"\";\n const qs = new URLSearchParams({\n type: \"truefoundry-agent\",\n limit: String(limit),\n offset: String(offset),\n namePrefix,\n });\n const raw = await cpFetch<unknown>(\n opts,\n `/api/svc/v1/agents?${qs.toString()}`,\n );\n return normalizeAgents(raw);\n}\n\n// ---------------------------------------------------------------------------\n// Save agent (PUT upsert by name)\n// ---------------------------------------------------------------------------\n\n/** Platform feature flags baked into every saved agent manifest. */\nexport const SAVE_AGENT_METADATA_TAGS = {\n agent: \"tfy-ai-gateway-agent\",\n TFY_ALPHA_ENABLE_OPENUI: \"true\",\n TFY_ALPHA_ENABLE_ASK_USER: \"true\",\n TFY_ALPHA_ENABLE_ASK_SECRET: \"true\",\n TFY_ALPHA_CONTEXT_MANAGEMENT:\n '{\"large_tool_response\":{\"individual_tool_response_token_threshold\":8000}}',\n TFY_ALPHA_ENABLE_FILE_DOWNLOAD: \"true\",\n} as const;\n\n/** Default ACL on create/update — everyone on the tenant gets agent-access. */\nexport const SAVE_AGENT_COLLABORATORS = [\n { subject: \"team:everyone\", role_id: \"agent-access\" },\n] as const;\n\nfunction camelToSnakeKey(key: string): string {\n return key.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);\n}\n\n/** Deep camelCase → snake_case for CP wire (model.params, config, mounts). */\nexport function toSnakeCaseDeep(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(toSnakeCaseDeep);\n }\n if (value != null && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[camelToSnakeKey(k)] = toSnakeCaseDeep(v);\n }\n return out;\n }\n return value;\n}\n\nfunction mcpMountForCp(mount: unknown): Record<string, unknown> {\n const snake = toSnakeCaseDeep(mount) as Record<string, unknown>;\n if (snake.type === \"truefoundry-mcp-registry\") {\n return {\n ...snake,\n enable_tools: snake.enable_tools ?? [\"@all\"],\n preload: snake.preload ?? false,\n };\n }\n return snake;\n}\n\nfunction skillMountForCp(mount: unknown): Record<string, unknown> {\n const snake = toSnakeCaseDeep(mount) as Record<string, unknown>;\n if (snake.type === \"truefoundry-skills-registry\") {\n return {\n ...snake,\n preload: snake.preload ?? false,\n };\n }\n return snake;\n}\n\n/**\n * Build CP `manifest` for `PUT /api/svc/v1/agents`.\n * Normalizes UI catalog mounts, snake_cases gateway fields, hardcodes type /\n * metadata_tags / collaborators.\n */\nexport function buildSaveAgentManifest(\n agentName: string,\n agentSpec: TfyAgentSpec,\n): Record<string, unknown> {\n const spec = normalizeAgentSpecForGateway(agentSpec);\n const mcpServers = (spec.mcpServers ?? []).map(mcpMountForCp);\n const skills = (spec.skills ?? []).map(skillMountForCp);\n // CP AgentManifest requires description; not on FE AgentSpec yet.\n const rawDescription = (agentSpec as { description?: unknown }).description;\n const description = typeof rawDescription === \"string\" ? rawDescription : \"\";\n\n return {\n type: \"truefoundry-agent\",\n name: agentName,\n description,\n model: toSnakeCaseDeep(spec.model),\n metadata_tags: { ...SAVE_AGENT_METADATA_TAGS },\n collaborators: [...SAVE_AGENT_COLLABORATORS],\n ...(spec.instructions != null ? { instructions: spec.instructions } : {}),\n ...(spec.config != null ? { config: toSnakeCaseDeep(spec.config) } : {}),\n ...(mcpServers.length > 0 ? { mcp_servers: mcpServers } : {}),\n ...(skills.length > 0 ? { skills } : {}),\n };\n}\n\n/**\n * Upsert a named agent on the Control Plane.\n * `PUT /api/svc/v1/agents` with `{ manifest }` — name is the upsert key.\n */\nexport async function saveAgent(\n opts: CpCredentials,\n req: { agentName: string; agentSpec: TfyAgentSpec },\n): Promise<unknown> {\n const manifest = buildSaveAgentManifest(req.agentName, req.agentSpec);\n return cpFetch(opts, \"/api/svc/v1/agents\", {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ manifest }),\n });\n}\n","import type { AgentBuilderServer } from \"../../server/types.js\";\nimport {\n listAgents,\n listAgentSkills,\n listEnabledModels,\n listMcpServers,\n resolveGatewayURL,\n saveAgent,\n type TfyAgentSelectorEntry,\n type TfyConnectorSelectorEntry,\n type TfyModelSelectorEntry,\n type TfySkillSelectorEntry,\n} from \"./cp.js\";\nimport {\n createTrueFoundryChatServer,\n type TrueFoundryChatServer,\n} from \"./chatServer.js\";\nimport type { TfyAgentSpec } from \"./types.js\";\n\nexport type CreateTrueFoundryAgentUIServerOptions = {\n apiKey: string;\n /** Control Plane base URL (builder lists + optional /session for gateway resolve). */\n cpURL: string;\n /**\n * Gateway base URL. When omitted, resolved via\n * `GET {cpURL}/api/svc/v1/session` → `{cpURL}{env.LLM_GATEWAY_URL ?? \"/api/llm\"}/{tenantName}`.\n * Session failure throws (no silent public-gateway fallback).\n */\n gatewayURL?: string;\n};\n\nexport type TrueFoundryAgentUIServer<TSpec extends TfyAgentSpec = TfyAgentSpec> =\n TrueFoundryChatServer<TSpec> &\n AgentBuilderServer<\n TSpec,\n TfyModelSelectorEntry,\n TfySkillSelectorEntry,\n TfyConnectorSelectorEntry,\n TfyAgentSelectorEntry,\n unknown\n >;\n\nfunction credentialsKey(opts: CreateTrueFoundryAgentUIServerOptions): string {\n return `${opts.apiKey}\\0${opts.cpURL}\\0${opts.gatewayURL ?? \"\"}`;\n}\n\nconst inflight = new Map<\n string,\n Promise<TrueFoundryAgentUIServer<TfyAgentSpec>>\n>();\n\n/**\n * Full pack: gateway chat + Control Plane builder lists.\n *\n * Same `apiKey` bearer is used for CP and gateway. Concurrent calls with the\n * same credentials share one in-flight promise (React Strict Mode safe).\n */\nexport async function createTrueFoundryAgentUIServer<\n TSpec extends TfyAgentSpec = TfyAgentSpec,\n>(\n opts: CreateTrueFoundryAgentUIServerOptions,\n): Promise<TrueFoundryAgentUIServer<TSpec>> {\n const key = credentialsKey(opts);\n const existing = inflight.get(key);\n if (existing != null) {\n return existing as Promise<TrueFoundryAgentUIServer<TSpec>>;\n }\n\n const promise = (async () => {\n const baseUrl = await resolveGatewayURL(opts);\n const chat = createTrueFoundryChatServer<TSpec>({\n apiKey: opts.apiKey,\n baseUrl,\n });\n const cp = { apiKey: opts.apiKey, cpURL: opts.cpURL };\n\n const server: TrueFoundryAgentUIServer<TSpec> = {\n ...chat,\n getModels: () => listEnabledModels(cp),\n getSkills: () => listAgentSkills(cp),\n getMcp: () => listMcpServers(cp),\n searchAgents: (req) => listAgents(cp, req),\n saveAgent: (req) => saveAgent(cp, req),\n };\n return server as TrueFoundryAgentUIServer<TfyAgentSpec>;\n })();\n\n inflight.set(key, promise);\n try {\n return (await promise) as TrueFoundryAgentUIServer<TSpec>;\n } finally {\n inflight.delete(key);\n }\n}\n","/**\n * Point-of-use narrowing for the event half of the gateway protocol.\n *\n * `AgentChatServer` hardcodes the runtime's event types on listEvents,\n * listTurnEvents, subscribeToTurn and createTurn — there is no\n * generic to override them from here. So instead of typing those channels,\n * hosts call these guards on the values they receive.\n *\n * They validate rather than cast: this data comes off the network, and the\n * runtime types the relevant fields as `unknown` precisely because nothing\n * has checked them yet.\n */\n\nimport type {\n TfyMcpServerInitInfo,\n TfyMcpToolInfo,\n TfyModelMessageUsage,\n TfySystemToolInfo,\n TfyThreadState,\n TfyToolInfo,\n} from \"./types.js\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction hasNumbers<K extends string>(\n value: unknown,\n keys: readonly K[],\n): value is Record<string, unknown> & Record<K, number> {\n return isRecord(value) && keys.every((key) => typeof value[key] === \"number\");\n}\n\n/**\n * Identifies built-in tools such as `ask_user_question` and `create_sub_agent`.\n * Note `toolInfo` is legitimately absent on streamed deltas, so callers must\n * keep their `function.name` fallback rather than treating absence as an error.\n */\nexport function isTfySystemToolInfo(\n toolInfo: unknown,\n): toolInfo is TfySystemToolInfo {\n return (\n isRecord(toolInfo) &&\n toolInfo.type === \"truefoundry-system\" &&\n typeof toolInfo.name === \"string\"\n );\n}\n\n/** Carries `serverId` / `serverName`, so the UI can attribute a call to its MCP server. */\nexport function isTfyMcpToolInfo(toolInfo: unknown): toolInfo is TfyMcpToolInfo {\n return (\n isRecord(toolInfo) &&\n toolInfo.type === \"mcp\" &&\n typeof toolInfo.name === \"string\" &&\n typeof toolInfo.serverId === \"string\" &&\n typeof toolInfo.serverName === \"string\"\n );\n}\n\nexport function isTfyToolInfo(toolInfo: unknown): toolInfo is TfyToolInfo {\n return isTfySystemToolInfo(toolInfo) || isTfyMcpToolInfo(toolInfo);\n}\n\nconst USAGE_BREAKDOWN_KEYS = [\n \"harness\",\n \"skills\",\n \"instructions\",\n \"toolDefinitions\",\n \"messages\",\n] as const;\n\n/**\n * Token usage including the TrueFoundry-specific `inputTokensBreakdown`, which\n * attributes input tokens across harness, skills, instructions, tool\n * definitions and messages.\n */\nexport function getTfyUsage(\n source: { usage?: unknown } | null | undefined,\n): TfyModelMessageUsage | undefined {\n const usage = source?.usage;\n if (!hasNumbers(usage, [\"inputTokens\", \"outputTokens\"])) {\n return undefined;\n }\n if (!hasNumbers(usage.inputTokensBreakdown, USAGE_BREAKDOWN_KEYS)) {\n return undefined;\n }\n return usage as unknown as TfyModelMessageUsage;\n}\n\n/**\n * Completion state of a sub-agent thread. The runtime types `thread.done`'s\n * `state` as `unknown`, so a sub-agent that errored is otherwise\n * indistinguishable from one that succeeded.\n */\nexport function getTfyThreadState(\n event: { state?: unknown } | null | undefined,\n): TfyThreadState | undefined {\n const state = event?.state;\n if (!isRecord(state)) {\n return undefined;\n }\n if (state.status === \"done\" && isRecord(state.output)) {\n return state as unknown as TfyThreadState;\n }\n if (state.status === \"error\" && typeof state.error === \"string\") {\n return state as unknown as TfyThreadState;\n }\n return undefined;\n}\n\n/**\n * Servers from an `mcp.initialize` event, including each one's `transportType`.\n * The runtime models this event with an index signature, so the array is\n * `unknown` until checked.\n */\nexport function getTfyMcpInitServers(\n event: { mcpServers?: unknown } | null | undefined,\n): TfyMcpServerInitInfo[] | undefined {\n const servers = event?.mcpServers;\n if (!Array.isArray(servers)) {\n return undefined;\n }\n const valid = servers.every(\n (server) =>\n isRecord(server) &&\n typeof server.id === \"string\" &&\n typeof server.name === \"string\",\n );\n return valid ? (servers as TfyMcpServerInitInfo[]) : undefined;\n}\n"],"mappings":"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","names":["inflight","isRecord","isRecord"]}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as _assistant_ui_core from '@assistant-ui/core';
2
2
  import { ExternalStoreSharedOptions, AttachmentAdapter, SpeechSynthesisAdapter, DictationAdapter, RealtimeVoiceAdapter, FeedbackAdapter, ThreadAssistantMessagePart, ThreadMessage, AppendMessage, ExportedMessageRepositoryItem, RemoteThreadListAdapter } from '@assistant-ui/core';
3
- import { A as AgentSpec, a as AgentChatServer, T as TurnEvent, b as ThreadCreatedEvent, U as UserToolResponseEvent, M as McpAuthRequiredEvent, c as UserToolApprovalEvent, d as Turn, e as TurnInputItem, S as Session } from './types-CgZUnILu.js';
4
- export { f as AgentBuilderServer, g as AgentUIServerPort, C as CatalogServer, h as ConnectorAuth, i as ConnectorAuthApiKey, j as ConnectorAuthNone, k as ConnectorAuthOAuth, l as ConnectorAuthPublic, m as ConnectorAuthPublicApiKey, n as ConnectorAuthPublicNone, o as ConnectorAuthPublicOAuth, p as ConnectorAuthType, q as ConnectorBase, r as ConnectorCatalogEntry, s as ConnectorCatalogServer, t as ConnectorConfigBase, u as CreateConnectorRequest, v as CreateModelProviderRequest, w as CreateSandboxRequest, x as CreateSessionRequest, y as CreateSkillRequest, z as CreateSkillRequestBase, D as DefinedSkill, G as GithubSkill, I as ImportGithubSkillRequest, L as ListResult, B as ListSessionsParams, E as ModelCatalogServer, F as ModelEntry, H as ModelMessageEvent, J as ModelProviderBase, K as ModelProviderCatalogEntry, N as ModelProviderConfigBase, P as PreviousTurnIdInput, O as ProviderType, R as RegistrySkill, Q as SandboxBase, V as SandboxCatalogEntry, W as SandboxCatalogServer, X as SandboxConfig, Y as SandboxCreatedEvent, Z as SelectRegistrySkillRequest, _ as SessionEventItem, $ as SkillBase, a0 as SkillCatalogEntry, a1 as SkillCatalogServer, a2 as SkillConfigBase, a3 as ToolApprovalRequiredEvent, a4 as ToolBase, a5 as ToolCall, a6 as ToolResponseRequiredEvent, a7 as TurnState, a8 as TurnStateDone, a9 as TurnStreamData, aa as TurnStreamingEvent, ab as UpdateConnectorRequest, ac as UpdateModelProviderRequest, ad as UpdateSandboxRequest, ae as UpdateSessionRequest, af as UserMessage } from './types-CgZUnILu.js';
3
+ import { A as AgentSpec, a as AgentChatServer, T as TurnEvent, b as ThreadCreatedEvent, U as UserToolResponseEvent, M as McpAuthRequiredEvent, c as UserToolApprovalEvent, d as Turn, e as TurnInputItem, S as Session } from './types-Bb8Kaf1h.js';
4
+ export { f as AgentBuilderServer, g as AgentUIServerPort, C as CatalogServer, h as ConnectorAuth, i as ConnectorAuthApiKey, j as ConnectorAuthNone, k as ConnectorAuthOAuth, l as ConnectorAuthPublic, m as ConnectorAuthPublicApiKey, n as ConnectorAuthPublicNone, o as ConnectorAuthPublicOAuth, p as ConnectorAuthType, q as ConnectorBase, r as ConnectorCatalogEntry, s as ConnectorCatalogServer, t as ConnectorConfigBase, u as CreateConnectorRequest, v as CreateModelProviderRequest, w as CreateSandboxRequest, x as CreateSessionRequest, y as CreateSkillRequest, z as CreateSkillRequestBase, D as DefinedSkill, G as GithubSkill, I as ImportGithubSkillRequest, L as ListResult, B as ListSessionsParams, E as ModelCatalogServer, F as ModelEntry, H as ModelMessageEvent, J as ModelProviderBase, K as ModelProviderCatalogEntry, N as ModelProviderConfigBase, P as PreviousTurnIdInput, O as ProviderType, R as RegistrySkill, Q as SandboxBase, V as SandboxCatalogEntry, W as SandboxCatalogServer, X as SandboxConfig, Y as SandboxCreatedEvent, Z as SelectRegistrySkillRequest, _ as SessionEventItem, $ as SkillBase, a0 as SkillCatalogEntry, a1 as SkillCatalogServer, a2 as SkillConfigBase, a3 as ToolApprovalRequiredEvent, a4 as ToolBase, a5 as ToolCall, a6 as ToolResponseRequiredEvent, a7 as TurnState, a8 as TurnStateDone, a9 as TurnStreamData, aa as TurnStreamingEvent, ab as UpdateConnectorRequest, ac as UpdateModelProviderRequest, ad as UpdateSandboxRequest, ae as UpdateSessionRequest, af as UserMessage } from './types-Bb8Kaf1h.js';
5
5
  import * as _assistant_ui_core_internal from '@assistant-ui/core/internal';
6
6
  export { isEventDelta, mergeEventDelta } from './server/index.js';
7
7
  export { CreateTrueFoundryAgentUIServerOptions, CreateTrueFoundryChatServerOptions, RequireApprovalToolSelectorItem, RequireApprovalToolsSelectorTag, TfyAgentSelectorEntry, TfyAgentSpec, TfyConnectorSelectorEntry, TfyCreateSessionRequest, TfyFinishReason, TfyListSessionsParams, TfyMcpServerInitInfo, TfyMcpServerMount, TfyMcpToolInfo, TfyModelMessageUsage, TfyModelParams, TfyModelSelectorEntry, TfyResponseFormat, TfyRuntimeConfig, TfySession, TfySkillMount, TfySkillSelectorEntry, TfySubject, TfySystemToolInfo, TfyThreadState, TfyToolInfo, TfyTurn, TfyTurnCancelledReason, TfyTurnState, TfyTurnStateDoneOutput, ToolsSelectorItem, ToolsSelectorTag, TrueFoundryAgentUIServer, TrueFoundryChatServer, createTrueFoundryAgentUIServer, createTrueFoundryChatServer, getTfyMcpInitServers, getTfyThreadState, getTfyUsage, isTfyMcpToolInfo, isTfySystemToolInfo, isTfyToolInfo } from './plugins/truefoundry-agent-server-adapter/index.js';
@@ -26,6 +26,11 @@ type TrueFoundryAgentRuntimeBaseOptions = ExternalStoreSharedOptions & {
26
26
  onThreadIdChange?: ((threadId: string | undefined) => void) | undefined;
27
27
  onError?: ((error: unknown) => void) | undefined;
28
28
  listEventsConcurrency?: number | undefined;
29
+ /**
30
+ * Optional filter forwarded to `listSessions({ agentId })`.
31
+ * Omit for all chats; hosts that key agents by name pass that name as the id.
32
+ */
33
+ listSessionsAgentId?: string | undefined;
29
34
  adapters?: {
30
35
  attachments?: AttachmentAdapter | undefined;
31
36
  speech?: SpeechSynthesisAdapter | undefined;
@@ -181,6 +186,8 @@ declare function createTrueFoundryDraftThreadListAdapter(options: {
181
186
  server: AgentChatServer;
182
187
  defaultAgentSpec: AgentSpec;
183
188
  getAgentSpec?: () => AgentSpec;
189
+ /** When set, filters `listSessions` by this agent id. Omit for all chats. */
190
+ listSessionsAgentId?: string;
184
191
  }): RemoteThreadListAdapter;
185
192
 
186
193
  /**
@@ -189,6 +196,8 @@ declare function createTrueFoundryDraftThreadListAdapter(options: {
189
196
  */
190
197
  declare function createTrueFoundryOwnedSessionsThreadListAdapter(options: {
191
198
  server: AgentChatServer;
199
+ /** When set, filters `listSessions` by this agent id. Omit for all chats. */
200
+ listSessionsAgentId?: string;
192
201
  }): RemoteThreadListAdapter;
193
202
 
194
203
  type DraftSessionBridge = {
@@ -312,6 +321,8 @@ declare function findPausedAssistantMessage(messages: readonly ThreadMessage[]):
312
321
  declare function createTrueFoundryThreadListAdapter(options: {
313
322
  server: AgentChatServer;
314
323
  agentName: string;
324
+ /** When set, filters `listSessions` by this agent id. Omit for all chats. */
325
+ listSessionsAgentId?: string;
315
326
  }): RemoteThreadListAdapter;
316
327
 
317
328
  /** `sessionId` is the assistant-ui thread `remoteId` from `RemoteThreadListAdapter.initialize`. */
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  isTfyMcpToolInfo,
12
12
  isTfySystemToolInfo,
13
13
  isTfyToolInfo
14
- } from "./chunk-BRPTG6VA.js";
14
+ } from "./chunk-6ZOGBD7E.js";
15
15
 
16
16
  // src/useTrueFoundryAgentRuntime.ts
17
17
  import {
@@ -2415,6 +2415,13 @@ function createDraftSessionBridge(server) {
2415
2415
  };
2416
2416
  }
2417
2417
 
2418
+ // src/sessionListStartTimestamp.ts
2419
+ function sessionListStartTimestamp() {
2420
+ const start = /* @__PURE__ */ new Date();
2421
+ start.setFullYear(start.getFullYear() - 1);
2422
+ return start.toISOString();
2423
+ }
2424
+
2418
2425
  // src/draft/agentSpec.ts
2419
2426
  function mergeAgentSpec(base, update) {
2420
2427
  const { model: modelUpdate, ...rest } = update;
@@ -2436,33 +2443,47 @@ function draftSessionTitle(draft) {
2436
2443
  return draft.title ?? draft.agentSpec.model.name;
2437
2444
  }
2438
2445
 
2439
- // src/sessionListStartTimestamp.ts
2440
- function sessionListStartTimestamp() {
2441
- const start = /* @__PURE__ */ new Date();
2442
- start.setFullYear(start.getFullYear() - 1);
2443
- return start.toISOString();
2446
+ // src/sessionThreadMetadata.ts
2447
+ function sessionDisplayTitle(session, defaultAgentSpec) {
2448
+ if (session.isMutable) {
2449
+ const agentSpec = session.agentSpec ?? defaultAgentSpec;
2450
+ if (agentSpec != null) {
2451
+ return draftSessionTitle({
2452
+ title: session.title,
2453
+ agentSpec
2454
+ });
2455
+ }
2456
+ }
2457
+ return session.title ?? session.agentName ?? session.id;
2458
+ }
2459
+ function sessionToThreadMetadata(session, title) {
2460
+ return {
2461
+ status: "regular",
2462
+ remoteId: session.id,
2463
+ title,
2464
+ lastMessageAt: new Date(session.updatedAt),
2465
+ ...session.agentName != null ? { custom: { agentName: session.agentName } } : {}
2466
+ };
2444
2467
  }
2445
2468
 
2446
2469
  // src/draft/truefoundryDraftThreadListAdapter.ts
2447
2470
  var THREAD_LIST_PAGE_SIZE = 20;
2448
2471
  function createTrueFoundryDraftThreadListAdapter(options) {
2449
- const { server, defaultAgentSpec, getAgentSpec } = options;
2472
+ const { server, defaultAgentSpec, getAgentSpec, listSessionsAgentId } = options;
2450
2473
  return {
2451
2474
  async list({ after } = {}) {
2452
2475
  const page = await server.listSessions({
2476
+ ...listSessionsAgentId != null ? { agentId: listSessionsAgentId } : {},
2453
2477
  limit: THREAD_LIST_PAGE_SIZE,
2454
2478
  pageToken: after,
2455
2479
  startTimestamp: sessionListStartTimestamp()
2456
2480
  });
2457
- const threads = page.data.filter((session) => session.isMutable).map((draft) => ({
2458
- status: "regular",
2459
- remoteId: draft.id,
2460
- title: draftSessionTitle({
2461
- title: draft.title,
2462
- agentSpec: draft.agentSpec ?? defaultAgentSpec
2463
- }),
2464
- lastMessageAt: new Date(draft.updatedAt)
2465
- }));
2481
+ const threads = page.data.map(
2482
+ (session) => sessionToThreadMetadata(
2483
+ session,
2484
+ sessionDisplayTitle(session, defaultAgentSpec)
2485
+ )
2486
+ );
2466
2487
  return {
2467
2488
  threads,
2468
2489
  nextCursor: page.nextPageToken ?? void 0
@@ -2476,15 +2497,10 @@ function createTrueFoundryDraftThreadListAdapter(options) {
2476
2497
  },
2477
2498
  async fetch(remoteId) {
2478
2499
  const draft = await server.getSession({ sessionId: remoteId });
2479
- return {
2480
- status: "regular",
2481
- remoteId: draft.id,
2482
- title: draftSessionTitle({
2483
- title: draft.title,
2484
- agentSpec: draft.agentSpec ?? defaultAgentSpec
2485
- }),
2486
- lastMessageAt: new Date(draft.updatedAt)
2487
- };
2500
+ return sessionToThreadMetadata(
2501
+ draft,
2502
+ sessionDisplayTitle(draft, defaultAgentSpec)
2503
+ );
2488
2504
  },
2489
2505
  async rename() {
2490
2506
  },
@@ -2536,21 +2552,18 @@ function getSession(server, sessionId) {
2536
2552
  // src/truefoundryThreadListAdapter.ts
2537
2553
  var THREAD_LIST_PAGE_SIZE2 = 20;
2538
2554
  function createTrueFoundryThreadListAdapter(options) {
2539
- const { server, agentName } = options;
2555
+ const { server, agentName, listSessionsAgentId } = options;
2540
2556
  return {
2541
2557
  async list({ after } = {}) {
2542
2558
  const page = await server.listSessions({
2543
- agentName,
2559
+ ...listSessionsAgentId != null ? { agentId: listSessionsAgentId } : {},
2544
2560
  limit: THREAD_LIST_PAGE_SIZE2,
2545
2561
  pageToken: after,
2546
2562
  startTimestamp: sessionListStartTimestamp()
2547
2563
  });
2548
- const threads = page.data.map((session) => ({
2549
- status: "regular",
2550
- remoteId: session.id,
2551
- title: session.title ?? void 0,
2552
- lastMessageAt: new Date(session.updatedAt)
2553
- }));
2564
+ const threads = page.data.map(
2565
+ (session) => sessionToThreadMetadata(session, session.title ?? void 0)
2566
+ );
2554
2567
  return {
2555
2568
  threads,
2556
2569
  nextCursor: page.nextPageToken ?? void 0
@@ -2562,12 +2575,7 @@ function createTrueFoundryThreadListAdapter(options) {
2562
2575
  },
2563
2576
  async fetch(remoteId) {
2564
2577
  const session = await getSession(server, remoteId);
2565
- return {
2566
- status: "regular",
2567
- remoteId: session.id,
2568
- title: session.title ?? void 0,
2569
- lastMessageAt: new Date(session.updatedAt)
2570
- };
2578
+ return sessionToThreadMetadata(session, session.title ?? void 0);
2571
2579
  },
2572
2580
  async rename() {
2573
2581
  },
@@ -3926,20 +3934,23 @@ function useTrueFoundryAgentRuntime(options) {
3926
3934
  );
3927
3935
  const agentMode = agent.mode;
3928
3936
  const namedAgentName = agent.mode === "named" ? agent.agentName : void 0;
3937
+ const listSessionsAgentId = resolved.listSessionsAgentId;
3929
3938
  const threadListAdapter = useMemo3(() => {
3930
3939
  if (agentMode === "draft") {
3931
3940
  const draftAgent = agent;
3932
3941
  return createTrueFoundryDraftThreadListAdapter({
3933
3942
  server,
3934
3943
  defaultAgentSpec: draftAgent.defaultAgentSpec,
3935
- getAgentSpec: () => pendingAgentSpecRef.current ?? draftAgent.defaultAgentSpec
3944
+ getAgentSpec: () => pendingAgentSpecRef.current ?? draftAgent.defaultAgentSpec,
3945
+ listSessionsAgentId
3936
3946
  });
3937
3947
  }
3938
3948
  return createTrueFoundryThreadListAdapter({
3939
3949
  server,
3940
- agentName: namedAgentName
3950
+ agentName: namedAgentName,
3951
+ listSessionsAgentId
3941
3952
  });
3942
- }, [agentMode, namedAgentName, server]);
3953
+ }, [agentMode, namedAgentName, listSessionsAgentId, server]);
3943
3954
  return useRemoteThreadListRuntime({
3944
3955
  allowNesting: true,
3945
3956
  adapter: threadListAdapter,
@@ -3952,30 +3963,19 @@ function useTrueFoundryAgentRuntime(options) {
3952
3963
 
3953
3964
  // src/truefoundryOwnedSessionsThreadListAdapter.ts
3954
3965
  var THREAD_LIST_PAGE_SIZE3 = 20;
3955
- function ownedSessionTitle(session) {
3956
- if (session.isMutable && session.agentSpec != null) {
3957
- return draftSessionTitle({
3958
- title: session.title,
3959
- agentSpec: session.agentSpec
3960
- });
3961
- }
3962
- return session.title ?? session.agentName ?? session.id;
3963
- }
3964
3966
  function createTrueFoundryOwnedSessionsThreadListAdapter(options) {
3965
- const { server } = options;
3967
+ const { server, listSessionsAgentId } = options;
3966
3968
  return {
3967
3969
  async list({ after } = {}) {
3968
3970
  const page = await server.listSessions({
3971
+ ...listSessionsAgentId != null ? { agentId: listSessionsAgentId } : {},
3969
3972
  limit: THREAD_LIST_PAGE_SIZE3,
3970
3973
  pageToken: after,
3971
3974
  startTimestamp: sessionListStartTimestamp()
3972
3975
  });
3973
- const threads = page.data.map((session) => ({
3974
- status: "regular",
3975
- remoteId: session.id,
3976
- title: ownedSessionTitle(session),
3977
- lastMessageAt: new Date(session.updatedAt)
3978
- }));
3976
+ const threads = page.data.map(
3977
+ (session) => sessionToThreadMetadata(session, sessionDisplayTitle(session))
3978
+ );
3979
3979
  return {
3980
3980
  threads,
3981
3981
  nextCursor: page.nextPageToken ?? void 0
@@ -3988,12 +3988,7 @@ function createTrueFoundryOwnedSessionsThreadListAdapter(options) {
3988
3988
  },
3989
3989
  async fetch(remoteId) {
3990
3990
  const session = await server.getSession({ sessionId: remoteId });
3991
- return {
3992
- status: "regular",
3993
- remoteId: session.id,
3994
- title: ownedSessionTitle(session),
3995
- lastMessageAt: new Date(session.updatedAt)
3996
- };
3991
+ return sessionToThreadMetadata(session, sessionDisplayTitle(session));
3997
3992
  },
3998
3993
  async rename() {
3999
3994
  },