@kognitivedev/ui 0.2.11
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/.turbo/turbo-build.log +2 -0
- package/CHANGELOG.md +19 -0
- package/README.md +264 -0
- package/dist/__tests__/context-provider.test.d.ts +1 -0
- package/dist/__tests__/context-provider.test.js +38 -0
- package/dist/__tests__/event-emitter.test.d.ts +1 -0
- package/dist/__tests__/event-emitter.test.js +62 -0
- package/dist/__tests__/keyboard-shortcuts.test.d.ts +1 -0
- package/dist/__tests__/keyboard-shortcuts.test.js +36 -0
- package/dist/__tests__/kognitive-runtime.test.d.ts +1 -0
- package/dist/__tests__/kognitive-runtime.test.js +58 -0
- package/dist/__tests__/kognitive-transport.test.d.ts +1 -0
- package/dist/__tests__/kognitive-transport.test.js +96 -0
- package/dist/__tests__/make-tool-ui.test.d.ts +1 -0
- package/dist/__tests__/make-tool-ui.test.js +50 -0
- package/dist/__tests__/message-helpers.test.d.ts +1 -0
- package/dist/__tests__/message-helpers.test.js +80 -0
- package/dist/__tests__/thread-manager.test.d.ts +1 -0
- package/dist/__tests__/thread-manager.test.js +84 -0
- package/dist/__tests__/tool-ui-registry.test.d.ts +1 -0
- package/dist/__tests__/tool-ui-registry.test.js +68 -0
- package/dist/__tests__/toolkit.test.d.ts +1 -0
- package/dist/__tests__/toolkit.test.js +33 -0
- package/dist/components/attachment-preview.d.ts +8 -0
- package/dist/components/attachment-preview.js +10 -0
- package/dist/components/composer.d.ts +6 -0
- package/dist/components/composer.js +10 -0
- package/dist/components/error-banner.d.ts +6 -0
- package/dist/components/error-banner.js +8 -0
- package/dist/components/markdown-content.d.ts +13 -0
- package/dist/components/markdown-content.js +31 -0
- package/dist/components/message.d.ts +7 -0
- package/dist/components/message.js +28 -0
- package/dist/components/status-indicator.d.ts +6 -0
- package/dist/components/status-indicator.js +16 -0
- package/dist/components/suggestions.d.ts +4 -0
- package/dist/components/suggestions.js +12 -0
- package/dist/components/thread-list.d.ts +4 -0
- package/dist/components/thread-list.js +20 -0
- package/dist/components/thread.d.ts +15 -0
- package/dist/components/thread.js +19 -0
- package/dist/components/tool-approval.d.ts +7 -0
- package/dist/components/tool-approval.js +12 -0
- package/dist/components/tool-invocation.d.ts +5 -0
- package/dist/components/tool-invocation.js +33 -0
- package/dist/context/kognitive-context.d.ts +2 -0
- package/dist/context/kognitive-context.js +6 -0
- package/dist/context/types.d.ts +44 -0
- package/dist/context/types.js +2 -0
- package/dist/context/use-kognitive.d.ts +1 -0
- package/dist/context/use-kognitive.js +7 -0
- package/dist/hooks/use-auto-scroll.d.ts +2 -0
- package/dist/hooks/use-auto-scroll.js +18 -0
- package/dist/hooks/use-copy-to-clipboard.d.ts +4 -0
- package/dist/hooks/use-copy-to-clipboard.js +13 -0
- package/dist/hooks/use-keyboard-shortcuts.d.ts +8 -0
- package/dist/hooks/use-keyboard-shortcuts.js +24 -0
- package/dist/hooks/use-kognitive-chat.d.ts +38 -0
- package/dist/hooks/use-kognitive-chat.js +35 -0
- package/dist/hooks/use-kognitive-event.d.ts +12 -0
- package/dist/hooks/use-kognitive-event.js +47 -0
- package/dist/hooks/use-streaming-status.d.ts +2 -0
- package/dist/hooks/use-streaming-status.js +8 -0
- package/dist/hooks/use-thread-manager.d.ts +20 -0
- package/dist/hooks/use-thread-manager.js +83 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +92 -0
- package/dist/kognitive-ui.d.ts +48 -0
- package/dist/kognitive-ui.js +130 -0
- package/dist/primitives/action-bar/action-bar-copy.d.ts +6 -0
- package/dist/primitives/action-bar/action-bar-copy.js +16 -0
- package/dist/primitives/action-bar/action-bar-edit.d.ts +6 -0
- package/dist/primitives/action-bar/action-bar-edit.js +11 -0
- package/dist/primitives/action-bar/action-bar-feedback.d.ts +10 -0
- package/dist/primitives/action-bar/action-bar-feedback.js +30 -0
- package/dist/primitives/action-bar/action-bar-retry.d.ts +6 -0
- package/dist/primitives/action-bar/action-bar-retry.js +25 -0
- package/dist/primitives/action-bar/action-bar-root.d.ts +6 -0
- package/dist/primitives/action-bar/action-bar-root.js +7 -0
- package/dist/primitives/action-bar/action-bar-stop.d.ts +6 -0
- package/dist/primitives/action-bar/action-bar-stop.js +11 -0
- package/dist/primitives/action-bar/index.d.ts +14 -0
- package/dist/primitives/action-bar/index.js +17 -0
- package/dist/primitives/composer/composer-attachment-trigger.d.ts +7 -0
- package/dist/primitives/composer/composer-attachment-trigger.js +33 -0
- package/dist/primitives/composer/composer-attachments.d.ts +7 -0
- package/dist/primitives/composer/composer-attachments.js +16 -0
- package/dist/primitives/composer/composer-input.d.ts +6 -0
- package/dist/primitives/composer/composer-input.js +19 -0
- package/dist/primitives/composer/composer-root.d.ts +6 -0
- package/dist/primitives/composer/composer-root.js +91 -0
- package/dist/primitives/composer/composer-send.d.ts +6 -0
- package/dist/primitives/composer/composer-send.js +10 -0
- package/dist/primitives/composer/edit-composer-root.d.ts +11 -0
- package/dist/primitives/composer/edit-composer-root.js +24 -0
- package/dist/primitives/composer/index.d.ts +15 -0
- package/dist/primitives/composer/index.js +19 -0
- package/dist/primitives/composer/use-composer.d.ts +12 -0
- package/dist/primitives/composer/use-composer.js +6 -0
- package/dist/primitives/message/index.d.ts +9 -0
- package/dist/primitives/message/index.js +13 -0
- package/dist/primitives/message/message-content.d.ts +25 -0
- package/dist/primitives/message/message-content.js +70 -0
- package/dist/primitives/message/message-role.d.ts +6 -0
- package/dist/primitives/message/message-role.js +11 -0
- package/dist/primitives/message/message-root.d.ts +9 -0
- package/dist/primitives/message/message-root.js +38 -0
- package/dist/primitives/message/use-message.d.ts +10 -0
- package/dist/primitives/message/use-message.js +6 -0
- package/dist/primitives/thread/index.d.ts +17 -0
- package/dist/primitives/thread/index.js +21 -0
- package/dist/primitives/thread/thread-empty.d.ts +5 -0
- package/dist/primitives/thread/thread-empty.js +11 -0
- package/dist/primitives/thread/thread-error.d.ts +6 -0
- package/dist/primitives/thread/thread-error.js +11 -0
- package/dist/primitives/thread/thread-loading.d.ts +5 -0
- package/dist/primitives/thread/thread-loading.js +11 -0
- package/dist/primitives/thread/thread-messages.d.ts +6 -0
- package/dist/primitives/thread/thread-messages.js +9 -0
- package/dist/primitives/thread/thread-root.d.ts +6 -0
- package/dist/primitives/thread/thread-root.js +12 -0
- package/dist/primitives/thread/thread-scroll-to-bottom.d.ts +6 -0
- package/dist/primitives/thread/thread-scroll-to-bottom.js +14 -0
- package/dist/primitives/thread/thread-suggestions.d.ts +6 -0
- package/dist/primitives/thread/thread-suggestions.js +14 -0
- package/dist/primitives/thread/use-thread.d.ts +9 -0
- package/dist/primitives/thread/use-thread.js +6 -0
- package/dist/primitives/thread-list/index.d.ts +11 -0
- package/dist/primitives/thread-list/index.js +15 -0
- package/dist/primitives/thread-list/thread-list-item.d.ts +9 -0
- package/dist/primitives/thread-list/thread-list-item.js +13 -0
- package/dist/primitives/thread-list/thread-list-items.d.ts +6 -0
- package/dist/primitives/thread-list/thread-list-items.js +9 -0
- package/dist/primitives/thread-list/thread-list-new.d.ts +6 -0
- package/dist/primitives/thread-list/thread-list-new.js +13 -0
- package/dist/primitives/thread-list/thread-list-root.d.ts +6 -0
- package/dist/primitives/thread-list/thread-list-root.js +16 -0
- package/dist/primitives/thread-list/use-thread-list.d.ts +9 -0
- package/dist/primitives/thread-list/use-thread-list.js +6 -0
- package/dist/primitives/tool-ui/index.d.ts +7 -0
- package/dist/primitives/tool-ui/index.js +11 -0
- package/dist/primitives/tool-ui/tool-ui-fallback.d.ts +5 -0
- package/dist/primitives/tool-ui/tool-ui-fallback.js +20 -0
- package/dist/primitives/tool-ui/tool-ui-root.d.ts +5 -0
- package/dist/primitives/tool-ui/tool-ui-root.js +20 -0
- package/dist/primitives/tool-ui/use-tool-ui.d.ts +2 -0
- package/dist/primitives/tool-ui/use-tool-ui.js +8 -0
- package/dist/runtime/kognitive-runtime.d.ts +30 -0
- package/dist/runtime/kognitive-runtime.js +32 -0
- package/dist/runtime/kognitive-transport.d.ts +26 -0
- package/dist/runtime/kognitive-transport.js +42 -0
- package/dist/runtime/thread-manager.d.ts +17 -0
- package/dist/runtime/thread-manager.js +62 -0
- package/dist/runtime/types.d.ts +58 -0
- package/dist/runtime/types.js +2 -0
- package/dist/tool-ui/make-tool-ui.d.ts +59 -0
- package/dist/tool-ui/make-tool-ui.js +10 -0
- package/dist/tool-ui/registry.d.ts +9 -0
- package/dist/tool-ui/registry.js +26 -0
- package/dist/tool-ui/tool-ui-context.d.ts +2 -0
- package/dist/tool-ui/tool-ui-context.js +6 -0
- package/dist/tool-ui/toolkit.d.ts +31 -0
- package/dist/tool-ui/toolkit.js +33 -0
- package/dist/tool-ui/types.d.ts +19 -0
- package/dist/tool-ui/types.js +2 -0
- package/dist/utils/cn.d.ts +2 -0
- package/dist/utils/cn.js +8 -0
- package/dist/utils/create-context.d.ts +1 -0
- package/dist/utils/create-context.js +16 -0
- package/dist/utils/message-helpers.d.ts +6 -0
- package/dist/utils/message-helpers.js +46 -0
- package/package.json +56 -0
- package/src/__tests__/context-provider.test.ts +43 -0
- package/src/__tests__/event-emitter.test.ts +69 -0
- package/src/__tests__/keyboard-shortcuts.test.ts +55 -0
- package/src/__tests__/kognitive-runtime.test.ts +62 -0
- package/src/__tests__/kognitive-transport.test.ts +113 -0
- package/src/__tests__/make-tool-ui.test.ts +60 -0
- package/src/__tests__/message-helpers.test.ts +101 -0
- package/src/__tests__/thread-manager.test.ts +118 -0
- package/src/__tests__/tool-ui-registry.test.ts +80 -0
- package/src/__tests__/toolkit.test.ts +37 -0
- package/src/components/attachment-preview.tsx +46 -0
- package/src/components/composer.tsx +59 -0
- package/src/components/error-banner.tsx +33 -0
- package/src/components/markdown-content.tsx +64 -0
- package/src/components/message.tsx +145 -0
- package/src/components/status-indicator.tsx +26 -0
- package/src/components/suggestions.tsx +27 -0
- package/src/components/thread-list.tsx +69 -0
- package/src/components/thread.tsx +89 -0
- package/src/components/tool-approval.tsx +54 -0
- package/src/components/tool-invocation.tsx +94 -0
- package/src/context/kognitive-context.tsx +8 -0
- package/src/context/types.ts +43 -0
- package/src/context/use-kognitive.ts +5 -0
- package/src/hooks/use-auto-scroll.ts +19 -0
- package/src/hooks/use-copy-to-clipboard.ts +16 -0
- package/src/hooks/use-keyboard-shortcuts.ts +34 -0
- package/src/hooks/use-kognitive-chat.ts +73 -0
- package/src/hooks/use-kognitive-event.ts +56 -0
- package/src/hooks/use-streaming-status.ts +7 -0
- package/src/hooks/use-thread-manager.ts +114 -0
- package/src/index.ts +56 -0
- package/src/kognitive-ui.tsx +216 -0
- package/src/primitives/action-bar/action-bar-copy.tsx +30 -0
- package/src/primitives/action-bar/action-bar-edit.tsx +24 -0
- package/src/primitives/action-bar/action-bar-feedback.tsx +59 -0
- package/src/primitives/action-bar/action-bar-retry.tsx +38 -0
- package/src/primitives/action-bar/action-bar-root.tsx +14 -0
- package/src/primitives/action-bar/action-bar-stop.tsx +24 -0
- package/src/primitives/action-bar/index.ts +15 -0
- package/src/primitives/composer/composer-attachment-trigger.tsx +70 -0
- package/src/primitives/composer/composer-attachments.tsx +36 -0
- package/src/primitives/composer/composer-input.tsx +46 -0
- package/src/primitives/composer/composer-root.tsx +130 -0
- package/src/primitives/composer/composer-send.tsx +23 -0
- package/src/primitives/composer/edit-composer-root.tsx +52 -0
- package/src/primitives/composer/index.ts +17 -0
- package/src/primitives/composer/use-composer.ts +19 -0
- package/src/primitives/message/index.ts +11 -0
- package/src/primitives/message/message-content.tsx +117 -0
- package/src/primitives/message/message-role.tsx +13 -0
- package/src/primitives/message/message-root.tsx +64 -0
- package/src/primitives/message/use-message.ts +17 -0
- package/src/primitives/thread/index.ts +19 -0
- package/src/primitives/thread/thread-empty.tsx +12 -0
- package/src/primitives/thread/thread-error.tsx +18 -0
- package/src/primitives/thread/thread-loading.tsx +12 -0
- package/src/primitives/thread/thread-messages.tsx +12 -0
- package/src/primitives/thread/thread-root.tsx +28 -0
- package/src/primitives/thread/thread-scroll-to-bottom.tsx +26 -0
- package/src/primitives/thread/thread-suggestions.tsx +31 -0
- package/src/primitives/thread/use-thread.ts +16 -0
- package/src/primitives/thread-list/index.ts +13 -0
- package/src/primitives/thread-list/thread-list-item.tsx +37 -0
- package/src/primitives/thread-list/thread-list-items.tsx +19 -0
- package/src/primitives/thread-list/thread-list-new.tsx +26 -0
- package/src/primitives/thread-list/thread-list-root.tsx +29 -0
- package/src/primitives/thread-list/use-thread-list.ts +16 -0
- package/src/primitives/tool-ui/index.ts +9 -0
- package/src/primitives/tool-ui/tool-ui-fallback.tsx +63 -0
- package/src/primitives/tool-ui/tool-ui-root.tsx +26 -0
- package/src/primitives/tool-ui/use-tool-ui.ts +7 -0
- package/src/runtime/kognitive-runtime.ts +56 -0
- package/src/runtime/kognitive-transport.ts +56 -0
- package/src/runtime/thread-manager.ts +92 -0
- package/src/runtime/types.ts +63 -0
- package/src/tool-ui/make-tool-ui.ts +71 -0
- package/src/tool-ui/registry.ts +27 -0
- package/src/tool-ui/tool-ui-context.tsx +8 -0
- package/src/tool-ui/toolkit.ts +40 -0
- package/src/tool-ui/types.ts +29 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/create-context.ts +18 -0
- package/src/utils/message-helpers.ts +42 -0
- package/tsconfig.json +15 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import React, { useCallback, type ReactNode } from "react";
|
|
2
|
+
import type { ThreadSummary } from "../../runtime/types";
|
|
3
|
+
import { useThreadList } from "./use-thread-list";
|
|
4
|
+
|
|
5
|
+
export interface ThreadListItemProps {
|
|
6
|
+
thread: ThreadSummary;
|
|
7
|
+
isActive: boolean;
|
|
8
|
+
className?: string;
|
|
9
|
+
children?: ReactNode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function ThreadListItem({ thread, isActive, className, children }: ThreadListItemProps) {
|
|
13
|
+
const { setActiveSessionId } = useThreadList();
|
|
14
|
+
|
|
15
|
+
const handleClick = useCallback(() => {
|
|
16
|
+
setActiveSessionId(thread.sessionId);
|
|
17
|
+
}, [thread.sessionId, setActiveSessionId]);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<button
|
|
21
|
+
type="button"
|
|
22
|
+
className={className}
|
|
23
|
+
onClick={handleClick}
|
|
24
|
+
data-active={isActive || undefined}
|
|
25
|
+
data-status={thread.status}
|
|
26
|
+
data-session-id={thread.sessionId}
|
|
27
|
+
aria-current={isActive ? "true" : undefined}
|
|
28
|
+
>
|
|
29
|
+
{children ?? (
|
|
30
|
+
<>
|
|
31
|
+
<span>{thread.title || thread.lastUserPreview || "New conversation"}</span>
|
|
32
|
+
<span>{thread.lastAssistantPreview}</span>
|
|
33
|
+
</>
|
|
34
|
+
)}
|
|
35
|
+
</button>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import React, { type ReactNode } from "react";
|
|
2
|
+
import type { ThreadSummary } from "../../runtime/types";
|
|
3
|
+
import { useThreadList } from "./use-thread-list";
|
|
4
|
+
|
|
5
|
+
export interface ThreadListItemsProps {
|
|
6
|
+
children: (thread: ThreadSummary, isActive: boolean) => ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function ThreadListItems({ children }: ThreadListItemsProps) {
|
|
10
|
+
const { threads, activeSessionId } = useThreadList();
|
|
11
|
+
|
|
12
|
+
return (
|
|
13
|
+
<>
|
|
14
|
+
{threads.map((thread) =>
|
|
15
|
+
children(thread, thread.sessionId === activeSessionId),
|
|
16
|
+
)}
|
|
17
|
+
</>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React, { useCallback, type ReactNode } from "react";
|
|
2
|
+
import { useThreadList } from "./use-thread-list";
|
|
3
|
+
|
|
4
|
+
export interface ThreadListNewProps {
|
|
5
|
+
className?: string;
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function ThreadListNew({ className, children }: ThreadListNewProps) {
|
|
10
|
+
const { createThread } = useThreadList();
|
|
11
|
+
|
|
12
|
+
const handleClick = useCallback(() => {
|
|
13
|
+
void createThread();
|
|
14
|
+
}, [createThread]);
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<button
|
|
18
|
+
type="button"
|
|
19
|
+
className={className}
|
|
20
|
+
onClick={handleClick}
|
|
21
|
+
aria-label="New conversation"
|
|
22
|
+
>
|
|
23
|
+
{children ?? "New conversation"}
|
|
24
|
+
</button>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React, { type ReactNode } from "react";
|
|
2
|
+
import { useKognitiveContext } from "../../context/kognitive-context";
|
|
3
|
+
import { ThreadListContextProvider } from "./use-thread-list";
|
|
4
|
+
|
|
5
|
+
export interface ThreadListRootProps {
|
|
6
|
+
className?: string;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ThreadListRoot({ className, children }: ThreadListRootProps) {
|
|
11
|
+
const { threads, activeSessionId, setActiveSessionId, createThread, refreshThreads } =
|
|
12
|
+
useKognitiveContext();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<ThreadListContextProvider
|
|
16
|
+
value={{
|
|
17
|
+
threads,
|
|
18
|
+
activeSessionId,
|
|
19
|
+
setActiveSessionId,
|
|
20
|
+
createThread,
|
|
21
|
+
refreshThreads,
|
|
22
|
+
}}
|
|
23
|
+
>
|
|
24
|
+
<div className={className} role="navigation" aria-label="Threads">
|
|
25
|
+
{children}
|
|
26
|
+
</div>
|
|
27
|
+
</ThreadListContextProvider>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createContext } from "../../utils/create-context";
|
|
2
|
+
import type { ThreadSummary } from "../../runtime/types";
|
|
3
|
+
|
|
4
|
+
export interface ThreadListContextValue {
|
|
5
|
+
threads: ThreadSummary[];
|
|
6
|
+
activeSessionId: string | null;
|
|
7
|
+
setActiveSessionId: (sessionId: string | null) => void;
|
|
8
|
+
createThread: () => Promise<void>;
|
|
9
|
+
refreshThreads: () => Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const [
|
|
13
|
+
ThreadListContextProvider,
|
|
14
|
+
useThreadList,
|
|
15
|
+
ThreadListContext,
|
|
16
|
+
] = createContext<ThreadListContextValue>("ThreadList");
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import React, { useState } from "react";
|
|
2
|
+
import type { ToolUIRenderProps } from "../../tool-ui/types";
|
|
3
|
+
|
|
4
|
+
export interface ToolUIFallbackProps extends ToolUIRenderProps {
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function stateLabel(state: string): string {
|
|
9
|
+
switch (state) {
|
|
10
|
+
case "input-streaming": return "streaming input...";
|
|
11
|
+
case "input-available": return "calling...";
|
|
12
|
+
case "approval-requested": return "awaiting approval";
|
|
13
|
+
case "approval-responded": return "approved";
|
|
14
|
+
case "output-available": return "done";
|
|
15
|
+
case "error": return "error";
|
|
16
|
+
default: return state;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function ToolUIFallback({ toolName, toolCallId, input, output, state, className }: ToolUIFallbackProps) {
|
|
21
|
+
const [expanded, setExpanded] = useState(false);
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<div
|
|
25
|
+
className={className}
|
|
26
|
+
data-tool={toolName}
|
|
27
|
+
data-tool-state={state}
|
|
28
|
+
data-tool-call-id={toolCallId}
|
|
29
|
+
>
|
|
30
|
+
<button
|
|
31
|
+
type="button"
|
|
32
|
+
onClick={() => setExpanded(!expanded)}
|
|
33
|
+
aria-expanded={expanded}
|
|
34
|
+
style={{ display: "flex", alignItems: "center", gap: "0.5rem", cursor: "pointer", background: "none", border: "none", padding: "0.5rem", width: "100%", textAlign: "left" }}
|
|
35
|
+
>
|
|
36
|
+
<span>🔧</span>
|
|
37
|
+
<strong>{toolName}</strong>
|
|
38
|
+
<span data-tool-state-badge={state}>{stateLabel(state)}</span>
|
|
39
|
+
<span style={{ marginLeft: "auto" }}>{expanded ? "\u25BC" : "\u25B6"}</span>
|
|
40
|
+
</button>
|
|
41
|
+
{expanded && (
|
|
42
|
+
<div style={{ padding: "0.5rem" }}>
|
|
43
|
+
{input !== undefined && (
|
|
44
|
+
<div>
|
|
45
|
+
<strong>Arguments:</strong>
|
|
46
|
+
<pre style={{ overflow: "auto", fontSize: "0.85em" }}>
|
|
47
|
+
{JSON.stringify(input, null, 2)}
|
|
48
|
+
</pre>
|
|
49
|
+
</div>
|
|
50
|
+
)}
|
|
51
|
+
{output !== undefined && (
|
|
52
|
+
<div>
|
|
53
|
+
<strong>Result:</strong>
|
|
54
|
+
<pre style={{ overflow: "auto", fontSize: "0.85em" }}>
|
|
55
|
+
{JSON.stringify(output, null, 2)}
|
|
56
|
+
</pre>
|
|
57
|
+
</div>
|
|
58
|
+
)}
|
|
59
|
+
</div>
|
|
60
|
+
)}
|
|
61
|
+
</div>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { useToolUIRegistry } from "../../tool-ui/tool-ui-context";
|
|
3
|
+
import type { ToolUIRenderProps } from "../../tool-ui/types";
|
|
4
|
+
import { ToolUIFallback } from "./tool-ui-fallback";
|
|
5
|
+
|
|
6
|
+
export interface ToolUIRootProps extends ToolUIRenderProps {
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function ToolUIRoot(props: ToolUIRootProps) {
|
|
11
|
+
let registry: ReturnType<typeof useToolUIRegistry> | undefined;
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
registry = useToolUIRegistry();
|
|
15
|
+
} catch {
|
|
16
|
+
// Registry not available
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const RegisteredUI = registry?.get(props.toolName);
|
|
20
|
+
|
|
21
|
+
if (RegisteredUI) {
|
|
22
|
+
return <RegisteredUI {...props} />;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return <ToolUIFallback {...props} />;
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { useToolUIRegistry } from "../../tool-ui/tool-ui-context";
|
|
2
|
+
import type { ToolUIComponent } from "../../tool-ui/types";
|
|
3
|
+
|
|
4
|
+
export function useToolUI(toolName: string): ToolUIComponent | undefined {
|
|
5
|
+
const registry = useToolUIRegistry();
|
|
6
|
+
return registry.get(toolName);
|
|
7
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { DefaultChatTransport, UIMessage } from "ai";
|
|
2
|
+
import { createKognitiveTransport, type KognitiveTransportConfig } from "./kognitive-transport";
|
|
3
|
+
import { ThreadManager, type ThreadManagerConfig } from "./thread-manager";
|
|
4
|
+
import type { ToolUIRegistry } from "../tool-ui/registry";
|
|
5
|
+
|
|
6
|
+
export interface KognitiveRuntimeConfig {
|
|
7
|
+
/** Base URL of the Kognitive runtime */
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
/** Agent name to connect to */
|
|
10
|
+
agentName: string;
|
|
11
|
+
/** Additional headers (e.g., auth) */
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
/** User identity */
|
|
14
|
+
resourceId?: { userId?: string };
|
|
15
|
+
/** Initial session/thread ID */
|
|
16
|
+
sessionId?: string;
|
|
17
|
+
/** Enable thread management. When true, uses threadApiBase for CRUD. */
|
|
18
|
+
threads?: boolean;
|
|
19
|
+
/** Thread API base URL. Defaults to {baseUrl}/api/agents/{agentName}/threads */
|
|
20
|
+
threadApiBase?: string;
|
|
21
|
+
/** Tool UI registry */
|
|
22
|
+
toolUIRegistry?: ToolUIRegistry;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class KognitiveRuntime {
|
|
26
|
+
readonly config: KognitiveRuntimeConfig;
|
|
27
|
+
readonly threadManager: ThreadManager | null;
|
|
28
|
+
readonly toolUIRegistry: ToolUIRegistry | null;
|
|
29
|
+
|
|
30
|
+
constructor(config: KognitiveRuntimeConfig) {
|
|
31
|
+
this.config = config;
|
|
32
|
+
this.toolUIRegistry = config.toolUIRegistry ?? null;
|
|
33
|
+
|
|
34
|
+
if (config.threads) {
|
|
35
|
+
const threadApiBase =
|
|
36
|
+
config.threadApiBase ??
|
|
37
|
+
`${config.baseUrl.replace(/\/$/, "")}/api/agents/${encodeURIComponent(config.agentName)}/threads`;
|
|
38
|
+
this.threadManager = new ThreadManager({
|
|
39
|
+
baseUrl: threadApiBase,
|
|
40
|
+
headers: config.headers,
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
this.threadManager = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
createTransport(sessionId?: string): DefaultChatTransport<UIMessage> {
|
|
48
|
+
return createKognitiveTransport({
|
|
49
|
+
baseUrl: this.config.baseUrl,
|
|
50
|
+
agentName: this.config.agentName,
|
|
51
|
+
sessionId: sessionId ?? this.config.sessionId,
|
|
52
|
+
resourceId: this.config.resourceId,
|
|
53
|
+
headers: this.config.headers,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { DefaultChatTransport, convertToModelMessages, type UIMessage } from "ai";
|
|
2
|
+
|
|
3
|
+
export interface KognitiveTransportConfig {
|
|
4
|
+
/**
|
|
5
|
+
* Explicit API endpoint URL for streaming.
|
|
6
|
+
* When set, takes priority over baseUrl + agentName URL construction.
|
|
7
|
+
* Use this for custom proxy routes (e.g., "/api/chat").
|
|
8
|
+
*/
|
|
9
|
+
api?: string;
|
|
10
|
+
/** Base URL of the Kognitive runtime. Combined with agentName to construct the stream URL. */
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
/** Agent name. Used with baseUrl to build the URL. Also sent in body when using `api` mode. */
|
|
13
|
+
agentName?: string;
|
|
14
|
+
/** Current session/thread ID — sent in every request body */
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
/** User identity — sent in every request body as resourceId */
|
|
17
|
+
resourceId?: { userId?: string; sessionId?: string; organizationId?: string };
|
|
18
|
+
/** Additional headers (e.g., auth) */
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
/** Extra fields merged into every request body (e.g., { agentName: "assistant" }) */
|
|
21
|
+
body?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createKognitiveTransport(
|
|
25
|
+
config: KognitiveTransportConfig,
|
|
26
|
+
): DefaultChatTransport<UIMessage> {
|
|
27
|
+
let apiUrl: string;
|
|
28
|
+
if (config.api) {
|
|
29
|
+
apiUrl = config.api;
|
|
30
|
+
} else if (config.baseUrl && config.agentName) {
|
|
31
|
+
apiUrl = `${config.baseUrl.replace(/\/$/, "")}/api/agents/${encodeURIComponent(config.agentName)}/stream`;
|
|
32
|
+
} else {
|
|
33
|
+
throw new Error(
|
|
34
|
+
"createKognitiveTransport requires either `api` or both `baseUrl` and `agentName`.",
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return new DefaultChatTransport<UIMessage>({
|
|
39
|
+
api: apiUrl,
|
|
40
|
+
headers: config.headers ?? {},
|
|
41
|
+
body: () => ({
|
|
42
|
+
...(config.body ?? {}),
|
|
43
|
+
...(config.agentName && config.api ? { agentName: config.agentName } : {}),
|
|
44
|
+
...(config.sessionId ? { sessionId: config.sessionId } : {}),
|
|
45
|
+
...(config.resourceId ? { resourceId: config.resourceId } : {}),
|
|
46
|
+
}),
|
|
47
|
+
prepareSendMessagesRequest: async ({ messages, body }) => ({
|
|
48
|
+
body: {
|
|
49
|
+
...(body ?? {}),
|
|
50
|
+
messages: await convertToModelMessages(
|
|
51
|
+
messages.map(({ id: _id, ...message }) => message),
|
|
52
|
+
),
|
|
53
|
+
},
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { ThreadSummary, ThreadDetail } from "./types";
|
|
2
|
+
|
|
3
|
+
export interface ThreadManagerConfig {
|
|
4
|
+
/** Base URL for thread API endpoints */
|
|
5
|
+
baseUrl: string;
|
|
6
|
+
/** Additional headers (e.g., auth) */
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class ThreadManager {
|
|
11
|
+
private baseUrl: string;
|
|
12
|
+
private headers: Record<string, string>;
|
|
13
|
+
|
|
14
|
+
constructor(config: ThreadManagerConfig) {
|
|
15
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
16
|
+
this.headers = {
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
...(config.headers ?? {}),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async list(): Promise<ThreadSummary[]> {
|
|
23
|
+
const res = await fetch(this.baseUrl, { headers: this.headers });
|
|
24
|
+
if (!res.ok) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
(await res.json().catch(() => ({ error: "Failed to list threads" }))).error,
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const data = await res.json();
|
|
30
|
+
return (data.threads ?? []) as ThreadSummary[];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async get(sessionId: string): Promise<ThreadDetail> {
|
|
34
|
+
const res = await fetch(`${this.baseUrl}/${encodeURIComponent(sessionId)}`, {
|
|
35
|
+
headers: this.headers,
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
(await res.json().catch(() => ({ error: "Failed to get thread" }))).error,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return (await res.json()) as ThreadDetail;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async create(): Promise<ThreadSummary> {
|
|
46
|
+
const res = await fetch(this.baseUrl, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: this.headers,
|
|
49
|
+
body: JSON.stringify({}),
|
|
50
|
+
});
|
|
51
|
+
if (!res.ok) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
(await res.json().catch(() => ({ error: "Failed to create thread" }))).error,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
const data = await res.json();
|
|
57
|
+
return data.thread as ThreadSummary;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async fork(sessionId: string): Promise<ThreadSummary> {
|
|
61
|
+
const res = await fetch(
|
|
62
|
+
`${this.baseUrl}/${encodeURIComponent(sessionId)}/fork`,
|
|
63
|
+
{
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: this.headers,
|
|
66
|
+
body: JSON.stringify({}),
|
|
67
|
+
},
|
|
68
|
+
);
|
|
69
|
+
if (!res.ok) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
(await res.json().catch(() => ({ error: "Failed to fork thread" }))).error,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
const data = await res.json();
|
|
75
|
+
return data.thread as ThreadSummary;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async interrupt(sessionId: string): Promise<void> {
|
|
79
|
+
const res = await fetch(
|
|
80
|
+
`${this.baseUrl}/${encodeURIComponent(sessionId)}/interrupt`,
|
|
81
|
+
{
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: this.headers,
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
if (!res.ok) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
(await res.json().catch(() => ({ error: "Failed to interrupt thread" }))).error,
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export type ThreadSummary = {
|
|
2
|
+
sessionDbId: string;
|
|
3
|
+
sessionId: string;
|
|
4
|
+
title: string;
|
|
5
|
+
status: string;
|
|
6
|
+
updatedAt: string;
|
|
7
|
+
messageCount: number;
|
|
8
|
+
lastUserPreview: string;
|
|
9
|
+
lastAssistantPreview: string;
|
|
10
|
+
lastError?: string | null;
|
|
11
|
+
lastTraceDbId?: string | null;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type ThreadEvent = {
|
|
15
|
+
id: string;
|
|
16
|
+
sequence: number;
|
|
17
|
+
eventType: "user_message" | "assistant_message" | "tool_call" | "tool_result" | "status";
|
|
18
|
+
payload: Record<string, unknown>;
|
|
19
|
+
createdAt: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type ThreadTrace = {
|
|
23
|
+
id: string;
|
|
24
|
+
traceId: string;
|
|
25
|
+
state: string;
|
|
26
|
+
durationMs: number | null;
|
|
27
|
+
totalCostCents: number;
|
|
28
|
+
inputTokens: number;
|
|
29
|
+
outputTokens: number;
|
|
30
|
+
modelId: string | null;
|
|
31
|
+
createdAt: string;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type ThreadRun = {
|
|
35
|
+
id: string;
|
|
36
|
+
runId: string;
|
|
37
|
+
agentName: string;
|
|
38
|
+
status: string;
|
|
39
|
+
triggerType: string;
|
|
40
|
+
inputPreview: string | null;
|
|
41
|
+
outputPreview: string | null;
|
|
42
|
+
inputTokens: number;
|
|
43
|
+
outputTokens: number;
|
|
44
|
+
totalCostCents: number;
|
|
45
|
+
durationMs: number | null;
|
|
46
|
+
startedAt: string;
|
|
47
|
+
completedAt: string | null;
|
|
48
|
+
parentRunId: string | null;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export type ThreadDetail = {
|
|
52
|
+
session: {
|
|
53
|
+
id: string;
|
|
54
|
+
sessionId: string;
|
|
55
|
+
messageCount: number;
|
|
56
|
+
metadata?: Record<string, unknown> | null;
|
|
57
|
+
};
|
|
58
|
+
events: ThreadEvent[];
|
|
59
|
+
traces: ThreadTrace[];
|
|
60
|
+
runs: ThreadRun[];
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export type RuntimeStatus = "ready" | "submitted" | "streaming" | "error";
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ToolUIRenderProps, ToolUIRegistration } from "./types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for makeToolUI when using a @kognitivedev/tools Tool definition.
|
|
6
|
+
* The tool's inputSchema and outputSchema provide type inference.
|
|
7
|
+
*/
|
|
8
|
+
export interface MakeToolUIOptions<TInput = any, TOutput = any> {
|
|
9
|
+
/** The tool definition from createTool(). Provides name and type info. */
|
|
10
|
+
tool: { id: string; inputSchema?: unknown; outputSchema?: unknown };
|
|
11
|
+
/** Render function with fully typed props from the tool definition. */
|
|
12
|
+
render: (props: ToolUIRenderProps<TInput, TOutput>) => ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Options for makeToolUI when registering by tool name string.
|
|
17
|
+
*/
|
|
18
|
+
export interface MakeToolUIByNameOptions {
|
|
19
|
+
/** The tool name (must match the tool ID used on the server) */
|
|
20
|
+
toolName: string;
|
|
21
|
+
/** Render function for the tool UI */
|
|
22
|
+
render: (props: ToolUIRenderProps) => ReactNode;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a type-safe tool UI registration from a @kognitivedev/tools Tool definition.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* const weatherTool = createTool({
|
|
31
|
+
* id: "get_weather",
|
|
32
|
+
* inputSchema: z.object({ city: z.string() }),
|
|
33
|
+
* execute: async ({ city }) => ({ temp: 22 }),
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* const WeatherUI = makeToolUI({
|
|
37
|
+
* tool: weatherTool,
|
|
38
|
+
* render: ({ input, output, state }) => (
|
|
39
|
+
* <div>{input.city}: {output?.temp}°</div>
|
|
40
|
+
* ),
|
|
41
|
+
* });
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export function makeToolUI<TInput, TOutput>(
|
|
45
|
+
options: MakeToolUIOptions<TInput, TOutput>,
|
|
46
|
+
): ToolUIRegistration;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Create a tool UI registration by tool name string.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* const SearchUI = makeToolUI({
|
|
54
|
+
* toolName: "search",
|
|
55
|
+
* render: ({ input, output, state }) => (
|
|
56
|
+
* <div>Searching for {input.query}...</div>
|
|
57
|
+
* ),
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function makeToolUI(options: MakeToolUIByNameOptions): ToolUIRegistration;
|
|
62
|
+
|
|
63
|
+
export function makeToolUI(
|
|
64
|
+
options: MakeToolUIOptions | MakeToolUIByNameOptions,
|
|
65
|
+
): ToolUIRegistration {
|
|
66
|
+
const toolName = "tool" in options ? options.tool.id : options.toolName;
|
|
67
|
+
return {
|
|
68
|
+
toolName,
|
|
69
|
+
component: options.render as any,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ToolUIComponent, ToolUIRegistration } from "./types";
|
|
2
|
+
|
|
3
|
+
export class ToolUIRegistry {
|
|
4
|
+
private map = new Map<string, ToolUIComponent>();
|
|
5
|
+
|
|
6
|
+
register(registration: ToolUIRegistration): void {
|
|
7
|
+
this.map.set(registration.toolName, registration.component);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
registerAll(registrations: ToolUIRegistration[]): void {
|
|
11
|
+
for (const reg of registrations) {
|
|
12
|
+
this.register(reg);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
get(toolName: string): ToolUIComponent | undefined {
|
|
17
|
+
return this.map.get(toolName);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
has(toolName: string): boolean {
|
|
21
|
+
return this.map.has(toolName);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
names(): string[] {
|
|
25
|
+
return Array.from(this.map.keys());
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ToolUIRenderProps, ToolUIRegistration } from "./types";
|
|
3
|
+
|
|
4
|
+
export interface ToolkitEntry {
|
|
5
|
+
/** Render function for this tool's UI */
|
|
6
|
+
render: (props: ToolUIRenderProps) => ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Register multiple tool UIs at once by tool name.
|
|
11
|
+
*
|
|
12
|
+
* Useful when you don't have the Tool objects on the client
|
|
13
|
+
* (e.g., backend-only tools) but still want custom renderers.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const myToolkit = toolkit({
|
|
18
|
+
* get_weather: {
|
|
19
|
+
* render: ({ input, output, state }) => (
|
|
20
|
+
* <WeatherCard city={input.city} data={output} />
|
|
21
|
+
* ),
|
|
22
|
+
* },
|
|
23
|
+
* search_database: {
|
|
24
|
+
* render: ({ input, output }) => (
|
|
25
|
+
* <QueryResults query={input.query} results={output?.rows} />
|
|
26
|
+
* ),
|
|
27
|
+
* },
|
|
28
|
+
* });
|
|
29
|
+
*
|
|
30
|
+
* <KognitiveUI toolkit={myToolkit} ... />
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export function toolkit(
|
|
34
|
+
map: Record<string, ToolkitEntry>,
|
|
35
|
+
): ToolUIRegistration[] {
|
|
36
|
+
return Object.entries(map).map(([toolName, entry]) => ({
|
|
37
|
+
toolName,
|
|
38
|
+
component: entry.render as any,
|
|
39
|
+
}));
|
|
40
|
+
}
|