@truefoundry/assistant-ui-runtime 0.1.10 → 0.1.12
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 +40 -0
- package/dist/{chunk-6ZOGBD7E.js → chunk-2NLIAJJX.js} +8 -1
- package/dist/{chunk-6ZOGBD7E.js.map → chunk-2NLIAJJX.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +13 -4
- package/dist/index.js.map +1 -1
- package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +3 -3
- package/dist/plugins/truefoundry-agent-server-adapter/index.js +1 -1
- package/dist/server/index.d.ts +2 -2
- package/dist/{types-Bb8Kaf1h.d.ts → types-CSRQSnHu.d.ts} +141 -78
- package/package.json +1 -1
- package/src/convertTurnMessages.test.ts +123 -0
- package/src/convertTurnMessages.ts +8 -2
- package/src/draft/truefoundryDraftThreadListAdapter.test.ts +3 -2
- package/src/index.ts +27 -0
- package/src/plugins/truefoundry-agent-server-adapter/createTrueFoundryAgentUIServer.ts +7 -0
- package/src/plugins/truefoundry-agent-server-adapter/types.ts +2 -2
- package/src/server/index.ts +15 -0
- package/src/server/types.ts +447 -385
- package/src/sessionThreadMetadata.ts +5 -2
- package/src/truefoundryOwnedSessionsThreadListAdapter.test.ts +2 -1
- package/src/truefoundryThreadListAdapter.test.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.12
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- **`SandboxCatalogServer` method renames (sandbox → sandbox provider)**
|
|
8
|
+
`getSandboxCatalog` → `getSandboxProviderCatalog`, `listSandboxes` → `listSandboxProviders`, `createSandbox` → `createSandboxProvider`, `updateSandbox` → `updateSandboxProvider`, `deleteSandbox` → `deleteSandboxProvider?` (now optional). Host aliases (`SandboxProviderConfig`, `SandboxProviderCatalogEntry`, `SandboxProviderBase`, `CreateSandboxProviderRequest`, `UpdateSandboxProviderRequest`) map to the existing DTO names.
|
|
9
|
+
|
|
10
|
+
- **`SandboxBase` now extends `SandboxConfig`**
|
|
11
|
+
Connected rows always carry last-saved provider settings so update forms can show previous values.
|
|
12
|
+
|
|
13
|
+
- **`UpdateSandboxRequest.apiKey` is optional**
|
|
14
|
+
Omit to keep the existing key; send a value to rotate.
|
|
15
|
+
|
|
16
|
+
- **`ConnectorBase.tools` removed**
|
|
17
|
+
Tools are no longer embedded on the connector row. Fetch with new required `ConnectorCatalogServer.getToolsByConnectorId({ id })`. `ConnectorBase` is no longer generic in `TTool`.
|
|
18
|
+
|
|
19
|
+
- **`ConnectorCatalogServer` adds required `getConnector` / `getToolsByConnectorId`**
|
|
20
|
+
Implement both on every catalog adapter.
|
|
21
|
+
|
|
22
|
+
- **`authenticateConnector` request/return changed**
|
|
23
|
+
Request is `AuthenticateConnectorRequest` (`id` + optional `redirectURL`). Return is `TConnector | ConnectorAuthenticationResult<TConnector>` — either an authenticated connector (or one carrying `auth.authUrl`) or a result with `authorization_endpoint` for the popup flow.
|
|
24
|
+
|
|
25
|
+
- **`ConnectorAuthPublicOAuth.authUrl` is optional**
|
|
26
|
+
Public dcr rows may omit `authUrl` when auth is started via `authorization_endpoint` instead. (Supersedes the 0.1.8 note that public dcr required `authUrl`.)
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- **Sole ownership of server-port types** — this package is the canonical home for `AgentChatServer` / `AgentBuilderServer` / catalog ports and DTOs. Hosts (e.g. trueforge-ui) should re-export, not fork.
|
|
31
|
+
- **`AgentUIServer`** — host-facing alias of `AgentUIServerPort`.
|
|
32
|
+
- **Selector / compose aliases** — `ModelSelection`, `AgentSkill`, `ConnectorState`, `AgentLibraryEntry`, `SearchAgentsParams` (aliases of the `*SelectorEntry` / `SearchAgentSelectorParams` names).
|
|
33
|
+
- **Root exports** for builder/catalog types previously internal to `server/` (`SaveAgentRequest`, `AgentBuilderCapabilitiesResponse`, `AuthenticateConnectorRequest`, `ConnectorAuthenticationResult`, mounts, selector entries, sandbox-provider aliases, etc.).
|
|
34
|
+
- **`ModelSelectorEntry.providerLogo?`**, **`ConnectorSelectorEntry.requiresAuth?` / `authenticated?`**, **`ModelProviderCatalogEntry.supportedReasoningEfforts?` / `logo?`**, **`ConnectorCatalogEntry.logo?`**.
|
|
35
|
+
- **`SaveAgentRequest`** — named request body for `AgentBuilderServer.saveAgent`.
|
|
36
|
+
- **`createTrueFoundryAgentUIServer.getCapabilities`** — returns sandbox / skill / settings enabled (stub; always `true` for this pack).
|
|
37
|
+
- **`PreviousTurnIdInput` documents `"none"`** alongside `"auto"` and turn ids.
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- **`sessionToThreadMetadata`** — always stamps `custom.isMutable` from the session (plus `agentName` when present). History UIs can trust mutability without inferring it from `agentName`, so ref sessions whose agent was deleted stay immutable.
|
|
42
|
+
|
|
3
43
|
## 0.1.10
|
|
4
44
|
|
|
5
45
|
### Breaking
|
|
@@ -632,6 +632,13 @@ async function createTrueFoundryAgentUIServer(opts) {
|
|
|
632
632
|
const cp = { apiKey: opts.apiKey, cpURL: opts.cpURL };
|
|
633
633
|
const server = {
|
|
634
634
|
...chat,
|
|
635
|
+
getCapabilities: async () => ({
|
|
636
|
+
data: {
|
|
637
|
+
sandbox: { enabled: true },
|
|
638
|
+
skill: { enabled: true },
|
|
639
|
+
settings: { enabled: true }
|
|
640
|
+
}
|
|
641
|
+
}),
|
|
635
642
|
getModels: () => listEnabledModels(cp),
|
|
636
643
|
getSkills: () => listAgentSkills(cp),
|
|
637
644
|
getMcp: () => listMcpServers(cp),
|
|
@@ -715,4 +722,4 @@ export {
|
|
|
715
722
|
getTfyThreadState,
|
|
716
723
|
getTfyMcpInitServers
|
|
717
724
|
};
|
|
718
|
-
//# sourceMappingURL=chunk-
|
|
725
|
+
//# sourceMappingURL=chunk-2NLIAJJX.js.map
|
|
@@ -1 +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"]}
|
|
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 getCapabilities: async () => ({\n data: {\n sandbox: { enabled: true },\n skill: { enabled: true },\n settings: { enabled: true },\n },\n }),\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-
|
|
4
|
-
export { f as
|
|
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-CSRQSnHu.js';
|
|
4
|
+
export { f as AgentBuilderCapabilitiesResponse, g as AgentBuilderServer, h as AgentLibraryEntry, i as AgentSelectorEntry, j as AgentSkill, k as AgentUIServer, l as AgentUIServerPort, m as ApprovalDecision, n as AuthenticateConnectorRequest, C as CatalogServer, o as ConnectorAuth, p as ConnectorAuthApiKey, q as ConnectorAuthNone, r as ConnectorAuthOAuth, s as ConnectorAuthPublic, t as ConnectorAuthPublicApiKey, u as ConnectorAuthPublicNone, v as ConnectorAuthPublicOAuth, w as ConnectorAuthType, x as ConnectorAuthenticationResult, y as ConnectorBase, z as ConnectorCatalogEntry, B as ConnectorCatalogServer, D as ConnectorConfigBase, E as ConnectorSelectorEntry, F as ConnectorState, G as CreateConnectorRequest, H as CreateModelProviderRequest, I as CreateSandboxProviderRequest, J as CreateSandboxRequest, K as CreateSessionRequest, L as CreateSkillRequest, N as CreateSkillRequestBase, O as DefinedSkill, P as GithubSkill, Q as ImportGithubSkillRequest, R as ListResult, V as ListSessionsOrder, W as ListSessionsParams, X as McpServerMount, Y as Model, Z as ModelCatalogServer, _ as ModelEntry, $ as ModelMessageEvent, a0 as ModelParams, a1 as ModelProviderBase, a2 as ModelProviderCatalogEntry, a3 as ModelProviderConfigBase, a4 as ModelSelection, a5 as ModelSelectorEntry, a6 as PageParams, a7 as PreviousTurnIdInput, a8 as ProviderType, a9 as RegistrySkill, aa as SandboxBase, ab as SandboxCatalogEntry, ac as SandboxCatalogServer, ad as SandboxConfig, ae as SandboxCreatedEvent, af as SandboxProviderBase, ag as SandboxProviderCatalogEntry, ah as SandboxProviderConfig, ai as SaveAgentRequest, aj as SearchAgentSelectorParams, ak as SearchAgentsParams, al as SelectRegistrySkillRequest, am as SessionEventItem, an as SkillBase, ao as SkillCatalogEntry, ap as SkillCatalogServer, aq as SkillConfigBase, ar as SkillMount, as as SkillSelectorEntry, at as ToolApprovalRequiredEvent, au as ToolBase, av as ToolCall, aw as ToolResponseRequiredEvent, ax as TurnState, ay as TurnStateDone, az as TurnStreamData, aA as TurnStreamingEvent, aB as UpdateConnectorRequest, aC as UpdateModelProviderRequest, aD as UpdateSandboxProviderRequest, aE as UpdateSandboxRequest, aF as UpdateSessionRequest, aG as UserMessage } from './types-CSRQSnHu.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';
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
isTfyMcpToolInfo,
|
|
12
12
|
isTfySystemToolInfo,
|
|
13
13
|
isTfyToolInfo
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-2NLIAJJX.js";
|
|
15
15
|
|
|
16
16
|
// src/useTrueFoundryAgentRuntime.ts
|
|
17
17
|
import {
|
|
@@ -1892,9 +1892,11 @@ function projectHistoryTurns(snapshot, options) {
|
|
|
1892
1892
|
const messages = [];
|
|
1893
1893
|
let lastAssistantIndex;
|
|
1894
1894
|
let groupRootIds = [];
|
|
1895
|
+
let sandboxId;
|
|
1895
1896
|
for (let turnIndex = 0; turnIndex < snapshot.turns.length; turnIndex++) {
|
|
1896
1897
|
const record = snapshot.turns[turnIndex];
|
|
1897
1898
|
const turnRootIds = record.rootModelMessageIds ?? [];
|
|
1899
|
+
sandboxId = record.sandboxId ?? sandboxId;
|
|
1898
1900
|
if (record.userText) {
|
|
1899
1901
|
groupRootIds = [...turnRootIds];
|
|
1900
1902
|
} else {
|
|
@@ -1932,7 +1934,7 @@ function projectHistoryTurns(snapshot, options) {
|
|
|
1932
1934
|
const custom = {
|
|
1933
1935
|
...baseCustom,
|
|
1934
1936
|
turnId: record.id,
|
|
1935
|
-
...
|
|
1937
|
+
...sandboxId != null ? { sandboxId } : {}
|
|
1936
1938
|
};
|
|
1937
1939
|
if (record.userText) {
|
|
1938
1940
|
messages.push(
|
|
@@ -2378,7 +2380,11 @@ function turnStreamUpdateToAssistantMessage(turnId, update, existing, options) {
|
|
|
2378
2380
|
unstable_annotations: [],
|
|
2379
2381
|
unstable_data: [],
|
|
2380
2382
|
steps: [],
|
|
2381
|
-
custom: {
|
|
2383
|
+
custom: {
|
|
2384
|
+
...existing?.role === "assistant" ? existing.metadata.custom : {},
|
|
2385
|
+
...update.metadata?.custom,
|
|
2386
|
+
turnId
|
|
2387
|
+
}
|
|
2382
2388
|
}
|
|
2383
2389
|
};
|
|
2384
2390
|
}
|
|
@@ -2462,7 +2468,10 @@ function sessionToThreadMetadata(session, title) {
|
|
|
2462
2468
|
remoteId: session.id,
|
|
2463
2469
|
title,
|
|
2464
2470
|
lastMessageAt: new Date(session.updatedAt),
|
|
2465
|
-
|
|
2471
|
+
custom: {
|
|
2472
|
+
isMutable: session.isMutable,
|
|
2473
|
+
...session.agentName != null ? { agentName: session.agentName } : {}
|
|
2474
|
+
}
|
|
2466
2475
|
};
|
|
2467
2476
|
}
|
|
2468
2477
|
|