@springbrand/message-panel 0.1.1 → 0.1.3-alpha.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/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@springbrand/message-panel",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3-alpha.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
6
|
+
"src",
|
|
7
|
+
"demo"
|
|
8
8
|
],
|
|
9
9
|
"publishConfig": {
|
|
10
10
|
"access": "public"
|
|
@@ -30,8 +30,7 @@
|
|
|
30
30
|
"radix-ui": "^1.6.2",
|
|
31
31
|
"streamdown": "^2.5.0",
|
|
32
32
|
"thinking-orbs": "0.1.1",
|
|
33
|
-
"use-stick-to-bottom": "^1.1.6"
|
|
34
|
-
"@springbrand/agent-runtime": "0.1.1"
|
|
33
|
+
"use-stick-to-bottom": "^1.1.6"
|
|
35
34
|
},
|
|
36
35
|
"devDependencies": {
|
|
37
36
|
"@types/react": "^19.2.17",
|
|
@@ -72,6 +72,8 @@ export interface CamelChatMessagesProps {
|
|
|
72
72
|
isHydrating?: boolean;
|
|
73
73
|
isRecovering?: boolean;
|
|
74
74
|
isServerStreaming?: boolean;
|
|
75
|
+
/** Show the opt-in activity bar for recovering or server-streaming states. */
|
|
76
|
+
showActivityStatus?: boolean;
|
|
75
77
|
hasPendingSteer?: boolean;
|
|
76
78
|
startedWithPending?: boolean;
|
|
77
79
|
error?: unknown;
|
|
@@ -1282,6 +1284,7 @@ export function CamelChatMessages({
|
|
|
1282
1284
|
isHydrating = false,
|
|
1283
1285
|
isRecovering = false,
|
|
1284
1286
|
isServerStreaming = false,
|
|
1287
|
+
showActivityStatus = false,
|
|
1285
1288
|
hasPendingSteer = false,
|
|
1286
1289
|
startedWithPending = false,
|
|
1287
1290
|
error,
|
|
@@ -1336,7 +1339,7 @@ export function CamelChatMessages({
|
|
|
1336
1339
|
data-status={status}
|
|
1337
1340
|
aria-busy={isActive || isHydrating}
|
|
1338
1341
|
>
|
|
1339
|
-
{(isRecovering || isServerStreaming) && (
|
|
1342
|
+
{showActivityStatus && (isRecovering || isServerStreaming) && (
|
|
1340
1343
|
<div
|
|
1341
1344
|
className="absolute inset-x-0 top-0 z-10 flex h-7 items-center justify-center gap-2 bg-background/85 text-xs text-muted-foreground backdrop-blur-sm"
|
|
1342
1345
|
role="status"
|
|
@@ -162,7 +162,7 @@ interface CamelPromptInputProps {
|
|
|
162
162
|
status: "ready" | "submitted" | "streaming" | "error";
|
|
163
163
|
attachments: readonly CamelAttachmentView[];
|
|
164
164
|
commands: readonly ComposerCommand[];
|
|
165
|
-
onFilesSelected
|
|
165
|
+
onFilesSelected?: (files: readonly File[]) => void;
|
|
166
166
|
onAttachmentRemove: (id: string) => void;
|
|
167
167
|
onAttachmentRetry: (id: string) => void;
|
|
168
168
|
tools?: ReactNode;
|
|
@@ -353,6 +353,7 @@ function CamelPromptInputContent({
|
|
|
353
353
|
};
|
|
354
354
|
|
|
355
355
|
const handlePaste = (event: ClipboardEvent<HTMLTextAreaElement>) => {
|
|
356
|
+
if (!onFilesSelected) return;
|
|
356
357
|
const files = Array.from(event.clipboardData.files);
|
|
357
358
|
if (files.length > 0) {
|
|
358
359
|
event.preventDefault();
|
|
@@ -362,11 +363,12 @@ function CamelPromptInputContent({
|
|
|
362
363
|
|
|
363
364
|
const handleFiles = (event: ChangeEvent<HTMLInputElement>) => {
|
|
364
365
|
const files = Array.from(event.currentTarget.files ?? []);
|
|
365
|
-
if (files.length > 0) onFilesSelected(files);
|
|
366
|
+
if (files.length > 0) onFilesSelected?.(files);
|
|
366
367
|
event.currentTarget.value = "";
|
|
367
368
|
};
|
|
368
369
|
|
|
369
370
|
const handleDragOver = (event: DragEvent<HTMLDivElement>) => {
|
|
371
|
+
if (!onFilesSelected) return;
|
|
370
372
|
event.preventDefault();
|
|
371
373
|
event.stopPropagation();
|
|
372
374
|
setIsDragOver(true);
|
|
@@ -382,6 +384,7 @@ function CamelPromptInputContent({
|
|
|
382
384
|
};
|
|
383
385
|
|
|
384
386
|
const handleDrop = (event: DragEvent<HTMLDivElement>) => {
|
|
387
|
+
if (!onFilesSelected) return;
|
|
385
388
|
event.preventDefault();
|
|
386
389
|
event.stopPropagation();
|
|
387
390
|
setIsDragOver(false);
|
|
@@ -407,14 +410,16 @@ function CamelPromptInputContent({
|
|
|
407
410
|
data-camel-prompt-input=""
|
|
408
411
|
data-drop-scope="document"
|
|
409
412
|
>
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
413
|
+
{onFilesSelected && (
|
|
414
|
+
<input
|
|
415
|
+
ref={fileInputRef}
|
|
416
|
+
type="file"
|
|
417
|
+
multiple
|
|
418
|
+
onChange={handleFiles}
|
|
419
|
+
className="hidden"
|
|
420
|
+
aria-hidden="true"
|
|
421
|
+
/>
|
|
422
|
+
)}
|
|
418
423
|
<ComposerTriggerPopover
|
|
419
424
|
char="/"
|
|
420
425
|
{...slash}
|
|
@@ -481,16 +486,18 @@ function CamelPromptInputContent({
|
|
|
481
486
|
className="justify-between px-3 pb-3"
|
|
482
487
|
>
|
|
483
488
|
<div className="flex items-center gap-1.5">
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
489
|
+
{onFilesSelected && (
|
|
490
|
+
<InputGroupButton
|
|
491
|
+
type="button"
|
|
492
|
+
size="icon-sm"
|
|
493
|
+
variant="ghost"
|
|
494
|
+
onClick={() => fileInputRef.current?.click()}
|
|
495
|
+
className="rounded-full text-muted-foreground hover:bg-muted hover:text-foreground"
|
|
496
|
+
aria-label="Upload file"
|
|
497
|
+
>
|
|
498
|
+
<PlusIcon className="size-4" />
|
|
499
|
+
</InputGroupButton>
|
|
500
|
+
)}
|
|
494
501
|
{tools}
|
|
495
502
|
</div>
|
|
496
503
|
<div className="flex items-center gap-1">
|
package/src/camel/camel-turn.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { UIMessage } from "ai";
|
|
2
|
-
import { USER_STOP_REASON } from "@springbrand/agent-runtime/contracts";
|
|
3
2
|
import { resolvePartKind, toolNameOfPart } from "../parts/kind";
|
|
4
3
|
|
|
4
|
+
const USER_STOP_REASON = "Stopped by user";
|
|
5
|
+
|
|
5
6
|
type UnknownRecord = Record<string, unknown>;
|
|
6
7
|
|
|
7
8
|
export type CamelPart = UIMessage["parts"][number];
|
package/src/contracts.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ComponentType, HTMLAttributes, ReactNode } from "react";
|
|
2
|
-
import type { ApprovalDecision } from "@springbrand/agent-runtime/contracts";
|
|
3
2
|
|
|
4
3
|
export type MessagePanelStatus = "ready" | "submitted" | "streaming" | "error";
|
|
5
4
|
export type MessageRole = "user" | "assistant" | "system" | "tool";
|
|
@@ -9,7 +8,7 @@ export interface ToolApprovalView {
|
|
|
9
8
|
approved?: boolean;
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
export type ToolApprovalDecision =
|
|
11
|
+
export type ToolApprovalDecision = "deny" | "allow_once" | "allow_level";
|
|
13
12
|
|
|
14
13
|
export interface MessageAdapter<TMessage> {
|
|
15
14
|
getId: (message: TMessage, index: number) => string;
|