@pikku/assistant-ui 0.12.4 → 0.12.6
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 +12 -1
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.js +6 -1
- package/dist/cjs/model-capabilities.d.ts +1 -0
- package/dist/cjs/model-capabilities.js +16 -0
- package/dist/cjs/pikku-agent-chat.d.ts +4 -0
- package/dist/cjs/pikku-agent-chat.js +91 -63
- package/dist/cjs/use-file-attachment.d.ts +26 -0
- package/dist/cjs/use-file-attachment.js +99 -0
- package/dist/cjs/use-pikku-agent-runtime.d.ts +4 -0
- package/dist/cjs/use-pikku-agent-runtime.js +72 -35
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +2 -0
- package/dist/esm/model-capabilities.d.ts +1 -0
- package/dist/esm/model-capabilities.js +13 -0
- package/dist/esm/pikku-agent-chat.d.ts +4 -0
- package/dist/esm/pikku-agent-chat.js +102 -67
- package/dist/esm/use-file-attachment.d.ts +26 -0
- package/dist/esm/use-file-attachment.js +85 -0
- package/dist/esm/use-pikku-agent-runtime.d.ts +4 -0
- package/dist/esm/use-pikku-agent-runtime.js +72 -19
- package/dist/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/index.ts +3 -0
- package/src/model-capabilities.ts +14 -0
- package/src/pikku-agent-chat.tsx +362 -156
- package/src/use-file-attachment.ts +110 -0
- package/src/use-pikku-agent-runtime.ts +109 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @pikku/assistant-ui
|
|
2
2
|
|
|
3
|
+
## 0.12.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- f4f7046: feat(assistant-ui): export useFileAttachment hook, modelSupportsVision, PendingFile, UploadAttachmentFn, and INLINE_SIZE_LIMIT
|
|
8
|
+
|
|
9
|
+
## 0.12.5
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 9060165: The console now shows function version history, live queue depths with a Failed column, and scheduler last-run status with run history. Workflow canvas and run selector have been polished. The console build is ~6.5× faster thanks to a switch to rolldown-vite (Vite 7 + Oxc React transform).
|
|
14
|
+
|
|
3
15
|
## 0.12.4
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -33,7 +45,6 @@
|
|
|
33
45
|
### Patch Changes
|
|
34
46
|
|
|
35
47
|
- f85c234: Add unified credential system with per-user OAuth and AI agent pre-flight checks
|
|
36
|
-
|
|
37
48
|
- Unified CredentialService with lazy loading per user via pikkuUserId
|
|
38
49
|
- wire.getCredential() for typed single credential lookup
|
|
39
50
|
- MissingCredentialError with structured payload for client-side connect flows
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -2,3 +2,6 @@ export { usePikkuAgentRuntime, usePikkuAgentNonStreamingRuntime, PikkuApprovalCo
|
|
|
2
2
|
export type { PikkuAgentRuntimeOptions, PendingApproval, PikkuApprovalContextValue, PikkuToolStatusType, PikkuToolStatus, MissingCredentialPayload, } 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';
|
|
5
|
+
export { useFileAttachment, INLINE_SIZE_LIMIT } from './use-file-attachment.js';
|
|
6
|
+
export type { PendingFile, UploadAttachmentFn } from './use-file-attachment.js';
|
|
7
|
+
export { modelSupportsVision } from './model-capabilities.js';
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PikkuAgentChat = exports.resolvePikkuToolStatus = exports.isDeniedResult = exports.convertDbMessages = exports.usePikkuApproval = exports.PikkuApprovalContext = exports.usePikkuAgentNonStreamingRuntime = exports.usePikkuAgentRuntime = void 0;
|
|
3
|
+
exports.modelSupportsVision = exports.INLINE_SIZE_LIMIT = exports.useFileAttachment = 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
6
|
Object.defineProperty(exports, "usePikkuAgentNonStreamingRuntime", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.usePikkuAgentNonStreamingRuntime; } });
|
|
@@ -11,3 +11,8 @@ Object.defineProperty(exports, "isDeniedResult", { enumerable: true, get: functi
|
|
|
11
11
|
Object.defineProperty(exports, "resolvePikkuToolStatus", { enumerable: true, get: function () { return use_pikku_agent_runtime_js_1.resolvePikkuToolStatus; } });
|
|
12
12
|
var pikku_agent_chat_js_1 = require("./pikku-agent-chat.js");
|
|
13
13
|
Object.defineProperty(exports, "PikkuAgentChat", { enumerable: true, get: function () { return pikku_agent_chat_js_1.PikkuAgentChat; } });
|
|
14
|
+
var use_file_attachment_js_1 = require("./use-file-attachment.js");
|
|
15
|
+
Object.defineProperty(exports, "useFileAttachment", { enumerable: true, get: function () { return use_file_attachment_js_1.useFileAttachment; } });
|
|
16
|
+
Object.defineProperty(exports, "INLINE_SIZE_LIMIT", { enumerable: true, get: function () { return use_file_attachment_js_1.INLINE_SIZE_LIMIT; } });
|
|
17
|
+
var model_capabilities_js_1 = require("./model-capabilities.js");
|
|
18
|
+
Object.defineProperty(exports, "modelSupportsVision", { enumerable: true, get: function () { return model_capabilities_js_1.modelSupportsVision; } });
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function modelSupportsVision(modelID: string): boolean;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.modelSupportsVision = modelSupportsVision;
|
|
4
|
+
const MODEL_VISION_SUPPORT = new Set([
|
|
5
|
+
'claude-sonnet-4-5',
|
|
6
|
+
'claude-opus-4-1',
|
|
7
|
+
'gpt-4o-mini',
|
|
8
|
+
'gpt-5',
|
|
9
|
+
'gpt-5-mini',
|
|
10
|
+
'gpt-5-codex',
|
|
11
|
+
'gemini-2.5-pro',
|
|
12
|
+
'gemini-2.5-flash',
|
|
13
|
+
]);
|
|
14
|
+
function modelSupportsVision(modelID) {
|
|
15
|
+
return MODEL_VISION_SUPPORT.has(modelID);
|
|
16
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from 'react';
|
|
1
2
|
import { type ToolCallMessagePartComponent } from '@assistant-ui/react';
|
|
2
3
|
import { type PikkuAgentRuntimeOptions } from './use-pikku-agent-runtime.js';
|
|
3
4
|
export interface PikkuAgentChatProps extends PikkuAgentRuntimeOptions {
|
|
5
|
+
initialPrompt?: string;
|
|
4
6
|
emptyMessage?: string;
|
|
5
7
|
/** Hide tool calls from the chat display.
|
|
6
8
|
* - `true`: hide all non-approval tool calls
|
|
@@ -21,5 +23,7 @@ export interface PikkuAgentChatProps extends PikkuAgentRuntimeOptions {
|
|
|
21
23
|
* (which still respects `hideToolCalls` and the approval-request UI).
|
|
22
24
|
*/
|
|
23
25
|
toolComponents?: Record<string, ToolCallMessagePartComponent>;
|
|
26
|
+
renderAssistantText?: (text: string) => ReactNode;
|
|
27
|
+
generativeUIComponents?: Record<string, ComponentType<any>>;
|
|
24
28
|
}
|
|
25
29
|
export declare function PikkuAgentChat(props: PikkuAgentChatProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -60,6 +60,8 @@ const darkColors = {
|
|
|
60
60
|
const ColorsContext = (0, react_1.createContext)(lightColors);
|
|
61
61
|
const HideToolCallsContext = (0, react_1.createContext)(undefined);
|
|
62
62
|
const ToolComponentsContext = (0, react_1.createContext)(undefined);
|
|
63
|
+
const GenerativeUIComponentsContext = (0, react_1.createContext)(undefined);
|
|
64
|
+
const RenderAssistantTextContext = (0, react_1.createContext)(undefined);
|
|
63
65
|
function shouldHideToolCall(hideToolCalls, toolName) {
|
|
64
66
|
if (!hideToolCalls)
|
|
65
67
|
return false;
|
|
@@ -310,6 +312,8 @@ const UserMessage = () => {
|
|
|
310
312
|
const AssistantMessage = () => {
|
|
311
313
|
const colors = (0, react_1.useContext)(ColorsContext);
|
|
312
314
|
const toolComponents = (0, react_1.useContext)(ToolComponentsContext);
|
|
315
|
+
const generativeUIComponents = (0, react_1.useContext)(GenerativeUIComponentsContext);
|
|
316
|
+
const renderAssistantText = (0, react_1.useContext)(RenderAssistantTextContext);
|
|
313
317
|
return ((0, jsx_runtime_1.jsx)("div", { style: {
|
|
314
318
|
display: 'flex',
|
|
315
319
|
justifyContent: 'flex-start',
|
|
@@ -318,13 +322,16 @@ const AssistantMessage = () => {
|
|
|
318
322
|
padding: 12,
|
|
319
323
|
borderRadius: 12,
|
|
320
324
|
backgroundColor: colors.assistantBubble,
|
|
321
|
-
}, children: [(0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.Content, { components: {
|
|
322
|
-
Text: ({ text }) => (0, jsx_runtime_1.jsx)(MarkdownText, { text: text, colors: colors }),
|
|
323
|
-
tools: {
|
|
325
|
+
}, children: [(0, jsx_runtime_1.jsx)(react_2.MessagePrimitive.Content, { components: Object.assign({ Text: ({ text }) => renderAssistantText ? ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: renderAssistantText(text) })) : ((0, jsx_runtime_1.jsx)(MarkdownText, { text: text, colors: colors })), tools: {
|
|
324
326
|
by_name: toolComponents,
|
|
325
327
|
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 })),
|
|
326
|
-
},
|
|
327
|
-
|
|
328
|
+
} }, (generativeUIComponents
|
|
329
|
+
? {
|
|
330
|
+
generativeUI: {
|
|
331
|
+
components: generativeUIComponents,
|
|
332
|
+
},
|
|
333
|
+
}
|
|
334
|
+
: {})) }), (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: {
|
|
328
335
|
display: 'flex',
|
|
329
336
|
alignItems: 'center',
|
|
330
337
|
gap: 6,
|
|
@@ -333,78 +340,99 @@ const AssistantMessage = () => {
|
|
|
333
340
|
color: colors.textMuted,
|
|
334
341
|
}, children: "Thinking..." }) }) })] })] }) }));
|
|
335
342
|
};
|
|
343
|
+
const ComposerPrefill = ({ text }) => {
|
|
344
|
+
const composer = (0, react_2.useComposerRuntime)();
|
|
345
|
+
const filled = (0, react_1.useRef)(false);
|
|
346
|
+
(0, react_1.useEffect)(() => {
|
|
347
|
+
if (filled.current || !text)
|
|
348
|
+
return;
|
|
349
|
+
filled.current = true;
|
|
350
|
+
if (composer.getState().text === '')
|
|
351
|
+
composer.setText(text);
|
|
352
|
+
}, [text, composer]);
|
|
353
|
+
return null;
|
|
354
|
+
};
|
|
336
355
|
const PikkuComposer = ({ disabled, }) => {
|
|
337
356
|
const colors = (0, react_1.useContext)(ColorsContext);
|
|
338
|
-
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({
|
|
357
|
+
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({ position: 'relative', zIndex: 2, display: 'flex', flexDirection: 'column', gap: 10, backgroundColor: colors.assistantBubble, border: `1px solid ${colors.border}`, borderRadius: 24, padding: '14px 12px 10px', boxShadow: darkColors.text === colors.text
|
|
358
|
+
? '0 14px 30px rgba(0,0,0,0.24)'
|
|
359
|
+
: '0 14px 30px rgba(0,0,0,0.08)' }, (disabled
|
|
339
360
|
? { opacity: 0.5, pointerEvents: 'none' }
|
|
340
|
-
: {})), children: [(0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Input, { placeholder: disabled ? 'Respond to approval request above...' : 'Message...', rows:
|
|
341
|
-
|
|
361
|
+
: {})), children: [(0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Input, { placeholder: disabled ? 'Respond to approval request above...' : 'Message...', rows: 1, disabled: disabled !== null && disabled !== void 0 ? disabled : false, style: {
|
|
362
|
+
width: '100%',
|
|
363
|
+
background: 'transparent',
|
|
342
364
|
border: 'none',
|
|
343
365
|
outline: 'none',
|
|
344
|
-
|
|
366
|
+
color: colors.text,
|
|
345
367
|
fontSize: 14,
|
|
346
368
|
fontFamily: 'inherit',
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
} }), (0, jsx_runtime_1.jsx)(
|
|
351
|
-
width:
|
|
352
|
-
height: 28,
|
|
353
|
-
borderRadius: '50%',
|
|
354
|
-
border: 'none',
|
|
355
|
-
background: disabled ? colors.textMuted : colors.sendBg,
|
|
356
|
-
color: colors.sendColor,
|
|
357
|
-
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
369
|
+
resize: 'none',
|
|
370
|
+
lineHeight: 1.5,
|
|
371
|
+
overflowY: 'auto',
|
|
372
|
+
} }), (0, jsx_runtime_1.jsx)("div", { style: {
|
|
373
|
+
width: '100%',
|
|
358
374
|
display: 'flex',
|
|
359
375
|
alignItems: 'center',
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
376
|
+
gap: 6,
|
|
377
|
+
minWidth: 0,
|
|
378
|
+
justifyContent: 'flex-end',
|
|
379
|
+
}, children: (0, jsx_runtime_1.jsx)(react_2.ComposerPrimitive.Send, { disabled: disabled !== null && disabled !== void 0 ? disabled : false, style: {
|
|
380
|
+
width: 30,
|
|
381
|
+
height: 30,
|
|
382
|
+
borderRadius: 999,
|
|
383
|
+
border: `1px solid ${colors.border}`,
|
|
384
|
+
background: '#e8e8e8',
|
|
385
|
+
color: '#111111',
|
|
386
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
387
|
+
display: 'flex',
|
|
388
|
+
alignItems: 'center',
|
|
389
|
+
justifyContent: 'center',
|
|
390
|
+
flexShrink: 0,
|
|
391
|
+
transition: 'background-color 150ms ease, color 150ms ease, border-color 150ms ease',
|
|
392
|
+
}, children: "\u2191" }) })] }) }) }));
|
|
365
393
|
};
|
|
366
394
|
function PikkuAgentChat(props) {
|
|
367
|
-
const { emptyMessage, hideToolCalls, dark, maxWidth = 768, toolComponents } = props, runtimeOptions = __rest(props, ["emptyMessage", "hideToolCalls", "dark", "maxWidth", "toolComponents"]);
|
|
395
|
+
const { emptyMessage, hideToolCalls, dark, maxWidth = 768, toolComponents, renderAssistantText, generativeUIComponents, initialPrompt } = props, runtimeOptions = __rest(props, ["emptyMessage", "hideToolCalls", "dark", "maxWidth", "toolComponents", "renderAssistantText", "generativeUIComponents", "initialPrompt"]);
|
|
368
396
|
const { runtime, isAwaitingApproval, pendingApprovals, handleApproval } = (0, use_pikku_agent_runtime_js_1.usePikkuAgentRuntime)(runtimeOptions);
|
|
369
397
|
const colors = dark ? darkColors : lightColors;
|
|
370
|
-
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)(ToolComponentsContext.Provider, { value: toolComponents, children: (0, jsx_runtime_1.jsx)(react_2.AssistantRuntimeProvider, { runtime: runtime, children: (0, jsx_runtime_1.jsx)("div", { style: {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
display: 'flex',
|
|
377
|
-
flexDirection: 'column',
|
|
378
|
-
flex: 1,
|
|
379
|
-
minHeight: 0,
|
|
380
|
-
}, children: [(0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Viewport, { style: {
|
|
381
|
-
flex: 1,
|
|
382
|
-
minHeight: 0,
|
|
383
|
-
overflowY: 'auto',
|
|
384
|
-
}, children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
385
|
-
maxWidth: maxWidth === 'none' ? undefined : maxWidth,
|
|
386
|
-
margin: '0 auto',
|
|
387
|
-
padding: 16,
|
|
398
|
+
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)(ToolComponentsContext.Provider, { value: toolComponents, children: (0, jsx_runtime_1.jsx)(GenerativeUIComponentsContext.Provider, { value: generativeUIComponents, children: (0, jsx_runtime_1.jsx)(RenderAssistantTextContext.Provider, { value: renderAssistantText, children: (0, jsx_runtime_1.jsxs)(react_2.AssistantRuntimeProvider, { runtime: runtime, children: [(0, jsx_runtime_1.jsx)(ComposerPrefill, { text: initialPrompt }), (0, jsx_runtime_1.jsx)("div", { style: {
|
|
399
|
+
height: '100%',
|
|
400
|
+
display: 'flex',
|
|
401
|
+
flexDirection: 'column',
|
|
402
|
+
background: colors.bg,
|
|
403
|
+
}, children: (0, jsx_runtime_1.jsxs)(react_2.ThreadPrimitive.Root, { style: {
|
|
388
404
|
display: 'flex',
|
|
389
405
|
flexDirection: 'column',
|
|
390
|
-
|
|
391
|
-
|
|
406
|
+
flex: 1,
|
|
407
|
+
minHeight: 0,
|
|
408
|
+
}, children: [(0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Viewport, { style: {
|
|
409
|
+
flex: 1,
|
|
410
|
+
minHeight: 0,
|
|
411
|
+
overflowY: 'auto',
|
|
412
|
+
}, children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
413
|
+
maxWidth: maxWidth === 'none' ? undefined : maxWidth,
|
|
414
|
+
margin: '0 auto',
|
|
415
|
+
padding: 16,
|
|
392
416
|
display: 'flex',
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
417
|
+
flexDirection: 'column',
|
|
418
|
+
gap: 16,
|
|
419
|
+
}, children: [(0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Empty, { children: (0, jsx_runtime_1.jsx)("div", { style: {
|
|
420
|
+
display: 'flex',
|
|
421
|
+
alignItems: 'center',
|
|
422
|
+
justifyContent: 'center',
|
|
423
|
+
minHeight: 300,
|
|
424
|
+
color: colors.textMuted,
|
|
425
|
+
textAlign: 'center',
|
|
426
|
+
fontSize: 14,
|
|
427
|
+
}, children: emptyMessage !== null && emptyMessage !== void 0 ? emptyMessage : (props.threadId
|
|
428
|
+
? 'Send a message to start the conversation.'
|
|
429
|
+
: 'Start a new conversation.') }) }), (0, jsx_runtime_1.jsx)(react_2.ThreadPrimitive.Messages, { components: {
|
|
430
|
+
UserMessage,
|
|
431
|
+
AssistantMessage,
|
|
432
|
+
} })] }) }), (0, jsx_runtime_1.jsx)("div", { style: {
|
|
433
|
+
maxWidth: maxWidth === 'none' ? undefined : maxWidth,
|
|
434
|
+
margin: '0 auto',
|
|
435
|
+
width: '100%',
|
|
436
|
+
padding: '0 16px',
|
|
437
|
+
}, children: (0, jsx_runtime_1.jsx)(PikkuComposer, { disabled: isAwaitingApproval }) })] }) })] }) }) }) }) }) }) }));
|
|
410
438
|
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type PendingFile = {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
mimeType: string;
|
|
5
|
+
previewUrl: string;
|
|
6
|
+
contentUrl: string;
|
|
7
|
+
isImage: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type UploadAttachmentFn = (args: {
|
|
10
|
+
contentType: string;
|
|
11
|
+
sizeBytes: number;
|
|
12
|
+
}) => Promise<{
|
|
13
|
+
uploadUrl: string;
|
|
14
|
+
signedReadUrl: string;
|
|
15
|
+
uploadMethod?: string;
|
|
16
|
+
}>;
|
|
17
|
+
export declare const INLINE_SIZE_LIMIT: number;
|
|
18
|
+
export declare function useFileAttachment(upload: UploadAttachmentFn): {
|
|
19
|
+
pendingFiles: PendingFile[];
|
|
20
|
+
uploading: boolean;
|
|
21
|
+
uploadError: string | null;
|
|
22
|
+
fileInputRef: import("react").RefObject<HTMLInputElement | null>;
|
|
23
|
+
handleFileChange: (e: React.ChangeEvent<HTMLInputElement>) => Promise<void>;
|
|
24
|
+
removeFile: (id: string) => void;
|
|
25
|
+
clearFiles: () => void;
|
|
26
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.INLINE_SIZE_LIMIT = void 0;
|
|
13
|
+
exports.useFileAttachment = useFileAttachment;
|
|
14
|
+
const react_1 = require("react");
|
|
15
|
+
exports.INLINE_SIZE_LIMIT = 1 * 1024 * 1024;
|
|
16
|
+
function useFileAttachment(upload) {
|
|
17
|
+
const [pendingFiles, setPendingFiles] = (0, react_1.useState)([]);
|
|
18
|
+
const [uploading, setUploading] = (0, react_1.useState)(false);
|
|
19
|
+
const [uploadError, setUploadError] = (0, react_1.useState)(null);
|
|
20
|
+
const fileInputRef = (0, react_1.useRef)(null);
|
|
21
|
+
const handleFileChange = (0, react_1.useCallback)((e) => __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
var _a;
|
|
23
|
+
const files = Array.from((_a = e.target.files) !== null && _a !== void 0 ? _a : []);
|
|
24
|
+
e.target.value = '';
|
|
25
|
+
if (!files.length)
|
|
26
|
+
return;
|
|
27
|
+
setUploading(true);
|
|
28
|
+
setUploadError(null);
|
|
29
|
+
try {
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
const previewUrl = URL.createObjectURL(file);
|
|
32
|
+
let contentUrl;
|
|
33
|
+
if (file.type.startsWith('image/') &&
|
|
34
|
+
file.size <= exports.INLINE_SIZE_LIMIT) {
|
|
35
|
+
contentUrl = yield new Promise((resolve, reject) => {
|
|
36
|
+
const reader = new FileReader();
|
|
37
|
+
reader.onload = (ev) => resolve(ev.target.result);
|
|
38
|
+
reader.onerror = reject;
|
|
39
|
+
reader.readAsDataURL(file);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
const { uploadUrl, signedReadUrl, uploadMethod } = yield upload({
|
|
44
|
+
contentType: file.type,
|
|
45
|
+
sizeBytes: file.size,
|
|
46
|
+
});
|
|
47
|
+
const resp = yield fetch(uploadUrl, {
|
|
48
|
+
method: uploadMethod !== null && uploadMethod !== void 0 ? uploadMethod : 'PUT',
|
|
49
|
+
body: file,
|
|
50
|
+
headers: { 'Content-Type': file.type },
|
|
51
|
+
});
|
|
52
|
+
if (!resp.ok)
|
|
53
|
+
throw new Error(`Upload failed (${resp.status})`);
|
|
54
|
+
contentUrl = signedReadUrl;
|
|
55
|
+
}
|
|
56
|
+
setPendingFiles((prev) => [
|
|
57
|
+
...prev,
|
|
58
|
+
{
|
|
59
|
+
id: `file_${Date.now().toString(36)}`,
|
|
60
|
+
name: file.name,
|
|
61
|
+
mimeType: file.type,
|
|
62
|
+
previewUrl,
|
|
63
|
+
contentUrl,
|
|
64
|
+
isImage: file.type.startsWith('image/'),
|
|
65
|
+
},
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
setUploadError(err instanceof Error ? err.message : 'Upload failed');
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
setUploading(false);
|
|
74
|
+
}
|
|
75
|
+
}), [upload]);
|
|
76
|
+
const removeFile = (0, react_1.useCallback)((id) => {
|
|
77
|
+
setPendingFiles((prev) => {
|
|
78
|
+
const f = prev.find((x) => x.id === id);
|
|
79
|
+
if (f)
|
|
80
|
+
URL.revokeObjectURL(f.previewUrl);
|
|
81
|
+
return prev.filter((x) => x.id !== id);
|
|
82
|
+
});
|
|
83
|
+
}, []);
|
|
84
|
+
const clearFiles = (0, react_1.useCallback)(() => {
|
|
85
|
+
setPendingFiles((prev) => {
|
|
86
|
+
prev.forEach((f) => URL.revokeObjectURL(f.previewUrl));
|
|
87
|
+
return [];
|
|
88
|
+
});
|
|
89
|
+
}, []);
|
|
90
|
+
return {
|
|
91
|
+
pendingFiles,
|
|
92
|
+
uploading,
|
|
93
|
+
uploadError,
|
|
94
|
+
fileInputRef,
|
|
95
|
+
handleFileChange,
|
|
96
|
+
removeFile,
|
|
97
|
+
clearFiles,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -10,6 +10,10 @@ export interface PikkuAgentRuntimeOptions {
|
|
|
10
10
|
headers?: Record<string, string>;
|
|
11
11
|
model?: string;
|
|
12
12
|
temperature?: number;
|
|
13
|
+
/** Structured context injected into the agent's system instructions.
|
|
14
|
+
* Provide upfront state (e.g. current org/project/branch/deployment IDs)
|
|
15
|
+
* so the agent can call tools without asking the user. */
|
|
16
|
+
context?: string;
|
|
13
17
|
}
|
|
14
18
|
export interface PendingApproval {
|
|
15
19
|
toolCallId: string;
|