@coral-ai/chat 0.4.0 → 0.4.2
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/dist/index.d.ts +24 -1
- package/dist/index.js +122 -10
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import React__default, { ReactNode } from 'react';
|
|
3
3
|
import { ChatFontSize, ChatFontFamily } from '@coral-ai/markdown';
|
|
4
|
+
import { CoralChartSpec } from '@coral-ai/charts';
|
|
4
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
6
|
|
|
6
7
|
type ErrorCategory = "auth_billing" | "rate_limit" | "overloaded" | "bad_input" | "not_found" | "server_error" | "unknown";
|
|
@@ -47,6 +48,14 @@ type ChatMessage = {
|
|
|
47
48
|
* persists in history for replay. Updated in place as the agent streams.
|
|
48
49
|
*/
|
|
49
50
|
todos?: ChatTodo[];
|
|
51
|
+
/**
|
|
52
|
+
* If present, this assistant message carries one or more chart specs.
|
|
53
|
+
* Rendered inline (above the message text) via `<CoralChart>` from
|
|
54
|
+
* `@coral-ai/charts`. Streamed in incrementally as the agent calls the
|
|
55
|
+
* built-in `render_chart` tool, and persisted with the conversation so
|
|
56
|
+
* the visualizations survive reloads.
|
|
57
|
+
*/
|
|
58
|
+
charts?: CoralChartSpec[];
|
|
50
59
|
/**
|
|
51
60
|
* If present, the turn that produced this assistant message failed. The
|
|
52
61
|
* message renders as an error card (with a Retry button) instead of normal
|
|
@@ -116,6 +125,11 @@ type ChatChunk = string | {
|
|
|
116
125
|
} | {
|
|
117
126
|
type: "todos";
|
|
118
127
|
todos: ChatTodo[];
|
|
128
|
+
}
|
|
129
|
+
/** Appends a chart spec to the current assistant message; renders inline. */
|
|
130
|
+
| {
|
|
131
|
+
type: "chart";
|
|
132
|
+
spec: CoralChartSpec;
|
|
119
133
|
};
|
|
120
134
|
type ChatResponse = string | AsyncIterable<ChatChunk> | {
|
|
121
135
|
content: string;
|
|
@@ -179,6 +193,13 @@ interface ChatProps {
|
|
|
179
193
|
* - Pass any other `ReactNode` to flex-fill the available height (centered).
|
|
180
194
|
*/
|
|
181
195
|
welcomeMessage?: string | React__default.ReactNode;
|
|
196
|
+
/**
|
|
197
|
+
* Slot rendered horizontally centered directly under `Chat.Input`, while
|
|
198
|
+
* the chat is empty (no user/assistant messages yet). Typical use is a row
|
|
199
|
+
* of `PromptCard`s as starter prompts. Children can call `useChatContext()`
|
|
200
|
+
* to invoke `sendMessage(text)` on click.
|
|
201
|
+
*/
|
|
202
|
+
promptSuggestions?: React__default.ReactNode;
|
|
182
203
|
/**
|
|
183
204
|
* Pass `null` to disable the chat's built-in surface motion (input slide to
|
|
184
205
|
* bottom on first message). Omit / leave undefined for default motion.
|
|
@@ -471,6 +492,8 @@ type AgentSessionStore = {
|
|
|
471
492
|
declare const UPDATE_TODOS_TOOL: ToolSpec;
|
|
472
493
|
/** Built-in tool: pause and ask the user to approve / choose before continuing. */
|
|
473
494
|
declare const REQUEST_APPROVAL_TOOL: ToolSpec;
|
|
495
|
+
/** Built-in tool: render a chart inline as part of the assistant message. */
|
|
496
|
+
declare const RENDER_CHART_TOOL: ToolSpec;
|
|
474
497
|
type CreateAgentHandlerOptions = {
|
|
475
498
|
/** Provider adapter — the only provider-specific code. */
|
|
476
499
|
callModel: CallModel;
|
|
@@ -651,4 +674,4 @@ declare const Chat: typeof Chat$1 & {
|
|
|
651
674
|
declare const normalizeChatError: typeof normalizeChatError$1;
|
|
652
675
|
declare const createHandler: typeof createHandler$1;
|
|
653
676
|
|
|
654
|
-
export { type AgentHandler, type AgentMessage, type AgentSessionStore, type AgentSnapshot, type AgentTool, type ApprovalOption, type CallModel, Chat, type ChatApprovalProps, type ChatApprovalRequest, type ChatAttachButtonProps, type ChatAttachType, type ChatAttachment, type ChatCanvasProps, type ChatChunk, type ChatComponents, type ChatErrorProps, type ChatInputProps, type ChatMessage, type ChatMessageRendererProps, type ChatMessagesProps, type ChatResponse, type ChatThread, type ChatThreadsAdapter, type ChatThreadsContextValue, ChatThreadsProvider, type ChatThreadsProviderProps, type ChatTodo, type ChatTodoListProps, type CoralTaskType, type CreateAgentHandlerOptions, DEFAULT_TASK_MESSAGES, type ErrorCategory, type ModelRequest, type ModelStreamEvent, type NormalizedChatError, REQUEST_APPROVAL_TOOL, type ToolCall, type ToolResult, type ToolSpec, UPDATE_TODOS_TOOL, createAgentHandler, createHandler, createMemoryThreadsAdapter, fileToBase64, normalizeChatError, resolveTaskMessages, useChatContext, useChatThreads };
|
|
677
|
+
export { type AgentHandler, type AgentMessage, type AgentSessionStore, type AgentSnapshot, type AgentTool, type ApprovalOption, type CallModel, Chat, type ChatApprovalProps, type ChatApprovalRequest, type ChatAttachButtonProps, type ChatAttachType, type ChatAttachment, type ChatCanvasProps, type ChatChunk, type ChatComponents, type ChatErrorProps, type ChatInputProps, type ChatMessage, type ChatMessageRendererProps, type ChatMessagesProps, type ChatResponse, type ChatThread, type ChatThreadsAdapter, type ChatThreadsContextValue, ChatThreadsProvider, type ChatThreadsProviderProps, type ChatTodo, type ChatTodoListProps, type CoralTaskType, type CreateAgentHandlerOptions, DEFAULT_TASK_MESSAGES, type ErrorCategory, type ModelRequest, type ModelStreamEvent, type NormalizedChatError, RENDER_CHART_TOOL, REQUEST_APPROVAL_TOOL, type ToolCall, type ToolResult, type ToolSpec, UPDATE_TODOS_TOOL, createAgentHandler, createHandler, createMemoryThreadsAdapter, fileToBase64, normalizeChatError, resolveTaskMessages, useChatContext, useChatThreads };
|
package/dist/index.js
CHANGED
|
@@ -428,6 +428,7 @@ var ChatCanvas = ({
|
|
|
428
428
|
let pendingContent = "";
|
|
429
429
|
let streamedApproval;
|
|
430
430
|
let streamedTodos;
|
|
431
|
+
let streamedCharts;
|
|
431
432
|
for await (const chunk of response) {
|
|
432
433
|
if (shouldStopRef.current) break;
|
|
433
434
|
if (sessionAtSend !== void 0 && currentConversationIdRef.current !== sessionAtSend) break;
|
|
@@ -476,6 +477,17 @@ var ChatCanvas = ({
|
|
|
476
477
|
}
|
|
477
478
|
return updated;
|
|
478
479
|
});
|
|
480
|
+
} else if (chunk.type === "chart") {
|
|
481
|
+
streamedCharts = [...streamedCharts ?? [], chunk.spec];
|
|
482
|
+
const nextCharts = streamedCharts;
|
|
483
|
+
setMessages((prev) => {
|
|
484
|
+
const updated = [...prev];
|
|
485
|
+
const last = updated[updated.length - 1];
|
|
486
|
+
if (last && last.id === assistantId) {
|
|
487
|
+
updated[updated.length - 1] = { ...last, charts: nextCharts };
|
|
488
|
+
}
|
|
489
|
+
return updated;
|
|
490
|
+
});
|
|
479
491
|
}
|
|
480
492
|
}
|
|
481
493
|
if (rafId !== null) cancelAnimationFrame(rafId);
|
|
@@ -489,7 +501,8 @@ var ChatCanvas = ({
|
|
|
489
501
|
content: assistantContent,
|
|
490
502
|
...reasoningRef.current ? { metadata: { reasoning: reasoningRef.current } } : {},
|
|
491
503
|
...streamedApproval ? { approval: streamedApproval } : {},
|
|
492
|
-
...streamedTodos ? { todos: streamedTodos } : {}
|
|
504
|
+
...streamedTodos ? { todos: streamedTodos } : {},
|
|
505
|
+
...streamedCharts ? { charts: streamedCharts } : {}
|
|
493
506
|
};
|
|
494
507
|
const finalMessages = [...updatedMessages, finalMsg];
|
|
495
508
|
setMessages(finalMessages);
|
|
@@ -1041,13 +1054,13 @@ import {
|
|
|
1041
1054
|
Body1 as Body14,
|
|
1042
1055
|
Caption1,
|
|
1043
1056
|
makeStyles as makeStyles6,
|
|
1044
|
-
Spinner as Spinner2,
|
|
1045
1057
|
tokens as tokens6
|
|
1046
1058
|
} from "@fluentui/react-components";
|
|
1047
1059
|
import {
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1060
|
+
CheckboxCheckedFilled,
|
|
1061
|
+
CheckboxUncheckedRegular,
|
|
1062
|
+
ChevronRightRegular,
|
|
1063
|
+
SquareHintRegular
|
|
1051
1064
|
} from "@fluentui/react-icons";
|
|
1052
1065
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1053
1066
|
var useStyles6 = makeStyles6({
|
|
@@ -1084,6 +1097,7 @@ var useStyles6 = makeStyles6({
|
|
|
1084
1097
|
chevron: {
|
|
1085
1098
|
color: tokens6.colorNeutralForeground3,
|
|
1086
1099
|
flexShrink: 0,
|
|
1100
|
+
fontSize: "16px",
|
|
1087
1101
|
transition: "transform 0.2s ease"
|
|
1088
1102
|
},
|
|
1089
1103
|
chevronExpanded: {
|
|
@@ -1104,15 +1118,19 @@ var useStyles6 = makeStyles6({
|
|
|
1104
1118
|
display: "flex",
|
|
1105
1119
|
alignItems: "center",
|
|
1106
1120
|
justifyContent: "center",
|
|
1107
|
-
width: "
|
|
1121
|
+
width: "20px",
|
|
1108
1122
|
height: "20px",
|
|
1123
|
+
fontSize: "20px",
|
|
1109
1124
|
flexShrink: 0
|
|
1110
1125
|
},
|
|
1111
1126
|
pendingIcon: {
|
|
1112
|
-
color: tokens6.
|
|
1127
|
+
color: tokens6.colorNeutralForegroundDisabled
|
|
1128
|
+
},
|
|
1129
|
+
activeIcon: {
|
|
1130
|
+
color: tokens6.colorNeutralForeground2
|
|
1113
1131
|
},
|
|
1114
1132
|
doneIcon: {
|
|
1115
|
-
color: tokens6.
|
|
1133
|
+
color: tokens6.colorPaletteSeafoamForeground2
|
|
1116
1134
|
},
|
|
1117
1135
|
text: {
|
|
1118
1136
|
minWidth: 0,
|
|
@@ -1157,7 +1175,7 @@ var ChatTodoList = ({
|
|
|
1157
1175
|
"aria-expanded": expanded,
|
|
1158
1176
|
children: [
|
|
1159
1177
|
/* @__PURE__ */ jsx6(
|
|
1160
|
-
|
|
1178
|
+
ChevronRightRegular,
|
|
1161
1179
|
{
|
|
1162
1180
|
className: `${styles.chevron}${expanded ? ` ${styles.chevronExpanded}` : ""}`
|
|
1163
1181
|
}
|
|
@@ -1180,7 +1198,7 @@ var ChatTodoList = ({
|
|
|
1180
1198
|
className: styles.item,
|
|
1181
1199
|
role: "listitem",
|
|
1182
1200
|
children: [
|
|
1183
|
-
/* @__PURE__ */ jsx6("span", { className: styles.iconCell, children: todo.status === "completed" ? /* @__PURE__ */ jsx6(
|
|
1201
|
+
/* @__PURE__ */ jsx6("span", { className: styles.iconCell, children: todo.status === "completed" ? /* @__PURE__ */ jsx6(CheckboxCheckedFilled, { className: styles.doneIcon }) : todo.status === "in_progress" ? /* @__PURE__ */ jsx6(CheckboxUncheckedRegular, { className: styles.activeIcon }) : /* @__PURE__ */ jsx6(SquareHintRegular, { className: styles.pendingIcon }) }),
|
|
1184
1202
|
/* @__PURE__ */ jsx6(Body14, { className: `${styles.text} ${textClass}`, children: text })
|
|
1185
1203
|
]
|
|
1186
1204
|
},
|
|
@@ -1194,6 +1212,7 @@ var ChatTodoList = ({
|
|
|
1194
1212
|
var Chat_TodoList_default = ChatTodoList;
|
|
1195
1213
|
|
|
1196
1214
|
// src/Chat.Messages.tsx
|
|
1215
|
+
import { CoralChart } from "@coral-ai/charts";
|
|
1197
1216
|
import { CheckmarkCircle20Filled } from "@fluentui/react-icons";
|
|
1198
1217
|
import { Fragment, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1199
1218
|
var useStyles7 = makeStyles7({
|
|
@@ -1560,6 +1579,7 @@ var ChatMessages = ({
|
|
|
1560
1579
|
}
|
|
1561
1580
|
),
|
|
1562
1581
|
msg.todos && msg.todos.length > 0 && /* @__PURE__ */ jsx7(Chat_TodoList_default, { todos: msg.todos }),
|
|
1582
|
+
msg.charts && msg.charts.length > 0 && /* @__PURE__ */ jsx7(Fragment, { children: msg.charts.map((spec, i) => /* @__PURE__ */ jsx7(CoralChart, { spec }, i)) }),
|
|
1563
1583
|
/* @__PURE__ */ jsx7(
|
|
1564
1584
|
CoralMarkdown,
|
|
1565
1585
|
{
|
|
@@ -2144,6 +2164,15 @@ var useStyles10 = makeStyles10({
|
|
|
2144
2164
|
maxWidth: "768px",
|
|
2145
2165
|
padding: "0 16px 16px 16px",
|
|
2146
2166
|
boxSizing: "border-box"
|
|
2167
|
+
},
|
|
2168
|
+
suggestionsRow: {
|
|
2169
|
+
display: "flex",
|
|
2170
|
+
width: "100%",
|
|
2171
|
+
maxWidth: "768px",
|
|
2172
|
+
margin: "0 auto",
|
|
2173
|
+
padding: "0 16px 16px 16px",
|
|
2174
|
+
boxSizing: "border-box",
|
|
2175
|
+
justifyContent: "center"
|
|
2147
2176
|
}
|
|
2148
2177
|
});
|
|
2149
2178
|
var remapFontSizeForSurface = (size, surface) => {
|
|
@@ -2154,6 +2183,7 @@ var remapFontSizeForSurface = (size, surface) => {
|
|
|
2154
2183
|
};
|
|
2155
2184
|
var ChatLayout = ({
|
|
2156
2185
|
welcomeMessage,
|
|
2186
|
+
promptSuggestions,
|
|
2157
2187
|
surfaceMotion,
|
|
2158
2188
|
placeholder,
|
|
2159
2189
|
disabled,
|
|
@@ -2241,6 +2271,7 @@ var ChatLayout = ({
|
|
|
2241
2271
|
}
|
|
2242
2272
|
)
|
|
2243
2273
|
] }) }),
|
|
2274
|
+
empty && promptSuggestions && /* @__PURE__ */ jsx11("div", { className: styles.suggestionsRow, children: promptSuggestions }),
|
|
2244
2275
|
/* @__PURE__ */ jsx11(
|
|
2245
2276
|
"div",
|
|
2246
2277
|
{
|
|
@@ -2282,6 +2313,7 @@ var Chat = ({
|
|
|
2282
2313
|
thinkingStatus,
|
|
2283
2314
|
onStop,
|
|
2284
2315
|
welcomeMessage,
|
|
2316
|
+
promptSuggestions,
|
|
2285
2317
|
surfaceMotion,
|
|
2286
2318
|
components,
|
|
2287
2319
|
onCopy,
|
|
@@ -2315,6 +2347,7 @@ var Chat = ({
|
|
|
2315
2347
|
ChatLayout,
|
|
2316
2348
|
{
|
|
2317
2349
|
welcomeMessage,
|
|
2350
|
+
promptSuggestions,
|
|
2318
2351
|
surfaceMotion,
|
|
2319
2352
|
placeholder,
|
|
2320
2353
|
disabled,
|
|
@@ -2444,6 +2477,49 @@ var REQUEST_APPROVAL_TOOL = {
|
|
|
2444
2477
|
required: ["question", "options"]
|
|
2445
2478
|
}
|
|
2446
2479
|
};
|
|
2480
|
+
var RENDER_CHART_TOOL = {
|
|
2481
|
+
name: "render_chart",
|
|
2482
|
+
description: 'Render a chart inline in the assistant message. Call this when a visualization (bar or line) communicates the data more clearly than prose or a table. The chart appears above your text \u2014 refer to it naturally ("as the chart above shows\u2026") and do NOT also produce ASCII charts or code blocks for the same data. May be called multiple times in a turn to render multiple charts.',
|
|
2483
|
+
parameters: {
|
|
2484
|
+
type: "object",
|
|
2485
|
+
properties: {
|
|
2486
|
+
kind: {
|
|
2487
|
+
type: "string",
|
|
2488
|
+
enum: ["bar", "line"],
|
|
2489
|
+
description: "Use 'bar' for categorical comparisons, 'line' for trends over an ordered axis."
|
|
2490
|
+
},
|
|
2491
|
+
title: { type: "string", description: "Title shown above the chart." },
|
|
2492
|
+
xKey: {
|
|
2493
|
+
type: "string",
|
|
2494
|
+
description: "Key in each `data` row that supplies the x-axis label."
|
|
2495
|
+
},
|
|
2496
|
+
series: {
|
|
2497
|
+
type: "array",
|
|
2498
|
+
description: "One entry per data series (one bar group / one line).",
|
|
2499
|
+
items: {
|
|
2500
|
+
type: "object",
|
|
2501
|
+
properties: {
|
|
2502
|
+
dataKey: {
|
|
2503
|
+
type: "string",
|
|
2504
|
+
description: "Key in each `data` row holding this series' numeric value."
|
|
2505
|
+
},
|
|
2506
|
+
label: {
|
|
2507
|
+
type: "string",
|
|
2508
|
+
description: "Display label shown in the legend and tooltip."
|
|
2509
|
+
}
|
|
2510
|
+
},
|
|
2511
|
+
required: ["dataKey", "label"]
|
|
2512
|
+
}
|
|
2513
|
+
},
|
|
2514
|
+
data: {
|
|
2515
|
+
type: "array",
|
|
2516
|
+
description: "Rows of data containing the xKey and every series' dataKey. Example: `[{ quarter: 'Q1', alice: 92, bob: 78 }, \u2026]`.",
|
|
2517
|
+
items: { type: "object" }
|
|
2518
|
+
}
|
|
2519
|
+
},
|
|
2520
|
+
required: ["kind", "title", "xKey", "series", "data"]
|
|
2521
|
+
}
|
|
2522
|
+
};
|
|
2447
2523
|
function createMemoryStore() {
|
|
2448
2524
|
const map = /* @__PURE__ */ new Map();
|
|
2449
2525
|
return {
|
|
@@ -2477,6 +2553,24 @@ function extractTodos(input) {
|
|
|
2477
2553
|
};
|
|
2478
2554
|
});
|
|
2479
2555
|
}
|
|
2556
|
+
function buildChartSpec(input) {
|
|
2557
|
+
const o = input ?? {};
|
|
2558
|
+
const kind = o.kind === "line" ? "line" : "bar";
|
|
2559
|
+
const title = typeof o.title === "string" ? o.title : "";
|
|
2560
|
+
const xKey = typeof o.xKey === "string" ? o.xKey : "";
|
|
2561
|
+
const rawSeries = Array.isArray(o.series) ? o.series : [];
|
|
2562
|
+
const series = rawSeries.map((s, i) => {
|
|
2563
|
+
const obj = s ?? {};
|
|
2564
|
+
const dataKey = typeof obj.dataKey === "string" ? obj.dataKey : "";
|
|
2565
|
+
const label = typeof obj.label === "string" ? obj.label : dataKey || `series-${i}`;
|
|
2566
|
+
return dataKey ? { dataKey, label } : null;
|
|
2567
|
+
}).filter((s) => s !== null);
|
|
2568
|
+
const data = Array.isArray(o.data) ? o.data.filter(
|
|
2569
|
+
(r) => r && typeof r === "object"
|
|
2570
|
+
) : [];
|
|
2571
|
+
if (!xKey || series.length === 0 || data.length === 0) return null;
|
|
2572
|
+
return { kind, title, xKey, series, data };
|
|
2573
|
+
}
|
|
2480
2574
|
function buildApproval(tc) {
|
|
2481
2575
|
const input = tc.input ?? {};
|
|
2482
2576
|
const rawOptions = Array.isArray(input.options) ? input.options : [];
|
|
@@ -2505,6 +2599,7 @@ function createAgentHandler(options) {
|
|
|
2505
2599
|
const toolSpecs = [
|
|
2506
2600
|
UPDATE_TODOS_TOOL,
|
|
2507
2601
|
REQUEST_APPROVAL_TOOL,
|
|
2602
|
+
RENDER_CHART_TOOL,
|
|
2508
2603
|
...tools.map((t) => t.spec)
|
|
2509
2604
|
];
|
|
2510
2605
|
return async function* (_input, history, attachments) {
|
|
@@ -2572,6 +2667,22 @@ function createAgentHandler(options) {
|
|
|
2572
2667
|
yield { type: "approval", approval: buildApproval(tc) };
|
|
2573
2668
|
await store.set(tc.id, { messages, pendingToolCallId: tc.id });
|
|
2574
2669
|
return;
|
|
2670
|
+
} else if (tc.name === RENDER_CHART_TOOL.name) {
|
|
2671
|
+
const spec = buildChartSpec(tc.input);
|
|
2672
|
+
if (spec) {
|
|
2673
|
+
yield { type: "chart", spec };
|
|
2674
|
+
messages.push({
|
|
2675
|
+
role: "tool",
|
|
2676
|
+
toolCallId: tc.id,
|
|
2677
|
+
content: "Chart rendered and shown to the user above your text."
|
|
2678
|
+
});
|
|
2679
|
+
} else {
|
|
2680
|
+
messages.push({
|
|
2681
|
+
role: "tool",
|
|
2682
|
+
toolCallId: tc.id,
|
|
2683
|
+
content: "Error: chart spec was invalid. Need non-empty `xKey`, at least one entry in `series`, and at least one row in `data`."
|
|
2684
|
+
});
|
|
2685
|
+
}
|
|
2575
2686
|
} else {
|
|
2576
2687
|
const tool = customByName.get(tc.name);
|
|
2577
2688
|
let content;
|
|
@@ -2768,6 +2879,7 @@ export {
|
|
|
2768
2879
|
Chat2 as Chat,
|
|
2769
2880
|
ChatThreadsProvider,
|
|
2770
2881
|
DEFAULT_TASK_MESSAGES,
|
|
2882
|
+
RENDER_CHART_TOOL,
|
|
2771
2883
|
REQUEST_APPROVAL_TOOL,
|
|
2772
2884
|
UPDATE_TODOS_TOOL,
|
|
2773
2885
|
createAgentHandler,
|