@iloveagents/foundry-web-ui 0.3.1 → 0.4.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.
- package/README.md +13 -4
- package/dist/components/ag-ui-runtime-provider.d.ts +64 -0
- package/dist/components/ag-ui-runtime-provider.js +71 -0
- package/dist/components/app-brand.d.ts +6 -0
- package/dist/components/app-brand.js +13 -0
- package/dist/components/assistant-chat.d.ts +26 -0
- package/dist/components/assistant-chat.js +93 -0
- package/dist/components/chat-attachments.d.ts +25 -0
- package/dist/components/chat-attachments.js +20 -0
- package/dist/components/chat-bubble.d.ts +1 -0
- package/dist/components/chat-bubble.js +103 -0
- package/dist/components/chat-header.d.ts +2 -0
- package/dist/components/chat-header.js +16 -0
- package/dist/components/client-tool-executor.d.ts +12 -0
- package/dist/components/client-tool-executor.js +108 -0
- package/dist/components/collection-empty-state.d.ts +9 -0
- package/dist/components/collection-empty-state.js +6 -0
- package/dist/components/collection-filter-bar.d.ts +19 -0
- package/dist/components/collection-filter-bar.js +28 -0
- package/dist/components/collection-search-input.d.ts +6 -0
- package/dist/components/collection-search-input.js +8 -0
- package/dist/components/collection-skeleton.d.ts +6 -0
- package/dist/components/collection-skeleton.js +10 -0
- package/dist/components/collection-sort-menu.d.ts +10 -0
- package/dist/components/collection-sort-menu.js +9 -0
- package/dist/components/collection-surface.d.ts +8 -0
- package/dist/components/collection-surface.js +5 -0
- package/dist/components/collection-toolbar.d.ts +9 -0
- package/dist/components/collection-toolbar.js +5 -0
- package/dist/components/collection-view-toggle.d.ts +7 -0
- package/dist/components/collection-view-toggle.js +17 -0
- package/dist/components/composer-submit-bridge.d.ts +1 -0
- package/dist/components/composer-submit-bridge.js +15 -0
- package/dist/components/confirm-dialog.d.ts +11 -0
- package/dist/components/confirm-dialog.js +6 -0
- package/dist/components/confirmation-card.d.ts +14 -0
- package/dist/components/confirmation-card.js +12 -0
- package/dist/components/context-badges.d.ts +16 -0
- package/dist/components/context-badges.js +56 -0
- package/dist/components/context-bar.d.ts +41 -0
- package/dist/components/context-bar.js +123 -0
- package/dist/components/form-dialog.d.ts +12 -0
- package/dist/components/form-dialog.js +13 -0
- package/dist/components/global-selection-popover.d.ts +7 -0
- package/dist/components/global-selection-popover.js +167 -0
- package/dist/components/infinite-scroll-sentinel.d.ts +6 -0
- package/dist/components/infinite-scroll-sentinel.js +25 -0
- package/dist/components/json-viewer.d.ts +10 -0
- package/dist/components/json-viewer.js +80 -0
- package/dist/components/loading-indicator.d.ts +4 -0
- package/dist/components/loading-indicator.js +22 -0
- package/dist/components/markdown-text.d.ts +13 -0
- package/dist/components/markdown-text.js +221 -0
- package/dist/components/name-dialog.d.ts +16 -0
- package/dist/components/name-dialog.js +23 -0
- package/dist/components/selection-popover.d.ts +12 -0
- package/dist/components/selection-popover.js +111 -0
- package/dist/components/show-document-tool-ui.d.ts +1 -0
- package/dist/components/show-document-tool-ui.js +53 -0
- package/dist/components/sidebar.d.ts +4 -0
- package/dist/components/sidebar.js +904 -0
- package/dist/components/surface-card.d.ts +9 -0
- package/dist/components/surface-card.js +33 -0
- package/dist/components/theme-runtime-provider.d.ts +15 -0
- package/dist/components/theme-runtime-provider.js +48 -0
- package/dist/components/theme-toggle.d.ts +2 -0
- package/dist/components/theme-toggle.js +19 -0
- package/dist/components/tool-call-card.d.ts +27 -0
- package/dist/components/tool-call-card.js +13 -0
- package/dist/components/tool-fallback.d.ts +26 -0
- package/dist/components/tool-fallback.js +129 -0
- package/dist/components/tool-panel-layout.d.ts +10 -0
- package/dist/components/tool-panel-layout.js +12 -0
- package/dist/components/tool-panel.d.ts +1 -0
- package/dist/components/tool-panel.js +89 -0
- package/dist/components/tooltip-icon-button.d.ts +7 -0
- package/dist/components/tooltip-icon-button.js +9 -0
- package/dist/components/user-menu.d.ts +2 -0
- package/dist/components/user-menu.js +14 -0
- package/dist/index.d.ts +68 -0
- package/dist/index.js +83 -0
- package/dist/lib/ag-ui-adapter.d.ts +29 -0
- package/dist/lib/ag-ui-adapter.js +373 -0
- package/dist/lib/app-store.d.ts +115 -0
- package/dist/lib/app-store.js +199 -0
- package/dist/lib/attachment-adapter.d.ts +20 -0
- package/dist/lib/attachment-adapter.js +99 -0
- package/dist/lib/auth-provider.d.ts +16 -0
- package/dist/lib/auth-provider.js +88 -0
- package/dist/lib/chat-bubble-store.d.ts +30 -0
- package/dist/lib/chat-bubble-store.js +23 -0
- package/dist/lib/chat-lifecycle-store.d.ts +10 -0
- package/{src/lib/chat-lifecycle-store.ts → dist/lib/chat-lifecycle-store.js} +3 -13
- package/dist/lib/client-tools.d.ts +11 -0
- package/dist/lib/client-tools.js +274 -0
- package/dist/lib/composer-submit-store.d.ts +12 -0
- package/dist/lib/composer-submit-store.js +17 -0
- package/dist/lib/dev-store.d.ts +38 -0
- package/dist/lib/dev-store.js +32 -0
- package/dist/lib/nav-config.d.ts +159 -0
- package/dist/lib/nav-config.js +162 -0
- package/dist/lib/nav-dnd.d.ts +8 -0
- package/dist/lib/nav-dnd.js +9 -0
- package/dist/lib/nav-store.d.ts +45 -0
- package/dist/lib/nav-store.js +49 -0
- package/dist/lib/selection-context.d.ts +21 -0
- package/dist/lib/selection-context.js +34 -0
- package/dist/lib/sidebar-store.d.ts +23 -0
- package/dist/lib/sidebar-store.js +98 -0
- package/dist/lib/theme-runtime.d.ts +130 -0
- package/dist/lib/theme-runtime.js +479 -0
- package/dist/lib/theme-store.d.ts +15 -0
- package/dist/lib/theme-store.js +53 -0
- package/dist/lib/tool-panel-store.d.ts +48 -0
- package/dist/lib/tool-panel-store.js +69 -0
- package/dist/lib/use-new-conversation.d.ts +8 -0
- package/dist/lib/use-new-conversation.js +62 -0
- package/dist/lib/use-page-tools.d.ts +27 -0
- package/{src/lib/use-page-tools.ts → dist/lib/use-page-tools.js} +11 -13
- package/dist/styles.css +142 -0
- package/dist/ui/collapsible.d.ts +5 -0
- package/{src/ui/collapsible.tsx → dist/ui/collapsible.js} +0 -2
- package/dist/ui/dialog.d.ts +15 -0
- package/dist/ui/dialog.js +25 -0
- package/dist/ui/dropdown-menu.d.ts +7 -0
- package/dist/ui/dropdown-menu.js +19 -0
- package/dist/ui/popover.d.ts +7 -0
- package/dist/ui/popover.js +10 -0
- package/dist/ui/select.d.ts +4 -0
- package/dist/ui/select.js +9 -0
- package/dist/ui/tooltip.d.ts +7 -0
- package/dist/ui/tooltip.js +10 -0
- package/package.json +31 -12
- package/AGENTS.md +0 -59
- package/CHANGELOG.md +0 -211
- package/CLAUDE.md +0 -1
- package/src/__tests__/no-spaces-imports.test.ts +0 -59
- package/src/__tests__/open-core-guards.test.ts +0 -307
- package/src/__tests__/theme-runtime.test.ts +0 -81
- package/src/__tests__/tool-fallback.test.tsx +0 -109
- package/src/components/__tests__/context-bar.test.ts +0 -112
- package/src/components/ag-ui-runtime-provider.tsx +0 -170
- package/src/components/app-brand.tsx +0 -38
- package/src/components/assistant-chat.tsx +0 -461
- package/src/components/chat-attachments.tsx +0 -68
- package/src/components/chat-bubble.tsx +0 -373
- package/src/components/chat-header.tsx +0 -44
- package/src/components/client-tool-executor.tsx +0 -230
- package/src/components/collection-empty-state.tsx +0 -37
- package/src/components/collection-filter-bar.tsx +0 -168
- package/src/components/collection-search-input.tsx +0 -41
- package/src/components/collection-skeleton.tsx +0 -55
- package/src/components/collection-sort-menu.tsx +0 -62
- package/src/components/collection-surface.tsx +0 -46
- package/src/components/collection-toolbar.tsx +0 -33
- package/src/components/collection-view-toggle.tsx +0 -61
- package/src/components/composer-submit-bridge.tsx +0 -19
- package/src/components/confirm-dialog.tsx +0 -49
- package/src/components/confirmation-card.tsx +0 -32
- package/src/components/context-badges.tsx +0 -136
- package/src/components/context-bar.tsx +0 -238
- package/src/components/form-dialog.tsx +0 -56
- package/src/components/global-selection-popover.tsx +0 -266
- package/src/components/infinite-scroll-sentinel.tsx +0 -48
- package/src/components/json-viewer.tsx +0 -232
- package/src/components/loading-indicator.tsx +0 -40
- package/src/components/markdown-text-citations.test.tsx +0 -108
- package/src/components/markdown-text.tsx +0 -508
- package/src/components/name-dialog.tsx +0 -87
- package/src/components/selection-popover.tsx +0 -156
- package/src/components/show-document-tool-ui.tsx +0 -90
- package/src/components/sidebar.test.tsx +0 -611
- package/src/components/sidebar.tsx +0 -1689
- package/src/components/surface-card.tsx +0 -45
- package/src/components/theme-runtime-provider.tsx +0 -93
- package/src/components/theme-toggle.tsx +0 -27
- package/src/components/tool-call-card.tsx +0 -126
- package/src/components/tool-fallback.tsx +0 -169
- package/src/components/tool-panel-layout.tsx +0 -36
- package/src/components/tool-panel.tsx +0 -233
- package/src/components/tooltip-icon-button.tsx +0 -28
- package/src/components/user-menu.tsx +0 -60
- package/src/index.ts +0 -185
- package/src/lib/__tests__/ag-ui-adapter.test.ts +0 -279
- package/src/lib/__tests__/app-store.test.ts +0 -405
- package/src/lib/__tests__/attachment-adapter.test.ts +0 -48
- package/src/lib/__tests__/chat-bubble-store.test.ts +0 -67
- package/src/lib/__tests__/client-tools.test.ts +0 -124
- package/src/lib/__tests__/dev-store.test.ts +0 -78
- package/src/lib/__tests__/nav-config.test.ts +0 -135
- package/src/lib/__tests__/nav-dnd.test.ts +0 -24
- package/src/lib/__tests__/nav-store.test.ts +0 -59
- package/src/lib/__tests__/selection-context.test.ts +0 -114
- package/src/lib/__tests__/sidebar-store.test.ts +0 -144
- package/src/lib/__tests__/theme-store.test.ts +0 -83
- package/src/lib/__tests__/tool-panel-store.test.ts +0 -61
- package/src/lib/__tests__/use-page-context.test.ts +0 -58
- package/src/lib/ag-ui-adapter.ts +0 -426
- package/src/lib/app-store.ts +0 -361
- package/src/lib/attachment-adapter.ts +0 -92
- package/src/lib/auth-provider.tsx +0 -144
- package/src/lib/chat-bubble-store.ts +0 -46
- package/src/lib/client-tools.ts +0 -293
- package/src/lib/composer-submit-store.ts +0 -32
- package/src/lib/dev-store.ts +0 -69
- package/src/lib/nav-config.ts +0 -329
- package/src/lib/nav-dnd.ts +0 -14
- package/src/lib/nav-store.ts +0 -89
- package/src/lib/selection-context.ts +0 -65
- package/src/lib/sidebar-store.ts +0 -113
- package/src/lib/theme-runtime.ts +0 -660
- package/src/lib/theme-store.ts +0 -67
- package/src/lib/tool-panel-store.ts +0 -121
- package/src/lib/use-new-conversation.test.tsx +0 -168
- package/src/lib/use-new-conversation.ts +0 -64
- package/src/ui/dialog.tsx +0 -109
- package/src/ui/dropdown-menu.tsx +0 -75
- package/src/ui/popover.tsx +0 -34
- package/src/ui/select.tsx +0 -15
- package/src/ui/tooltip.tsx +0 -30
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -16
- package/vitest.config.ts +0 -8
package/dist/index.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// --- Components ---
|
|
2
|
+
export { Sidebar } from "./components/sidebar.js";
|
|
3
|
+
export { ToolPanel } from "./components/tool-panel.js";
|
|
4
|
+
export { ToolPanelLayout } from "./components/tool-panel-layout.js";
|
|
5
|
+
export { MarkdownText, markdownComponents } from "./components/markdown-text.js";
|
|
6
|
+
export { ClientToolExecutor } from "./components/client-tool-executor.js";
|
|
7
|
+
export { AGUIRuntimeProvider, useAGUIAdapter } from "./components/ag-ui-runtime-provider.js";
|
|
8
|
+
export { ChatContent, DEFAULT_STARTER_SUGGESTIONS } from "./components/assistant-chat.js";
|
|
9
|
+
export { ChatBubble } from "./components/chat-bubble.js";
|
|
10
|
+
export { ChatHeader } from "./components/chat-header.js";
|
|
11
|
+
export { ComposerAttachment, UserMessageAttachment, userAttachmentComponents, composerAttachmentComponents, } from "./components/chat-attachments.js";
|
|
12
|
+
export { ShowDocumentToolUI } from "./components/show-document-tool-ui.js";
|
|
13
|
+
export { ToolCallCard } from "./components/tool-call-card.js";
|
|
14
|
+
export { ToolFallback } from "./components/tool-fallback.js";
|
|
15
|
+
export { ConfirmationCard } from "./components/confirmation-card.js";
|
|
16
|
+
export { TooltipIconButton } from "./components/tooltip-icon-button.js";
|
|
17
|
+
export { ComposerContextBadges, SentContextBadges } from "./components/context-badges.js";
|
|
18
|
+
export { ContextPins } from "./components/context-bar.js";
|
|
19
|
+
export { SelectionPopover } from "./components/selection-popover.js";
|
|
20
|
+
export { GlobalSelectionPopover } from "./components/global-selection-popover.js";
|
|
21
|
+
export { LoadingIndicator } from "./components/loading-indicator.js";
|
|
22
|
+
export { ThemeToggle } from "./components/theme-toggle.js";
|
|
23
|
+
export { AppBrand } from "./components/app-brand.js";
|
|
24
|
+
export { CollectionToolbar } from "./components/collection-toolbar.js";
|
|
25
|
+
export { CollectionSearchInput } from "./components/collection-search-input.js";
|
|
26
|
+
export { CollectionFilterBar, } from "./components/collection-filter-bar.js";
|
|
27
|
+
export { CollectionSortMenu, } from "./components/collection-sort-menu.js";
|
|
28
|
+
export { CollectionViewToggle, } from "./components/collection-view-toggle.js";
|
|
29
|
+
export { CollectionEmptyState } from "./components/collection-empty-state.js";
|
|
30
|
+
export { CollectionSkeleton } from "./components/collection-skeleton.js";
|
|
31
|
+
export { InfiniteScrollSentinel } from "./components/infinite-scroll-sentinel.js";
|
|
32
|
+
export { CollectionSurface } from "./components/collection-surface.js";
|
|
33
|
+
export { ThemeRuntimeProvider, ThemeScope, ThemeDocumentMetadata, useThemeRuntime, } from "./components/theme-runtime-provider.js";
|
|
34
|
+
export { JsonViewer } from "./components/json-viewer.js";
|
|
35
|
+
export { UserMenu } from "./components/user-menu.js";
|
|
36
|
+
export { FormDialog } from "./components/form-dialog.js";
|
|
37
|
+
export { ConfirmDialog } from "./components/confirm-dialog.js";
|
|
38
|
+
export { NameDialog } from "./components/name-dialog.js";
|
|
39
|
+
export { SurfaceCard, surfaceCardVariants } from "./components/surface-card.js";
|
|
40
|
+
// --- Composite UI primitives (theme-runtime-coupled — stay here for now) ---
|
|
41
|
+
// Button, Checkbox, Input, Textarea, Field, FieldSet have moved to
|
|
42
|
+
// @iloveagents/foundry-web-primitives (#94). The primitives below have a runtime
|
|
43
|
+
// coupling to ThemeScope (theme-runtime-provider.tsx) — they need a
|
|
44
|
+
// theme-system refactor before they can move to the leaf primitives
|
|
45
|
+
// package. Tracked for a follow-up under #95/#96.
|
|
46
|
+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, } from "./ui/tooltip.js";
|
|
47
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent, } from "./ui/collapsible.js";
|
|
48
|
+
export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuLabel, } from "./ui/dropdown-menu.js";
|
|
49
|
+
export { Dialog, DialogPortal, DialogOverlay, DialogTrigger, DialogClose, DialogContent, DialogHeader, DialogFooter, DialogTitle, DialogDescription, } from "./ui/dialog.js";
|
|
50
|
+
export { Popover, PopoverTrigger, PopoverAnchor, PopoverContent } from "./ui/popover.js";
|
|
51
|
+
export { Select, selectClassName } from "./ui/select.js";
|
|
52
|
+
// --- Stores ---
|
|
53
|
+
export { useAppStore } from "./lib/app-store.js";
|
|
54
|
+
export { useNavStore } from "./lib/nav-store.js";
|
|
55
|
+
export { useToolPanelStore } from "./lib/tool-panel-store.js";
|
|
56
|
+
export { useSidebarStore, SIDEBAR_WIDTH, RAIL_WIDTH } from "./lib/sidebar-store.js";
|
|
57
|
+
export { useChatBubbleStore } from "./lib/chat-bubble-store.js";
|
|
58
|
+
export { useChatLifecycleStore } from "./lib/chat-lifecycle-store.js";
|
|
59
|
+
export { submitComposerText } from "./lib/composer-submit-store.js";
|
|
60
|
+
export { registerSelectionContextResolver, resolveSelectionContext, } from "./lib/selection-context.js";
|
|
61
|
+
export { useThemeStore } from "./lib/theme-store.js";
|
|
62
|
+
export { mergeThemeDefinitions, resolveThemeRuntime, getEffectiveThemeMode, getThemePreset, } from "./lib/theme-runtime.js";
|
|
63
|
+
// Stores moved to @iloveagents/foundry-agent (#95): authStore, citationStore,
|
|
64
|
+
// streamingStatusStore, clientToolRegistry. Consumers import directly from
|
|
65
|
+
// `@iloveagents/foundry-agent` / `@iloveagents/foundry-agent/msal` — no re-exports here per
|
|
66
|
+
// the no-shim rule.
|
|
67
|
+
export { useDevStore } from "./lib/dev-store.js";
|
|
68
|
+
// --- Nav types ---
|
|
69
|
+
export { DEFAULT_NAV_CONFIG, findNavItem } from "./lib/nav-config.js";
|
|
70
|
+
// --- Hooks ---
|
|
71
|
+
export { usePageTools } from "./lib/use-page-tools.js";
|
|
72
|
+
export { useNewConversation } from "./lib/use-new-conversation.js";
|
|
73
|
+
// --- Adapters ---
|
|
74
|
+
export { AGUIAdapterSDK } from "./lib/ag-ui-adapter.js";
|
|
75
|
+
export { FileAttachmentAdapter } from "./lib/attachment-adapter.js";
|
|
76
|
+
// --- Auth ---
|
|
77
|
+
// `AuthProvider` is the React MSAL bootstrap (uses `@azure/msal-react`).
|
|
78
|
+
// Token store, config, fetch wrapper all live in `@iloveagents/foundry-agent/msal`.
|
|
79
|
+
export { AuthProvider } from "./lib/auth-provider.js";
|
|
80
|
+
// --- Utils ---
|
|
81
|
+
// `cn` is sourced from @iloveagents/foundry-web-primitives (the leaf primitives package).
|
|
82
|
+
// Re-exporting here would create two canonical sources for the same
|
|
83
|
+
// utility — banned per the "no shims" pre-1.0 rule (#90).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AG-UI Adapter for assistant-ui.
|
|
3
|
+
*
|
|
4
|
+
* Thin shim around `@iloveagents/foundry-agent`'s `AGUIRunner`:
|
|
5
|
+
* - converts assistant-ui `Message[]` → AG-UI `Message[]` on input,
|
|
6
|
+
* - feeds the runner, drains its `RunnerEvent` stream,
|
|
7
|
+
* - accumulates text + tool-call state,
|
|
8
|
+
* - yields cumulative `ChatModelRunResult` snapshots (assistant-ui requires
|
|
9
|
+
* each yield to carry the *complete* content array — never deltas).
|
|
10
|
+
*
|
|
11
|
+
* Wires the React-only stores that don't belong in `@iloveagents/foundry-agent`:
|
|
12
|
+
* - `useAppStore` for context-item snapshot + lifecycle hooks
|
|
13
|
+
* - `useDevStore` for dev-panel request/tool capture (driven by the
|
|
14
|
+
* runner's `request-sent` event).
|
|
15
|
+
*
|
|
16
|
+
* @see https://docs.ag-ui.com/sdk/js/client/http-agent
|
|
17
|
+
* @see https://www.assistant-ui.com/docs/runtimes/custom/local
|
|
18
|
+
*/
|
|
19
|
+
import type { ChatModelAdapter, ChatModelRunOptions, ChatModelRunResult } from "@assistant-ui/react";
|
|
20
|
+
export declare class AGUIAdapterSDK implements ChatModelAdapter {
|
|
21
|
+
private readonly runner;
|
|
22
|
+
constructor(url?: string, options?: {
|
|
23
|
+
threadId?: string;
|
|
24
|
+
fetchFn?: typeof fetch;
|
|
25
|
+
});
|
|
26
|
+
get threadId(): string;
|
|
27
|
+
get state(): unknown;
|
|
28
|
+
run({ messages, abortSignal }: ChatModelRunOptions): AsyncGenerator<ChatModelRunResult>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AG-UI Adapter for assistant-ui.
|
|
3
|
+
*
|
|
4
|
+
* Thin shim around `@iloveagents/foundry-agent`'s `AGUIRunner`:
|
|
5
|
+
* - converts assistant-ui `Message[]` → AG-UI `Message[]` on input,
|
|
6
|
+
* - feeds the runner, drains its `RunnerEvent` stream,
|
|
7
|
+
* - accumulates text + tool-call state,
|
|
8
|
+
* - yields cumulative `ChatModelRunResult` snapshots (assistant-ui requires
|
|
9
|
+
* each yield to carry the *complete* content array — never deltas).
|
|
10
|
+
*
|
|
11
|
+
* Wires the React-only stores that don't belong in `@iloveagents/foundry-agent`:
|
|
12
|
+
* - `useAppStore` for context-item snapshot + lifecycle hooks
|
|
13
|
+
* - `useDevStore` for dev-panel request/tool capture (driven by the
|
|
14
|
+
* runner's `request-sent` event).
|
|
15
|
+
*
|
|
16
|
+
* @see https://docs.ag-ui.com/sdk/js/client/http-agent
|
|
17
|
+
* @see https://www.assistant-ui.com/docs/runtimes/custom/local
|
|
18
|
+
*/
|
|
19
|
+
import { AGUIRunner, clientToolRegistry, streamingStatusStore } from "@iloveagents/foundry-agent";
|
|
20
|
+
import { tokenFetch } from "@iloveagents/foundry-agent/msal";
|
|
21
|
+
import { useAppStore } from "./app-store.js";
|
|
22
|
+
import { useDevStore } from "./dev-store.js";
|
|
23
|
+
export class AGUIAdapterSDK {
|
|
24
|
+
constructor(url = "/api/agent", options) {
|
|
25
|
+
this.runner = new AGUIRunner({
|
|
26
|
+
url,
|
|
27
|
+
threadId: options?.threadId,
|
|
28
|
+
fetchFn: options?.fetchFn ?? tokenFetch,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
get threadId() {
|
|
32
|
+
return this.runner.threadId;
|
|
33
|
+
}
|
|
34
|
+
get state() {
|
|
35
|
+
return this.runner.state;
|
|
36
|
+
}
|
|
37
|
+
async *run({ messages, abortSignal }) {
|
|
38
|
+
const aguiMessages = convertMessagesToAGUI(messages);
|
|
39
|
+
// App-level lifecycle: mark thread active, snapshot context, consume
|
|
40
|
+
// ephemeral context off the last user message.
|
|
41
|
+
useAppStore.getState().markThreadActive();
|
|
42
|
+
const appState = useAppStore.getState().getAgentState();
|
|
43
|
+
const context = buildAGUIContext(appState);
|
|
44
|
+
const lastUserMsg = [...messages].reverse().find((m) => m.role === "user");
|
|
45
|
+
if (lastUserMsg) {
|
|
46
|
+
useAppStore.getState().consumeContextForMessage(lastUserMsg.id);
|
|
47
|
+
}
|
|
48
|
+
let currentText = "";
|
|
49
|
+
const toolCalls = new Map();
|
|
50
|
+
let runError = null;
|
|
51
|
+
/**
|
|
52
|
+
* Build a `ChatModelRunResult` from the accumulated state.
|
|
53
|
+
*
|
|
54
|
+
* Per assistant-ui v0.12 contract, every yield must carry the COMPLETE
|
|
55
|
+
* cumulative content array (not deltas). The runner drives multi-turn
|
|
56
|
+
* follow-ups internally; we yield `running` for every intermediate
|
|
57
|
+
* yield, then a single terminal `complete` after the runner's
|
|
58
|
+
* generator returns. assistant-ui leaves the message stuck in the
|
|
59
|
+
* loading state if the last yield's status is `running`.
|
|
60
|
+
*/
|
|
61
|
+
const buildResult = (statusOverride) => {
|
|
62
|
+
const content = [];
|
|
63
|
+
for (const [id, tc] of toolCalls) {
|
|
64
|
+
let parsedArgs = {};
|
|
65
|
+
try {
|
|
66
|
+
parsedArgs = JSON.parse(tc.args || "{}");
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Keep empty object for invalid JSON
|
|
70
|
+
}
|
|
71
|
+
content.push({
|
|
72
|
+
type: "tool-call",
|
|
73
|
+
toolCallId: id,
|
|
74
|
+
toolName: tc.name,
|
|
75
|
+
args: parsedArgs,
|
|
76
|
+
argsText: tc.args,
|
|
77
|
+
result: tc.result,
|
|
78
|
+
isError: tc.isError,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
if (currentText) {
|
|
82
|
+
content.push({ type: "text", text: currentText });
|
|
83
|
+
}
|
|
84
|
+
const status = statusOverride ?? { type: "running" };
|
|
85
|
+
return {
|
|
86
|
+
content,
|
|
87
|
+
status,
|
|
88
|
+
metadata: {
|
|
89
|
+
custom: {
|
|
90
|
+
threadId: this.runner.threadId,
|
|
91
|
+
timestamp: Date.now(),
|
|
92
|
+
state: this.runner.state,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
try {
|
|
98
|
+
for await (const event of this.runner.run({
|
|
99
|
+
messages: aguiMessages,
|
|
100
|
+
state: appState,
|
|
101
|
+
context,
|
|
102
|
+
registry: clientToolRegistry.getState(),
|
|
103
|
+
abortSignal,
|
|
104
|
+
})) {
|
|
105
|
+
let shouldYield = false;
|
|
106
|
+
switch (event.type) {
|
|
107
|
+
case "request-sent":
|
|
108
|
+
if (import.meta.env.DEV) {
|
|
109
|
+
useDevStore.getState().captureRequest(event.input);
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
case "turn-started":
|
|
113
|
+
currentText = "";
|
|
114
|
+
shouldYield = true;
|
|
115
|
+
break;
|
|
116
|
+
case "run-started":
|
|
117
|
+
// Per-turn signal — the runner may issue multiple turns for
|
|
118
|
+
// multi-turn tool follow-ups. Terminal completion is yielded
|
|
119
|
+
// post-loop, not on the per-turn run-finished.
|
|
120
|
+
break;
|
|
121
|
+
case "run-finished":
|
|
122
|
+
// Intermediate yield — keeps the message in the running state
|
|
123
|
+
// while the runner decides whether to re-issue.
|
|
124
|
+
shouldYield = true;
|
|
125
|
+
break;
|
|
126
|
+
case "run-error":
|
|
127
|
+
runError = event.message;
|
|
128
|
+
console.error("Run error:", event.message);
|
|
129
|
+
shouldYield = true;
|
|
130
|
+
break;
|
|
131
|
+
case "streaming-status":
|
|
132
|
+
streamingStatusStore.getState().setStreamingStatus(event.status);
|
|
133
|
+
break;
|
|
134
|
+
case "text-delta":
|
|
135
|
+
currentText += event.delta;
|
|
136
|
+
shouldYield = true;
|
|
137
|
+
break;
|
|
138
|
+
case "text-message-end":
|
|
139
|
+
shouldYield = true;
|
|
140
|
+
break;
|
|
141
|
+
case "tool-call-start":
|
|
142
|
+
toolCalls.set(event.id, { id: event.id, name: event.name, args: "" });
|
|
143
|
+
if (import.meta.env.DEV) {
|
|
144
|
+
useDevStore.getState().addToolCall({
|
|
145
|
+
id: event.id,
|
|
146
|
+
name: event.name,
|
|
147
|
+
args: "",
|
|
148
|
+
isClientSide: event.isClientSide,
|
|
149
|
+
timestamp: Date.now(),
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
shouldYield = true;
|
|
153
|
+
break;
|
|
154
|
+
case "tool-call-args": {
|
|
155
|
+
const tc = toolCalls.get(event.id);
|
|
156
|
+
if (tc) {
|
|
157
|
+
tc.args += event.delta;
|
|
158
|
+
shouldYield = true;
|
|
159
|
+
}
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
case "tool-call-end": {
|
|
163
|
+
const tc = toolCalls.get(event.id);
|
|
164
|
+
if (tc) {
|
|
165
|
+
tc.args = event.args;
|
|
166
|
+
if (event.result !== undefined)
|
|
167
|
+
tc.result = event.result;
|
|
168
|
+
if (event.isError !== undefined)
|
|
169
|
+
tc.isError = event.isError;
|
|
170
|
+
if (import.meta.env.DEV) {
|
|
171
|
+
useDevStore.getState().updateToolCall(event.id, {
|
|
172
|
+
args: tc.args,
|
|
173
|
+
result: tc.result,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
shouldYield = true;
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case "tool-call-result": {
|
|
181
|
+
const tc = toolCalls.get(event.id);
|
|
182
|
+
if (tc) {
|
|
183
|
+
tc.result = event.result;
|
|
184
|
+
tc.isError = event.isError;
|
|
185
|
+
if (import.meta.env.DEV) {
|
|
186
|
+
useDevStore.getState().updateToolCall(event.id, {
|
|
187
|
+
result: tc.result,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
shouldYield = true;
|
|
191
|
+
}
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (shouldYield) {
|
|
196
|
+
const result = buildResult();
|
|
197
|
+
if ((result.content?.length ?? 0) > 0) {
|
|
198
|
+
yield result;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// Terminal yield — runner generator returned. assistant-ui leaves
|
|
203
|
+
// the message stuck in the loading state if the last yield's
|
|
204
|
+
// `status` is `running`, so we always emit a final settle once the
|
|
205
|
+
// runner is fully done (after every turn + every follow-up).
|
|
206
|
+
//
|
|
207
|
+
// If the run errored (the AG-UI backend emitted RUN_ERROR — e.g. the
|
|
208
|
+
// agent exhausted rate-limit/transient retries, or a non-retryable
|
|
209
|
+
// 4xx), settle as `incomplete`/`error` instead of `complete`/`stop`,
|
|
210
|
+
// carrying the error message. This keeps any partial content AND
|
|
211
|
+
// flips the message into assistant-ui's error state so the existing
|
|
212
|
+
// `<MessagePrimitive.Error>` renders a visible, retryable error —
|
|
213
|
+
// not a silent empty bubble. We yield the terminal status rather
|
|
214
|
+
// than throwing; an unhandled throw re-introduces the stuck-running
|
|
215
|
+
// bug (the runner generator has already returned here).
|
|
216
|
+
if (runError !== null) {
|
|
217
|
+
yield buildResult({
|
|
218
|
+
type: "incomplete",
|
|
219
|
+
reason: "error",
|
|
220
|
+
error: runError || "The run failed.",
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
yield buildResult({ type: "complete", reason: "stop" });
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
streamingStatusStore.getState().setStreamingStatus({ status: "idle" });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
function buildAGUIContext(appState) {
|
|
233
|
+
return appState.contextItems.map((item, index) => ({
|
|
234
|
+
description: describeContextItem(item, index),
|
|
235
|
+
value: stringifyContextItem(item),
|
|
236
|
+
}));
|
|
237
|
+
}
|
|
238
|
+
function describeContextItem(item, index) {
|
|
239
|
+
const type = typeof item.type === "string" ? item.type : "context";
|
|
240
|
+
const label = typeof item.label === "string" ? item.label : "";
|
|
241
|
+
if (type === "ref") {
|
|
242
|
+
const refType = typeof item.refType === "string" ? item.refType : "reference";
|
|
243
|
+
const target = isRecord(item.target) ? item.target : undefined;
|
|
244
|
+
const targetPath = typeof item.targetPath === "string"
|
|
245
|
+
? item.targetPath
|
|
246
|
+
: typeof target?.path === "string"
|
|
247
|
+
? target.path
|
|
248
|
+
: undefined;
|
|
249
|
+
const targetLabel = typeof target?.label === "string" ? target.label : undefined;
|
|
250
|
+
const targetScope = typeof target?.scope === "string" ? target.scope : undefined;
|
|
251
|
+
if (targetPath) {
|
|
252
|
+
if (!targetLabel && !targetScope) {
|
|
253
|
+
return `Selected ${refType} atom. Use targetPath as the exact edit target when the user asks to modify, rewrite, or transform selected content.`;
|
|
254
|
+
}
|
|
255
|
+
const targetText = targetLabel || targetScope || "JSON atom";
|
|
256
|
+
return `Selected ${refType} ${targetText}. Use targetPath as the exact JSON edit target when the user asks to modify, rewrite, or transform this reference.`;
|
|
257
|
+
}
|
|
258
|
+
return `Selected ${refType} reference. Use refId as the edit target when the user asks to modify, rewrite, or transform selected content.`;
|
|
259
|
+
}
|
|
260
|
+
if (type === "selection") {
|
|
261
|
+
return "Selected text from the current UI. Use it as the focus when the user asks about, rewrites, or modifies selected content.";
|
|
262
|
+
}
|
|
263
|
+
if (type === "page") {
|
|
264
|
+
return `Pinned page context${label ? `: ${label}` : ""}.`;
|
|
265
|
+
}
|
|
266
|
+
return `Context item ${index + 1}${label ? `: ${label}` : ""}.`;
|
|
267
|
+
}
|
|
268
|
+
function stringifyContextItem(item) {
|
|
269
|
+
try {
|
|
270
|
+
return JSON.stringify(item);
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
const type = typeof item.type === "string" ? item.type : "context";
|
|
274
|
+
const label = typeof item.label === "string" ? item.label : "";
|
|
275
|
+
return JSON.stringify({ type, label });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
function isRecord(value) {
|
|
279
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Convert assistant-ui's `Message[]` into AG-UI's wire format.
|
|
283
|
+
*
|
|
284
|
+
* Our Python backend doesn't keep server-side thread state, so prior turns'
|
|
285
|
+
* tool calls + results need to ride along on every request.
|
|
286
|
+
*/
|
|
287
|
+
function convertMessagesToAGUI(messages) {
|
|
288
|
+
const out = [];
|
|
289
|
+
for (let idx = 0; idx < messages.length; idx++) {
|
|
290
|
+
const msg = messages[idx];
|
|
291
|
+
const id = msg.id || `msg-${idx}`;
|
|
292
|
+
const textContent = msg.content
|
|
293
|
+
.filter((c) => c.type === "text")
|
|
294
|
+
.map((c) => c.text)
|
|
295
|
+
.join("\n");
|
|
296
|
+
if (msg.role === "system") {
|
|
297
|
+
out.push({ id, role: "system", content: textContent });
|
|
298
|
+
continue;
|
|
299
|
+
}
|
|
300
|
+
if (msg.role === "assistant") {
|
|
301
|
+
const toolCallParts = msg.content.filter((c) => c.type === "tool-call");
|
|
302
|
+
if (toolCallParts.length > 0) {
|
|
303
|
+
out.push({
|
|
304
|
+
id,
|
|
305
|
+
role: "assistant",
|
|
306
|
+
content: textContent || undefined,
|
|
307
|
+
toolCalls: toolCallParts.map((tc) => ({
|
|
308
|
+
id: tc.toolCallId,
|
|
309
|
+
type: "function",
|
|
310
|
+
function: {
|
|
311
|
+
name: tc.toolName,
|
|
312
|
+
arguments: tc.argsText ?? JSON.stringify(tc.args ?? {}),
|
|
313
|
+
},
|
|
314
|
+
})),
|
|
315
|
+
});
|
|
316
|
+
for (const tc of toolCallParts) {
|
|
317
|
+
if (tc.result !== undefined) {
|
|
318
|
+
out.push({
|
|
319
|
+
id: `tool-result-${tc.toolCallId}`,
|
|
320
|
+
role: "tool",
|
|
321
|
+
toolCallId: tc.toolCallId,
|
|
322
|
+
content: typeof tc.result === "string" ? tc.result : JSON.stringify(tc.result),
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
out.push({ id, role: "assistant", content: textContent });
|
|
329
|
+
}
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
// User role: extract binary attachments if present
|
|
333
|
+
const parts = [];
|
|
334
|
+
for (const c of msg.content) {
|
|
335
|
+
if (c.type === "text") {
|
|
336
|
+
parts.push({ type: "text", text: c.text });
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
if ("attachments" in msg && Array.isArray(msg.attachments)) {
|
|
340
|
+
for (const att of msg.attachments) {
|
|
341
|
+
if (!att.content)
|
|
342
|
+
continue;
|
|
343
|
+
for (const part of att.content) {
|
|
344
|
+
if (part.type === "text") {
|
|
345
|
+
parts.push({ type: "text", text: part.text });
|
|
346
|
+
}
|
|
347
|
+
else if (part.type === "file" && "data" in part) {
|
|
348
|
+
parts.push({
|
|
349
|
+
type: "binary",
|
|
350
|
+
mimeType: part.mimeType,
|
|
351
|
+
data: part.data,
|
|
352
|
+
filename: part.filename,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
else if (part.type === "image" && "image" in part) {
|
|
356
|
+
parts.push({
|
|
357
|
+
type: "binary",
|
|
358
|
+
mimeType: "image/*",
|
|
359
|
+
data: part.image,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
const hasBinary = parts.some((p) => p.type === "binary");
|
|
366
|
+
const textWithAttachments = parts
|
|
367
|
+
.filter((p) => p.type === "text")
|
|
368
|
+
.map((p) => p.text)
|
|
369
|
+
.join("\n");
|
|
370
|
+
out.push({ id, role: "user", content: hasBinary ? parts : textWithAttachments });
|
|
371
|
+
}
|
|
372
|
+
return out;
|
|
373
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* App Store — unified shared state for the AG-UI multi-page application.
|
|
3
|
+
*
|
|
4
|
+
* - Navigation context (synced from nav store via app-layout)
|
|
5
|
+
* - Persistent vs ephemeral context lifecycle
|
|
6
|
+
* - Shared UI state (selectedItemId, content, highlights)
|
|
7
|
+
* - Strict AG-UI state projection sent to the agent on every request
|
|
8
|
+
*/
|
|
9
|
+
export type ContextPersistence = "persistent" | "ephemeral";
|
|
10
|
+
export interface TextPayload {
|
|
11
|
+
kind: "text";
|
|
12
|
+
text: string;
|
|
13
|
+
}
|
|
14
|
+
export interface PagePayload {
|
|
15
|
+
kind: "page";
|
|
16
|
+
path: string;
|
|
17
|
+
label: string;
|
|
18
|
+
meta?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface ReferencePayload {
|
|
21
|
+
kind: "ref";
|
|
22
|
+
/** Domain decides: "block", "entity", "row", "cell", etc. */
|
|
23
|
+
refType: string;
|
|
24
|
+
/** Domain-specific ID: "entityId:blockId", "table:row", etc. */
|
|
25
|
+
refId: string;
|
|
26
|
+
/** Optional display text (~100 chars) */
|
|
27
|
+
preview?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Optional exact JSON target inside the referenced domain object.
|
|
30
|
+
*
|
|
31
|
+
* This keeps the existing refType/refId contract stable for deep links
|
|
32
|
+
* while allowing feature modules to target one schema-declared field,
|
|
33
|
+
* table cell, JSON atom, or app-defined custom value precisely.
|
|
34
|
+
*/
|
|
35
|
+
target?: {
|
|
36
|
+
kind?: string;
|
|
37
|
+
path?: string;
|
|
38
|
+
label?: string;
|
|
39
|
+
scope?: string;
|
|
40
|
+
containerId?: string;
|
|
41
|
+
containerLabel?: string;
|
|
42
|
+
currentValue?: unknown;
|
|
43
|
+
proposedValue?: unknown;
|
|
44
|
+
changeIds?: string[];
|
|
45
|
+
meta?: Record<string, unknown>;
|
|
46
|
+
};
|
|
47
|
+
/** Domain-specific data the agent can use */
|
|
48
|
+
meta?: Record<string, unknown>;
|
|
49
|
+
}
|
|
50
|
+
export type ContextPayload = TextPayload | PagePayload | ReferencePayload;
|
|
51
|
+
export type ContextItemType = "selection" | "page" | "ref" | "note";
|
|
52
|
+
export interface ContextItem {
|
|
53
|
+
id: string;
|
|
54
|
+
type: ContextItemType;
|
|
55
|
+
label: string;
|
|
56
|
+
payload: ContextPayload;
|
|
57
|
+
sourcePage: string;
|
|
58
|
+
persistence: ContextPersistence;
|
|
59
|
+
createdAt: number;
|
|
60
|
+
}
|
|
61
|
+
export interface NavContext {
|
|
62
|
+
group: string | null;
|
|
63
|
+
groupDescription: string | null;
|
|
64
|
+
groupMeta: Record<string, unknown>;
|
|
65
|
+
label: string;
|
|
66
|
+
description: string | null;
|
|
67
|
+
meta: Record<string, unknown>;
|
|
68
|
+
/** Merged instructions from group + page (assembled by app-layout from hierarchy) */
|
|
69
|
+
contextInstructions: string | null;
|
|
70
|
+
}
|
|
71
|
+
export interface AgentStateProjection {
|
|
72
|
+
navigation: {
|
|
73
|
+
group: string | null;
|
|
74
|
+
groupDescription: string | null;
|
|
75
|
+
groupMeta: Record<string, unknown>;
|
|
76
|
+
page: string;
|
|
77
|
+
label: string;
|
|
78
|
+
description: string | null;
|
|
79
|
+
meta: Record<string, unknown>;
|
|
80
|
+
contextInstructions: string | null;
|
|
81
|
+
};
|
|
82
|
+
selectedItemId: string | null;
|
|
83
|
+
content: Record<string, unknown>;
|
|
84
|
+
highlights: string[];
|
|
85
|
+
/** Compact context items — text truncated, pages as paths, refs as IDs */
|
|
86
|
+
contextItems: Array<Record<string, unknown>>;
|
|
87
|
+
}
|
|
88
|
+
interface AppState {
|
|
89
|
+
threadActive: boolean;
|
|
90
|
+
markThreadActive: () => void;
|
|
91
|
+
currentPage: string;
|
|
92
|
+
setCurrentPage: (page: string) => void;
|
|
93
|
+
navContext: NavContext;
|
|
94
|
+
setNavContext: (ctx: NavContext) => void;
|
|
95
|
+
selectedItemId: string | null;
|
|
96
|
+
setSelectedItemId: (id: string | null) => void;
|
|
97
|
+
content: Record<string, unknown>;
|
|
98
|
+
updateContentField: (key: string, value: unknown) => void;
|
|
99
|
+
clearContent: () => void;
|
|
100
|
+
highlights: string[];
|
|
101
|
+
addHighlight: (id: string) => void;
|
|
102
|
+
removeHighlight: (id: string) => void;
|
|
103
|
+
clearHighlights: () => void;
|
|
104
|
+
contextItems: ContextItem[];
|
|
105
|
+
sentContext: Record<string, ContextItem[]>;
|
|
106
|
+
addContextItem: (item: Omit<ContextItem, "id" | "createdAt">) => void;
|
|
107
|
+
removeContextItem: (id: string) => void;
|
|
108
|
+
promoteContextItem: (id: string) => void;
|
|
109
|
+
clearAllContext: () => void;
|
|
110
|
+
consumeContextForMessage: (messageId: string) => ContextItem[];
|
|
111
|
+
getAgentState: () => AgentStateProjection;
|
|
112
|
+
resetAll: () => void;
|
|
113
|
+
}
|
|
114
|
+
export declare const useAppStore: import("zustand").UseBoundStore<import("zustand").StoreApi<AppState>>;
|
|
115
|
+
export {};
|