@truefoundry/trueforge-ui 0.1.0 → 0.2.1

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 (61) hide show
  1. package/CHANGELOG.md +34 -15
  2. package/README.md +38 -38
  3. package/dist/{ConnectorSettings-H37ZFC6Z.js → ConnectorSettings-XEO5ZQO5.js} +8 -6
  4. package/dist/{ConnectorSettings-H37ZFC6Z.js.map → ConnectorSettings-XEO5ZQO5.js.map} +1 -1
  5. package/dist/{DockLayout-KEMFRWIR.js → DockLayout-F2KYSY4U.js} +10 -8
  6. package/dist/{DockLayout-KEMFRWIR.js.map → DockLayout-F2KYSY4U.js.map} +1 -1
  7. package/dist/{DrawerLayout-ZVWCKEIS.js → DrawerLayout-FJ7XC2FU.js} +12 -9
  8. package/dist/{DrawerLayout-ZVWCKEIS.js.map → DrawerLayout-FJ7XC2FU.js.map} +1 -1
  9. package/dist/{ModelSettings-QJMYHCMD.js → ModelSettings-2QB7LE22.js} +8 -6
  10. package/dist/{ModelSettings-QJMYHCMD.js.map → ModelSettings-2QB7LE22.js.map} +1 -1
  11. package/dist/OpenUiFenceBlock-3EFPY4JW.js +9 -0
  12. package/dist/{SandboxSettings-BUBMLW7Q.js → SandboxSettings-QDDIPRBP.js} +8 -6
  13. package/dist/{SandboxSettings-BUBMLW7Q.js.map → SandboxSettings-QDDIPRBP.js.map} +1 -1
  14. package/dist/{SettingsBuilder-26XSGIHK.js → SettingsBuilder-4NF3Y7UZ.js} +10 -8
  15. package/dist/{SettingsBuilder-26XSGIHK.js.map → SettingsBuilder-4NF3Y7UZ.js.map} +1 -1
  16. package/dist/ShellRouteSync-T4WLY57Q.js +172 -0
  17. package/dist/ShellRouteSync-T4WLY57Q.js.map +1 -0
  18. package/dist/{SidebarLayout-F3XFXW7B.js → SidebarLayout-KX6RSJTP.js} +12 -9
  19. package/dist/{SidebarLayout-F3XFXW7B.js.map → SidebarLayout-KX6RSJTP.js.map} +1 -1
  20. package/dist/{SkillSettings-IRMGDFRG.js → SkillSettings-5EETEEDI.js} +8 -6
  21. package/dist/{SkillSettings-IRMGDFRG.js.map → SkillSettings-5EETEEDI.js.map} +1 -1
  22. package/dist/TrueForgeUIWithRouter-IAQQTD5V.js +30 -0
  23. package/dist/TrueForgeUIWithRouter-IAQQTD5V.js.map +1 -0
  24. package/dist/{WidgetLayout-SZMABKIR.js → WidgetLayout-S6EK62TZ.js} +10 -8
  25. package/dist/{WidgetLayout-SZMABKIR.js.map → WidgetLayout-S6EK62TZ.js.map} +1 -1
  26. package/dist/chunk-72LC2M3R.js +567 -0
  27. package/dist/chunk-72LC2M3R.js.map +1 -0
  28. package/dist/chunk-EKVN6QSO.js +493 -0
  29. package/dist/chunk-EKVN6QSO.js.map +1 -0
  30. package/dist/chunk-FXCYLEFB.js +64 -0
  31. package/dist/chunk-FXCYLEFB.js.map +1 -0
  32. package/dist/chunk-IFLE7OMM.js +527 -0
  33. package/dist/chunk-IFLE7OMM.js.map +1 -0
  34. package/dist/{chunk-HT5HKQXE.js → chunk-JRRCAKEP.js} +2 -2
  35. package/dist/{chunk-7EEOWDLE.js → chunk-PTYEOSHT.js} +10 -8
  36. package/dist/{chunk-7EEOWDLE.js.map → chunk-PTYEOSHT.js.map} +1 -1
  37. package/dist/{chunk-H7DR64W3.js → chunk-UACLSDNL.js} +39 -94
  38. package/dist/chunk-UACLSDNL.js.map +1 -0
  39. package/dist/{chunk-QGNLP2EE.js → chunk-UU7C5DQ3.js} +18 -8
  40. package/dist/chunk-UU7C5DQ3.js.map +1 -0
  41. package/dist/chunk-WQULF5AT.js +460 -0
  42. package/dist/chunk-WQULF5AT.js.map +1 -0
  43. package/dist/{chunk-LRQHHZDX.js → chunk-X6U2Q7X5.js} +7 -5
  44. package/dist/{chunk-LRQHHZDX.js.map → chunk-X6U2Q7X5.js.map} +1 -1
  45. package/dist/chunk-YIWUG6MC.js +101 -0
  46. package/dist/chunk-YIWUG6MC.js.map +1 -0
  47. package/dist/index.d.ts +57 -9
  48. package/dist/index.js +41 -428
  49. package/dist/index.js.map +1 -1
  50. package/dist/plugins/trueforge-agent-server-adapter/index.js.map +1 -1
  51. package/dist/styles.css +1 -1
  52. package/package.json +9 -6
  53. package/dist/OpenUiFenceBlock-XFBUGPKQ.js +0 -9
  54. package/dist/chunk-DTF7ZMUJ.js +0 -567
  55. package/dist/chunk-DTF7ZMUJ.js.map +0 -1
  56. package/dist/chunk-H7DR64W3.js.map +0 -1
  57. package/dist/chunk-QGNLP2EE.js.map +0 -1
  58. package/dist/chunk-XAZ5HJXV.js +0 -862
  59. package/dist/chunk-XAZ5HJXV.js.map +0 -1
  60. /package/dist/{OpenUiFenceBlock-XFBUGPKQ.js.map → OpenUiFenceBlock-3EFPY4JW.js.map} +0 -0
  61. /package/dist/{chunk-HT5HKQXE.js.map → chunk-JRRCAKEP.js.map} +0 -0
@@ -0,0 +1,493 @@
1
+ import {
2
+ notifyComposerBusyFailure
3
+ } from "./chunk-FXCYLEFB.js";
4
+ import {
5
+ useAuiState
6
+ } from "./chunk-M6MHLVSO.js";
7
+ import {
8
+ SlotsProvider,
9
+ ToasterProvider,
10
+ modelPatchWithReasoningEffort,
11
+ useToaster
12
+ } from "./chunk-UU7C5DQ3.js";
13
+ import {
14
+ DraftCatalogProvider,
15
+ Spinner,
16
+ getErrorMessage,
17
+ useDraftCatalog
18
+ } from "./chunk-IFLE7OMM.js";
19
+ import {
20
+ DEFAULT_AGENT_CONFIG,
21
+ ServerProvider,
22
+ ShellModeProvider,
23
+ useServerCapabilities,
24
+ useShellMode,
25
+ withCapabilitiesSandbox
26
+ } from "./chunk-WQULF5AT.js";
27
+ import {
28
+ cn
29
+ } from "./chunk-72LC2M3R.js";
30
+
31
+ // src/containers/TrueFoundryChatProvider.tsx
32
+ import { AssistantRuntimeProvider } from "@assistant-ui/react";
33
+ import {
34
+ trueFoundryAttachmentAdapter,
35
+ useTrueFoundryAgentRuntime
36
+ } from "@truefoundry/assistant-ui-runtime";
37
+ import { useCallback, useMemo } from "react";
38
+ import { jsx } from "react/jsx-runtime";
39
+ function ChatRuntimeScope({
40
+ server,
41
+ agent,
42
+ agentName,
43
+ listSessionsAgentId,
44
+ initialSessionId,
45
+ adapters,
46
+ onError,
47
+ children
48
+ }) {
49
+ const { showError } = useToaster();
50
+ const reportError = onError ?? showError;
51
+ const resolvedOnError = useCallback(
52
+ (error) => {
53
+ notifyComposerBusyFailure();
54
+ reportError(error);
55
+ },
56
+ [reportError]
57
+ );
58
+ const runtime = useTrueFoundryAgentRuntime({
59
+ server,
60
+ agent,
61
+ agentName,
62
+ listSessionsAgentId,
63
+ initialSessionId,
64
+ onError: resolvedOnError,
65
+ adapters: {
66
+ ...adapters,
67
+ attachments: adapters?.attachments ?? trueFoundryAttachmentAdapter
68
+ }
69
+ });
70
+ return /* @__PURE__ */ jsx(AssistantRuntimeProvider, { runtime, children });
71
+ }
72
+ function TrueFoundryChatProvider(props) {
73
+ const { server, initialSessionId, adapters, onError, children, agent, agentName, listSessionsAgentId } = props;
74
+ const stableServer = useMemo(() => server, [server]);
75
+ return /* @__PURE__ */ jsx(ToasterProvider, { children: /* @__PURE__ */ jsx(
76
+ ChatRuntimeScope,
77
+ {
78
+ server: stableServer,
79
+ agent,
80
+ agentName,
81
+ listSessionsAgentId,
82
+ initialSessionId,
83
+ adapters,
84
+ onError,
85
+ children
86
+ }
87
+ ) });
88
+ }
89
+
90
+ // src/containers/TrueForgeUIShell.tsx
91
+ import { lazy, Suspense, useCallback as useCallback2, useMemo as useMemo2, useState as useState2 } from "react";
92
+
93
+ // src/atoms/draft/DraftSpecPreferenceBridge.tsx
94
+ import { useTrueFoundryAgentSpec, useTrueFoundryUpdateAgentSpec } from "@truefoundry/assistant-ui-runtime";
95
+ import { useEffect } from "react";
96
+ function mountName(mount) {
97
+ const name = Reflect.get(mount, "name");
98
+ return typeof name === "string" ? name : null;
99
+ }
100
+ function filterMounts(mounts, availableNames) {
101
+ if (mounts === void 0) return void 0;
102
+ const filtered = mounts.filter((mount) => {
103
+ const name = mountName(mount);
104
+ return name !== null && availableNames.has(name);
105
+ });
106
+ return filtered.length === mounts.length ? mounts : filtered;
107
+ }
108
+ function reconcileDraftSpecPreferences({
109
+ agentSpec,
110
+ models,
111
+ skills,
112
+ connectors,
113
+ skillsEnabled
114
+ }) {
115
+ const update = {};
116
+ const selectedModel = agentSpec.model.name.trim();
117
+ if (!models.some((model) => model.name === selectedModel)) {
118
+ const fallback = models[0];
119
+ if (fallback !== void 0) {
120
+ update.model = modelPatchWithReasoningEffort(
121
+ fallback.name,
122
+ agentSpec.model.params,
123
+ fallback.properties.reasoningEfforts
124
+ );
125
+ }
126
+ }
127
+ const nextMcpServers = filterMounts(agentSpec.mcpServers, new Set(connectors.map((connector) => connector.name)));
128
+ if (nextMcpServers !== agentSpec.mcpServers) {
129
+ update.mcpServers = nextMcpServers;
130
+ }
131
+ if (skillsEnabled === false) {
132
+ if (agentSpec.skills !== void 0 && agentSpec.skills.length > 0) {
133
+ update.skills = [];
134
+ }
135
+ } else {
136
+ const nextSkills = filterMounts(agentSpec.skills, new Set(skills.map((skill) => skill.name)));
137
+ if (nextSkills !== agentSpec.skills) {
138
+ update.skills = nextSkills;
139
+ }
140
+ }
141
+ return update;
142
+ }
143
+ function reconcileDraftSandbox({
144
+ agentSpec,
145
+ sandboxEnabled
146
+ }) {
147
+ const nextSpec = withCapabilitiesSandbox(agentSpec, sandboxEnabled);
148
+ return nextSpec === agentSpec ? {} : { config: nextSpec.config };
149
+ }
150
+ function DraftSpecPreferenceBridge() {
151
+ const { mode, pendingSessionId, rememberDraftSpec } = useShellMode();
152
+ const { agentSpec } = useTrueFoundryAgentSpec();
153
+ const updateAgentSpec = useTrueFoundryUpdateAgentSpec();
154
+ const capabilities = useServerCapabilities();
155
+ const sandboxEnabled = capabilities?.sandbox.enabled;
156
+ const { models, skills, connectors, loaded, error, ensureLoaded } = useDraftCatalog();
157
+ const isPlainDraft = mode.status === "active" && mode.isMutable && mode.agentId == null && pendingSessionId == null;
158
+ useEffect(() => {
159
+ if (isPlainDraft) ensureLoaded();
160
+ }, [ensureLoaded, isPlainDraft]);
161
+ useEffect(() => {
162
+ if (isPlainDraft && agentSpec != null) {
163
+ rememberDraftSpec(agentSpec);
164
+ }
165
+ }, [agentSpec, isPlainDraft, rememberDraftSpec]);
166
+ useEffect(() => {
167
+ if (!isPlainDraft || agentSpec == null || updateAgentSpec == null) return;
168
+ const update = reconcileDraftSandbox({ agentSpec, sandboxEnabled });
169
+ if (Object.keys(update).length > 0) {
170
+ updateAgentSpec(update);
171
+ }
172
+ }, [agentSpec, isPlainDraft, sandboxEnabled, updateAgentSpec]);
173
+ useEffect(() => {
174
+ if (!isPlainDraft || agentSpec == null || updateAgentSpec == null || !loaded || error != null) return;
175
+ const update = reconcileDraftSpecPreferences({
176
+ agentSpec,
177
+ models,
178
+ skills,
179
+ connectors,
180
+ skillsEnabled: capabilities?.skill.enabled
181
+ });
182
+ if (Object.keys(update).length > 0) {
183
+ updateAgentSpec(update);
184
+ }
185
+ }, [
186
+ agentSpec,
187
+ capabilities?.skill.enabled,
188
+ connectors,
189
+ error,
190
+ isPlainDraft,
191
+ loaded,
192
+ models,
193
+ skills,
194
+ updateAgentSpec
195
+ ]);
196
+ return null;
197
+ }
198
+
199
+ // src/routing/RemoteIdRouteBridge.tsx
200
+ import { useEffect as useEffect2 } from "react";
201
+ function RemoteIdRouteBridge({ onRemoteIdChange }) {
202
+ const remoteId = useAuiState((s) => s.threadListItem.remoteId);
203
+ useEffect2(() => {
204
+ onRemoteIdChange(remoteId ?? void 0);
205
+ }, [remoteId, onRemoteIdChange]);
206
+ return null;
207
+ }
208
+
209
+ // src/containers/useResolvedServer.ts
210
+ import { createTrueFoundryAgentUIServer } from "@truefoundry/assistant-ui-runtime/plugins/truefoundry-agent-server-adapter";
211
+ import { useEffect as useEffect3, useState } from "react";
212
+ var DEFAULT_CAPABILITIES = {
213
+ data: {
214
+ sandbox: { enabled: true },
215
+ skill: { enabled: true },
216
+ settings: { enabled: true }
217
+ }
218
+ };
219
+ function isBuiltInConfig(config) {
220
+ return typeof config === "object" && config !== null && "type" in config && (config.type === "truefoundry" || config.type === "trueforge");
221
+ }
222
+ function hasGetCapabilities(server) {
223
+ return typeof Reflect.get(server, "getCapabilities") === "function";
224
+ }
225
+ function toAgentUIServer(server, catalog) {
226
+ const getCapabilities = hasGetCapabilities(server) ? () => server.getCapabilities() : async () => DEFAULT_CAPABILITIES;
227
+ const withCapabilities = { ...server, getCapabilities };
228
+ const withCatalog = catalog != null ? { ...withCapabilities, catalog } : withCapabilities;
229
+ if (!isAgentUIServer(withCatalog)) {
230
+ throw new Error("TrueForgeUI: runtime adapter returned an incomplete AgentUIServer");
231
+ }
232
+ return withCatalog;
233
+ }
234
+ function isAgentUIServer(value) {
235
+ return typeof Reflect.get(value, "createSession") === "function" && typeof Reflect.get(value, "listSessions") === "function" && typeof Reflect.get(value, "getSession") === "function" && typeof Reflect.get(value, "updateSession") === "function" && typeof Reflect.get(value, "createTurn") === "function" && typeof Reflect.get(value, "cancelSession") === "function" && typeof Reflect.get(value, "listTurns") === "function" && typeof Reflect.get(value, "getTurn") === "function" && typeof Reflect.get(value, "listEvents") === "function" && typeof Reflect.get(value, "getCapabilities") === "function" && typeof Reflect.get(value, "getModels") === "function" && typeof Reflect.get(value, "getSkills") === "function" && typeof Reflect.get(value, "getMcp") === "function" && typeof Reflect.get(value, "searchAgents") === "function" && typeof Reflect.get(value, "saveAgent") === "function";
236
+ }
237
+ function useResolvedServer(config, onError) {
238
+ const builtIn = isBuiltInConfig(config) ? config : null;
239
+ const directServer = isBuiltInConfig(config) ? null : config;
240
+ const type = builtIn?.type;
241
+ const apiKey = builtIn?.type === "truefoundry" ? builtIn.apiKey : "";
242
+ const controlPlaneURL = builtIn?.type === "truefoundry" ? builtIn.controlPlaneURL : "";
243
+ const gatewayPlaneURL = builtIn?.type === "truefoundry" ? builtIn.gatewayPlaneURL ?? "" : "";
244
+ const trueforgeBaseUrl = builtIn?.type === "trueforge" ? builtIn.baseUrl ?? "" : "";
245
+ const trueforgeToken = builtIn?.type === "trueforge" ? builtIn.token ?? "" : "";
246
+ const trueforgeFetch = builtIn?.type === "trueforge" ? builtIn.fetch : void 0;
247
+ const catalog = builtIn?.catalog;
248
+ const [state, setState] = useState(() => {
249
+ if (directServer) {
250
+ return { status: "ready", server: directServer, error: null };
251
+ }
252
+ return { status: "loading", server: null, error: null };
253
+ });
254
+ useEffect3(() => {
255
+ if (directServer) {
256
+ setState({ status: "ready", server: directServer, error: null });
257
+ return;
258
+ }
259
+ let cancelled = false;
260
+ setState({ status: "loading", server: null, error: null });
261
+ const resolve = async () => {
262
+ if (type === "trueforge") {
263
+ const { createTrueForgeAgentUIServer } = await import("./plugins/trueforge-agent-server-adapter/index.js");
264
+ return createTrueForgeAgentUIServer({
265
+ ...trueforgeBaseUrl ? { baseUrl: trueforgeBaseUrl } : {},
266
+ ...trueforgeToken ? { token: trueforgeToken } : {},
267
+ ...trueforgeFetch !== void 0 ? { fetch: trueforgeFetch } : {},
268
+ ...catalog != null ? { catalog } : {}
269
+ });
270
+ }
271
+ const runtimeServer = await createTrueFoundryAgentUIServer({
272
+ apiKey,
273
+ cpURL: controlPlaneURL,
274
+ ...gatewayPlaneURL ? { gatewayURL: gatewayPlaneURL } : {}
275
+ });
276
+ return toAgentUIServer(runtimeServer, catalog);
277
+ };
278
+ void resolve().then((server) => {
279
+ if (cancelled) return;
280
+ try {
281
+ setState({
282
+ status: "ready",
283
+ server: type === "trueforge" ? toAgentUIServer(server, void 0) : server,
284
+ error: null
285
+ });
286
+ } catch (error) {
287
+ onError?.(error);
288
+ setState({ status: "error", server: null, error });
289
+ }
290
+ }).catch((error) => {
291
+ if (cancelled) return;
292
+ onError?.(error);
293
+ setState({ status: "error", server: null, error });
294
+ });
295
+ return () => {
296
+ cancelled = true;
297
+ };
298
+ }, [
299
+ type,
300
+ directServer,
301
+ apiKey,
302
+ controlPlaneURL,
303
+ gatewayPlaneURL,
304
+ trueforgeBaseUrl,
305
+ trueforgeToken,
306
+ trueforgeFetch,
307
+ catalog,
308
+ onError
309
+ ]);
310
+ return state;
311
+ }
312
+
313
+ // src/containers/TrueForgeUIShell.tsx
314
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
315
+ var SidebarLayout = lazy(() => import("./SidebarLayout-KX6RSJTP.js").then((m) => ({ default: m.SidebarLayout })));
316
+ var DrawerLayout = lazy(() => import("./DrawerLayout-FJ7XC2FU.js").then((m) => ({ default: m.DrawerLayout })));
317
+ var DockLayout = lazy(() => import("./DockLayout-F2KYSY4U.js").then((m) => ({ default: m.DockLayout })));
318
+ var WidgetLayout = lazy(() => import("./WidgetLayout-S6EK62TZ.js").then((m) => ({ default: m.WidgetLayout })));
319
+ var ShellRouteSync = lazy(() => import("./ShellRouteSync-T4WLY57Q.js").then((m) => ({ default: m.ShellRouteSync })));
320
+ function LayoutFallback({ className }) {
321
+ return /* @__PURE__ */ jsx2(
322
+ "div",
323
+ {
324
+ className,
325
+ style: {
326
+ height: "100%",
327
+ minHeight: "12rem",
328
+ background: "linear-gradient(90deg, color-mix(in oklab, var(--secondary-bg) 55%, transparent) 25%, color-mix(in oklab, var(--secondary-bg) 25%, transparent) 50%, color-mix(in oklab, var(--secondary-bg) 55%, transparent) 75%)",
329
+ backgroundSize: "200% 100%",
330
+ animation: "tfy-aui-pulse 1.2s ease-in-out infinite"
331
+ },
332
+ "aria-hidden": true
333
+ }
334
+ );
335
+ }
336
+ function ServerInitLoader({ className }) {
337
+ return /* @__PURE__ */ jsxs(
338
+ "div",
339
+ {
340
+ role: "status",
341
+ "aria-live": "polite",
342
+ "aria-busy": "true",
343
+ className: cn(
344
+ "flex h-full min-h-48 w-full flex-1 items-center justify-center bg-primary-bg text-text-secondary",
345
+ className
346
+ ),
347
+ children: [
348
+ /* @__PURE__ */ jsx2(Spinner, { size: 28, className: "text-text-primary" }),
349
+ /* @__PURE__ */ jsx2("span", { className: "sr-only", children: "Loading" })
350
+ ]
351
+ }
352
+ );
353
+ }
354
+ function ServerInitError({ error, className }) {
355
+ const message = getErrorMessage(error, "Failed to initialize server");
356
+ return /* @__PURE__ */ jsx2(
357
+ "div",
358
+ {
359
+ role: "alert",
360
+ className: cn(
361
+ "flex h-full min-h-48 items-center justify-center bg-primary-bg px-6 text-center text-sm text-failure-bg",
362
+ className
363
+ ),
364
+ children: message
365
+ }
366
+ );
367
+ }
368
+ function isBuiltInLayout(layout) {
369
+ return layout === "sidebar" || layout === "drawer" || layout === "dock" || layout === "widget";
370
+ }
371
+ function BuiltInLayoutView({ layout, className }) {
372
+ switch (layout) {
373
+ case "sidebar":
374
+ return /* @__PURE__ */ jsx2(SidebarLayout, { className });
375
+ case "drawer":
376
+ return /* @__PURE__ */ jsx2(DrawerLayout, { className });
377
+ case "dock":
378
+ return /* @__PURE__ */ jsx2(DockLayout, { className });
379
+ case "widget":
380
+ return /* @__PURE__ */ jsx2(WidgetLayout, { className });
381
+ }
382
+ }
383
+ function LayoutChildren({ layout, className }) {
384
+ if (isBuiltInLayout(layout)) {
385
+ return /* @__PURE__ */ jsx2(Suspense, { fallback: /* @__PURE__ */ jsx2(LayoutFallback, { className }), children: /* @__PURE__ */ jsx2(BuiltInLayoutView, { layout, className }) });
386
+ }
387
+ const HostLayout = layout;
388
+ return /* @__PURE__ */ jsx2(HostLayout, { className });
389
+ }
390
+ function ChatProviderFromShell({
391
+ children,
392
+ initialSessionId: hostInitialSessionId,
393
+ onRemoteIdChange,
394
+ ...providerRest
395
+ }) {
396
+ const { mode, runtimeKey, listSessionsAgentId, pendingSessionId } = useShellMode();
397
+ const draftDefaultAgentSpec = useMemo2(() => {
398
+ if (mode.status === "active" && mode.isMutable) {
399
+ return mode.agentSpec ?? { model: { name: "openai-main/gpt-4.1" } };
400
+ }
401
+ return { model: { name: "openai-main/gpt-4.1" } };
402
+ }, [runtimeKey]);
403
+ const agent = useMemo2(() => {
404
+ if (mode.status === "idle") {
405
+ return {
406
+ mode: "draft",
407
+ defaultAgentSpec: { model: { name: "openai-main/gpt-4.1" } }
408
+ };
409
+ }
410
+ if (!mode.isMutable) {
411
+ const agentName = mode.agentName ?? mode.agentId ?? pendingSessionId;
412
+ if (agentName == null) {
413
+ return {
414
+ mode: "draft",
415
+ defaultAgentSpec: { model: { name: "openai-main/gpt-4.1" } }
416
+ };
417
+ }
418
+ return { mode: "named", agentName };
419
+ }
420
+ return {
421
+ mode: "draft",
422
+ defaultAgentSpec: draftDefaultAgentSpec
423
+ };
424
+ }, [mode, draftDefaultAgentSpec, pendingSessionId]);
425
+ return /* @__PURE__ */ jsx2(
426
+ TrueFoundryChatProvider,
427
+ {
428
+ ...providerRest,
429
+ agent,
430
+ listSessionsAgentId,
431
+ initialSessionId: pendingSessionId ?? hostInitialSessionId,
432
+ children: /* @__PURE__ */ jsxs(DraftCatalogProvider, { children: [
433
+ /* @__PURE__ */ jsx2(DraftSpecPreferenceBridge, {}),
434
+ onRemoteIdChange != null ? /* @__PURE__ */ jsx2(RemoteIdRouteBridge, { onRemoteIdChange }) : null,
435
+ children
436
+ ] })
437
+ },
438
+ runtimeKey
439
+ );
440
+ }
441
+ function TrueForgeUIShell(props) {
442
+ const {
443
+ layout = "sidebar",
444
+ overrides,
445
+ theme,
446
+ className,
447
+ agentConfig = DEFAULT_AGENT_CONFIG,
448
+ initialSettingsOpen = false,
449
+ server: serverConfig,
450
+ onError,
451
+ resolvedRoutes,
452
+ routes: _routes,
453
+ ...providerRest
454
+ } = props;
455
+ const resolved = useResolvedServer(serverConfig, onError);
456
+ const [activeRemoteId, setActiveRemoteId] = useState2(void 0);
457
+ const handleRemoteIdChange = useCallback2((id) => setActiveRemoteId(id), []);
458
+ if (resolved.status === "loading") {
459
+ return /* @__PURE__ */ jsx2(SlotsProvider, { overrides, theme, children: /* @__PURE__ */ jsx2(ServerInitLoader, { className }) });
460
+ }
461
+ if (resolved.status === "error") {
462
+ return /* @__PURE__ */ jsx2(SlotsProvider, { overrides, theme, children: /* @__PURE__ */ jsx2(ServerInitError, { error: resolved.error, className }) });
463
+ }
464
+ const server = resolved.server;
465
+ const layoutTree = /* @__PURE__ */ jsx2(LayoutChildren, { layout, className });
466
+ return /* @__PURE__ */ jsx2(SlotsProvider, { overrides, theme, children: /* @__PURE__ */ jsx2(ServerProvider, { server, children: /* @__PURE__ */ jsxs(ShellModeProvider, { agentConfig, initialSettingsOpen, children: [
467
+ resolvedRoutes != null ? /* @__PURE__ */ jsx2(Suspense, { fallback: null, children: /* @__PURE__ */ jsx2(
468
+ ShellRouteSync,
469
+ {
470
+ routes: resolvedRoutes,
471
+ activeRemoteId,
472
+ initialSettingsOpen
473
+ }
474
+ ) }) : null,
475
+ /* @__PURE__ */ jsx2(
476
+ ChatProviderFromShell,
477
+ {
478
+ server,
479
+ onError,
480
+ onRemoteIdChange: resolvedRoutes != null ? handleRemoteIdChange : void 0,
481
+ ...providerRest,
482
+ children: layoutTree
483
+ }
484
+ )
485
+ ] }) }) });
486
+ }
487
+
488
+ export {
489
+ TrueFoundryChatProvider,
490
+ ServerInitLoader,
491
+ TrueForgeUIShell
492
+ };
493
+ //# sourceMappingURL=chunk-EKVN6QSO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/containers/TrueFoundryChatProvider.tsx","../src/containers/TrueForgeUIShell.tsx","../src/atoms/draft/DraftSpecPreferenceBridge.tsx","../src/routing/RemoteIdRouteBridge.tsx","../src/containers/useResolvedServer.ts"],"sourcesContent":["'use client';\n\nimport { AssistantRuntimeProvider } from '@assistant-ui/react';\nimport {\n trueFoundryAttachmentAdapter,\n useTrueFoundryAgentRuntime,\n type TrueFoundryAgentConfig,\n type UseTrueFoundryAgentRuntimeOptions,\n} from '@truefoundry/assistant-ui-runtime';\nimport { useCallback, useMemo, type ReactNode } from 'react';\n\nimport { notifyComposerBusyFailure } from '../hooks/useComposerBusyState.js';\nimport type { AgentUIServer } from '../server/types.js';\nimport { ToasterProvider, useToaster } from './ToasterContainer.js';\n\ntype RuntimeAdapters = NonNullable<UseTrueFoundryAgentRuntimeOptions['adapters']>;\n\nexport type TrueFoundryChatProviderProps = {\n server: AgentUIServer;\n initialSessionId?: string;\n adapters?: RuntimeAdapters;\n onError?: (error: unknown) => void;\n children: ReactNode;\n /** Discriminated agent source. Prefer over legacy `agentName`. */\n agent?: TrueFoundryAgentConfig;\n /** Legacy named-agent shorthand. Prefer `agent: { mode: \"named\", agentName }`. */\n agentName?: string;\n /** Forwarded to `listSessions({ agentId })` for history filtering. */\n listSessionsAgentId?: string;\n};\n\nfunction ChatRuntimeScope({\n server,\n agent,\n agentName,\n listSessionsAgentId,\n initialSessionId,\n adapters,\n onError,\n children,\n}: {\n server: AgentUIServer;\n agent?: TrueFoundryAgentConfig;\n agentName?: string;\n listSessionsAgentId?: string;\n initialSessionId?: string;\n adapters?: RuntimeAdapters;\n onError?: (error: unknown) => void;\n children: ReactNode;\n}) {\n const { showError } = useToaster();\n const reportError = onError ?? showError;\n // composer().send() is void and swallows onNew rejections; clear optimistic\n // busy when the runtime reports a pre-stream failure (e.g. createSession).\n const resolvedOnError = useCallback(\n (error: unknown) => {\n notifyComposerBusyFailure();\n reportError(error);\n },\n [reportError],\n );\n\n const runtime = useTrueFoundryAgentRuntime({\n server: server as never,\n agent,\n agentName,\n listSessionsAgentId,\n initialSessionId,\n onError: resolvedOnError,\n adapters: {\n ...adapters,\n attachments: adapters?.attachments ?? trueFoundryAttachmentAdapter,\n },\n });\n\n return <AssistantRuntimeProvider runtime={runtime as never}>{children}</AssistantRuntimeProvider>;\n}\n\n/**\n * Chat shell: wires `useTrueFoundryAgentRuntime` from `server` and provides\n * assistant-ui + error toasts.\n */\nexport function TrueFoundryChatProvider(props: TrueFoundryChatProviderProps) {\n const { server, initialSessionId, adapters, onError, children, agent, agentName, listSessionsAgentId } = props;\n\n const stableServer = useMemo(() => server, [server]);\n\n return (\n <ToasterProvider>\n <ChatRuntimeScope\n server={stableServer}\n agent={agent}\n agentName={agentName}\n listSessionsAgentId={listSessionsAgentId}\n initialSessionId={initialSessionId}\n adapters={adapters}\n onError={onError}\n >\n {children}\n </ChatRuntimeScope>\n </ToasterProvider>\n );\n}\n","'use client';\n\nimport type { TrueFoundryAgentConfig, UseTrueFoundryAgentRuntimeOptions } from '@truefoundry/assistant-ui-runtime';\nimport { lazy, Suspense, useCallback, useMemo, useState, type ReactNode } from 'react';\n\nimport { DraftCatalogProvider } from '../atoms/draft/DraftCatalogProvider.js';\nimport { DraftSpecPreferenceBridge } from '../atoms/draft/DraftSpecPreferenceBridge.js';\nimport { cn } from '../atoms/lib/cn.js';\nimport { Spinner } from '../atoms/primitives/Spinner.js';\nimport { RemoteIdRouteBridge } from '../routing/RemoteIdRouteBridge.js';\nimport type { ResolvedRoutes, RoutesConfig } from '../routing/types.js';\nimport { ServerProvider } from '../server/ServerContext.js';\nimport { DEFAULT_AGENT_CONFIG, ShellModeProvider, useShellMode, type AgentConfig } from '../server/ShellModeContext.js';\nimport type { TrueForgeServerConfig } from '../server/TrueForgeServerConfig.js';\nimport { SlotsProvider, type SlotOverrides } from '../theme/SlotsProvider.js';\nimport type { LayoutProp, ThemeConfig } from '../theme/types.js';\nimport { getErrorMessage } from '../utils/getErrorMessage.js';\nimport { TrueFoundryChatProvider, type TrueFoundryChatProviderProps } from './TrueFoundryChatProvider.js';\nimport { useResolvedServer } from './useResolvedServer.js';\n\nconst SidebarLayout = lazy(() => import('../layouts/SidebarLayout.js').then(m => ({ default: m.SidebarLayout })));\nconst DrawerLayout = lazy(() => import('../layouts/DrawerLayout.js').then(m => ({ default: m.DrawerLayout })));\nconst DockLayout = lazy(() => import('../layouts/DockLayout.js').then(m => ({ default: m.DockLayout })));\nconst WidgetLayout = lazy(() => import('../layouts/WidgetLayout.js').then(m => ({ default: m.WidgetLayout })));\nconst ShellRouteSync = lazy(() => import('../routing/ShellRouteSync.js').then(m => ({ default: m.ShellRouteSync })));\n\nexport type ChatLayout = 'sidebar' | 'drawer' | 'dock' | 'widget';\n\ntype RuntimeAdapters = NonNullable<UseTrueFoundryAgentRuntimeOptions['adapters']>;\n\nexport type TrueForgeUIProps = {\n server: TrueForgeServerConfig;\n /** Built-in layout string or a custom layout component. Defaults to `\"sidebar\"`. */\n layout?: LayoutProp;\n overrides?: SlotOverrides;\n theme?: ThemeConfig;\n className?: string;\n initialSessionId?: string;\n adapters?: RuntimeAdapters;\n onError?: (error: unknown) => void;\n /**\n * Agent / library / composer shell mode.\n * Defaults to `{ mode: \"AgentLibraryWithComposer\" }`.\n */\n agentConfig?: AgentConfig;\n /** Open settings on first paint only (host boot with no models configured). */\n initialSettingsOpen?: boolean;\n /**\n * Sync shell navigation to the browser URL via react-router (opt-in).\n * Requires `react-router-dom` in the host. Leave off for dock/widget embeds\n * and hosts that own their own router. Defaults to `false`.\n */\n withRouter?: boolean;\n /** URL path customization; only honored when `withRouter`. */\n routes?: RoutesConfig;\n};\n\nexport type TrueForgeUIShellProps = Omit<TrueForgeUIProps, 'withRouter'> & { resolvedRoutes?: ResolvedRoutes };\n\nfunction LayoutFallback({ className }: { className?: string }) {\n return (\n <div\n className={className}\n style={{\n height: '100%',\n minHeight: '12rem',\n background:\n 'linear-gradient(90deg, color-mix(in oklab, var(--secondary-bg) 55%, transparent) 25%, color-mix(in oklab, var(--secondary-bg) 25%, transparent) 50%, color-mix(in oklab, var(--secondary-bg) 55%, transparent) 75%)',\n backgroundSize: '200% 100%',\n animation: 'tfy-aui-pulse 1.2s ease-in-out infinite',\n }}\n aria-hidden\n />\n );\n}\n\n/** Shown while `type: \"truefoundry\"` resolves the agent UI server. */\nexport function ServerInitLoader({ className }: { className?: string }) {\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-busy=\"true\"\n className={cn(\n 'flex h-full min-h-48 w-full flex-1 items-center justify-center bg-primary-bg text-text-secondary',\n className,\n )}\n >\n <Spinner size={28} className=\"text-text-primary\" />\n <span className=\"sr-only\">Loading</span>\n </div>\n );\n}\n\nfunction ServerInitError({ error, className }: { error: unknown; className?: string }) {\n const message = getErrorMessage(error, 'Failed to initialize server');\n return (\n <div\n role=\"alert\"\n className={cn(\n 'flex h-full min-h-48 items-center justify-center bg-primary-bg px-6 text-center text-sm text-failure-bg',\n className,\n )}\n >\n {message}\n </div>\n );\n}\n\nfunction isBuiltInLayout(layout: LayoutProp): layout is ChatLayout {\n return layout === 'sidebar' || layout === 'drawer' || layout === 'dock' || layout === 'widget';\n}\n\nfunction BuiltInLayoutView({ layout, className }: { layout: ChatLayout; className?: string }) {\n switch (layout) {\n case 'sidebar':\n return <SidebarLayout className={className} />;\n case 'drawer':\n return <DrawerLayout className={className} />;\n case 'dock':\n return <DockLayout className={className} />;\n case 'widget':\n return <WidgetLayout className={className} />;\n }\n}\n\nfunction LayoutChildren({ layout, className }: { layout: LayoutProp; className?: string }) {\n if (isBuiltInLayout(layout)) {\n return (\n <Suspense fallback={<LayoutFallback className={className} />}>\n <BuiltInLayoutView layout={layout} className={className} />\n </Suspense>\n );\n }\n const HostLayout = layout;\n return <HostLayout className={className} />;\n}\n\nfunction ChatProviderFromShell({\n children,\n initialSessionId: hostInitialSessionId,\n onRemoteIdChange,\n ...providerRest\n}: {\n children: ReactNode;\n /** When routing, reports the active thread's remote id up to `ShellRouteSync`. */\n onRemoteIdChange?: (id: string | undefined) => void;\n} & Omit<TrueFoundryChatProviderProps, 'agent' | 'agentName' | 'listSessionsAgentId' | 'children'>) {\n const { mode, runtimeKey, listSessionsAgentId, pendingSessionId } = useShellMode();\n\n // Freeze draft seed for the life of this runtimeKey so bindMutableAgent (identity /\n // instructions on shell) does not push a new defaultAgentSpec into the runtime.\n const draftDefaultAgentSpec = useMemo(() => {\n if (mode.status === 'active' && mode.isMutable) {\n return mode.agentSpec ?? { model: { name: 'openai-main/gpt-4.1' } };\n }\n return { model: { name: 'openai-main/gpt-4.1' } };\n // runtimeKey is the remount boundary for mutable chats.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- intentionally keyed on runtimeKey only\n }, [runtimeKey]);\n\n const agent: TrueFoundryAgentConfig = useMemo(() => {\n // idle uses a placeholder draft so layout chrome (useAui) still mounts;\n // layouts render an empty CTA instead of the thread.\n if (mode.status === 'idle') {\n return {\n mode: 'draft',\n defaultAgentSpec: { model: { name: 'openai-main/gpt-4.1' } },\n };\n }\n // Runtime still uses named|draft; shell mutability maps onto that adapter.\n if (!mode.isMutable) {\n const agentName = mode.agentName ?? mode.agentId ?? pendingSessionId;\n if (agentName == null) {\n // Active immutable without identity should not happen; keep chrome mounted.\n return {\n mode: 'draft',\n defaultAgentSpec: { model: { name: 'openai-main/gpt-4.1' } },\n };\n }\n return { mode: 'named', agentName };\n }\n return {\n mode: 'draft',\n defaultAgentSpec: draftDefaultAgentSpec,\n };\n }, [mode, draftDefaultAgentSpec, pendingSessionId]);\n\n return (\n <TrueFoundryChatProvider\n key={runtimeKey}\n {...providerRest}\n agent={agent}\n listSessionsAgentId={listSessionsAgentId}\n initialSessionId={pendingSessionId ?? hostInitialSessionId}\n >\n <DraftCatalogProvider>\n <DraftSpecPreferenceBridge />\n {onRemoteIdChange != null ? <RemoteIdRouteBridge onRemoteIdChange={onRemoteIdChange} /> : null}\n {children}\n </DraftCatalogProvider>\n </TrueFoundryChatProvider>\n );\n}\n\n/** Internal shell. `resolvedRoutes` present iff mounted under `TrueForgeUIWithRouter`. */\nexport function TrueForgeUIShell(props: TrueForgeUIShellProps) {\n const {\n layout = 'sidebar',\n overrides,\n theme,\n className,\n agentConfig = DEFAULT_AGENT_CONFIG,\n initialSettingsOpen = false,\n server: serverConfig,\n onError,\n resolvedRoutes,\n routes: _routes,\n ...providerRest\n } = props;\n\n const resolved = useResolvedServer(serverConfig, onError);\n const [activeRemoteId, setActiveRemoteId] = useState<string | undefined>(undefined);\n const handleRemoteIdChange = useCallback((id: string | undefined) => setActiveRemoteId(id), []);\n\n if (resolved.status === 'loading') {\n return (\n <SlotsProvider overrides={overrides} theme={theme}>\n <ServerInitLoader className={className} />\n </SlotsProvider>\n );\n }\n\n if (resolved.status === 'error') {\n return (\n <SlotsProvider overrides={overrides} theme={theme}>\n <ServerInitError error={resolved.error} className={className} />\n </SlotsProvider>\n );\n }\n\n const server = resolved.server;\n const layoutTree = <LayoutChildren layout={layout} className={className} />;\n\n return (\n <SlotsProvider overrides={overrides} theme={theme}>\n <ServerProvider server={server}>\n <ShellModeProvider agentConfig={agentConfig} initialSettingsOpen={initialSettingsOpen}>\n {resolvedRoutes != null ? (\n <Suspense fallback={null}>\n <ShellRouteSync\n routes={resolvedRoutes}\n activeRemoteId={activeRemoteId}\n initialSettingsOpen={initialSettingsOpen}\n />\n </Suspense>\n ) : null}\n <ChatProviderFromShell\n server={server}\n onError={onError}\n onRemoteIdChange={resolvedRoutes != null ? handleRemoteIdChange : undefined}\n {...providerRest}\n >\n {layoutTree}\n </ChatProviderFromShell>\n </ShellModeProvider>\n </ServerProvider>\n </SlotsProvider>\n );\n}\n","'use client';\n\nimport { useTrueFoundryAgentSpec, useTrueFoundryUpdateAgentSpec } from '@truefoundry/assistant-ui-runtime';\nimport { useEffect } from 'react';\n\nimport { withCapabilitiesSandbox } from '../../server/draftSpecPreferences.js';\nimport { useServerCapabilities } from '../../server/ServerContext.js';\nimport { useShellMode } from '../../server/ShellModeContext.js';\nimport type { AgentSkill, AgentSpec, ConnectorState, ModelSelection } from '../../server/types.js';\nimport { useDraftCatalog } from './DraftCatalogProvider.js';\nimport { modelPatchWithReasoningEffort } from './reasoningEffort.js';\n\nfunction mountName(mount: object): string | null {\n const name = Reflect.get(mount, 'name');\n return typeof name === 'string' ? name : null;\n}\n\nfunction filterMounts<T extends object>(mounts: T[] | undefined, availableNames: Set<string>): T[] | undefined {\n if (mounts === undefined) return undefined;\n const filtered = mounts.filter(mount => {\n const name = mountName(mount);\n return name !== null && availableNames.has(name);\n });\n return filtered.length === mounts.length ? mounts : filtered;\n}\n\nexport function reconcileDraftSpecPreferences({\n agentSpec,\n models,\n skills,\n connectors,\n skillsEnabled,\n}: {\n agentSpec: AgentSpec;\n models: ModelSelection[];\n skills: AgentSkill[];\n connectors: ConnectorState[];\n skillsEnabled: boolean | undefined;\n}): Partial<AgentSpec> {\n const update: Partial<AgentSpec> = {};\n const selectedModel = agentSpec.model.name.trim();\n if (!models.some(model => model.name === selectedModel)) {\n const fallback = models[0];\n if (fallback !== undefined) {\n update.model = modelPatchWithReasoningEffort(\n fallback.name,\n agentSpec.model.params,\n fallback.properties.reasoningEfforts,\n );\n }\n }\n\n const nextMcpServers = filterMounts(agentSpec.mcpServers, new Set(connectors.map(connector => connector.name)));\n if (nextMcpServers !== agentSpec.mcpServers) {\n update.mcpServers = nextMcpServers;\n }\n\n if (skillsEnabled === false) {\n // Only clear when there is something to clear — a fresh `[]` each call would\n // fail reference equality and loop `updateAgentSpec` forever.\n if (agentSpec.skills !== undefined && agentSpec.skills.length > 0) {\n update.skills = [];\n }\n } else {\n const nextSkills = filterMounts(agentSpec.skills, new Set(skills.map(skill => skill.name)));\n if (nextSkills !== agentSpec.skills) {\n update.skills = nextSkills;\n }\n }\n\n return update;\n}\n\nexport function reconcileDraftSandbox({\n agentSpec,\n sandboxEnabled,\n}: {\n agentSpec: AgentSpec;\n sandboxEnabled: boolean | null | undefined;\n}): Partial<AgentSpec> {\n const nextSpec = withCapabilitiesSandbox(agentSpec, sandboxEnabled);\n return nextSpec === agentSpec ? {} : { config: nextSpec.config };\n}\n\n/**\n * Mirrors plain-draft composer choices into the shell seed and removes catalog\n * entries that disappeared since those choices were stored.\n */\nexport function DraftSpecPreferenceBridge() {\n const { mode, pendingSessionId, rememberDraftSpec } = useShellMode();\n const { agentSpec } = useTrueFoundryAgentSpec();\n const updateAgentSpec = useTrueFoundryUpdateAgentSpec();\n const capabilities = useServerCapabilities();\n const sandboxEnabled = capabilities?.sandbox.enabled;\n const { models, skills, connectors, loaded, error, ensureLoaded } = useDraftCatalog();\n const isPlainDraft = mode.status === 'active' && mode.isMutable && mode.agentId == null && pendingSessionId == null;\n\n useEffect(() => {\n if (isPlainDraft) ensureLoaded();\n }, [ensureLoaded, isPlainDraft]);\n\n useEffect(() => {\n if (isPlainDraft && agentSpec != null) {\n rememberDraftSpec(agentSpec);\n }\n }, [agentSpec, isPlainDraft, rememberDraftSpec]);\n\n useEffect(() => {\n if (!isPlainDraft || agentSpec == null || updateAgentSpec == null) return;\n const update = reconcileDraftSandbox({ agentSpec, sandboxEnabled });\n if (Object.keys(update).length > 0) {\n updateAgentSpec(update);\n }\n }, [agentSpec, isPlainDraft, sandboxEnabled, updateAgentSpec]);\n\n useEffect(() => {\n if (!isPlainDraft || agentSpec == null || updateAgentSpec == null || !loaded || error != null) return;\n\n const update = reconcileDraftSpecPreferences({\n agentSpec,\n models,\n skills,\n connectors,\n skillsEnabled: capabilities?.skill.enabled,\n });\n if (Object.keys(update).length > 0) {\n updateAgentSpec(update);\n }\n }, [\n agentSpec,\n capabilities?.skill.enabled,\n connectors,\n error,\n isPlainDraft,\n loaded,\n models,\n skills,\n updateAgentSpec,\n ]);\n\n return null;\n}\n","'use client';\n\nimport { useEffect } from 'react';\n\nimport { useAuiState } from '../assistant-ui.js';\n\n/**\n * Observes the active thread's remote id (assigned once a fresh chat persists)\n * and lifts it to the parent so `ShellRouteSync` can mirror it to `/sessions/:id`.\n * Lives inside the chat runtime, so it remounts with `runtimeKey`; reporting is\n * idempotent, so that is harmless. Carries no react-router dependency.\n */\nexport function RemoteIdRouteBridge({ onRemoteIdChange }: { onRemoteIdChange: (id: string | undefined) => void }) {\n const remoteId = useAuiState(s => s.threadListItem.remoteId);\n useEffect(() => {\n onRemoteIdChange(remoteId ?? undefined);\n }, [remoteId, onRemoteIdChange]);\n return null;\n}\n","'use client';\n\nimport { createTrueFoundryAgentUIServer } from '@truefoundry/assistant-ui-runtime/plugins/truefoundry-agent-server-adapter';\nimport { useEffect, useState } from 'react';\n\nimport type { TrueForgeBuiltInServerConfig, TrueForgeServerConfig } from '../server/TrueForgeServerConfig.js';\nimport type { AgentBuilderCapabilitiesResponse, AgentUIServer, CatalogServer } from '../server/types.js';\n\nexport type ResolvedServerState =\n | { status: 'loading'; server: null; error: null }\n | { status: 'ready'; server: AgentUIServer; error: null }\n | { status: 'error'; server: null; error: unknown };\n\n/** Fallback when an older runtime adapter omits `getCapabilities`. */\nconst DEFAULT_CAPABILITIES = {\n data: {\n sandbox: { enabled: true },\n skill: { enabled: true },\n settings: { enabled: true },\n },\n} satisfies AgentBuilderCapabilitiesResponse;\n\nfunction isBuiltInConfig(config: TrueForgeServerConfig): config is TrueForgeBuiltInServerConfig {\n return (\n typeof config === 'object' &&\n config !== null &&\n 'type' in config &&\n (config.type === 'truefoundry' || config.type === 'trueforge')\n );\n}\n\nfunction hasGetCapabilities(\n server: object,\n): server is { getCapabilities: () => Promise<AgentBuilderCapabilitiesResponse> } {\n return typeof Reflect.get(server, 'getCapabilities') === 'function';\n}\n\n/**\n * Attach optional catalog and ensure `getCapabilities` exists on the composed port.\n */\nfunction toAgentUIServer(server: object, catalog: CatalogServer | undefined): AgentUIServer {\n const getCapabilities = hasGetCapabilities(server)\n ? () => server.getCapabilities()\n : async () => DEFAULT_CAPABILITIES;\n const withCapabilities = { ...server, getCapabilities };\n const withCatalog = catalog != null ? { ...withCapabilities, catalog } : withCapabilities;\n if (!isAgentUIServer(withCatalog)) {\n throw new Error('TrueForgeUI: runtime adapter returned an incomplete AgentUIServer');\n }\n return withCatalog;\n}\n\nfunction isAgentUIServer(value: object): value is AgentUIServer {\n return (\n typeof Reflect.get(value, 'createSession') === 'function' &&\n typeof Reflect.get(value, 'listSessions') === 'function' &&\n typeof Reflect.get(value, 'getSession') === 'function' &&\n typeof Reflect.get(value, 'updateSession') === 'function' &&\n typeof Reflect.get(value, 'createTurn') === 'function' &&\n typeof Reflect.get(value, 'cancelSession') === 'function' &&\n typeof Reflect.get(value, 'listTurns') === 'function' &&\n typeof Reflect.get(value, 'getTurn') === 'function' &&\n typeof Reflect.get(value, 'listEvents') === 'function' &&\n typeof Reflect.get(value, 'getCapabilities') === 'function' &&\n typeof Reflect.get(value, 'getModels') === 'function' &&\n typeof Reflect.get(value, 'getSkills') === 'function' &&\n typeof Reflect.get(value, 'getMcp') === 'function' &&\n typeof Reflect.get(value, 'searchAgents') === 'function' &&\n typeof Reflect.get(value, 'saveAgent') === 'function'\n );\n}\n\n/**\n * Resolves a {@link TrueForgeServerConfig} to an {@link AgentUIServer}.\n * - `AgentUIServer` — sync passthrough\n * - `truefoundry` — async via `createTrueFoundryAgentUIServer`\n * - `trueforge` — via dynamic import of the Harness plugin adapter\n */\nexport function useResolvedServer(\n config: TrueForgeServerConfig,\n onError?: (error: unknown) => void,\n): ResolvedServerState {\n const builtIn = isBuiltInConfig(config) ? config : null;\n const directServer: AgentUIServer | null = isBuiltInConfig(config) ? null : config;\n const type = builtIn?.type;\n const apiKey = builtIn?.type === 'truefoundry' ? builtIn.apiKey : '';\n const controlPlaneURL = builtIn?.type === 'truefoundry' ? builtIn.controlPlaneURL : '';\n const gatewayPlaneURL = builtIn?.type === 'truefoundry' ? (builtIn.gatewayPlaneURL ?? '') : '';\n const trueforgeBaseUrl = builtIn?.type === 'trueforge' ? (builtIn.baseUrl ?? '') : '';\n const trueforgeToken = builtIn?.type === 'trueforge' ? (builtIn.token ?? '') : '';\n const trueforgeFetch = builtIn?.type === 'trueforge' ? builtIn.fetch : undefined;\n const catalog = builtIn?.catalog;\n\n const [state, setState] = useState<ResolvedServerState>(() => {\n if (directServer) {\n return { status: 'ready', server: directServer, error: null };\n }\n return { status: 'loading', server: null, error: null };\n });\n\n useEffect(() => {\n if (directServer) {\n setState({ status: 'ready', server: directServer, error: null });\n return;\n }\n\n let cancelled = false;\n setState({ status: 'loading', server: null, error: null });\n\n const resolve = async (): Promise<AgentUIServer> => {\n if (type === 'trueforge') {\n const { createTrueForgeAgentUIServer } = await import('../plugins/trueforge-agent-server-adapter/index.js');\n return createTrueForgeAgentUIServer({\n ...(trueforgeBaseUrl ? { baseUrl: trueforgeBaseUrl } : {}),\n ...(trueforgeToken ? { token: trueforgeToken } : {}),\n ...(trueforgeFetch !== undefined ? { fetch: trueforgeFetch } : {}),\n ...(catalog != null ? { catalog } : {}),\n });\n }\n\n const runtimeServer = await createTrueFoundryAgentUIServer({\n apiKey,\n cpURL: controlPlaneURL,\n ...(gatewayPlaneURL ? { gatewayURL: gatewayPlaneURL } : {}),\n });\n // TrueFoundry adapter may omit catalog; attach host-supplied catalog here.\n return toAgentUIServer(runtimeServer, catalog);\n };\n\n void resolve()\n .then(server => {\n if (cancelled) return;\n try {\n // trueforge factory already includes catalog; still normalize capabilities.\n setState({\n status: 'ready',\n server: type === 'trueforge' ? toAgentUIServer(server, undefined) : server,\n error: null,\n });\n } catch (error: unknown) {\n onError?.(error);\n setState({ status: 'error', server: null, error });\n }\n })\n .catch((error: unknown) => {\n if (cancelled) return;\n onError?.(error);\n setState({ status: 'error', server: null, error });\n });\n\n return () => {\n cancelled = true;\n };\n }, [\n type,\n directServer,\n apiKey,\n controlPlaneURL,\n gatewayPlaneURL,\n trueforgeBaseUrl,\n trueforgeToken,\n trueforgeFetch,\n catalog,\n onError,\n ]);\n\n return state;\n}\n"],"mappings":"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","names":["useCallback","useMemo","useState","useEffect","useEffect","useEffect","jsx","useMemo","useState","useCallback"]}
@@ -0,0 +1,64 @@
1
+ // src/hooks/useComposerBusyState.ts
2
+ import { useThreadIsRunning } from "@assistant-ui/core/react";
3
+ import { createContext, createElement, useCallback, useContext, useEffect, useState } from "react";
4
+ var ComposerBusyContext = createContext(null);
5
+ var busyFailureListeners = /* @__PURE__ */ new Set();
6
+ function notifyComposerBusyFailure() {
7
+ for (const listener of busyFailureListeners) {
8
+ listener();
9
+ }
10
+ }
11
+ function useComposerBusyStateValue() {
12
+ const isRunning = useThreadIsRunning();
13
+ const [isSubmitting, setIsSubmitting] = useState(false);
14
+ useEffect(() => {
15
+ if (!isRunning) {
16
+ setIsSubmitting(false);
17
+ }
18
+ }, [isRunning]);
19
+ useEffect(() => {
20
+ const clearSubmitting = () => {
21
+ setIsSubmitting(false);
22
+ };
23
+ busyFailureListeners.add(clearSubmitting);
24
+ return () => {
25
+ busyFailureListeners.delete(clearSubmitting);
26
+ };
27
+ }, []);
28
+ const isBusy = isRunning || isSubmitting;
29
+ const resetBusy = useCallback(() => {
30
+ setIsSubmitting(false);
31
+ }, []);
32
+ const send = useCallback((sendFn) => {
33
+ setIsSubmitting(true);
34
+ try {
35
+ const result = sendFn();
36
+ if (result != null && typeof result.then === "function") {
37
+ void result.catch(() => {
38
+ setIsSubmitting(false);
39
+ });
40
+ }
41
+ } catch {
42
+ setIsSubmitting(false);
43
+ }
44
+ }, []);
45
+ return { isBusy, isRunning, isSubmitting, send, resetBusy };
46
+ }
47
+ function ComposerBusyProvider({ children }) {
48
+ const value = useComposerBusyStateValue();
49
+ return createElement(ComposerBusyContext.Provider, { value }, children);
50
+ }
51
+ function useComposerBusyState() {
52
+ const value = useContext(ComposerBusyContext);
53
+ if (value == null) {
54
+ throw new Error("useComposerBusyState must be used within ComposerBusyProvider");
55
+ }
56
+ return value;
57
+ }
58
+
59
+ export {
60
+ notifyComposerBusyFailure,
61
+ ComposerBusyProvider,
62
+ useComposerBusyState
63
+ };
64
+ //# sourceMappingURL=chunk-FXCYLEFB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/hooks/useComposerBusyState.ts"],"sourcesContent":["'use client';\n\nimport { useThreadIsRunning } from '@assistant-ui/core/react';\nimport { createContext, createElement, useCallback, useContext, useEffect, useState, type ReactNode } from 'react';\n\nexport type ComposerBusyState = {\n /** True while submitting or while the turn stream is active. */\n isBusy: boolean;\n isRunning: boolean;\n isSubmitting: boolean;\n send: (sendFn: () => void | Promise<void>) => void;\n resetBusy: () => void;\n};\n\nconst ComposerBusyContext = createContext<ComposerBusyState | null>(null);\n\n/**\n * `aui.composer().send()` returns void and swallows `onNew` rejections, so the\n * optimistic submitting flag cannot clear via Promise.catch. First-message\n * failures (e.g. createSession) also never flip `useThreadIsRunning()`. Chat\n * runtime `onError` calls this so the Cancel/spinner state does not stick.\n */\nconst busyFailureListeners = new Set<() => void>();\n\nexport function notifyComposerBusyFailure(): void {\n for (const listener of busyFailureListeners) {\n listener();\n }\n}\n\nfunction useComposerBusyStateValue(): ComposerBusyState {\n const isRunning = useThreadIsRunning();\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n useEffect(() => {\n if (!isRunning) {\n setIsSubmitting(false);\n }\n }, [isRunning]);\n\n useEffect(() => {\n const clearSubmitting = () => {\n setIsSubmitting(false);\n };\n busyFailureListeners.add(clearSubmitting);\n return () => {\n busyFailureListeners.delete(clearSubmitting);\n };\n }, []);\n\n const isBusy = isRunning || isSubmitting;\n\n const resetBusy = useCallback(() => {\n setIsSubmitting(false);\n }, []);\n\n const send = useCallback((sendFn: () => void | Promise<void>) => {\n setIsSubmitting(true);\n try {\n const result = sendFn();\n if (result != null && typeof result.then === 'function') {\n void result.catch(() => {\n setIsSubmitting(false);\n });\n }\n } catch {\n setIsSubmitting(false);\n }\n }, []);\n\n return { isBusy, isRunning, isSubmitting, send, resetBusy };\n}\n\nexport function ComposerBusyProvider({ children }: { children: ReactNode }) {\n const value = useComposerBusyStateValue();\n return createElement(ComposerBusyContext.Provider, { value }, children);\n}\n\n/**\n * Optimistic composer busy state shared across the thread. `useThreadIsRunning()`\n * only becomes true once the turn stream starts; this hook flips to busy\n * immediately on submit so the send button shows loading before session setup /\n * turn API work finishes.\n *\n * Must be used within `<ComposerBusyProvider>` (wired by default in `<Thread />`).\n */\nexport function useComposerBusyState(): ComposerBusyState {\n const value = useContext(ComposerBusyContext);\n if (value == null) {\n throw new Error('useComposerBusyState must be used within ComposerBusyProvider');\n }\n return value;\n}\n"],"mappings":";AAEA,SAAS,0BAA0B;AACnC,SAAS,eAAe,eAAe,aAAa,YAAY,WAAW,gBAAgC;AAW3G,IAAM,sBAAsB,cAAwC,IAAI;AAQxE,IAAM,uBAAuB,oBAAI,IAAgB;AAE1C,SAAS,4BAAkC;AAChD,aAAW,YAAY,sBAAsB;AAC3C,aAAS;AAAA,EACX;AACF;AAEA,SAAS,4BAA+C;AACtD,QAAM,YAAY,mBAAmB;AACrC,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,KAAK;AAEtD,YAAU,MAAM;AACd,QAAI,CAAC,WAAW;AACd,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,SAAS,CAAC;AAEd,YAAU,MAAM;AACd,UAAM,kBAAkB,MAAM;AAC5B,sBAAgB,KAAK;AAAA,IACvB;AACA,yBAAqB,IAAI,eAAe;AACxC,WAAO,MAAM;AACX,2BAAqB,OAAO,eAAe;AAAA,IAC7C;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,SAAS,aAAa;AAE5B,QAAM,YAAY,YAAY,MAAM;AAClC,oBAAgB,KAAK;AAAA,EACvB,GAAG,CAAC,CAAC;AAEL,QAAM,OAAO,YAAY,CAAC,WAAuC;AAC/D,oBAAgB,IAAI;AACpB,QAAI;AACF,YAAM,SAAS,OAAO;AACtB,UAAI,UAAU,QAAQ,OAAO,OAAO,SAAS,YAAY;AACvD,aAAK,OAAO,MAAM,MAAM;AACtB,0BAAgB,KAAK;AAAA,QACvB,CAAC;AAAA,MACH;AAAA,IACF,QAAQ;AACN,sBAAgB,KAAK;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,QAAQ,WAAW,cAAc,MAAM,UAAU;AAC5D;AAEO,SAAS,qBAAqB,EAAE,SAAS,GAA4B;AAC1E,QAAM,QAAQ,0BAA0B;AACxC,SAAO,cAAc,oBAAoB,UAAU,EAAE,MAAM,GAAG,QAAQ;AACxE;AAUO,SAAS,uBAA0C;AACxD,QAAM,QAAQ,WAAW,mBAAmB;AAC5C,MAAI,SAAS,MAAM;AACjB,UAAM,IAAI,MAAM,+DAA+D;AAAA,EACjF;AACA,SAAO;AACT;","names":[]}