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

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 (57) hide show
  1. package/README.md +374 -190
  2. package/dist/index.d.ts +32 -29
  3. package/dist/index.js +334 -241
  4. package/dist/index.js.map +1 -1
  5. package/dist/plugins/truefoundry-agent-server-adapter/index.d.ts +30 -0
  6. package/dist/plugins/truefoundry-agent-server-adapter/index.js +198 -0
  7. package/dist/plugins/truefoundry-agent-server-adapter/index.js.map +1 -0
  8. package/dist/types-VUBzoJT2.d.ts +462 -0
  9. package/package.json +12 -4
  10. package/src/askUserQuestion.ts +3 -3
  11. package/src/collectPending.ts +1 -1
  12. package/src/convertTurnMessages.test.ts +141 -196
  13. package/src/convertTurnMessages.ts +131 -77
  14. package/src/createSubAgent.ts +1 -1
  15. package/src/draftAgentConfig.test.ts +26 -29
  16. package/src/extractTurnUserText.ts +1 -1
  17. package/src/foldPeerThreads.test.ts +1 -1
  18. package/src/foldPeerThreads.ts +3 -2
  19. package/src/index.ts +39 -4
  20. package/src/listPages.ts +21 -0
  21. package/src/loadSessionSnapshot.test.ts +9 -8
  22. package/src/loadSessionSnapshot.ts +9 -14
  23. package/src/mcpAuth.ts +6 -3
  24. package/src/messageCustomMetadata.ts +1 -1
  25. package/src/modelMessageContent.ts +1 -1
  26. package/src/modelMessageImageContent.test.ts +1 -1
  27. package/src/modelMessageImageContent.ts +7 -6
  28. package/src/plugins/truefoundry-agent-server-adapter/index.ts +285 -0
  29. package/src/private/agentSpec.ts +8 -3
  30. package/src/private/draftSessionBridge.ts +14 -13
  31. package/src/private/truefoundryDraftThreadListAdapter.test.ts +44 -49
  32. package/src/private/truefoundryDraftThreadListAdapter.ts +22 -16
  33. package/src/requiredActionInputs.ts +1 -1
  34. package/src/requiredActionsFromActiveUpdate.test.ts +1 -1
  35. package/src/server/eventUtils.ts +120 -0
  36. package/src/server/events.ts +246 -0
  37. package/src/server/index.ts +66 -0
  38. package/src/server/types.ts +313 -0
  39. package/src/sessionSnapshot.ts +1 -1
  40. package/src/sessions.ts +5 -21
  41. package/src/streamTurn.test.ts +175 -158
  42. package/src/streamTurn.ts +51 -57
  43. package/src/toolApproval.ts +4 -4
  44. package/src/toolResponse.ts +4 -4
  45. package/src/truefoundryExtras.ts +1 -1
  46. package/src/truefoundryOwnedSessionsThreadListAdapter.test.ts +26 -29
  47. package/src/truefoundryOwnedSessionsThreadListAdapter.ts +18 -23
  48. package/src/truefoundryThreadListAdapter.test.ts +16 -18
  49. package/src/truefoundryThreadListAdapter.ts +9 -9
  50. package/src/turnEventHelpers.ts +1 -1
  51. package/src/types.ts +2 -16
  52. package/src/useTrueFoundryAgentMessages.test.tsx +38 -70
  53. package/src/useTrueFoundryAgentMessages.ts +33 -45
  54. package/src/useTrueFoundryAgentRuntime.ts +11 -28
  55. package/src/private/bindDraftAgentSession.test.ts +0 -54
  56. package/src/private/bindDraftAgentSession.ts +0 -28
  57. package/src/private/getGatewayFromPrivateClient.ts +0 -13
@@ -0,0 +1,66 @@
1
+ export type {
2
+ ModelSelectorEntry,
3
+ SkillSelectorEntry,
4
+ ConnectorSelectorEntry,
5
+ AgentSelectorEntry,
6
+ SearchAgentSelectorParams,
7
+ SkillMount,
8
+ McpServerMount,
9
+ ModelParams,
10
+ Model,
11
+ AgentSpec,
12
+ Session,
13
+ CreateSessionRequest,
14
+ UpdateSessionRequest,
15
+ ListResult,
16
+ ListSessionsOrder,
17
+ PageParams,
18
+ ListSessionsParams,
19
+ PreviousTurnIdInput,
20
+ UserMessageContent,
21
+ UserMessage,
22
+ ApprovalDecision,
23
+ UserToolApprovalEvent,
24
+ UserToolResponseEvent,
25
+ TurnInputItem,
26
+ TurnStateRunning,
27
+ TurnStateDone,
28
+ TurnStateCancelled,
29
+ TurnStateError,
30
+ TurnState,
31
+ Turn,
32
+ AgentChatServer,
33
+ AgentBuilderServer,
34
+ } from "./types.js";
35
+
36
+ export type {
37
+ ToolCallFunction,
38
+ ToolInfo,
39
+ ToolCall,
40
+ ToolCallRef,
41
+ ChunkDeltaToolCall,
42
+ ModelMessageContentPart,
43
+ ModelMessageEvent,
44
+ ModelMessageDeltaEvent,
45
+ ToolResponseEvent,
46
+ ToolApprovalRequiredEvent,
47
+ ToolResponseRequiredEvent,
48
+ AgentInfo,
49
+ AgentParent,
50
+ ThreadCreatedEvent,
51
+ ThreadDoneEvent,
52
+ McpServerAuthInfo,
53
+ McpAuthRequiredEvent,
54
+ SandboxCreatedEvent,
55
+ McpInitializeEvent,
56
+ TurnCreatedEvent,
57
+ TurnDoneEvent,
58
+ TurnEvent,
59
+ TurnStreamingEvent,
60
+ ActionRequiredEvent,
61
+ TurnStreamData,
62
+ SessionEventItem,
63
+ DeltaEvents,
64
+ } from "./events.js";
65
+
66
+ export { isEventDelta, mergeEventDelta } from "./eventUtils.js";
@@ -0,0 +1,313 @@
1
+ /**
2
+ * FE-owned AgentUIServer contract.
3
+ *
4
+ * Rule: only methods/fields the runtime or UI invokes.
5
+ * Hosts extend via `T extends Base` for system-specific extras.
6
+ * No dependency on truefoundry-gateway-sdk.
7
+ */
8
+
9
+ import type {
10
+ ActionRequiredEvent,
11
+ SessionEventItem,
12
+ TurnEvent,
13
+ TurnStreamData,
14
+ TurnStreamingEvent,
15
+ } from "./events.js";
16
+
17
+ // ---------------------------------------------------------------------------
18
+ // Catalog — selector rows (SDK-minimal; host extends via generics)
19
+ // ---------------------------------------------------------------------------
20
+
21
+ /** Model selector row. Host extends for apiModel, modelId, pricing, etc. */
22
+ export interface ModelSelectorEntry {
23
+ name: string;
24
+ provider: string;
25
+ }
26
+
27
+ /** Skill selector row. Host extends for fqn, preload, etc. */
28
+ export interface SkillSelectorEntry {
29
+ id: string;
30
+ name: string;
31
+ description?: string;
32
+ }
33
+
34
+ /** MCP connector selector row. Host extends for type, enableTools, url, etc. */
35
+ export interface ConnectorSelectorEntry {
36
+ id: string;
37
+ name: string;
38
+ description?: string;
39
+ }
40
+
41
+ /** Agent selector row — UI shows name only. Host extends for metadata. */
42
+ export interface AgentSelectorEntry {
43
+ name: string;
44
+ }
45
+
46
+ export type SearchAgentSelectorParams = {
47
+ query?: string;
48
+ limit?: number;
49
+ offset?: number;
50
+ };
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Mounts — neutral SDK base (host extends with backend-specific fields)
54
+ // ---------------------------------------------------------------------------
55
+
56
+ /** Skill mount base written to AgentSpec.skills[]. Host extends for fqn, preload, etc. */
57
+ export interface SkillMount {
58
+ id: string;
59
+ name: string;
60
+ }
61
+
62
+ /** MCP server mount base written to AgentSpec.mcpServers[]. Host extends for type, enableTools, etc. */
63
+ export interface McpServerMount {
64
+ id: string;
65
+ name: string;
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------
69
+ // AgentSpec — model + skills + mcpServers on base; host widens the rest
70
+ // ---------------------------------------------------------------------------
71
+
72
+ export interface ModelParams {
73
+ maxTokens?: number;
74
+ reasoningEffort?: string;
75
+ }
76
+
77
+ export interface Model {
78
+ name: string;
79
+ params?: ModelParams;
80
+ }
81
+
82
+ /**
83
+ * SDK-owned agent definition — fields the FE reads/writes.
84
+ * Host adds additional fields via `TSpec extends AgentSpec`.
85
+ */
86
+ export interface AgentSpec {
87
+ model: Model;
88
+ skills?: SkillMount[];
89
+ mcpServers?: McpServerMount[];
90
+ instructions?: string;
91
+ messages?: unknown[];
92
+ variables?: Record<string, string>;
93
+ responseFormat?: unknown;
94
+ config?: unknown;
95
+ }
96
+
97
+ // ---------------------------------------------------------------------------
98
+ // Session — plain DTO, generic in TSpec so host's spec type flows through
99
+ // ---------------------------------------------------------------------------
100
+
101
+ export interface Session<TSpec extends AgentSpec = AgentSpec> {
102
+ id: string;
103
+ title?: string | null;
104
+ agentName?: string | null;
105
+ agentSpec?: TSpec;
106
+ /** true → mutable builder + updateSession(spec) allowed. */
107
+ isMutable: boolean;
108
+ createdAt: string;
109
+ updatedAt: string;
110
+ }
111
+
112
+ export interface CreateSessionRequest<TSpec extends AgentSpec = AgentSpec> {
113
+ agentName?: string;
114
+ agentSpec?: TSpec;
115
+ title?: string;
116
+ }
117
+
118
+ export interface UpdateSessionRequest<TSpec extends AgentSpec = AgentSpec> {
119
+ sessionId: string;
120
+ agentSpec?: TSpec;
121
+ title?: string;
122
+ }
123
+
124
+ // ---------------------------------------------------------------------------
125
+ // Pagination — flat token-based (no Page objects with methods)
126
+ // ---------------------------------------------------------------------------
127
+
128
+ export interface ListResult<T> {
129
+ data: T[];
130
+ nextPageToken?: string;
131
+ }
132
+
133
+ export type ListSessionsOrder = "asc" | "desc";
134
+
135
+ export type PageParams = {
136
+ limit?: number;
137
+ order?: ListSessionsOrder;
138
+ pageToken?: string;
139
+ };
140
+
141
+ export interface ListSessionsParams extends PageParams {
142
+ agentName?: string;
143
+ /** Host-specific filter (e.g. TFY startTimestamp). */
144
+ startTimestamp?: string;
145
+ }
146
+
147
+ export type PreviousTurnIdInput = "auto" | string;
148
+
149
+ // ---------------------------------------------------------------------------
150
+ // Turn input / state — what runtime sends and reads
151
+ // ---------------------------------------------------------------------------
152
+
153
+ export type UserMessageContent =
154
+ | string
155
+ | Array<{ type: "text"; text: string } | { type: "file"; name: string; data: string }>;
156
+
157
+ export interface UserMessage {
158
+ type: "user.message";
159
+ content: UserMessageContent;
160
+ }
161
+
162
+ export type ApprovalDecision =
163
+ | { status: "allow" }
164
+ | { status: "deny"; reason?: string };
165
+
166
+ export interface UserToolApprovalEvent {
167
+ type: "user.tool_approval";
168
+ threadId: string;
169
+ toolCallId: string;
170
+ approval: ApprovalDecision;
171
+ }
172
+
173
+ export interface UserToolResponseEvent {
174
+ type: "user.tool_response";
175
+ threadId: string;
176
+ toolCallId: string;
177
+ content: string;
178
+ }
179
+
180
+ export type TurnInputItem =
181
+ | UserMessage
182
+ | UserToolApprovalEvent
183
+ | UserToolResponseEvent;
184
+
185
+ export type TurnStateRunning = { status: "running" };
186
+
187
+ export type TurnStateDone = {
188
+ status: "done";
189
+ output?: unknown;
190
+ requiredActions?: ActionRequiredEvent[];
191
+ completedAt: string;
192
+ };
193
+
194
+ export type TurnStateCancelled = {
195
+ status: "cancelled";
196
+ reason: string;
197
+ completedAt: string;
198
+ };
199
+
200
+ export type TurnStateError = {
201
+ status: "error";
202
+ message: string;
203
+ completedAt: string;
204
+ };
205
+
206
+ export type TurnState =
207
+ | TurnStateRunning
208
+ | TurnStateDone
209
+ | TurnStateCancelled
210
+ | TurnStateError;
211
+
212
+ /** Plain turn DTO — no methods. */
213
+ export interface Turn {
214
+ id: string;
215
+ sessionId: string;
216
+ previousTurnId?: string | null;
217
+ input?: TurnInputItem[];
218
+ state: TurnState;
219
+ createdAt: string;
220
+ }
221
+
222
+ // ---------------------------------------------------------------------------
223
+ // Server ports — flat methods, no session-with-methods objects
224
+ // ---------------------------------------------------------------------------
225
+
226
+ /**
227
+ * Chat / session port — the runtime calls these.
228
+ *
229
+ * All session ops are flat (sessionId param). No gateway client dependency.
230
+ * `createTrueFoundryServer` is one possible implementation (TFY adapter).
231
+ */
232
+ export interface AgentChatServer<
233
+ TSpec extends AgentSpec = AgentSpec,
234
+ TSession extends Session<TSpec> = Session<TSpec>,
235
+ TCreate extends CreateSessionRequest<TSpec> = CreateSessionRequest<TSpec>,
236
+ TList extends ListSessionsParams = ListSessionsParams,
237
+ TUpdate extends UpdateSessionRequest<TSpec> = UpdateSessionRequest<TSpec>,
238
+ TTurn extends Turn = Turn,
239
+ > {
240
+ createSession(req: TCreate): Promise<TSession>;
241
+ listSessions(req?: TList): Promise<ListResult<TSession>>;
242
+ getSession(req: { sessionId: string }): Promise<TSession>;
243
+ updateSession(req: TUpdate): Promise<TSession>;
244
+
245
+ prepareAndExecuteTurn(req: {
246
+ sessionId: string;
247
+ input?: TurnInputItem[];
248
+ previousTurnId?: PreviousTurnIdInput;
249
+ abortSignal?: AbortSignal;
250
+ headers?: Record<string, string>;
251
+ }): AsyncIterable<TurnStreamData>;
252
+
253
+ cancelSession(req: { sessionId: string }): Promise<void>;
254
+ deleteSession?(req: { sessionId: string }): Promise<void>;
255
+
256
+ listTurns(req: {
257
+ sessionId: string;
258
+ limit?: number;
259
+ pageToken?: string;
260
+ order?: ListSessionsOrder;
261
+ }): Promise<ListResult<TTurn>>;
262
+ getTurn(req: { sessionId: string; turnId: string }): Promise<TTurn>;
263
+ listEvents(req: {
264
+ sessionId: string;
265
+ pageToken?: string;
266
+ lastTurnId?: string;
267
+ limit?: number;
268
+ }): Promise<ListResult<SessionEventItem>>;
269
+
270
+ /** Optional per-turn event listing (hydrate in-flight turn content). */
271
+ listTurnEvents?(req: {
272
+ sessionId: string;
273
+ turnId: string;
274
+ limit?: number;
275
+ pageToken?: string;
276
+ order?: ListSessionsOrder;
277
+ }): Promise<ListResult<TurnEvent>>;
278
+
279
+ subscribeToTurn?(req: {
280
+ sessionId: string;
281
+ turnId: string;
282
+ afterSequenceNumber?: number;
283
+ abortSignal?: AbortSignal;
284
+ }): AsyncIterable<TurnStreamData>;
285
+
286
+ downloadSandboxFile?(
287
+ sandboxId: string,
288
+ req: { path: string },
289
+ ): Promise<Blob>;
290
+ }
291
+
292
+ /**
293
+ * Builder catalog + persist port — atoms call these.
294
+ * Passed separately from the runtime's chat server.
295
+ */
296
+ export interface AgentBuilderServer<
297
+ TSpec extends AgentSpec = AgentSpec,
298
+ TModel extends ModelSelectorEntry = ModelSelectorEntry,
299
+ TSkill extends SkillSelectorEntry = SkillSelectorEntry,
300
+ TMcp extends ConnectorSelectorEntry = ConnectorSelectorEntry,
301
+ TAgent extends AgentSelectorEntry = AgentSelectorEntry,
302
+ TSave = unknown,
303
+ > {
304
+ getModels(): Promise<TModel[]>;
305
+ getSkills(): Promise<TSkill[]>;
306
+ getMcp(): Promise<TMcp[]>;
307
+ searchAgents(req?: SearchAgentSelectorParams): Promise<TAgent[]>;
308
+ saveAgent(req: {
309
+ agentName: string;
310
+ agentSpec: TSpec;
311
+ }): Promise<TSave>;
312
+ deleteAgent?(req: { agentName: string }): Promise<void>;
313
+ }
@@ -5,7 +5,7 @@ import type {
5
5
  TurnDoneEvent,
6
6
  TurnEvent,
7
7
  TurnInputItem,
8
- } from "truefoundry-gateway-sdk/agents";
8
+ } from "./server/index.js";
9
9
 
10
10
  import { extractTurnUserText } from "./extractTurnUserText.js";
11
11
  import { PeerThreadFoldState } from "./foldPeerThreads.js";
package/src/sessions.ts CHANGED
@@ -1,31 +1,15 @@
1
- import type {
2
- AgentSession,
3
- AgentSessionClient,
4
- } from "truefoundry-gateway-sdk/agents";
5
- import type { PrivateAgentSessionClient } from "truefoundry-gateway-sdk/agents/private";
1
+ import type { AgentChatServer, Session } from "./server/types.js";
6
2
 
7
- import { bindDraftAgentSession } from "./private/bindDraftAgentSession.js";
8
-
9
- const inflightBySessionId = new Map<string, Promise<AgentSession>>();
10
-
11
- export type GetSessionOptions = {
12
- /** When set, validates the draft and binds turns via PrivateAgentSessionClient. */
13
- privateClient?: PrivateAgentSessionClient;
14
- };
3
+ const inflightBySessionId = new Map<string, Promise<Session>>();
15
4
 
16
5
  /** `sessionId` is the assistant-ui thread `remoteId` from `RemoteThreadListAdapter.initialize`. */
17
6
  export function getSession(
18
- client: AgentSessionClient,
7
+ server: AgentChatServer,
19
8
  sessionId: string,
20
- options?: GetSessionOptions,
21
- ): Promise<AgentSession> {
22
- if (options?.privateClient != null) {
23
- return bindDraftAgentSession(options.privateClient, sessionId);
24
- }
25
-
9
+ ): Promise<Session> {
26
10
  let inflight = inflightBySessionId.get(sessionId);
27
11
  if (inflight == null) {
28
- inflight = client.getSession({ sessionId }).finally(() => {
12
+ inflight = server.getSession({ sessionId }).finally(() => {
29
13
  if (inflightBySessionId.get(sessionId) === inflight) {
30
14
  inflightBySessionId.delete(sessionId);
31
15
  }