@kitnai/chat 0.1.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/LICENSE +21 -0
- package/README.md +314 -0
- package/dist/bash-InADTalH.js +6 -0
- package/dist/core-AYMC6_lb.js +5874 -0
- package/dist/engine-javascript-vq0WuIJl.js +2643 -0
- package/dist/github-dark-dimmed-DUshB20C.js +4 -0
- package/dist/github-light-JYsPkUQd.js +4 -0
- package/dist/javascript-C25yR2R2.js +6 -0
- package/dist/json-DxJze_jm.js +6 -0
- package/dist/kitn-chat.es.js +6632 -0
- package/dist/tsx-B8rCNbgL.js +6 -0
- package/dist/typescript-RycA9KXf.js +6 -0
- package/package.json +80 -0
- package/src/components/attachments.stories.tsx +304 -0
- package/src/components/attachments.tsx +394 -0
- package/src/components/chain-of-thought.stories.tsx +212 -0
- package/src/components/chain-of-thought.tsx +139 -0
- package/src/components/chat-container.stories.tsx +188 -0
- package/src/components/chat-container.tsx +78 -0
- package/src/components/chat-scope-picker.tsx +47 -0
- package/src/components/checkpoint.stories.tsx +103 -0
- package/src/components/checkpoint.tsx +81 -0
- package/src/components/code-block.stories.tsx +151 -0
- package/src/components/code-block.tsx +99 -0
- package/src/components/context.stories.tsx +180 -0
- package/src/components/context.tsx +323 -0
- package/src/components/conversation-item.stories.tsx +126 -0
- package/src/components/conversation-item.tsx +18 -0
- package/src/components/conversation-list.stories.tsx +134 -0
- package/src/components/conversation-list.tsx +100 -0
- package/src/components/empty.stories.tsx +435 -0
- package/src/components/empty.tsx +166 -0
- package/src/components/feedback-bar.stories.tsx +101 -0
- package/src/components/feedback-bar.tsx +58 -0
- package/src/components/file-upload.stories.tsx +157 -0
- package/src/components/file-upload.tsx +161 -0
- package/src/components/image.stories.tsx +90 -0
- package/src/components/image.tsx +67 -0
- package/src/components/loader.stories.tsx +182 -0
- package/src/components/loader.tsx +333 -0
- package/src/components/markdown.stories.tsx +181 -0
- package/src/components/markdown.tsx +81 -0
- package/src/components/message-narrow.stories.tsx +330 -0
- package/src/components/message-skills.stories.tsx +212 -0
- package/src/components/message-skills.tsx +36 -0
- package/src/components/message.stories.tsx +282 -0
- package/src/components/message.tsx +149 -0
- package/src/components/model-switcher.stories.tsx +98 -0
- package/src/components/model-switcher.tsx +36 -0
- package/src/components/prompt-input.stories.tsx +223 -0
- package/src/components/prompt-input.tsx +190 -0
- package/src/components/prompt-suggestion.stories.tsx +143 -0
- package/src/components/prompt-suggestion.tsx +115 -0
- package/src/components/reasoning.stories.tsx +141 -0
- package/src/components/reasoning.tsx +157 -0
- package/src/components/response-stream.tsx +103 -0
- package/src/components/scroll-button.stories.tsx +101 -0
- package/src/components/scroll-button.tsx +33 -0
- package/src/components/slash-command.stories.tsx +164 -0
- package/src/components/slash-command.tsx +223 -0
- package/src/components/source.stories.tsx +125 -0
- package/src/components/source.tsx +129 -0
- package/src/components/text-shimmer.stories.tsx +88 -0
- package/src/components/text-shimmer.tsx +37 -0
- package/src/components/thinking-bar.stories.tsx +88 -0
- package/src/components/thinking-bar.tsx +50 -0
- package/src/components/tool.stories.tsx +154 -0
- package/src/components/tool.tsx +173 -0
- package/src/components/voice-input.stories.tsx +84 -0
- package/src/components/voice-input.tsx +103 -0
- package/src/elements/chat-types.ts +14 -0
- package/src/elements/chat.tsx +111 -0
- package/src/elements/compiled.css +2 -0
- package/src/elements/conversation-list.tsx +26 -0
- package/src/elements/css.ts +5 -0
- package/src/elements/default-input.tsx +53 -0
- package/src/elements/define.tsx +54 -0
- package/src/elements/kitn-chat.stories.tsx +105 -0
- package/src/elements/kitn-conversation-list.stories.tsx +177 -0
- package/src/elements/kitn-prompt-input.stories.tsx +123 -0
- package/src/elements/prompt-input.tsx +39 -0
- package/src/elements/register.ts +9 -0
- package/src/elements/styles.css +12 -0
- package/src/index.ts +128 -0
- package/src/primitives/chat-config.tsx +76 -0
- package/src/primitives/highlighter.ts +150 -0
- package/src/primitives/use-auto-resize.ts +31 -0
- package/src/primitives/use-stick-to-bottom.ts +43 -0
- package/src/primitives/use-text-stream.ts +112 -0
- package/src/primitives/use-voice-recorder.ts +50 -0
- package/src/stories/chat-panel-layout.stories.tsx +144 -0
- package/src/stories/chat-scene.tsx +570 -0
- package/src/stories/checkpoint-restore.stories.tsx +224 -0
- package/src/stories/context-usage.stories.tsx +155 -0
- package/src/stories/conversation-with-reasoning.stories.tsx +151 -0
- package/src/stories/conversation-with-sources.stories.tsx +165 -0
- package/src/stories/docs/GettingStarted.mdx +76 -0
- package/src/stories/docs/Installation.mdx +48 -0
- package/src/stories/docs/Integrations.mdx +110 -0
- package/src/stories/docs/Introduction.mdx +29 -0
- package/src/stories/docs/Theming.mdx +87 -0
- package/src/stories/docs/theme-editor/canvas.tsx +32 -0
- package/src/stories/docs/theme-editor/inspector.tsx +66 -0
- package/src/stories/docs/theme-editor/presets.test.ts +32 -0
- package/src/stories/docs/theme-editor/presets.ts +64 -0
- package/src/stories/docs/theme-editor/theme-css.test.ts +19 -0
- package/src/stories/docs/theme-editor/theme-css.ts +15 -0
- package/src/stories/docs/theme-editor/theme-editor.tsx +145 -0
- package/src/stories/docs/theme-tokens.tsx +174 -0
- package/src/stories/full-chat.stories.tsx +18 -0
- package/src/stories/message-actions.stories.tsx +167 -0
- package/src/stories/prompt-input-variants.stories.tsx +179 -0
- package/src/stories/streaming-response.stories.tsx +234 -0
- package/src/stories/theme-editor.stories.tsx +16 -0
- package/src/stories/token-reference.stories.tsx +18 -0
- package/src/types.ts +41 -0
- package/src/ui/avatar.stories.tsx +104 -0
- package/src/ui/avatar.tsx +23 -0
- package/src/ui/badge.stories.tsx +87 -0
- package/src/ui/badge.tsx +21 -0
- package/src/ui/button.stories.tsx +146 -0
- package/src/ui/button.tsx +37 -0
- package/src/ui/collapsible.tsx +14 -0
- package/src/ui/dialog.tsx +21 -0
- package/src/ui/dropdown.tsx +26 -0
- package/src/ui/hover-card.tsx +48 -0
- package/src/ui/resizable.stories.tsx +171 -0
- package/src/ui/resizable.tsx +219 -0
- package/src/ui/scroll-area.tsx +13 -0
- package/src/ui/separator.stories.tsx +82 -0
- package/src/ui/separator.tsx +10 -0
- package/src/ui/skeleton.stories.tsx +338 -0
- package/src/ui/skeleton.tsx +16 -0
- package/src/ui/textarea.tsx +21 -0
- package/src/ui/tooltip.stories.tsx +75 -0
- package/src/ui/tooltip.tsx +22 -0
- package/src/utils/cn.ts +6 -0
- package/theme.css +115 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
+
import { CodeBlock, CodeBlockCode, CodeBlockGroup } from './code-block';
|
|
3
|
+
import { Button } from '../ui/button';
|
|
4
|
+
|
|
5
|
+
const tsCode = `interface User {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
email: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function greet(user: User): string {
|
|
12
|
+
return \`Hello, \${user.name}!\`;
|
|
13
|
+
}`;
|
|
14
|
+
|
|
15
|
+
const pythonCode = `def fibonacci(n: int) -> list[int]:
|
|
16
|
+
"""Generate fibonacci sequence up to n numbers."""
|
|
17
|
+
if n <= 0:
|
|
18
|
+
return []
|
|
19
|
+
sequence = [0, 1]
|
|
20
|
+
while len(sequence) < n:
|
|
21
|
+
sequence.append(sequence[-1] + sequence[-2])
|
|
22
|
+
return sequence[:n]
|
|
23
|
+
|
|
24
|
+
print(fibonacci(10))`;
|
|
25
|
+
|
|
26
|
+
const cssCode = `:root {
|
|
27
|
+
--primary: hsl(240 5.9% 10%);
|
|
28
|
+
--background: hsl(0 0% 100%);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.button {
|
|
32
|
+
background: var(--color-primary);
|
|
33
|
+
color: white;
|
|
34
|
+
border-radius: 0.5rem;
|
|
35
|
+
padding: 0.5rem 1rem;
|
|
36
|
+
}`;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Story for the compound `CodeBlock` family. The root `CodeBlock` is a bordered
|
|
40
|
+
* card container; `CodeBlockCode` does the (on-demand, Shiki) syntax
|
|
41
|
+
* highlighting; `CodeBlockGroup` is a flex header/footer row. The controllable
|
|
42
|
+
* props live on `CodeBlockCode`, so `Playground` drives that piece directly.
|
|
43
|
+
*/
|
|
44
|
+
const meta = {
|
|
45
|
+
title: 'Components/CodeBlock',
|
|
46
|
+
component: CodeBlockCode,
|
|
47
|
+
tags: ['autodocs'],
|
|
48
|
+
parameters: {
|
|
49
|
+
layout: 'padded',
|
|
50
|
+
docs: {
|
|
51
|
+
description: {
|
|
52
|
+
component: [
|
|
53
|
+
'A bordered code card with optional syntax highlighting. `CodeBlock` is the container, `CodeBlockCode` renders the (Shiki-)highlighted source, and `CodeBlockGroup` is a flex row for a header/footer (filename + copy button).',
|
|
54
|
+
'**When to use:** to display code snippets in chat messages, documentation, or anywhere fenced code appears — typically emitted by the Markdown renderer for ``` blocks.',
|
|
55
|
+
'**How to use:** wrap one or more children in `<CodeBlock>`. Pass the source string and a `language` to `<CodeBlockCode>`; optionally override the `theme`. Add a `<CodeBlockGroup>` for a filename row and copy action.',
|
|
56
|
+
'**Placement:** inside assistant message content, README/docs panes, and tool-output views.',
|
|
57
|
+
].join('\n\n'),
|
|
58
|
+
},
|
|
59
|
+
controls: { exclude: ['use:eventListener'] },
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
argTypes: {
|
|
63
|
+
code: {
|
|
64
|
+
control: 'text',
|
|
65
|
+
description: 'The source code string to render.',
|
|
66
|
+
},
|
|
67
|
+
language: {
|
|
68
|
+
control: 'text',
|
|
69
|
+
description: 'Language id for syntax highlighting (e.g. `typescript`, `python`, `css`).',
|
|
70
|
+
table: { defaultValue: { summary: 'tsx' } },
|
|
71
|
+
},
|
|
72
|
+
theme: {
|
|
73
|
+
control: 'text',
|
|
74
|
+
description: 'Shiki theme id. Falls back to the active ChatConfig `codeTheme`.',
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
args: {
|
|
78
|
+
code: tsCode,
|
|
79
|
+
language: 'typescript',
|
|
80
|
+
},
|
|
81
|
+
render: (args) => (
|
|
82
|
+
<div class="max-w-lg">
|
|
83
|
+
<CodeBlock>
|
|
84
|
+
<CodeBlockCode {...args} />
|
|
85
|
+
</CodeBlock>
|
|
86
|
+
</div>
|
|
87
|
+
),
|
|
88
|
+
} satisfies Meta<typeof CodeBlockCode>;
|
|
89
|
+
|
|
90
|
+
export default meta;
|
|
91
|
+
type Story = StoryObj<typeof meta>;
|
|
92
|
+
|
|
93
|
+
const IMPORT = `import { CodeBlock, CodeBlockCode, CodeBlockGroup } from '@kitnai/chat';`;
|
|
94
|
+
const src = (code: string) => ({
|
|
95
|
+
parameters: { docs: { source: { code: `${IMPORT}\n\n${code}`, language: 'tsx' } } },
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
/** Interactive playground — edit the code, language, or theme via controls. */
|
|
99
|
+
export const Playground: Story = {
|
|
100
|
+
...src(`<CodeBlock>
|
|
101
|
+
<CodeBlockCode code={tsCode} language="typescript" />
|
|
102
|
+
</CodeBlock>`),
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const TypeScript: Story = {
|
|
106
|
+
args: { code: tsCode, language: 'typescript' },
|
|
107
|
+
...src(`<CodeBlock>
|
|
108
|
+
<CodeBlockCode code={tsCode} language="typescript" />
|
|
109
|
+
</CodeBlock>`),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const Python: Story = {
|
|
113
|
+
args: { code: pythonCode, language: 'python' },
|
|
114
|
+
...src(`<CodeBlock>
|
|
115
|
+
<CodeBlockCode code={pythonCode} language="python" />
|
|
116
|
+
</CodeBlock>`),
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const CSS: Story = {
|
|
120
|
+
args: { code: cssCode, language: 'css' },
|
|
121
|
+
...src(`<CodeBlock>
|
|
122
|
+
<CodeBlockCode code={cssCode} language="css" />
|
|
123
|
+
</CodeBlock>`),
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/** A header row (`CodeBlockGroup`) with a filename and a copy button — showcase. */
|
|
127
|
+
export const WithHeader: Story = {
|
|
128
|
+
render: () => (
|
|
129
|
+
<div class="max-w-lg">
|
|
130
|
+
<CodeBlock>
|
|
131
|
+
<CodeBlockGroup class="border-b border-border px-4 py-2">
|
|
132
|
+
<span class="text-xs text-muted-foreground font-mono">user.ts</span>
|
|
133
|
+
<Button variant="ghost" size="icon-sm">
|
|
134
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
135
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
|
|
136
|
+
<path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1" />
|
|
137
|
+
</svg>
|
|
138
|
+
</Button>
|
|
139
|
+
</CodeBlockGroup>
|
|
140
|
+
<CodeBlockCode code={tsCode} language="typescript" />
|
|
141
|
+
</CodeBlock>
|
|
142
|
+
</div>
|
|
143
|
+
),
|
|
144
|
+
...src(`<CodeBlock>
|
|
145
|
+
<CodeBlockGroup class="border-b border-border px-4 py-2">
|
|
146
|
+
<span class="text-xs text-muted-foreground font-mono">user.ts</span>
|
|
147
|
+
<Button variant="ghost" size="icon-sm">{/* copy icon */}</Button>
|
|
148
|
+
</CodeBlockGroup>
|
|
149
|
+
<CodeBlockCode code={tsCode} language="typescript" />
|
|
150
|
+
</CodeBlock>`),
|
|
151
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { type JSX, splitProps, createResource, Show } from 'solid-js';
|
|
2
|
+
import { cn } from '../utils/cn';
|
|
3
|
+
import { useChatConfig } from '../primitives/chat-config';
|
|
4
|
+
import { highlight, isCodeHighlightingEnabled } from '../primitives/highlighter';
|
|
5
|
+
|
|
6
|
+
// --- CodeBlock (Root) ---
|
|
7
|
+
|
|
8
|
+
export interface CodeBlockProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
9
|
+
children?: JSX.Element;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function CodeBlock(props: CodeBlockProps) {
|
|
13
|
+
const [local, rest] = splitProps(props, ['children', 'class']);
|
|
14
|
+
return (
|
|
15
|
+
<div
|
|
16
|
+
class={cn(
|
|
17
|
+
'not-prose flex w-full flex-col overflow-clip border',
|
|
18
|
+
'border-border bg-card text-card-foreground rounded-xl',
|
|
19
|
+
local.class
|
|
20
|
+
)}
|
|
21
|
+
{...rest}
|
|
22
|
+
>
|
|
23
|
+
{local.children}
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// --- CodeBlockCode ---
|
|
29
|
+
|
|
30
|
+
export interface CodeBlockCodeProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
31
|
+
code: string;
|
|
32
|
+
language?: string;
|
|
33
|
+
theme?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function CodeBlockCode(props: CodeBlockCodeProps) {
|
|
37
|
+
const [local, rest] = splitProps(props, ['code', 'language', 'theme', 'class']);
|
|
38
|
+
const config = useChatConfig();
|
|
39
|
+
|
|
40
|
+
const lang = () => local.language ?? 'tsx';
|
|
41
|
+
const theme = () => local.theme ?? config.codeTheme();
|
|
42
|
+
const highlightingOn = () => isCodeHighlightingEnabled() && config.codeHighlight();
|
|
43
|
+
|
|
44
|
+
// When highlighting is off, the source is null so the fetcher never runs and
|
|
45
|
+
// no Shiki code is ever imported — the plain `<pre>` fallback renders instead.
|
|
46
|
+
const [highlighted] = createResource(
|
|
47
|
+
() => (highlightingOn() ? { code: local.code, lang: lang(), theme: theme() } : null),
|
|
48
|
+
(src) => highlight(src.code, src.lang, src.theme)
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const codeTextSize = () => {
|
|
52
|
+
switch (config.proseSize()) {
|
|
53
|
+
case 'xs': return 'text-[11px]';
|
|
54
|
+
case 'sm': return 'text-[13px]';
|
|
55
|
+
case 'base': return 'text-sm';
|
|
56
|
+
case 'lg': return 'text-base';
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const classNames = () =>
|
|
61
|
+
cn(
|
|
62
|
+
'w-full overflow-x-auto [&>pre]:px-4 [&>pre]:py-4',
|
|
63
|
+
codeTextSize(),
|
|
64
|
+
local.class
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Show
|
|
69
|
+
when={highlighted()}
|
|
70
|
+
fallback={
|
|
71
|
+
<div class={classNames()} {...rest}>
|
|
72
|
+
<pre><code>{local.code}</code></pre>
|
|
73
|
+
</div>
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
<div class={classNames()} innerHTML={highlighted()} {...rest} />
|
|
77
|
+
</Show>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- CodeBlockGroup ---
|
|
82
|
+
|
|
83
|
+
export interface CodeBlockGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
|
84
|
+
children?: JSX.Element;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function CodeBlockGroup(props: CodeBlockGroupProps) {
|
|
88
|
+
const [local, rest] = splitProps(props, ['children', 'class']);
|
|
89
|
+
return (
|
|
90
|
+
<div
|
|
91
|
+
class={cn('flex items-center justify-between', local.class)}
|
|
92
|
+
{...rest}
|
|
93
|
+
>
|
|
94
|
+
{local.children}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { CodeBlock, CodeBlockCode, CodeBlockGroup };
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from 'storybook-solidjs-vite';
|
|
2
|
+
import {
|
|
3
|
+
Context,
|
|
4
|
+
ContextTrigger,
|
|
5
|
+
ContextContent,
|
|
6
|
+
ContextContentHeader,
|
|
7
|
+
ContextContentBody,
|
|
8
|
+
ContextContentFooter,
|
|
9
|
+
ContextInputUsage,
|
|
10
|
+
ContextOutputUsage,
|
|
11
|
+
ContextReasoningUsage,
|
|
12
|
+
ContextCacheUsage,
|
|
13
|
+
} from './context';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Story for the compound `Context` family. `Context` is the root provider that
|
|
17
|
+
* holds the token-usage values; the trigger/content/usage-row subcomponents read
|
|
18
|
+
* from it. The controllable props all live on the `Context` root, so `Playground`
|
|
19
|
+
* drives the root and composes a full hover-card breakdown.
|
|
20
|
+
*/
|
|
21
|
+
const meta = {
|
|
22
|
+
title: 'Components/Context',
|
|
23
|
+
component: Context,
|
|
24
|
+
tags: ['autodocs'],
|
|
25
|
+
parameters: {
|
|
26
|
+
layout: 'padded',
|
|
27
|
+
docs: {
|
|
28
|
+
description: {
|
|
29
|
+
component: [
|
|
30
|
+
'A model context-window usage indicator: a hover-card trigger showing the used-percent ring, with a popover breaking down token usage (input / output / reasoning / cache) and estimated cost.',
|
|
31
|
+
'**When to use:** to surface how much of a model\'s context window a conversation has consumed and roughly what it costs — near the prompt input or in a chat header.',
|
|
32
|
+
'**How to use:** wrap the composition in `<Context>` and pass `usedTokens` / `maxTokens` (plus optional `inputTokens`, `outputTokens`, `reasoningTokens`, `cacheTokens`, `estimatedCost`). Compose `ContextTrigger`, `ContextContent` (with `Header`/`Body`/`Footer`), and the usage rows.',
|
|
33
|
+
'**Placement:** chat toolbars, prompt-input action bars, and conversation headers.',
|
|
34
|
+
].join('\n\n'),
|
|
35
|
+
},
|
|
36
|
+
controls: { exclude: ['use:eventListener'] },
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
argTypes: {
|
|
40
|
+
usedTokens: {
|
|
41
|
+
control: 'number',
|
|
42
|
+
description: 'Tokens consumed so far. Drives the ring fill and progress bar.',
|
|
43
|
+
},
|
|
44
|
+
maxTokens: {
|
|
45
|
+
control: 'number',
|
|
46
|
+
description: 'Total context window size.',
|
|
47
|
+
},
|
|
48
|
+
inputTokens: {
|
|
49
|
+
control: 'number',
|
|
50
|
+
description: 'Prompt/input tokens (shown by `ContextInputUsage`).',
|
|
51
|
+
},
|
|
52
|
+
outputTokens: {
|
|
53
|
+
control: 'number',
|
|
54
|
+
description: 'Generated/output tokens (shown by `ContextOutputUsage`).',
|
|
55
|
+
},
|
|
56
|
+
reasoningTokens: {
|
|
57
|
+
control: 'number',
|
|
58
|
+
description: 'Reasoning tokens (shown by `ContextReasoningUsage`).',
|
|
59
|
+
},
|
|
60
|
+
cacheTokens: {
|
|
61
|
+
control: 'number',
|
|
62
|
+
description: 'Cached tokens (shown by `ContextCacheUsage`).',
|
|
63
|
+
},
|
|
64
|
+
estimatedCost: {
|
|
65
|
+
control: 'number',
|
|
66
|
+
description: 'Estimated cost in USD (shown by `ContextContentFooter`).',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
args: {
|
|
70
|
+
usedTokens: 85000,
|
|
71
|
+
maxTokens: 128000,
|
|
72
|
+
inputTokens: 60000,
|
|
73
|
+
outputTokens: 15000,
|
|
74
|
+
reasoningTokens: 8000,
|
|
75
|
+
cacheTokens: 2000,
|
|
76
|
+
estimatedCost: 0.45,
|
|
77
|
+
},
|
|
78
|
+
render: (args) => (
|
|
79
|
+
<Context {...args}>
|
|
80
|
+
<ContextTrigger />
|
|
81
|
+
<ContextContent>
|
|
82
|
+
<ContextContentHeader />
|
|
83
|
+
<ContextContentBody>
|
|
84
|
+
<div class="space-y-1">
|
|
85
|
+
<ContextInputUsage />
|
|
86
|
+
<ContextOutputUsage />
|
|
87
|
+
<ContextReasoningUsage />
|
|
88
|
+
<ContextCacheUsage />
|
|
89
|
+
</div>
|
|
90
|
+
</ContextContentBody>
|
|
91
|
+
<ContextContentFooter />
|
|
92
|
+
</ContextContent>
|
|
93
|
+
</Context>
|
|
94
|
+
),
|
|
95
|
+
} satisfies Meta<typeof Context>;
|
|
96
|
+
|
|
97
|
+
export default meta;
|
|
98
|
+
type Story = StoryObj<typeof meta>;
|
|
99
|
+
|
|
100
|
+
const IMPORT = `import {
|
|
101
|
+
Context, ContextTrigger, ContextContent, ContextContentHeader,
|
|
102
|
+
ContextContentBody, ContextContentFooter,
|
|
103
|
+
ContextInputUsage, ContextOutputUsage, ContextReasoningUsage, ContextCacheUsage,
|
|
104
|
+
} from '@kitnai/chat';`;
|
|
105
|
+
const src = (code: string) => ({
|
|
106
|
+
parameters: { docs: { source: { code: `${IMPORT}\n\n${code}`, language: 'tsx' } } },
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const usage = `<Context usedTokens={85000} maxTokens={128000} inputTokens={60000} outputTokens={15000} reasoningTokens={8000} cacheTokens={2000} estimatedCost={0.45}>
|
|
110
|
+
<ContextTrigger />
|
|
111
|
+
<ContextContent>
|
|
112
|
+
<ContextContentHeader />
|
|
113
|
+
<ContextContentBody>
|
|
114
|
+
<div class="space-y-1">
|
|
115
|
+
<ContextInputUsage />
|
|
116
|
+
<ContextOutputUsage />
|
|
117
|
+
<ContextReasoningUsage />
|
|
118
|
+
<ContextCacheUsage />
|
|
119
|
+
</div>
|
|
120
|
+
</ContextContentBody>
|
|
121
|
+
<ContextContentFooter />
|
|
122
|
+
</ContextContent>
|
|
123
|
+
</Context>`;
|
|
124
|
+
|
|
125
|
+
/** Interactive playground — tweak token counts to watch the ring, bar color, and breakdown update. */
|
|
126
|
+
export const Playground: Story = {
|
|
127
|
+
...src(usage),
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export const LowUsage: Story = {
|
|
131
|
+
args: {
|
|
132
|
+
usedTokens: 12000,
|
|
133
|
+
maxTokens: 128000,
|
|
134
|
+
inputTokens: 8000,
|
|
135
|
+
outputTokens: 4000,
|
|
136
|
+
reasoningTokens: undefined,
|
|
137
|
+
cacheTokens: undefined,
|
|
138
|
+
estimatedCost: 0.02,
|
|
139
|
+
},
|
|
140
|
+
...src(usage),
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export const MediumUsage: Story = {
|
|
144
|
+
args: {
|
|
145
|
+
usedTokens: 85000,
|
|
146
|
+
maxTokens: 128000,
|
|
147
|
+
inputTokens: 60000,
|
|
148
|
+
outputTokens: 15000,
|
|
149
|
+
reasoningTokens: 8000,
|
|
150
|
+
cacheTokens: 2000,
|
|
151
|
+
estimatedCost: 0.45,
|
|
152
|
+
},
|
|
153
|
+
...src(usage),
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export const HighUsage: Story = {
|
|
157
|
+
args: {
|
|
158
|
+
usedTokens: 122000,
|
|
159
|
+
maxTokens: 128000,
|
|
160
|
+
inputTokens: 90000,
|
|
161
|
+
outputTokens: 22000,
|
|
162
|
+
reasoningTokens: 10000,
|
|
163
|
+
cacheTokens: undefined,
|
|
164
|
+
estimatedCost: 1.85,
|
|
165
|
+
},
|
|
166
|
+
...src(usage),
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
export const WithCost: Story = {
|
|
170
|
+
args: {
|
|
171
|
+
usedTokens: 50000,
|
|
172
|
+
maxTokens: 200000,
|
|
173
|
+
inputTokens: 35000,
|
|
174
|
+
outputTokens: 10000,
|
|
175
|
+
reasoningTokens: 5000,
|
|
176
|
+
cacheTokens: undefined,
|
|
177
|
+
estimatedCost: 0.32,
|
|
178
|
+
},
|
|
179
|
+
...src(usage),
|
|
180
|
+
};
|