@truefoundry/assistant-ui-runtime 0.1.6-rc.0 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +193 -579
  2. package/dist/chunk-3A2EPLQG.js +93 -0
  3. package/dist/chunk-3A2EPLQG.js.map +1 -0
  4. package/dist/chunk-SQDOTGP2.js +292 -0
  5. package/dist/chunk-SQDOTGP2.js.map +1 -0
  6. package/dist/index.d.ts +24 -36
  7. package/dist/index.js +276 -249
  8. package/dist/index.js.map +1 -1
  9. package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +134 -5
  10. package/dist/plugins/truefoundry-agent-server-adapter/index.js +16 -195
  11. package/dist/plugins/truefoundry-agent-server-adapter/index.js.map +1 -1
  12. package/dist/server/index.d.ts +17 -0
  13. package/dist/server/index.js +9 -0
  14. package/dist/server/index.js.map +1 -0
  15. package/dist/{types-VUBzoJT2.d.ts → types-DbNsU075.d.ts} +212 -19
  16. package/package.json +10 -5
  17. package/src/{private → draft}/agentSpec.ts +14 -17
  18. package/src/{private → draft}/draftSessionBridge.ts +1 -2
  19. package/src/{private → draft}/truefoundryDraftThreadListAdapter.test.ts +1 -1
  20. package/src/{private → draft}/truefoundryDraftThreadListAdapter.ts +2 -1
  21. package/src/{private → draft}/useDraftAgentSpec.ts +16 -5
  22. package/src/draftAgentConfig.test.ts +2 -1
  23. package/src/index.ts +71 -7
  24. package/src/plugins/truefoundry-agent-server-adapter/README.md +178 -0
  25. package/src/plugins/truefoundry-agent-server-adapter/guards.test.ts +113 -0
  26. package/src/plugins/truefoundry-agent-server-adapter/guards.ts +130 -0
  27. package/src/plugins/truefoundry-agent-server-adapter/index.ts +154 -40
  28. package/src/plugins/truefoundry-agent-server-adapter/types.ts +137 -0
  29. package/src/plugins/truefoundry-agent-server-adapter/types.typecheck.ts +164 -0
  30. package/src/server/index.ts +23 -0
  31. package/src/server/types.ts +272 -21
  32. package/src/truefoundryExtras.ts +4 -1
  33. package/src/truefoundryOwnedSessionsThreadListAdapter.ts +1 -1
  34. package/src/types.ts +1 -2
  35. package/src/useTrueFoundryAgentMessages.test.tsx +261 -1
  36. package/src/useTrueFoundryAgentMessages.ts +284 -176
  37. package/src/useTrueFoundryAgentRuntime.ts +31 -21
  38. /package/src/{private → draft}/useDraftAgentSpec.test.tsx +0 -0
@@ -253,16 +253,22 @@ type SearchAgentSelectorParams = {
253
253
  limit?: number;
254
254
  offset?: number;
255
255
  };
256
- /** Skill mount base written to AgentSpec.skills[]. Host extends for fqn, preload, etc. */
257
- interface SkillMount {
258
- id: string;
259
- name: string;
260
- }
261
- /** MCP server mount base written to AgentSpec.mcpServers[]. Host extends for type, enableTools, etc. */
262
- interface McpServerMount {
263
- id: string;
264
- name: string;
265
- }
256
+ /**
257
+ * Mounts written to AgentSpec.skills[] / AgentSpec.mcpServers[].
258
+ *
259
+ * These are opaque to the runtime — it stores and forwards them but never reads
260
+ * a field, and the backend owns the shape (the gateway identifies a skill by
261
+ * `fqn`, with no `id` or `name` anywhere). So the base constrains only that a
262
+ * mount is an object; hosts intersect their concrete mount type over it, as
263
+ * `TfySkillMount` / `TfyMcpServerMount` do in the gateway adapter.
264
+ *
265
+ * Naming a field here would not just be unread, it would be wrong: a base with
266
+ * required fields rejects the backend's own payloads, and one with only optional
267
+ * fields is a weak type, which TypeScript rejects for a source that shares no
268
+ * property with it — the gateway's registry skill shares none.
269
+ */
270
+ type SkillMount = object;
271
+ type McpServerMount = object;
266
272
  interface ModelParams {
267
273
  maxTokens?: number;
268
274
  reasoningEffort?: string;
@@ -273,17 +279,15 @@ interface Model {
273
279
  }
274
280
  /**
275
281
  * SDK-owned agent definition — fields the FE reads/writes.
276
- * Host adds additional fields via `TSpec extends AgentSpec`.
282
+ * Host widens `model` / `skills` / `mcpServers` via type params, and adds
283
+ * extra fields via `TSpec extends AgentSpec<...>`.
277
284
  */
278
- interface AgentSpec {
279
- model: Model;
280
- skills?: SkillMount[];
281
- mcpServers?: McpServerMount[];
285
+ interface AgentSpec<TModel extends Model = Model, TSkill extends SkillMount = SkillMount, TMcp extends McpServerMount = McpServerMount> {
286
+ model: TModel;
287
+ skills?: TSkill[];
288
+ mcpServers?: TMcp[];
282
289
  instructions?: string;
283
- messages?: unknown[];
284
290
  variables?: Record<string, string>;
285
- responseFormat?: unknown;
286
- config?: unknown;
287
291
  }
288
292
  interface Session<TSpec extends AgentSpec = AgentSpec> {
289
293
  id: string;
@@ -458,5 +462,194 @@ interface AgentBuilderServer<TSpec extends AgentSpec = AgentSpec, TModel extends
458
462
  agentName: string;
459
463
  }): Promise<void>;
460
464
  }
465
+ /**
466
+ * Provider type id. Reserved literal: `"custom"` for user-defined providers;
467
+ * any other string is a builtin (e.g. `"openai"`, `"anthropic"`).
468
+ *
469
+ * Note: `string | "custom"` is useless in TypeScript (`"custom"` ⊆ `string`),
470
+ * so this stays `string` and `"custom"` is a documented convention.
471
+ */
472
+ type ProviderType = string;
473
+ /**
474
+ * Model row — form "Model ID" + "Display name".
475
+ * Host extends for properties, etc.
476
+ */
477
+ interface ModelEntry {
478
+ id: string;
479
+ name: string;
480
+ }
481
+ /**
482
+ * Write config for create/update (custom form + catalog "Save key").
483
+ * Host extends. `baseUrl` present iff `type === "custom"`.
484
+ */
485
+ interface ModelProviderConfigBase<TModel extends ModelEntry = ModelEntry> {
486
+ type: ProviderType;
487
+ name: string;
488
+ /** Present iff `type === "custom"`. */
489
+ baseUrl?: string;
490
+ apiKey: string;
491
+ models: TModel[];
492
+ }
493
+ /**
494
+ * Configured provider card (list/read). No raw `apiKey`.
495
+ * Host extends for apiKeySet, timestamps, etc.
496
+ */
497
+ interface ModelProviderBase<TModel extends ModelEntry = ModelEntry> {
498
+ id: string;
499
+ type: ProviderType;
500
+ name: string;
501
+ /** Present iff `type === "custom"`. */
502
+ baseUrl?: string;
503
+ models: TModel[];
504
+ }
505
+ /**
506
+ * Discovery-only catalog provider (AVAILABLE list).
507
+ * `type` must not be `"custom"` — custom providers use the custom form.
508
+ * Host extends for richer model rows.
509
+ */
510
+ interface ModelProviderCatalogEntry<TModel extends ModelEntry = ModelEntry> {
511
+ type: ProviderType;
512
+ name: string;
513
+ models: TModel[];
514
+ }
515
+ /** Create — no `id`; server assigns it. Catalog path = entry + apiKey. */
516
+ type CreateModelProviderRequest<TModel extends ModelEntry = ModelEntry> = ModelProviderConfigBase<TModel>;
517
+ /** Update — `id` required. */
518
+ type UpdateModelProviderRequest<TModel extends ModelEntry = ModelEntry> = ModelProviderConfigBase<TModel> & {
519
+ id: string;
520
+ };
521
+ interface ModelCatalogServer<TModel extends ModelEntry = ModelEntry, TProvider extends ModelProviderBase<TModel> = ModelProviderBase<TModel>, TCatalogProvider extends ModelProviderCatalogEntry<TModel> = ModelProviderCatalogEntry<TModel>, TCreate extends CreateModelProviderRequest<TModel> = CreateModelProviderRequest<TModel>, TUpdate extends UpdateModelProviderRequest<TModel> = UpdateModelProviderRequest<TModel>> {
522
+ getModelProviderCatalog(): Promise<TCatalogProvider[]>;
523
+ listModelProviders(): Promise<TProvider[]>;
524
+ createModelProvider(req: TCreate): Promise<TProvider>;
525
+ /** Full replace update keyed by provider `id`. */
526
+ updateModelProvider(req: TUpdate): Promise<TProvider>;
527
+ deleteModelProvider?(req: {
528
+ id: string;
529
+ }): Promise<void>;
530
+ }
531
+ /** Tool row on a connector detail. Host extends for schemas, etc. */
532
+ interface ToolBase {
533
+ id: string;
534
+ name: string;
535
+ }
536
+ /**
537
+ * Auth type id. Reserved literals: `"None"`, `"OAuth"`, `"API Key"`.
538
+ * Stays `string` so hosts can widen (same pattern as `ProviderType`).
539
+ */
540
+ type ConnectorAuthType = string;
541
+ /**
542
+ * Write-time connector auth. Host extends / narrows via `TType`.
543
+ * For `"API Key"`, pass `apiKey` (and optional `headerName`).
544
+ */
545
+ interface ConnectorAuth<TType extends ConnectorAuthType = ConnectorAuthType> {
546
+ type: TType;
547
+ apiKey?: string;
548
+ headerName?: string;
549
+ }
550
+ /**
551
+ * Catalog / list auth — no secrets. Host extends / narrows via `TType`.
552
+ */
553
+ interface ConnectorAuthPublic<TType extends ConnectorAuthType = ConnectorAuthType> {
554
+ type: TType;
555
+ headerName?: string;
556
+ }
557
+ /**
558
+ * MCP / connector create-edit config. Host extends for extra fields, etc.
559
+ */
560
+ interface ConnectorConfigBase<TAuth extends ConnectorAuth = ConnectorAuth> {
561
+ name: string;
562
+ url: string;
563
+ auth: TAuth;
564
+ }
565
+ /**
566
+ * Connected connector row (settings/connectors). No raw `apiKey`.
567
+ * Host extends.
568
+ */
569
+ interface ConnectorBase<TTool extends ToolBase = ToolBase, TAuth extends ConnectorAuthPublic = ConnectorAuthPublic> {
570
+ id: string;
571
+ name: string;
572
+ description: string;
573
+ url: string;
574
+ auth: TAuth;
575
+ authenticated: boolean;
576
+ tools: TTool[];
577
+ }
578
+ /** Discovery catalog entry for "+ Add MCP server". Host extends. */
579
+ interface ConnectorCatalogEntry<TAuth extends ConnectorAuthPublic = ConnectorAuthPublic> {
580
+ id: string;
581
+ name: string;
582
+ description?: string;
583
+ url: string;
584
+ auth: TAuth;
585
+ }
586
+ /** Create connector — no `id`; server assigns it. Host extends. */
587
+ type CreateConnectorRequest<TAuth extends ConnectorAuth = ConnectorAuth> = ConnectorConfigBase<TAuth>;
588
+ /** Update connector — `id` required. Host extends. */
589
+ type UpdateConnectorRequest<TAuth extends ConnectorAuth = ConnectorAuth> = ConnectorConfigBase<TAuth> & {
590
+ id: string;
591
+ };
592
+ interface ConnectorCatalogServer<TTool extends ToolBase = ToolBase, TAuthWrite extends ConnectorAuth = ConnectorAuth, TAuthPublic extends ConnectorAuthPublic = ConnectorAuthPublic, TConnector extends ConnectorBase<TTool, TAuthPublic> = ConnectorBase<TTool, TAuthPublic>, TCatalogEntry extends ConnectorCatalogEntry<TAuthPublic> = ConnectorCatalogEntry<TAuthPublic>, TCreate extends CreateConnectorRequest<TAuthWrite> = CreateConnectorRequest<TAuthWrite>, TUpdate extends UpdateConnectorRequest<TAuthWrite> = UpdateConnectorRequest<TAuthWrite>> {
593
+ getConnectorCatalog(): Promise<TCatalogEntry[]>;
594
+ listConnectors(req?: {
595
+ query?: string;
596
+ }): Promise<TConnector[]>;
597
+ createConnector(req: TCreate): Promise<TConnector>;
598
+ /** Full replace update keyed by connector `id`. */
599
+ updateConnector(req: TUpdate): Promise<TConnector>;
600
+ /** Start connector auth (e.g. OAuth). Host may widen return with `authUrl`. */
601
+ authenticateConnector(req: {
602
+ id: string;
603
+ }): Promise<TConnector>;
604
+ /** Clear connector auth. */
605
+ disconnectConnector(req: {
606
+ id: string;
607
+ }): Promise<TConnector>;
608
+ deleteConnector?(req: {
609
+ id: string;
610
+ }): Promise<void>;
611
+ }
612
+ /** Skill row shown in settings/skills (list + delete). Host extends for fqn, etc. */
613
+ interface SkillBase {
614
+ id: string;
615
+ name: string;
616
+ description: string;
617
+ }
618
+ /** Create-skill request. Host extends for branch, auth, etc. */
619
+ interface CreateSkillRequest {
620
+ repo: string;
621
+ directory: string;
622
+ }
623
+ interface SkillCatalogServer<TSkill extends SkillBase = SkillBase, TCreate extends CreateSkillRequest = CreateSkillRequest> {
624
+ listSkills(req?: {
625
+ query?: string;
626
+ }): Promise<TSkill[]>;
627
+ createSkill(req: TCreate): Promise<TSkill>;
628
+ deleteSkill?(req: {
629
+ id: string;
630
+ }): Promise<void>;
631
+ }
632
+ /**
633
+ * Settings management aggregate — modelCatalog + connectorCatalog + optional skillCatalog.
634
+ * Hosts may pass the whole object to an app shell, or a focused sub-port to a page.
635
+ */
636
+ interface CatalogServer<TModelCatalog extends ModelCatalogServer = ModelCatalogServer, TConnectorCatalog extends ConnectorCatalogServer = ConnectorCatalogServer, TSkillCatalog extends SkillCatalogServer = SkillCatalogServer> {
637
+ modelCatalog: TModelCatalog;
638
+ connectorCatalog: TConnectorCatalog;
639
+ /** Optional — omit when the host has no skills settings surface. */
640
+ skillCatalog?: TSkillCatalog;
641
+ }
642
+ /**
643
+ * Composed host port: chat + builder + optional settings catalog.
644
+ * Agent-ui's `AgentUIServer` mirrors this shape; named differently here to
645
+ * avoid colliding with that package's local type name.
646
+ *
647
+ * `catalog` is optional — if the host passes it, settings UI can call
648
+ * `useCatalogServer()` / show modelCatalog, connectorCatalog, and skillCatalog;
649
+ * if omitted, those surfaces stay hidden.
650
+ */
651
+ type AgentUIServerPort<TChat extends AgentChatServer = AgentChatServer, TBuilder extends AgentBuilderServer = AgentBuilderServer, TCatalog extends CatalogServer = CatalogServer> = TChat & TBuilder & {
652
+ catalog?: TCatalog;
653
+ };
461
654
 
462
- export type { AgentSpec as A, CreateSessionRequest as C, DeltaEvents as D, ListResult as L, McpAuthRequiredEvent as M, PreviousTurnIdInput as P, Session as S, TurnStreamingEvent as T, UserToolResponseEvent as U, AgentChatServer as a, TurnEvent as b, ThreadCreatedEvent as c, UserToolApprovalEvent as d, Turn as e, TurnInputItem as f, AgentBuilderServer as g, ListSessionsParams as h, ModelMessageEvent as i, SandboxCreatedEvent as j, SessionEventItem as k, ToolApprovalRequiredEvent as l, ToolCall as m, ToolResponseRequiredEvent as n, TurnState as o, TurnStateDone as p, TurnStreamData as q, UpdateSessionRequest as r, UserMessage as s };
655
+ export type { AgentParent as $, AgentSpec as A, ModelProviderConfigBase as B, CreateSessionRequest as C, ProviderType as D, SandboxCreatedEvent as E, SessionEventItem as F, SkillBase as G, SkillCatalogServer as H, ToolApprovalRequiredEvent as I, ToolBase as J, ToolCall as K, ListSessionsParams as L, McpAuthRequiredEvent as M, ToolResponseRequiredEvent as N, TurnStateDone as O, PreviousTurnIdInput as P, TurnStreamData as Q, TurnStreamingEvent as R, Session as S, Turn as T, UpdateSessionRequest as U, UpdateConnectorRequest as V, UpdateModelProviderRequest as W, UserMessage as X, DeltaEvents as Y, ActionRequiredEvent as Z, AgentInfo as _, TurnState as a, AgentSelectorEntry as a0, ApprovalDecision as a1, ChunkDeltaToolCall as a2, ConnectorSelectorEntry as a3, ListSessionsOrder as a4, McpInitializeEvent as a5, McpServerAuthInfo as a6, McpServerMount as a7, Model as a8, ModelMessageContentPart as a9, ModelMessageDeltaEvent as aa, ModelParams as ab, ModelSelectorEntry as ac, PageParams as ad, SearchAgentSelectorParams as ae, SkillMount as af, SkillSelectorEntry as ag, ThreadDoneEvent as ah, ToolCallFunction as ai, ToolCallRef as aj, ToolInfo as ak, ToolResponseEvent as al, TurnCreatedEvent as am, TurnDoneEvent as an, TurnStateCancelled as ao, TurnStateError as ap, TurnStateRunning as aq, UserMessageContent as ar, AgentChatServer as b, TurnEvent as c, ThreadCreatedEvent as d, UserToolResponseEvent as e, UserToolApprovalEvent as f, TurnInputItem as g, AgentBuilderServer as h, AgentUIServerPort as i, CatalogServer as j, ConnectorAuth as k, ConnectorAuthPublic as l, ConnectorAuthType as m, ConnectorBase as n, ConnectorCatalogEntry as o, ConnectorCatalogServer as p, ConnectorConfigBase as q, CreateConnectorRequest as r, CreateModelProviderRequest as s, CreateSkillRequest as t, ListResult as u, ModelCatalogServer as v, ModelEntry as w, ModelMessageEvent as x, ModelProviderBase as y, ModelProviderCatalogEntry as z };
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@truefoundry/assistant-ui-runtime",
3
- "version": "0.1.6-rc.0",
3
+ "version": "0.1.7",
4
4
  "description": "TrueFoundry Gateway agent runtime adapter for assistant-ui",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/truefoundry/truefoundry-agents-assistant-ui-runtime"
8
+ "url": "git+https://github.com/truefoundry/truefoundry-agents-assistant-ui-runtime.git"
9
9
  },
10
10
  "homepage": "https://github.com/truefoundry/truefoundry-agents-assistant-ui-runtime#readme",
11
11
  "keywords": [
@@ -27,6 +27,11 @@
27
27
  "import": "./dist/index.js",
28
28
  "default": "./dist/index.js"
29
29
  },
30
+ "./server": {
31
+ "types": "./dist/server/index.d.ts",
32
+ "import": "./dist/server/index.js",
33
+ "default": "./dist/server/index.js"
34
+ },
30
35
  "./plugins/truefoundry-agent-server-adapter": {
31
36
  "types": "./dist/plugins/truefoundry-agent-server-adapter/index.d.ts",
32
37
  "import": "./dist/plugins/truefoundry-agent-server-adapter/index.js",
@@ -55,7 +60,7 @@
55
60
  "peerDependencies": {
56
61
  "@types/react": "*",
57
62
  "react": "^18 || ^19",
58
- "truefoundry-gateway-sdk": "^0.4.0-rc.5"
63
+ "truefoundry-gateway-sdk": "^0.4.0-rc.6"
59
64
  },
60
65
  "peerDependenciesMeta": {
61
66
  "@types/react": {
@@ -71,9 +76,9 @@
71
76
  "@types/react": "^19.2.17",
72
77
  "jsdom": "^29.1.1",
73
78
  "react": "^19.2.4",
74
- "truefoundry-gateway-sdk": "0.4.0-rc.5",
79
+ "truefoundry-gateway-sdk": "0.4.0-rc.6",
75
80
  "tsup": "^8.5.0",
76
81
  "typescript": "^5.9.3",
77
82
  "vitest": "4.1.9"
78
83
  }
79
- }
84
+ }
@@ -1,33 +1,30 @@
1
1
  import type { AgentSpec } from "../server/types.js";
2
2
 
3
- export type { AgentSpec } from "../server/types.js";
4
-
5
3
  /** @deprecated Use Session with isMutable: true instead. Kept for title helper. */
6
4
  export type DraftSession = {
7
5
  title?: string | null;
8
6
  agentSpec: AgentSpec;
9
7
  };
10
8
 
11
- export type AgentSpecUpdate = {
12
- instructions?: string;
13
- model?: Partial<AgentSpec["model"]> & {
14
- params?: Partial<NonNullable<AgentSpec["model"]["params"]>>;
15
- };
16
- mcpServers?: AgentSpec["mcpServers"];
17
- skills?: AgentSpec["skills"];
18
- messages?: AgentSpec["messages"];
19
- variables?: AgentSpec["variables"];
20
- responseFormat?: AgentSpec["responseFormat"];
21
- config?: AgentSpec["config"];
9
+ /** Partial update host fields flow through when `TSpec` is widened. */
10
+ export type AgentSpecUpdate<TSpec extends AgentSpec = AgentSpec> = {
11
+ [K in keyof TSpec]?: K extends "model"
12
+ ? Omit<Partial<TSpec["model"]>, "params"> & {
13
+ params?: Partial<NonNullable<TSpec["model"]["params"]>>;
14
+ }
15
+ : TSpec[K];
22
16
  };
23
17
 
24
- export function mergeAgentSpec(base: AgentSpec, update: AgentSpecUpdate): AgentSpec {
18
+ export function mergeAgentSpec<TSpec extends AgentSpec>(
19
+ base: TSpec,
20
+ update: AgentSpecUpdate<TSpec>,
21
+ ): TSpec {
25
22
  const { model: modelUpdate, ...rest } = update;
26
23
 
27
- const next: AgentSpec = {
24
+ const next = {
28
25
  ...base,
29
26
  ...rest,
30
- };
27
+ } as TSpec;
31
28
 
32
29
  if (modelUpdate != null) {
33
30
  next.model = {
@@ -38,7 +35,7 @@ export function mergeAgentSpec(base: AgentSpec, update: AgentSpecUpdate): AgentS
38
35
  modelUpdate.params != null
39
36
  ? { ...base.model.params, ...modelUpdate.params }
40
37
  : base.model.params,
41
- };
38
+ } as TSpec["model"];
42
39
  }
43
40
 
44
41
  return next;
@@ -1,5 +1,4 @@
1
- import type { AgentChatServer } from "../server/types.js";
2
- import type { AgentSpec } from "./agentSpec.js";
1
+ import type { AgentChatServer, AgentSpec } from "../server/types.js";
3
2
 
4
3
  export const DRAFT_SESSION_LAST_UPDATED_AT_HEADER = "x-tfy-session-last-updated-at";
5
4
 
@@ -3,7 +3,7 @@ import { describe, expect, it, vi } from "vitest";
3
3
  import type { AgentChatServer, Session } from "../server/index.js";
4
4
 
5
5
  import { createTrueFoundryDraftThreadListAdapter } from "./truefoundryDraftThreadListAdapter.js";
6
- import type { AgentSpec } from "./agentSpec.js";
6
+ import type { AgentSpec } from "../server/types.js";
7
7
 
8
8
  const defaultAgentSpec: AgentSpec = {
9
9
  model: { name: "anthropic/claude-sonnet-4-6" },
@@ -1,7 +1,8 @@
1
1
  import type { RemoteThreadListAdapter } from "@assistant-ui/core";
2
2
 
3
3
  import type { AgentChatServer } from "../server/types.js";
4
- import { draftSessionTitle, type AgentSpec } from "./agentSpec.js";
4
+ import type { AgentSpec } from "../server/types.js";
5
+ import { draftSessionTitle } from "./agentSpec.js";
5
6
  import { sessionListStartTimestamp } from "../sessionListStartTimestamp.js";
6
7
 
7
8
  const THREAD_LIST_PAGE_SIZE = 20;
@@ -2,11 +2,8 @@
2
2
 
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
 
5
- import {
6
- mergeAgentSpec,
7
- type AgentSpec,
8
- type AgentSpecUpdate,
9
- } from "./agentSpec.js";
5
+ import type { AgentSpec } from "../server/types.js";
6
+ import { mergeAgentSpec, type AgentSpecUpdate } from "./agentSpec.js";
10
7
  import type { DraftSessionBridge } from "./draftSessionBridge.js";
11
8
 
12
9
  const SPEC_SYNC_DEBOUNCE_MS = 400;
@@ -22,6 +19,7 @@ export type UseDraftAgentSpecOptions = {
22
19
  export type UseDraftAgentSpecResult = {
23
20
  agentSpec: AgentSpec | null;
24
21
  draftSessionId: string | undefined;
22
+ isSpecLoading: boolean;
25
23
  isSpecSyncing: boolean;
26
24
  specError: unknown | null;
27
25
  updateAgentSpec: (update: AgentSpecUpdate) => void;
@@ -37,6 +35,7 @@ export function useDraftAgentSpec({
37
35
  }: UseDraftAgentSpecOptions): UseDraftAgentSpecResult {
38
36
  const enabled = draftBridge != null;
39
37
  const [agentSpec, setAgentSpec] = useState<AgentSpec>(defaultAgentSpec);
38
+ const [isSpecLoading, setIsSpecLoading] = useState(false);
40
39
  const [isSpecSyncing, setIsSpecSyncing] = useState(false);
41
40
  const [specError, setSpecError] = useState<unknown | null>(null);
42
41
 
@@ -86,6 +85,7 @@ export function useDraftAgentSpec({
86
85
  setAgentSpec(defaultAgentSpec);
87
86
  localDirtyRef.current = false;
88
87
  setSpecError(null);
88
+ setIsSpecLoading(false);
89
89
  return;
90
90
  }
91
91
 
@@ -94,6 +94,7 @@ export function useDraftAgentSpec({
94
94
  }
95
95
 
96
96
  let cancelled = false;
97
+ setIsSpecLoading(true);
97
98
  void (async () => {
98
99
  try {
99
100
  const loaded = await draftBridge.getDraftAgentSpec(draftSessionId);
@@ -106,21 +107,29 @@ export function useDraftAgentSpec({
106
107
  scheduleSpecSyncRef.current?.(draftSessionId, agentSpecRef.current);
107
108
  localDirtyRef.current = false;
108
109
  setSpecError(null);
110
+ setIsSpecLoading(false);
109
111
  return;
110
112
  }
111
113
 
112
114
  setAgentSpec(loaded);
113
115
  setSpecError(null);
116
+ setIsSpecLoading(false);
114
117
  } catch (error) {
115
118
  if (!cancelled) {
116
119
  onError?.(error);
117
120
  setSpecError(error);
121
+ setIsSpecLoading(false);
118
122
  }
119
123
  }
120
124
  })();
121
125
 
122
126
  return () => {
123
127
  cancelled = true;
128
+ // The cancelled load can no longer clear the flag itself. Releasing it
129
+ // here keeps it from sticking when the next run early-returns on an
130
+ // already-loaded draft; a run that starts a fresh load re-raises it in
131
+ // the same commit.
132
+ setIsSpecLoading(false);
124
133
  };
125
134
  }, [defaultAgentSpec, draftBridge, draftSessionId, enabled, onError]);
126
135
 
@@ -232,6 +241,7 @@ export function useDraftAgentSpec({
232
241
  () => ({
233
242
  agentSpec: enabled ? agentSpec : null,
234
243
  draftSessionId: enabled ? draftSessionId : undefined,
244
+ isSpecLoading: enabled ? isSpecLoading : false,
235
245
  isSpecSyncing: enabled ? isSpecSyncing : false,
236
246
  specError: enabled ? specError : null,
237
247
  updateAgentSpec,
@@ -241,6 +251,7 @@ export function useDraftAgentSpec({
241
251
  agentSpec,
242
252
  draftSessionId,
243
253
  enabled,
254
+ isSpecLoading,
244
255
  isSpecSyncing,
245
256
  specError,
246
257
  takeTurnHeaderTimestamp,
@@ -1,6 +1,7 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
 
3
- import { mergeAgentSpec, type AgentSpec } from "./private/agentSpec.js";
3
+ import { mergeAgentSpec } from "./draft/agentSpec.js";
4
+ import type { AgentSpec } from "./server/types.js";
4
5
  import {
5
6
  resolveTrueFoundryAgentConfig,
6
7
  resolveTrueFoundryAgentRuntimeOptions,
package/src/index.ts CHANGED
@@ -13,17 +13,17 @@ export {
13
13
  export type { ConvertTurnsResult, UserMessageContent } from "./convertTurnMessages.js";
14
14
  export { ROOT_THREAD_ID } from "./constants.js";
15
15
  export type {
16
- UseTrueFoundryAgentRuntimeOptions,
17
16
  NamedAgentConfig,
18
17
  DraftAgentConfig,
19
18
  TrueFoundryAgentConfig,
19
+ UseTrueFoundryAgentRuntimeOptions,
20
20
  } from "./types.js";
21
- export type { AgentSpec, AgentSpecUpdate, DraftSession } from "./private/agentSpec.js";
22
- export { mergeAgentSpec, draftSessionTitle } from "./private/agentSpec.js";
23
- export { createTrueFoundryDraftThreadListAdapter } from "./private/truefoundryDraftThreadListAdapter.js";
21
+ export type { AgentSpecUpdate, DraftSession } from "./draft/agentSpec.js";
22
+ export { mergeAgentSpec, draftSessionTitle } from "./draft/agentSpec.js";
23
+ export { createTrueFoundryDraftThreadListAdapter } from "./draft/truefoundryDraftThreadListAdapter.js";
24
24
  export { createTrueFoundryOwnedSessionsThreadListAdapter } from "./truefoundryOwnedSessionsThreadListAdapter.js";
25
- export { createDraftSessionBridge } from "./private/draftSessionBridge.js";
26
- export type { DraftSessionBridge } from "./private/draftSessionBridge.js";
25
+ export { createDraftSessionBridge } from "./draft/draftSessionBridge.js";
26
+ export type { DraftSessionBridge } from "./draft/draftSessionBridge.js";
27
27
  export {
28
28
  useTrueFoundryAgentSpec,
29
29
  useTrueFoundryUpdateAgentSpec,
@@ -82,7 +82,7 @@ export type {
82
82
  TurnState,
83
83
  TurnStateDone,
84
84
  TurnInputItem,
85
- AgentSpec as ServerAgentSpec,
85
+ AgentSpec,
86
86
  ListResult,
87
87
  CreateSessionRequest,
88
88
  UpdateSessionRequest,
@@ -91,6 +91,29 @@ export type {
91
91
  UserToolApprovalEvent,
92
92
  UserToolResponseEvent,
93
93
  PreviousTurnIdInput,
94
+ ProviderType,
95
+ ModelEntry,
96
+ ModelProviderConfigBase,
97
+ ModelProviderBase,
98
+ ModelProviderCatalogEntry,
99
+ CreateModelProviderRequest,
100
+ UpdateModelProviderRequest,
101
+ ModelCatalogServer,
102
+ ToolBase,
103
+ ConnectorAuthType,
104
+ ConnectorAuth,
105
+ ConnectorAuthPublic,
106
+ ConnectorConfigBase,
107
+ ConnectorBase,
108
+ ConnectorCatalogEntry,
109
+ CreateConnectorRequest,
110
+ UpdateConnectorRequest,
111
+ ConnectorCatalogServer,
112
+ SkillBase,
113
+ CreateSkillRequest,
114
+ SkillCatalogServer,
115
+ CatalogServer,
116
+ AgentUIServerPort,
94
117
  } from "./server/index.js";
95
118
  export type {
96
119
  SandboxCreatedEvent,
@@ -106,3 +129,44 @@ export type {
106
129
  ToolResponseRequiredEvent,
107
130
  } from "./server/index.js";
108
131
  export { isEventDelta, mergeEventDelta } from "./server/index.js";
132
+
133
+ // ---------------------------------------------------------------------------
134
+ // Plugin: truefoundry-agent-server-adapter
135
+ // ---------------------------------------------------------------------------
136
+
137
+ export {
138
+ createTrueFoundryChatServer,
139
+ type CreateTrueFoundryChatServerOptions,
140
+ type TrueFoundryChatServer,
141
+ type TfyAgentSpec,
142
+ type TfySkillMount,
143
+ type TfyMcpServerMount,
144
+ type TfyModelParams,
145
+ type TfyRuntimeConfig,
146
+ type TfyResponseFormat,
147
+ type TfySubject,
148
+ type ToolsSelectorItem,
149
+ type ToolsSelectorTag,
150
+ type RequireApprovalToolSelectorItem,
151
+ type RequireApprovalToolsSelectorTag,
152
+ type TfyTurn,
153
+ type TfyTurnState,
154
+ type TfyTurnCancelledReason,
155
+ type TfyTurnStateDoneOutput,
156
+ type TfySession,
157
+ type TfyCreateSessionRequest,
158
+ type TfyListSessionsParams,
159
+ type TfyToolInfo,
160
+ type TfySystemToolInfo,
161
+ type TfyMcpToolInfo,
162
+ type TfyModelMessageUsage,
163
+ type TfyFinishReason,
164
+ type TfyThreadState,
165
+ type TfyMcpServerInitInfo,
166
+ isTfyToolInfo,
167
+ isTfySystemToolInfo,
168
+ isTfyMcpToolInfo,
169
+ getTfyUsage,
170
+ getTfyThreadState,
171
+ getTfyMcpInitServers,
172
+ } from "./plugins/truefoundry-agent-server-adapter/index.js";