@pikku/assistant-ui 0.12.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @pikku/assistant-ui
2
+
3
+ ## 0.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 387b2ee: Rework agent chat UI with approval flows, tool call error badges, hideToolCalls option, and non-streaming runtime support
@@ -1,4 +1,4 @@
1
- export { usePikkuAgentRuntime } from './use-pikku-agent-runtime.js';
2
- export type { PikkuAgentRuntimeOptions } from './use-pikku-agent-runtime.js';
1
+ export { usePikkuAgentRuntime, usePikkuAgentNonStreamingRuntime, PikkuApprovalContext, usePikkuApproval, convertDbMessages, isDeniedResult, resolvePikkuToolStatus, } from './use-pikku-agent-runtime.js';
2
+ export type { PikkuAgentRuntimeOptions, PendingApproval, PikkuApprovalContextValue, PikkuToolStatusType, PikkuToolStatus, } from './use-pikku-agent-runtime.js';
3
3
  export { PikkuAgentChat } from './pikku-agent-chat.js';
4
4
  export type { PikkuAgentChatProps } from './pikku-agent-chat.js';
package/dist/cjs/index.js CHANGED
@@ -1,7 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PikkuAgentChat = exports.usePikkuAgentRuntime = void 0;
3
+ exports.PikkuAgentChat = exports.resolvePikkuToolStatus = exports.isDeniedResult = exports.convertDbMessages = exports.usePikkuApproval = exports.PikkuApprovalContext = exports.usePikkuAgentNonStreamingRuntime = exports.usePikkuAgentRuntime = void 0;
4
4
  var use_pikku_agent_runtime_js_1 = require("./use-pikku-agent-runtime.js");
5
5
  Object.defineProperty(exports, "usePikkuAgentRuntime", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.usePikkuAgentRuntime; } });
6
+ Object.defineProperty(exports, "usePikkuAgentNonStreamingRuntime", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.usePikkuAgentNonStreamingRuntime; } });
7
+ Object.defineProperty(exports, "PikkuApprovalContext", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.PikkuApprovalContext; } });
8
+ Object.defineProperty(exports, "usePikkuApproval", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.usePikkuApproval; } });
9
+ Object.defineProperty(exports, "convertDbMessages", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.convertDbMessages; } });
10
+ Object.defineProperty(exports, "isDeniedResult", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.isDeniedResult; } });
11
+ Object.defineProperty(exports, "resolvePikkuToolStatus", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.resolvePikkuToolStatus; } });
6
12
  var pikku_agent_chat_js_1 = require("./pikku-agent-chat.js");
7
13
  Object.defineProperty(exports, "PikkuAgentChat", { enumerable: true, get: function () { return pikku_agent_chat_js_1.PikkuAgentChat; } });
@@ -1,5 +1,11 @@
1
1
  import { type PikkuAgentRuntimeOptions } from './use-pikku-agent-runtime.js';
2
2
  export interface PikkuAgentChatProps extends PikkuAgentRuntimeOptions {
3
3
  emptyMessage?: string;
4
+ /** Hide tool calls from the chat display.
5
+ * - `true`: hide all non-approval tool calls
6
+ * - `string[]`: hide tool calls matching these names
7
+ */
8
+ hideToolCalls?: boolean | string[];
9
+ dark?: boolean;
4
10
  }
5
11
  export declare function PikkuAgentChat(props: PikkuAgentChatProps): import("react/jsx-runtime").JSX.Element;
@@ -14,22 +14,79 @@ Object.defineProperty(exports, "__esModule", { value: true });
14
14
  exports.PikkuAgentChat = PikkuAgentChat;
15
15
  const jsx_runtime_1 = require("react/jsx-runtime");
16
16
  const react_1 = require("react");
17
+ const react_markdown_1 = require("react-markdown");
17
18
  const react_2 = require("@assistant-ui/react");
18
19
  const use_pikku_agent_runtime_js_1 = require("./use-pikku-agent-runtime.js");
19
- const ToolCallDisplay = ({ toolName, args, result, status, addResult }) => {
20
+ const lightColors = {
21
+ bg: '#ffffff',
22
+ userBubble: '#e3f2fd',
23
+ assistantBubble: '#f5f5f5',
24
+ text: '#1a1a1a',
25
+ textMuted: '#888',
26
+ border: '#ddd',
27
+ codeBg: '#f5f5f5',
28
+ inputBg: 'transparent',
29
+ sendBg: '#1976d2',
30
+ sendColor: '#fff',
31
+ approvalBg: '#fef9e7',
32
+ approvalBorder: '#e9a211',
33
+ successBg: '#e8f5e9',
34
+ successColor: '#2e7d32',
35
+ errorBg: '#ffebee',
36
+ errorColor: '#c62828',
37
+ };
38
+ const darkColors = {
39
+ bg: 'transparent',
40
+ userBubble: 'rgba(0, 230, 138, 0.1)',
41
+ assistantBubble: '#1e1e2e',
42
+ text: '#e0e0e8',
43
+ textMuted: '#8888a0',
44
+ border: '#2a2a3e',
45
+ codeBg: '#0e0e16',
46
+ inputBg: 'transparent',
47
+ sendBg: '#00cc7a',
48
+ sendColor: '#0a0a0f',
49
+ approvalBg: 'rgba(233, 162, 17, 0.1)',
50
+ approvalBorder: '#e9a211',
51
+ successBg: 'rgba(0, 230, 138, 0.1)',
52
+ successColor: '#00e68a',
53
+ errorBg: 'rgba(220, 38, 38, 0.1)',
54
+ errorColor: '#f87171',
55
+ };
56
+ const ColorsContext = (0, react_1.createContext)(lightColors);
57
+ const HideToolCallsContext = (0, react_1.createContext)(undefined);
58
+ function shouldHideToolCall(hideToolCalls, toolName) {
59
+ if (!hideToolCalls)
60
+ return false;
61
+ if (hideToolCalls === true)
62
+ return true;
63
+ return hideToolCalls.includes(toolName);
64
+ }
65
+ const ToolCallDisplay = ({ toolCallId, toolName, args, result, status, addResult }) => {
66
+ const colors = (0, react_1.useContext)(ColorsContext);
67
+ const hideToolCalls = (0, react_1.useContext)(HideToolCallsContext);
68
+ const { handleApproval } = (0, use_pikku_agent_runtime_js_1.usePikkuApproval)();
20
69
  const [expanded, setExpanded] = (0, react_1.useState)(false);
21
70
  const isApproval = status.type === 'requires-action';
22
71
  const approvalReason = args === null || args === void 0 ? void 0 : args.__approvalReason;
23
72
  const displayArgs = Object.assign({}, args);
24
73
  delete displayArgs.__approvalReason;
25
74
  const [responded, setResponded] = (0, react_1.useState)(null);
75
+ // Hide responded approval tool calls
76
+ if (isApproval && responded && shouldHideToolCall(hideToolCalls, toolName)) {
77
+ return null;
78
+ }
79
+ // Hide non-approval tool calls
80
+ if (!isApproval && shouldHideToolCall(hideToolCalls, toolName)) {
81
+ return null;
82
+ }
26
83
  if (isApproval && !responded) {
27
84
  return ((0, jsx_runtime_1.jsxs)("div", { style: {
28
- border: '1px solid #e9a211',
85
+ border: `1px solid ${colors.approvalBorder}`,
29
86
  borderRadius: 6,
30
87
  padding: 12,
31
88
  margin: '4px 0',
32
- backgroundColor: '#fef9e7',
89
+ backgroundColor: colors.approvalBg,
33
90
  }, children: [(0, jsx_runtime_1.jsx)("div", { style: {
34
91
  display: 'flex',
35
92
  alignItems: 'center',
@@ -37,40 +94,44 @@ const ToolCallDisplay = ({ toolName, args, result, status, addResult }) => {
37
94
  marginBottom: 8,
38
95
  fontWeight: 600,
39
96
  fontSize: 13,
40
- }, children: "Approval required" }), approvalReason && ((0, jsx_runtime_1.jsx)("div", { style: { fontSize: 13, marginBottom: 4 }, children: approvalReason })), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: 12, color: '#666', marginBottom: 4 }, children: ["The agent wants to call ", (0, jsx_runtime_1.jsx)("code", { children: toolName })] }), (0, jsx_runtime_1.jsx)("pre", { style: {
97
+ color: colors.text,
98
+ }, children: "Approval required" }), approvalReason && ((0, jsx_runtime_1.jsx)("div", { style: { fontSize: 13, marginBottom: 4, color: colors.text }, children: approvalReason })), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: 12, color: colors.textMuted, marginBottom: 4 }, children: ["The agent wants to call ", (0, jsx_runtime_1.jsx)("code", { children: toolName })] }), (0, jsx_runtime_1.jsx)("pre", { style: {
41
99
  fontSize: 11,
42
- background: '#f5f5f5',
100
+ background: colors.codeBg,
43
101
  padding: 8,
44
102
  borderRadius: 4,
45
103
  overflow: 'auto',
46
104
  marginBottom: 8,
105
+ color: colors.text,
47
106
  }, children: JSON.stringify(displayArgs, null, 2) }), (0, jsx_runtime_1.jsxs)("div", { style: { display: 'flex', gap: 8 }, children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => {
48
107
  setResponded('approved');
108
+ handleApproval(toolCallId, true);
49
109
  addResult === null || addResult === void 0 ? void 0 : addResult({ approved: true });
50
110
  }, style: {
51
111
  padding: '4px 12px',
52
112
  fontSize: 12,
53
- border: '1px solid #2e7d32',
113
+ border: `1px solid ${colors.successColor}`,
54
114
  borderRadius: 4,
55
- background: '#e8f5e9',
56
- color: '#2e7d32',
115
+ background: colors.successBg,
116
+ color: colors.successColor,
57
117
  cursor: 'pointer',
58
118
  }, children: "Approve" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => {
59
119
  setResponded('denied');
120
+ handleApproval(toolCallId, false);
60
121
  addResult === null || addResult === void 0 ? void 0 : addResult({ approved: false });
61
122
  }, style: {
62
123
  padding: '4px 12px',
63
124
  fontSize: 12,
64
- border: '1px solid #c62828',
125
+ border: `1px solid ${colors.errorColor}`,
65
126
  borderRadius: 4,
66
- background: '#ffebee',
67
- color: '#c62828',
127
+ background: colors.errorBg,
128
+ color: colors.errorColor,
68
129
  cursor: 'pointer',
69
130
  }, children: "Deny" })] })] }));
70
131
  }
71
132
  if (isApproval && responded) {
72
133
  return ((0, jsx_runtime_1.jsxs)("div", { style: {
73
- border: '1px solid #ddd',
134
+ border: `1px solid ${colors.border}`,
74
135
  borderRadius: 6,
75
136
  padding: 8,
76
137
  margin: '4px 0',
@@ -78,16 +139,17 @@ const ToolCallDisplay = ({ toolName, args, result, status, addResult }) => {
78
139
  alignItems: 'center',
79
140
  gap: 8,
80
141
  fontSize: 13,
142
+ color: colors.text,
81
143
  }, children: [(0, jsx_runtime_1.jsx)("span", { style: { fontWeight: 500 }, children: toolName }), (0, jsx_runtime_1.jsx)("span", { style: {
82
144
  fontSize: 11,
83
145
  padding: '2px 6px',
84
146
  borderRadius: 3,
85
- background: responded === 'approved' ? '#e8f5e9' : '#ffebee',
86
- color: responded === 'approved' ? '#2e7d32' : '#c62828',
147
+ background: responded === 'approved' ? colors.successBg : colors.errorBg,
148
+ color: responded === 'approved' ? colors.successColor : colors.errorColor,
87
149
  }, children: responded })] }));
88
150
  }
89
151
  return ((0, jsx_runtime_1.jsxs)("div", { style: {
90
- border: '1px solid #ddd',
152
+ border: `1px solid ${colors.border}`,
91
153
  borderRadius: 6,
92
154
  padding: 8,
93
155
  margin: '4px 0',
@@ -101,132 +163,174 @@ const ToolCallDisplay = ({ toolName, args, result, status, addResult }) => {
101
163
  width: '100%',
102
164
  padding: 0,
103
165
  fontSize: 13,
104
- }, children: [(0, jsx_runtime_1.jsx)("span", { children: expanded ? '\u25BC' : '\u25B6' }), (0, jsx_runtime_1.jsx)("span", { style: { fontFamily: 'monospace', fontWeight: 500 }, children: toolName }), status.type === 'running' && ((0, jsx_runtime_1.jsx)("span", { style: { fontSize: 11, color: '#888' }, children: "running..." })), status.type === 'complete' && ((0, jsx_runtime_1.jsx)("span", { style: {
166
+ color: colors.text,
167
+ }, children: [(0, jsx_runtime_1.jsx)("span", { children: expanded ? '\u25BC' : '\u25B6' }), (0, jsx_runtime_1.jsx)("span", { style: { fontFamily: 'monospace', fontWeight: 500 }, children: toolName }), status.type === 'running' && ((0, jsx_runtime_1.jsx)("span", { style: { fontSize: 11, color: colors.textMuted }, children: "running..." })), status.type === 'error' && ((0, jsx_runtime_1.jsx)("span", { style: {
168
+ fontSize: 11,
169
+ padding: '1px 5px',
170
+ borderRadius: 3,
171
+ background: colors.errorBg,
172
+ color: colors.errorColor,
173
+ }, children: "error" })), status.type === 'denied' && ((0, jsx_runtime_1.jsx)("span", { style: {
174
+ fontSize: 11,
175
+ padding: '1px 5px',
176
+ borderRadius: 3,
177
+ background: colors.errorBg,
178
+ color: colors.errorColor,
179
+ }, children: "denied" })), status.type === 'completed' && ((0, jsx_runtime_1.jsx)("span", { style: {
105
180
  fontSize: 11,
106
181
  padding: '1px 5px',
107
182
  borderRadius: 3,
108
- background: '#e8f5e9',
109
- color: '#2e7d32',
110
- }, children: "done" }))] }), expanded && ((0, jsx_runtime_1.jsxs)("div", { style: { marginTop: 8 }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: '#888', marginBottom: 2 }, children: "Arguments:" }), (0, jsx_runtime_1.jsx)("pre", { style: {
183
+ background: colors.successBg,
184
+ color: colors.successColor,
185
+ }, children: "done" }))] }), expanded && ((0, jsx_runtime_1.jsxs)("div", { style: { marginTop: 8 }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: colors.textMuted, marginBottom: 2 }, children: "Arguments:" }), (0, jsx_runtime_1.jsx)("pre", { style: {
111
186
  fontSize: 11,
112
- background: '#f5f5f5',
187
+ background: colors.codeBg,
113
188
  padding: 8,
114
189
  borderRadius: 4,
115
190
  overflow: 'auto',
116
- }, children: JSON.stringify(displayArgs, null, 2) }), result !== undefined && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: '#888', marginTop: 8, marginBottom: 2 }, children: "Result:" }), (0, jsx_runtime_1.jsx)("pre", { style: {
191
+ color: colors.text,
192
+ }, children: JSON.stringify(displayArgs, null, 2) }), result !== undefined && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: colors.textMuted, marginTop: 8, marginBottom: 2 }, children: "Result:" }), (0, jsx_runtime_1.jsx)("pre", { style: {
117
193
  fontSize: 11,
118
- background: '#f5f5f5',
194
+ background: colors.codeBg,
119
195
  padding: 8,
120
196
  borderRadius: 4,
121
197
  overflow: 'auto',
198
+ color: colors.text,
122
199
  }, children: typeof result === 'string'
123
200
  ? result
124
201
  : JSON.stringify(result, null, 2) })] }))] }))] }));
125
202
  };
126
- const UserMessage = () => ((0, jsx_runtime_1.jsx)("div", { style: {
127
- display: 'flex',
128
- justifyContent: 'flex-end',
129
- width: '100%',
130
- }, children: (0, jsx_runtime_1.jsxs)("div", { style: { maxWidth: '80%' }, children: [(0, jsx_runtime_1.jsx)("div", { style: {
131
- fontSize: 12,
132
- color: '#888',
133
- marginBottom: 4,
134
- textAlign: 'right',
135
- }, children: "You" }), (0, jsx_runtime_1.jsx)("div", { style: {
136
- padding: 12,
137
- borderRadius: 12,
138
- backgroundColor: '#e3f2fd',
139
- }, children: (0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.Content, { components: {
140
- Text: ({ text }) => ((0, jsx_runtime_1.jsx)("span", { style: { fontSize: 14, whiteSpace: 'pre-wrap' }, children: text })),
141
- } }) })] }) }));
142
- const AssistantMessage = () => ((0, jsx_runtime_1.jsx)("div", { style: {
143
- display: 'flex',
144
- justifyContent: 'flex-start',
145
- width: '100%',
146
- }, children: (0, jsx_runtime_1.jsxs)("div", { style: { maxWidth: '80%' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: '#888', marginBottom: 4 }, children: "Assistant" }), (0, jsx_runtime_1.jsxs)("div", { style: {
147
- padding: 12,
148
- borderRadius: 12,
149
- backgroundColor: '#f5f5f5',
150
- }, children: [(0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.Content, { components: {
151
- Text: ({ text }) => ((0, jsx_runtime_1.jsx)("span", { style: { fontSize: 14, whiteSpace: 'pre-wrap' }, children: text })),
152
- tools: {
153
- Fallback: (props) => ((0, jsx_runtime_1.jsx)(ToolCallDisplay, { toolName: props.toolName, args: props.args, result: props.result, status: props.status, addResult: props.addResult })),
154
- },
155
- } }), (0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.If, { last: true, children: (0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.If, { running: true, children: (0, jsx_runtime_1.jsx)("div", { style: {
156
- display: 'flex',
157
- alignItems: 'center',
158
- gap: 6,
159
- marginTop: 8,
160
- fontSize: 13,
161
- color: '#888',
162
- }, children: "Thinking..." }) }) })] })] }) }));
163
- const PikkuComposer = () => ((0, jsx_runtime_1.jsx)("div", { style: { padding: '8px 0 16px' }, children: (0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Root, { children: (0, jsx_runtime_1.jsxs)("div", { style: {
164
- border: '1px solid #ddd',
165
- borderRadius: 12,
166
- overflow: 'hidden',
167
- display: 'flex',
168
- alignItems: 'flex-end',
169
- padding: '6px 12px',
170
- gap: 8,
171
- }, children: [(0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Input, { placeholder: "Message...", rows: 2, style: {
172
- flex: 1,
173
- border: 'none',
174
- outline: 'none',
175
- resize: 'none',
176
- fontSize: 14,
177
- fontFamily: 'inherit',
178
- padding: '4px 0',
179
- background: 'transparent',
180
- } }), (0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Send, { style: {
181
- width: 28,
182
- height: 28,
183
- borderRadius: '50%',
184
- border: 'none',
185
- background: '#1976d2',
186
- color: '#fff',
187
- cursor: 'pointer',
188
- display: 'flex',
189
- alignItems: 'center',
190
- justifyContent: 'center',
191
- flexShrink: 0,
192
- marginBottom: 2,
193
- fontSize: 14,
194
- }, children: "\u25B6" })] }) }) }));
195
- function PikkuAgentChat(props) {
196
- const { emptyMessage } = props, runtimeOptions = __rest(props, ["emptyMessage"]);
197
- const runtime = (0, use_pikku_agent_runtime_js_1.usePikkuAgentRuntime)(runtimeOptions);
198
- return ((0, jsx_runtime_1.jsx)(react_2.AssistantRuntimeProvider, { runtime: runtime, children: (0, jsx_runtime_1.jsx)("div", { style: {
199
- height: '100%',
200
- display: 'flex',
201
- flexDirection: 'column',
202
- }, children: (0, jsx_runtime_1.jsxs)(react_2.ThreadPrimitive.Root, { style: {
203
- display: 'flex',
204
- flexDirection: 'column',
205
- flex: 1,
206
- minHeight: 0,
207
- }, children: [(0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Viewport, { style: {
203
+ const MarkdownText = ({ text, colors }) => {
204
+ const components = (0, react_1.useMemo)(() => ({
205
+ p: ({ children }) => ((0, jsx_runtime_1.jsx)("p", { style: { margin: '0 0 8px', fontSize: 14, lineHeight: 1.6, color: colors.text }, children: children })),
206
+ strong: ({ children }) => ((0, jsx_runtime_1.jsx)("strong", { style: { fontWeight: 600, color: colors.text }, children: children })),
207
+ em: ({ children }) => ((0, jsx_runtime_1.jsx)("em", { style: { color: colors.text }, children: children })),
208
+ ul: ({ children }) => ((0, jsx_runtime_1.jsx)("ul", { style: { margin: '4px 0 8px', paddingLeft: 20, fontSize: 14, color: colors.text }, children: children })),
209
+ ol: ({ children }) => ((0, jsx_runtime_1.jsx)("ol", { style: { margin: '4px 0 8px', paddingLeft: 20, fontSize: 14, color: colors.text }, children: children })),
210
+ li: ({ children }) => ((0, jsx_runtime_1.jsx)("li", { style: { marginBottom: 2, lineHeight: 1.6 }, children: children })),
211
+ code: ({ children, className }) => {
212
+ const isBlock = className === null || className === void 0 ? void 0 : className.startsWith('language-');
213
+ if (isBlock) {
214
+ return ((0, jsx_runtime_1.jsx)("pre", { style: { background: colors.codeBg, padding: 10, borderRadius: 4, overflow: 'auto', margin: '4px 0 8px', fontSize: 12 }, children: (0, jsx_runtime_1.jsx)("code", { style: { color: colors.text }, children: children }) }));
215
+ }
216
+ return ((0, jsx_runtime_1.jsx)("code", { style: { background: colors.codeBg, padding: '1px 4px', borderRadius: 3, fontSize: 13, color: colors.text }, children: children }));
217
+ },
218
+ pre: ({ children }) => (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children }),
219
+ h1: ({ children }) => (0, jsx_runtime_1.jsx)("h3", { style: { margin: '8px 0 4px', fontSize: 16, fontWeight: 600, color: colors.text }, children: children }),
220
+ h2: ({ children }) => (0, jsx_runtime_1.jsx)("h4", { style: { margin: '8px 0 4px', fontSize: 15, fontWeight: 600, color: colors.text }, children: children }),
221
+ h3: ({ children }) => (0, jsx_runtime_1.jsx)("h5", { style: { margin: '8px 0 4px', fontSize: 14, fontWeight: 600, color: colors.text }, children: children }),
222
+ a: ({ href, children }) => ((0, jsx_runtime_1.jsx)("a", { href: href, target: "_blank", rel: "noopener noreferrer", style: { color: colors.textMuted, textDecoration: 'underline' }, children: children })),
223
+ }), [colors]);
224
+ return (0, jsx_runtime_1.jsx)(react_markdown_1.default, { components: components, children: text });
225
+ };
226
+ const UserMessage = () => {
227
+ const colors = (0, react_1.useContext)(ColorsContext);
228
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
229
+ display: 'flex',
230
+ justifyContent: 'flex-end',
231
+ width: '100%',
232
+ }, children: (0, jsx_runtime_1.jsxs)("div", { style: { maxWidth: '80%' }, children: [(0, jsx_runtime_1.jsx)("div", { style: {
233
+ fontSize: 12,
234
+ color: colors.textMuted,
235
+ marginBottom: 4,
236
+ textAlign: 'right',
237
+ }, children: "You" }), (0, jsx_runtime_1.jsx)("div", { style: {
238
+ padding: 12,
239
+ borderRadius: 12,
240
+ backgroundColor: colors.userBubble,
241
+ }, children: (0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.Content, { components: {
242
+ Text: ({ text }) => ((0, jsx_runtime_1.jsx)("span", { style: { fontSize: 14, whiteSpace: 'pre-wrap', color: colors.text }, children: text })),
243
+ } }) })] }) }));
244
+ };
245
+ const AssistantMessage = () => {
246
+ const colors = (0, react_1.useContext)(ColorsContext);
247
+ return ((0, jsx_runtime_1.jsx)("div", { style: {
248
+ display: 'flex',
249
+ justifyContent: 'flex-start',
250
+ width: '100%',
251
+ }, children: (0, jsx_runtime_1.jsxs)("div", { style: { maxWidth: '80%' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontSize: 12, color: colors.textMuted, marginBottom: 4 }, children: "Assistant" }), (0, jsx_runtime_1.jsxs)("div", { style: {
252
+ padding: 12,
253
+ borderRadius: 12,
254
+ backgroundColor: colors.assistantBubble,
255
+ }, children: [(0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.Content, { components: {
256
+ Text: ({ text }) => ((0, jsx_runtime_1.jsx)(MarkdownText, { text: text, colors: colors })),
257
+ tools: {
258
+ Fallback: (props) => ((0, jsx_runtime_1.jsx)(ToolCallDisplay, { toolCallId: props.toolCallId, toolName: props.toolName, args: props.args, result: props.result, status: (0, use_pikku_agent_runtime_js_1.resolvePikkuToolStatus)(props.status, props.result), addResult: props.addResult })),
259
+ },
260
+ } }), (0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.If, { last: true, children: (0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.If, { running: true, children: (0, jsx_runtime_1.jsx)("div", { style: {
261
+ display: 'flex',
262
+ alignItems: 'center',
263
+ gap: 6,
264
+ marginTop: 8,
265
+ fontSize: 13,
266
+ color: colors.textMuted,
267
+ }, children: "Thinking..." }) }) })] })] }) }));
268
+ };
269
+ const PikkuComposer = ({ disabled, }) => {
270
+ const colors = (0, react_1.useContext)(ColorsContext);
271
+ return ((0, jsx_runtime_1.jsx)("div", { style: { padding: '8px 0 16px' }, children: (0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Root, { children: (0, jsx_runtime_1.jsxs)("div", { style: Object.assign({ border: `1px solid ${colors.border}`, borderRadius: 12, overflow: 'hidden', display: 'flex', alignItems: 'flex-end', padding: '6px 12px', gap: 8 }, (disabled ? { opacity: 0.5, pointerEvents: 'none' } : {})), children: [(0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Input, { placeholder: disabled ? 'Respond to approval request above...' : 'Message...', rows: 2, disabled: disabled, style: {
208
272
  flex: 1,
209
- minHeight: 0,
210
- overflowY: 'auto',
211
- }, children: (0, jsx_runtime_1.jsxs)("div", { style: {
212
- maxWidth: 768,
213
- margin: '0 auto',
214
- padding: 16,
273
+ border: 'none',
274
+ outline: 'none',
275
+ resize: 'none',
276
+ fontSize: 14,
277
+ fontFamily: 'inherit',
278
+ padding: '4px 0',
279
+ background: colors.inputBg,
280
+ color: colors.text,
281
+ } }), (0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Send, { disabled: disabled, style: {
282
+ width: 28,
283
+ height: 28,
284
+ borderRadius: '50%',
285
+ border: 'none',
286
+ background: disabled ? colors.textMuted : colors.sendBg,
287
+ color: colors.sendColor,
288
+ cursor: disabled ? 'not-allowed' : 'pointer',
289
+ display: 'flex',
290
+ alignItems: 'center',
291
+ justifyContent: 'center',
292
+ flexShrink: 0,
293
+ marginBottom: 2,
294
+ fontSize: 14,
295
+ }, children: "\u25B6" })] }) }) }));
296
+ };
297
+ function PikkuAgentChat(props) {
298
+ const { emptyMessage, hideToolCalls, dark } = props, runtimeOptions = __rest(props, ["emptyMessage", "hideToolCalls", "dark"]);
299
+ const { runtime, isAwaitingApproval, pendingApprovals, handleApproval } = (0, use_pikku_agent_runtime_js_1.usePikkuAgentRuntime)(runtimeOptions);
300
+ const colors = dark ? darkColors : lightColors;
301
+ return ((0, jsx_runtime_1.jsx)(ColorsContext.Provider, { value: colors, children: (0, jsx_runtime_1.jsx)(use_pikku_agent_runtime_js_1.PikkuApprovalContext.Provider, { value: { pendingApprovals, handleApproval }, children: (0, jsx_runtime_1.jsx)(HideToolCallsContext.Provider, { value: hideToolCalls, children: (0, jsx_runtime_1.jsx)(react_2.AssistantRuntimeProvider, { runtime: runtime, children: (0, jsx_runtime_1.jsx)("div", { style: {
302
+ height: '100%',
303
+ display: 'flex',
304
+ flexDirection: 'column',
305
+ background: colors.bg,
306
+ }, children: (0, jsx_runtime_1.jsxs)(react_2.ThreadPrimitive.Root, { style: {
215
307
  display: 'flex',
216
308
  flexDirection: 'column',
217
- gap: 16,
218
- }, children: [(0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Empty, { children: (0, jsx_runtime_1.jsx)("div", { style: {
309
+ flex: 1,
310
+ minHeight: 0,
311
+ }, children: [(0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Viewport, { style: {
312
+ flex: 1,
313
+ minHeight: 0,
314
+ overflowY: 'auto',
315
+ }, children: (0, jsx_runtime_1.jsxs)("div", { style: {
316
+ maxWidth: 768,
317
+ margin: '0 auto',
318
+ padding: 16,
219
319
  display: 'flex',
220
- alignItems: 'center',
221
- justifyContent: 'center',
222
- minHeight: 300,
223
- color: '#888',
224
- textAlign: 'center',
225
- fontSize: 14,
226
- }, children: emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : (props.threadId
227
- ? 'Send a message to start the conversation.'
228
- : 'Start a new conversation.') }) }), (0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Messages, { components: {
229
- UserMessage,
230
- AssistantMessage,
231
- } })] }) }), (0, jsx_runtime_1.jsx)("div", { style: { maxWidth: 768, margin: '0 auto', width: '100%', padding: '0 16px' }, children: (0, jsx_runtime_1.jsx)(PikkuComposer, {}) })] }) }) }));
320
+ flexDirection: 'column',
321
+ gap: 16,
322
+ }, children: [(0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Empty, { children: (0, jsx_runtime_1.jsx)("div", { style: {
323
+ display: 'flex',
324
+ alignItems: 'center',
325
+ justifyContent: 'center',
326
+ minHeight: 300,
327
+ color: colors.textMuted,
328
+ textAlign: 'center',
329
+ fontSize: 14,
330
+ }, children: emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : (props.threadId
331
+ ? 'Send a message to start the conversation.'
332
+ : 'Start a new conversation.') }) }), (0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Messages, { components: {
333
+ UserMessage,
334
+ AssistantMessage,
335
+ } })] }) }), (0, jsx_runtime_1.jsx)("div", { style: { maxWidth: 768, margin: '0 auto', width: '100%', padding: '0 16px' }, children: (0, jsx_runtime_1.jsx)(PikkuComposer, { disabled: isAwaitingApproval }) })] }) }) }) }) }) }));
232
336
  }
@@ -1,13 +1,47 @@
1
+ import { type ThreadMessageLike } from '@assistant-ui/react';
1
2
  export interface PikkuAgentRuntimeOptions {
2
3
  api: string;
3
- threadId?: string | null;
4
+ agentName: string;
5
+ threadId: string;
6
+ resourceId: string;
4
7
  initialMessages?: any[];
5
- onThreadCreated?: (id: string) => void;
6
8
  onFinish?: () => void;
7
- onApprovalRequest?: (data: {
8
- toolCallId: string;
9
- }) => void;
10
9
  credentials?: RequestCredentials;
11
10
  headers?: Record<string, string>;
11
+ model?: string;
12
+ temperature?: number;
12
13
  }
13
- export declare function usePikkuAgentRuntime(options: PikkuAgentRuntimeOptions): import("@assistant-ui/react").AssistantRuntime;
14
+ export interface PendingApproval {
15
+ toolCallId: string;
16
+ toolName: string;
17
+ args: unknown;
18
+ reason?: string;
19
+ runId: string;
20
+ }
21
+ export interface PikkuApprovalContextValue {
22
+ pendingApprovals: PendingApproval[];
23
+ handleApproval: (toolCallId: string, approved: boolean) => void;
24
+ }
25
+ export declare const PikkuApprovalContext: import("react").Context<PikkuApprovalContextValue>;
26
+ export declare const usePikkuApproval: () => PikkuApprovalContextValue;
27
+ export declare function isDeniedResult(result: unknown): boolean;
28
+ export type PikkuToolStatusType = 'running' | 'requires-action' | 'completed' | 'denied' | 'error';
29
+ export type PikkuToolStatus = {
30
+ type: PikkuToolStatusType;
31
+ };
32
+ export declare function resolvePikkuToolStatus(status: {
33
+ type: string;
34
+ }, result?: unknown): PikkuToolStatus;
35
+ export declare const convertDbMessages: (dbMessages: any[]) => ThreadMessageLike[];
36
+ export declare function usePikkuAgentRuntime(options: PikkuAgentRuntimeOptions): {
37
+ runtime: import("@assistant-ui/react").AssistantRuntime;
38
+ pendingApprovals: PendingApproval[];
39
+ isAwaitingApproval: boolean;
40
+ handleApproval: (toolCallId: string, approved: boolean) => void;
41
+ };
42
+ export declare function usePikkuAgentNonStreamingRuntime(options: PikkuAgentRuntimeOptions): {
43
+ runtime: import("@assistant-ui/react").AssistantRuntime;
44
+ pendingApprovals: PendingApproval[];
45
+ isAwaitingApproval: boolean;
46
+ handleApproval: (toolCallId: string, approved: boolean) => void;
47
+ };