@getcatalystiq/agent-plane-ui 0.1.14 → 0.1.16
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.cjs +440 -8
- package/dist/index.d.cts +63 -1
- package/dist/index.d.ts +63 -1
- package/dist/index.js +439 -9
- package/package.json +6 -1
package/dist/index.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var swr = require('swr');
|
|
|
7
7
|
var ReactMarkdown = require('react-markdown');
|
|
8
8
|
var cmdk = require('cmdk');
|
|
9
9
|
var Popover = require('@radix-ui/react-popover');
|
|
10
|
+
var remarkGfm = require('remark-gfm');
|
|
10
11
|
|
|
11
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
13
|
|
|
@@ -31,6 +32,7 @@ function _interopNamespace(e) {
|
|
|
31
32
|
var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
|
|
32
33
|
var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
33
34
|
var Popover__namespace = /*#__PURE__*/_interopNamespace(Popover);
|
|
35
|
+
var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
|
|
34
36
|
|
|
35
37
|
function Select({ className = "", ...props }) {
|
|
36
38
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative w-full", children: [
|
|
@@ -1698,14 +1700,6 @@ function PluginDetailPage({ marketplaceId, pluginName }) {
|
|
|
1698
1700
|
];
|
|
1699
1701
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
|
|
1700
1702
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1701
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3 mb-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1702
|
-
LinkComponent,
|
|
1703
|
-
{
|
|
1704
|
-
href: `${basePath}/plugin-marketplaces/${marketplaceId}`,
|
|
1705
|
-
className: "text-muted-foreground hover:text-foreground text-sm",
|
|
1706
|
-
children: "\u2190 Back to marketplace"
|
|
1707
|
-
}
|
|
1708
|
-
) }),
|
|
1709
1703
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1710
1704
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-semibold", children: plugin.displayName }),
|
|
1711
1705
|
plugin.version && /* @__PURE__ */ jsxRuntime.jsxs(chunk4XBBDUSZ_cjs.Badge, { variant: "outline", children: [
|
|
@@ -4394,6 +4388,443 @@ function ScheduleCard({
|
|
|
4394
4388
|
] })
|
|
4395
4389
|
] });
|
|
4396
4390
|
}
|
|
4391
|
+
function MarkdownContent({ children }) {
|
|
4392
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground [&_p]:my-1 [&_h1]:text-lg [&_h1]:font-bold [&_h1]:my-2 [&_h2]:text-base [&_h2]:font-semibold [&_h2]:my-2 [&_h3]:text-sm [&_h3]:font-semibold [&_h3]:my-1 [&_ul]:list-disc [&_ul]:pl-5 [&_ul]:my-1 [&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:my-1 [&_li]:my-0.5 [&_pre]:bg-muted [&_pre]:rounded-md [&_pre]:p-3 [&_pre]:overflow-x-auto [&_pre]:text-xs [&_pre]:my-2 [&_code:not(pre_code)]:bg-muted [&_code:not(pre_code)]:px-1 [&_code:not(pre_code)]:py-0.5 [&_code:not(pre_code)]:rounded [&_code:not(pre_code)]:text-xs [&_code:not(pre_code)]:font-mono [&_a]:text-blue-400 [&_a]:underline [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_blockquote]:my-2 [&_hr]:border-border [&_hr]:my-3 [&_table]:border-collapse [&_table]:text-xs [&_table]:w-full [&_th]:border [&_th]:border-border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold [&_th]:bg-muted [&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1 [&_strong]:font-semibold [&_em]:italic", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4393
|
+
ReactMarkdown__default.default,
|
|
4394
|
+
{
|
|
4395
|
+
remarkPlugins: [remarkGfm__default.default],
|
|
4396
|
+
components: {
|
|
4397
|
+
a: ({ href, children: linkChildren }) => /* @__PURE__ */ jsxRuntime.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children: linkChildren })
|
|
4398
|
+
},
|
|
4399
|
+
children
|
|
4400
|
+
}
|
|
4401
|
+
) });
|
|
4402
|
+
}
|
|
4403
|
+
function CollapsibleJson({ data, maxHeight = "12rem" }) {
|
|
4404
|
+
const [expanded, setExpanded] = React3.useState(false);
|
|
4405
|
+
const json = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
4406
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
4407
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4408
|
+
"pre",
|
|
4409
|
+
{
|
|
4410
|
+
className: `text-xs font-mono text-muted-foreground bg-muted/50 rounded-md p-2 overflow-x-auto whitespace-pre-wrap break-all ${expanded ? "" : "overflow-hidden"}`,
|
|
4411
|
+
style: expanded ? void 0 : { maxHeight },
|
|
4412
|
+
children: json
|
|
4413
|
+
}
|
|
4414
|
+
),
|
|
4415
|
+
json.length > 200 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4416
|
+
"button",
|
|
4417
|
+
{
|
|
4418
|
+
onClick: () => setExpanded(!expanded),
|
|
4419
|
+
className: "text-xs text-blue-400 hover:text-blue-300 mt-1",
|
|
4420
|
+
children: expanded ? "Collapse" : "Expand"
|
|
4421
|
+
}
|
|
4422
|
+
)
|
|
4423
|
+
] });
|
|
4424
|
+
}
|
|
4425
|
+
function renderEvent(event, idx) {
|
|
4426
|
+
if (event.type === "heartbeat") return null;
|
|
4427
|
+
if (event.type === "text_delta") return null;
|
|
4428
|
+
if (event.type === "session_created") return null;
|
|
4429
|
+
if (event.type === "session_info") return null;
|
|
4430
|
+
if (event.type === "mcp_status") return null;
|
|
4431
|
+
if (event.type === "rate_limit_event") return null;
|
|
4432
|
+
if (event.type === "user_message") {
|
|
4433
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-border pt-3 mt-1", children: [
|
|
4434
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-emerald-400 uppercase", children: "You" }),
|
|
4435
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground mt-1 whitespace-pre-wrap", children: String(event.text) })
|
|
4436
|
+
] }, idx);
|
|
4437
|
+
}
|
|
4438
|
+
if (event.type === "assistant") {
|
|
4439
|
+
const content = event.message;
|
|
4440
|
+
const blocks = content?.content ?? [];
|
|
4441
|
+
const textBlocks = blocks.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
4442
|
+
const toolUseBlocks = blocks.filter((c) => c.type === "tool_use");
|
|
4443
|
+
if (!textBlocks && toolUseBlocks.length === 0) return null;
|
|
4444
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
4445
|
+
textBlocks && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
4446
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-blue-400 uppercase", children: "Assistant" }),
|
|
4447
|
+
/* @__PURE__ */ jsxRuntime.jsx(MarkdownContent, { children: textBlocks })
|
|
4448
|
+
] }),
|
|
4449
|
+
toolUseBlocks.map((tool, ti) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 ml-3 pl-3 border-l-2 border-yellow-800/50", children: [
|
|
4450
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs font-semibold text-yellow-400 uppercase", children: [
|
|
4451
|
+
"Tool Call: ",
|
|
4452
|
+
tool.name ?? "unknown"
|
|
4453
|
+
] }),
|
|
4454
|
+
tool.id && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground ml-2 font-mono", children: String(tool.id) }),
|
|
4455
|
+
tool.input != null && /* @__PURE__ */ jsxRuntime.jsx(CollapsibleJson, { data: tool.input })
|
|
4456
|
+
] }, ti))
|
|
4457
|
+
] }, idx);
|
|
4458
|
+
}
|
|
4459
|
+
if (event.type === "tool_use") {
|
|
4460
|
+
const toolName = String(event.tool_name ?? event.name ?? "unknown");
|
|
4461
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 ml-3 pl-3 border-l-2 border-yellow-800/50", children: [
|
|
4462
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4463
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-yellow-400 uppercase", children: "Tool Call" }),
|
|
4464
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-yellow-400/80", children: toolName }),
|
|
4465
|
+
event.tool_use_id ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground font-mono", children: String(event.tool_use_id) }) : null
|
|
4466
|
+
] }),
|
|
4467
|
+
event.input != null ? /* @__PURE__ */ jsxRuntime.jsx(CollapsibleJson, { data: event.input }) : null
|
|
4468
|
+
] }, idx);
|
|
4469
|
+
}
|
|
4470
|
+
if (event.type === "tool_result") {
|
|
4471
|
+
const isError = event.is_error === true || event.error === true;
|
|
4472
|
+
const content = event.output ?? event.content ?? "";
|
|
4473
|
+
const contentStr = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
4474
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `space-y-1 ml-3 pl-3 border-l-2 ${isError ? "border-red-800/50" : "border-green-800/50"}`, children: [
|
|
4475
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4476
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-xs font-semibold uppercase ${isError ? "text-red-400" : "text-green-400"}`, children: isError ? "Tool Error" : "Tool Result" }),
|
|
4477
|
+
event.tool_name ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-muted-foreground", children: String(event.tool_name) }) : null,
|
|
4478
|
+
event.tool_use_id ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground font-mono", children: String(event.tool_use_id) }) : null
|
|
4479
|
+
] }),
|
|
4480
|
+
contentStr ? /* @__PURE__ */ jsxRuntime.jsx(CollapsibleJson, { data: contentStr }) : null
|
|
4481
|
+
] }, idx);
|
|
4482
|
+
}
|
|
4483
|
+
if (event.type === "result") {
|
|
4484
|
+
const success = event.subtype === "success";
|
|
4485
|
+
const costUsd = event.cost_usd ?? event.total_cost_usd;
|
|
4486
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `rounded-md px-3 py-2 flex items-center gap-3 ${success ? "bg-green-950 border border-green-900" : "bg-red-950 border border-red-900"}`, children: [
|
|
4487
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: `text-xs font-semibold ${success ? "text-green-400" : "text-red-400"}`, children: success ? "Completed" : "Failed" }),
|
|
4488
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-3 text-xs text-zinc-400", children: [
|
|
4489
|
+
event.num_turns != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4490
|
+
String(event.num_turns),
|
|
4491
|
+
" turns"
|
|
4492
|
+
] }),
|
|
4493
|
+
costUsd != null && Number(costUsd) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4494
|
+
"$",
|
|
4495
|
+
Number(costUsd).toFixed(4)
|
|
4496
|
+
] }),
|
|
4497
|
+
event.duration_ms != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4498
|
+
(Number(event.duration_ms) / 1e3).toFixed(1),
|
|
4499
|
+
"s"
|
|
4500
|
+
] }),
|
|
4501
|
+
event.duration_api_ms != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4502
|
+
"API: ",
|
|
4503
|
+
(Number(event.duration_api_ms) / 1e3).toFixed(1),
|
|
4504
|
+
"s"
|
|
4505
|
+
] })
|
|
4506
|
+
] })
|
|
4507
|
+
] }, idx);
|
|
4508
|
+
}
|
|
4509
|
+
if (event.type === "error") {
|
|
4510
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-md p-3 bg-red-950 border border-red-800", children: [
|
|
4511
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4512
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-red-400", children: "Error" }),
|
|
4513
|
+
event.code ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-mono text-red-400/70", children: String(event.code) }) : null
|
|
4514
|
+
] }),
|
|
4515
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-foreground mt-1", children: String(event.error ?? "Unknown error") })
|
|
4516
|
+
] }, idx);
|
|
4517
|
+
}
|
|
4518
|
+
if (event.type === "stream_detached") {
|
|
4519
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground italic border-t border-border pt-2", children: [
|
|
4520
|
+
"Stream detached at ",
|
|
4521
|
+
event.timestamp ? new Date(String(event.timestamp)).toLocaleTimeString() : "unknown",
|
|
4522
|
+
" \u2014 run continues in background"
|
|
4523
|
+
] }, idx);
|
|
4524
|
+
}
|
|
4525
|
+
if (event.type === "queued") {
|
|
4526
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "Queued\u2026" }, idx);
|
|
4527
|
+
}
|
|
4528
|
+
if (event.type === "sandbox_starting") {
|
|
4529
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground", children: "Starting sandbox\u2026" }, idx);
|
|
4530
|
+
}
|
|
4531
|
+
if (event.type === "run_started") {
|
|
4532
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
4533
|
+
"Agent started",
|
|
4534
|
+
event.model ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2 font-mono text-foreground/60", children: String(event.model) }) : null,
|
|
4535
|
+
event.mcp_server_count != null && Number(event.mcp_server_count) > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2", children: [
|
|
4536
|
+
String(event.mcp_server_count),
|
|
4537
|
+
" MCP server",
|
|
4538
|
+
Number(event.mcp_server_count) !== 1 ? "s" : ""
|
|
4539
|
+
] })
|
|
4540
|
+
] }, idx);
|
|
4541
|
+
}
|
|
4542
|
+
if (event.type === "system") {
|
|
4543
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground italic", children: String(event.message ?? JSON.stringify(event)) }, idx);
|
|
4544
|
+
}
|
|
4545
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
4546
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-purple-400 uppercase", children: event.type }),
|
|
4547
|
+
/* @__PURE__ */ jsxRuntime.jsx(CollapsibleJson, { data: event, maxHeight: "8rem" })
|
|
4548
|
+
] }, idx);
|
|
4549
|
+
}
|
|
4550
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "timed_out"]);
|
|
4551
|
+
function PlaygroundPage({ agentId }) {
|
|
4552
|
+
const client = chunk4XBBDUSZ_cjs.useAgentPlaneClient();
|
|
4553
|
+
const { LinkComponent, basePath } = chunk4XBBDUSZ_cjs.useNavigation();
|
|
4554
|
+
const { data: agent, error: agentError, isLoading } = chunk4XBBDUSZ_cjs.useApi(
|
|
4555
|
+
`agent-${agentId}`,
|
|
4556
|
+
(c) => c.agents.get(agentId)
|
|
4557
|
+
);
|
|
4558
|
+
const [prompt, setPrompt] = React3.useState("");
|
|
4559
|
+
const [events, setEvents] = React3.useState([]);
|
|
4560
|
+
const [streamingText, setStreamingText] = React3.useState("");
|
|
4561
|
+
const [running, setRunning] = React3.useState(false);
|
|
4562
|
+
const [polling, setPolling] = React3.useState(false);
|
|
4563
|
+
const [error, setError] = React3.useState(null);
|
|
4564
|
+
const [sessionId, setSessionId] = React3.useState(null);
|
|
4565
|
+
const sessionIdRef = React3.useRef(null);
|
|
4566
|
+
const abortRef = React3.useRef(null);
|
|
4567
|
+
const runIdRef = React3.useRef(null);
|
|
4568
|
+
const streamRef = React3.useRef(null);
|
|
4569
|
+
const scrollRef = React3.useRef(null);
|
|
4570
|
+
const textareaRef = React3.useRef(null);
|
|
4571
|
+
React3.useEffect(() => {
|
|
4572
|
+
const el = scrollRef.current;
|
|
4573
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
4574
|
+
}, [events, streamingText]);
|
|
4575
|
+
React3.useEffect(() => {
|
|
4576
|
+
return () => {
|
|
4577
|
+
abortRef.current?.abort();
|
|
4578
|
+
streamRef.current?.abort();
|
|
4579
|
+
};
|
|
4580
|
+
}, []);
|
|
4581
|
+
const pollForFinalResult = React3.useCallback(async (runId) => {
|
|
4582
|
+
setPolling(true);
|
|
4583
|
+
let delay = 3e3;
|
|
4584
|
+
const maxDelay = 1e4;
|
|
4585
|
+
try {
|
|
4586
|
+
while (true) {
|
|
4587
|
+
if (abortRef.current?.signal.aborted) break;
|
|
4588
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
4589
|
+
if (abortRef.current?.signal.aborted) break;
|
|
4590
|
+
try {
|
|
4591
|
+
const run = await client.runs.get(runId);
|
|
4592
|
+
if (TERMINAL_STATUSES.has(run.status)) {
|
|
4593
|
+
try {
|
|
4594
|
+
const transcriptEvents = await client.runs.transcriptArray(runId);
|
|
4595
|
+
if (transcriptEvents.length > 0) {
|
|
4596
|
+
const detachIdx = transcriptEvents.findIndex((ev) => ev.type === "stream_detached");
|
|
4597
|
+
const eventsAfterDetach = detachIdx >= 0 ? transcriptEvents.slice(detachIdx + 1) : [];
|
|
4598
|
+
const newEvents = eventsAfterDetach.filter(
|
|
4599
|
+
(ev) => ev.type !== "heartbeat" && ev.type !== "text_delta" && ev.type !== "run_started" && ev.type !== "queued" && ev.type !== "sandbox_starting"
|
|
4600
|
+
);
|
|
4601
|
+
if (newEvents.length > 0) {
|
|
4602
|
+
setEvents((prev) => [...prev, ...newEvents]);
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
} catch {
|
|
4606
|
+
}
|
|
4607
|
+
setEvents((prev) => {
|
|
4608
|
+
if (prev.some((ev) => ev.type === "result")) return prev;
|
|
4609
|
+
const syntheticResult = {
|
|
4610
|
+
type: "result",
|
|
4611
|
+
subtype: run.status === "completed" ? "success" : "failed",
|
|
4612
|
+
cost_usd: run.cost_usd,
|
|
4613
|
+
num_turns: run.num_turns,
|
|
4614
|
+
duration_ms: run.duration_ms
|
|
4615
|
+
};
|
|
4616
|
+
if (run.error_type) {
|
|
4617
|
+
syntheticResult.result = run.error_type;
|
|
4618
|
+
}
|
|
4619
|
+
return [...prev, syntheticResult];
|
|
4620
|
+
});
|
|
4621
|
+
break;
|
|
4622
|
+
}
|
|
4623
|
+
delay = Math.min(delay * 2, maxDelay);
|
|
4624
|
+
} catch (err) {
|
|
4625
|
+
if (err?.name === "AbortError") break;
|
|
4626
|
+
delay = Math.min(delay * 2, maxDelay);
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
} finally {
|
|
4630
|
+
setPolling(false);
|
|
4631
|
+
setRunning(false);
|
|
4632
|
+
abortRef.current = null;
|
|
4633
|
+
runIdRef.current = null;
|
|
4634
|
+
streamRef.current = null;
|
|
4635
|
+
}
|
|
4636
|
+
}, [client]);
|
|
4637
|
+
const consumeStream = React3.useCallback(async (stream) => {
|
|
4638
|
+
streamRef.current = stream;
|
|
4639
|
+
let handedOffToPoll = false;
|
|
4640
|
+
try {
|
|
4641
|
+
for await (const event of stream) {
|
|
4642
|
+
const ev = event;
|
|
4643
|
+
if (ev.type === "session_created" && ev.session_id) {
|
|
4644
|
+
const sid = ev.session_id;
|
|
4645
|
+
sessionIdRef.current = sid;
|
|
4646
|
+
setSessionId(sid);
|
|
4647
|
+
}
|
|
4648
|
+
if (ev.type === "run_started" && ev.run_id) {
|
|
4649
|
+
runIdRef.current = ev.run_id;
|
|
4650
|
+
}
|
|
4651
|
+
if (ev.type === "text_delta") {
|
|
4652
|
+
setStreamingText((prev) => prev + (ev.text ?? ""));
|
|
4653
|
+
} else if (ev.type === "stream_detached") {
|
|
4654
|
+
setStreamingText("");
|
|
4655
|
+
setEvents((prev) => [...prev, ev]);
|
|
4656
|
+
if (runIdRef.current) {
|
|
4657
|
+
handedOffToPoll = true;
|
|
4658
|
+
pollForFinalResult(runIdRef.current);
|
|
4659
|
+
return;
|
|
4660
|
+
}
|
|
4661
|
+
} else {
|
|
4662
|
+
if (ev.type === "assistant") setStreamingText("");
|
|
4663
|
+
setEvents((prev) => [...prev, ev]);
|
|
4664
|
+
}
|
|
4665
|
+
}
|
|
4666
|
+
} finally {
|
|
4667
|
+
if (!handedOffToPoll) {
|
|
4668
|
+
setRunning(false);
|
|
4669
|
+
abortRef.current = null;
|
|
4670
|
+
runIdRef.current = null;
|
|
4671
|
+
streamRef.current = null;
|
|
4672
|
+
}
|
|
4673
|
+
}
|
|
4674
|
+
}, [pollForFinalResult]);
|
|
4675
|
+
const handleSend = React3.useCallback(async () => {
|
|
4676
|
+
if (!prompt.trim() || running) return;
|
|
4677
|
+
const messageText = prompt.trim();
|
|
4678
|
+
setPrompt("");
|
|
4679
|
+
setRunning(true);
|
|
4680
|
+
setStreamingText("");
|
|
4681
|
+
setError(null);
|
|
4682
|
+
setPolling(false);
|
|
4683
|
+
setEvents((prev) => [...prev, { type: "user_message", text: messageText }]);
|
|
4684
|
+
const abort = new AbortController();
|
|
4685
|
+
abortRef.current = abort;
|
|
4686
|
+
try {
|
|
4687
|
+
let stream;
|
|
4688
|
+
const currentSessionId = sessionIdRef.current;
|
|
4689
|
+
if (currentSessionId) {
|
|
4690
|
+
stream = await client.sessions.sendMessage(
|
|
4691
|
+
currentSessionId,
|
|
4692
|
+
{ prompt: messageText },
|
|
4693
|
+
{ signal: abort.signal }
|
|
4694
|
+
);
|
|
4695
|
+
} else {
|
|
4696
|
+
stream = await client.sessions.create(
|
|
4697
|
+
{ agent_id: agentId, prompt: messageText },
|
|
4698
|
+
{ signal: abort.signal }
|
|
4699
|
+
);
|
|
4700
|
+
}
|
|
4701
|
+
await consumeStream(stream);
|
|
4702
|
+
} catch (err) {
|
|
4703
|
+
if (err?.name !== "AbortError") {
|
|
4704
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
4705
|
+
setError(msg);
|
|
4706
|
+
}
|
|
4707
|
+
setRunning(false);
|
|
4708
|
+
abortRef.current = null;
|
|
4709
|
+
runIdRef.current = null;
|
|
4710
|
+
streamRef.current = null;
|
|
4711
|
+
}
|
|
4712
|
+
}, [prompt, running, agentId, client, consumeStream]);
|
|
4713
|
+
function handleNewChat() {
|
|
4714
|
+
abortRef.current?.abort();
|
|
4715
|
+
streamRef.current?.abort();
|
|
4716
|
+
if (sessionId) {
|
|
4717
|
+
client.sessions.stop(sessionId).catch(() => {
|
|
4718
|
+
});
|
|
4719
|
+
}
|
|
4720
|
+
sessionIdRef.current = null;
|
|
4721
|
+
setSessionId(null);
|
|
4722
|
+
setEvents([]);
|
|
4723
|
+
setStreamingText("");
|
|
4724
|
+
setRunning(false);
|
|
4725
|
+
setPolling(false);
|
|
4726
|
+
setError(null);
|
|
4727
|
+
setPrompt("");
|
|
4728
|
+
runIdRef.current = null;
|
|
4729
|
+
abortRef.current = null;
|
|
4730
|
+
streamRef.current = null;
|
|
4731
|
+
textareaRef.current?.focus();
|
|
4732
|
+
}
|
|
4733
|
+
function handleStop() {
|
|
4734
|
+
abortRef.current?.abort();
|
|
4735
|
+
streamRef.current?.abort();
|
|
4736
|
+
const id = runIdRef.current;
|
|
4737
|
+
if (id) {
|
|
4738
|
+
runIdRef.current = null;
|
|
4739
|
+
client.runs.cancel(id).catch(() => {
|
|
4740
|
+
});
|
|
4741
|
+
}
|
|
4742
|
+
}
|
|
4743
|
+
if (isLoading) {
|
|
4744
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-[calc(100vh-6rem)]", children: [
|
|
4745
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
4746
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Skeleton, { className: "h-8 w-24" }),
|
|
4747
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Skeleton, { className: "h-4 w-40" })
|
|
4748
|
+
] }),
|
|
4749
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Skeleton, { className: "flex-1 rounded-lg" }),
|
|
4750
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 space-y-2", children: [
|
|
4751
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Skeleton, { className: "h-24 w-full rounded-lg" }),
|
|
4752
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Skeleton, { className: "h-8 w-20" })
|
|
4753
|
+
] })
|
|
4754
|
+
] });
|
|
4755
|
+
}
|
|
4756
|
+
if (agentError || !agent) {
|
|
4757
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center h-[calc(100vh-6rem)] gap-3", children: [
|
|
4758
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-destructive text-sm", children: agentError?.status === 404 ? "Agent not found." : `Failed to load agent: ${agentError?.message ?? "Unknown error"}` }),
|
|
4759
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4760
|
+
LinkComponent,
|
|
4761
|
+
{
|
|
4762
|
+
href: `${basePath}/agents`,
|
|
4763
|
+
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
4764
|
+
children: "\u2190 Back to agents"
|
|
4765
|
+
}
|
|
4766
|
+
)
|
|
4767
|
+
] });
|
|
4768
|
+
}
|
|
4769
|
+
const hasContent = events.length > 0 || running;
|
|
4770
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col h-[calc(100vh-6rem)]", children: [
|
|
4771
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
4772
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4773
|
+
LinkComponent,
|
|
4774
|
+
{
|
|
4775
|
+
href: `${basePath}/agents/${agentId}`,
|
|
4776
|
+
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
4777
|
+
children: [
|
|
4778
|
+
"\u2190 ",
|
|
4779
|
+
agent.name
|
|
4780
|
+
]
|
|
4781
|
+
}
|
|
4782
|
+
),
|
|
4783
|
+
(sessionId || events.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Button, { onClick: handleNewChat, variant: "outline", size: "sm", disabled: running, children: "New Chat" }),
|
|
4784
|
+
sessionId && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground font-mono", children: [
|
|
4785
|
+
"Session: ",
|
|
4786
|
+
sessionId.slice(0, 12),
|
|
4787
|
+
"\u2026"
|
|
4788
|
+
] })
|
|
4789
|
+
] }),
|
|
4790
|
+
hasContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: scrollRef, className: "flex-1 min-h-0 overflow-y-auto rounded-lg border border-border bg-muted/20 p-4 space-y-4 mb-4", children: [
|
|
4791
|
+
events.map((ev, i) => renderEvent(ev, i)),
|
|
4792
|
+
streamingText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1", children: [
|
|
4793
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-blue-400 uppercase", children: "Assistant" }),
|
|
4794
|
+
/* @__PURE__ */ jsxRuntime.jsx(MarkdownContent, { children: streamingText }),
|
|
4795
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-0.5 h-4 bg-foreground animate-pulse align-text-bottom" })
|
|
4796
|
+
] }),
|
|
4797
|
+
running && !streamingText && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
4798
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "animate-pulse", children: "\u25CF" }),
|
|
4799
|
+
" ",
|
|
4800
|
+
polling ? "Reconnected, streaming updates\u2026" : "Running\u2026"
|
|
4801
|
+
] })
|
|
4802
|
+
] }),
|
|
4803
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 shrink-0", children: [
|
|
4804
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-destructive", children: error }),
|
|
4805
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4806
|
+
Textarea,
|
|
4807
|
+
{
|
|
4808
|
+
ref: textareaRef,
|
|
4809
|
+
placeholder: sessionId ? "Send a follow-up message\u2026" : "Enter your prompt\u2026",
|
|
4810
|
+
value: prompt,
|
|
4811
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
4812
|
+
rows: hasContent ? 3 : 12,
|
|
4813
|
+
disabled: running,
|
|
4814
|
+
className: "font-mono text-sm resize-none",
|
|
4815
|
+
onKeyDown: (e) => {
|
|
4816
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) handleSend();
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
),
|
|
4820
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4821
|
+
/* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Button, { onClick: handleSend, disabled: running || !prompt.trim(), size: "sm", children: running ? "Running\u2026" : sessionId ? "Send" : "Run" }),
|
|
4822
|
+
running && /* @__PURE__ */ jsxRuntime.jsx(chunk4XBBDUSZ_cjs.Button, { onClick: handleStop, variant: "outline", size: "sm", children: "Stop" }),
|
|
4823
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground ml-1", children: "\u2318+Enter to send" })
|
|
4824
|
+
] })
|
|
4825
|
+
] })
|
|
4826
|
+
] });
|
|
4827
|
+
}
|
|
4397
4828
|
|
|
4398
4829
|
Object.defineProperty(exports, "AgentPlaneProvider", {
|
|
4399
4830
|
enumerable: true,
|
|
@@ -4494,6 +4925,7 @@ exports.McpServerListPage = McpServerListPage;
|
|
|
4494
4925
|
exports.MetricCard = MetricCard;
|
|
4495
4926
|
exports.ModelSelector = ModelSelector;
|
|
4496
4927
|
exports.PaginationBar = PaginationBar;
|
|
4928
|
+
exports.PlaygroundPage = PlaygroundPage;
|
|
4497
4929
|
exports.PluginDetailPage = PluginDetailPage;
|
|
4498
4930
|
exports.PluginMarketplaceDetailPage = PluginMarketplaceDetailPage;
|
|
4499
4931
|
exports.PluginMarketplaceListPage = PluginMarketplaceListPage;
|
package/dist/index.d.cts
CHANGED
|
@@ -7,6 +7,52 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
|
|
|
7
7
|
import { VariantProps } from 'class-variance-authority';
|
|
8
8
|
import { DailyAgentStat } from './charts.cjs';
|
|
9
9
|
|
|
10
|
+
/** Minimal stream event types used by the playground UI. */
|
|
11
|
+
interface PlaygroundTextDeltaEvent {
|
|
12
|
+
type: "text_delta";
|
|
13
|
+
text: string;
|
|
14
|
+
}
|
|
15
|
+
interface PlaygroundRunStartedEvent {
|
|
16
|
+
type: "run_started";
|
|
17
|
+
run_id: string;
|
|
18
|
+
agent_id: string;
|
|
19
|
+
model: string;
|
|
20
|
+
timestamp: string;
|
|
21
|
+
}
|
|
22
|
+
interface PlaygroundToolUseEvent {
|
|
23
|
+
type: "tool_use";
|
|
24
|
+
name?: string;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
interface PlaygroundToolResultEvent {
|
|
28
|
+
type: "tool_result";
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
interface PlaygroundResultEvent {
|
|
32
|
+
type: "result";
|
|
33
|
+
subtype: string;
|
|
34
|
+
total_cost_usd?: number;
|
|
35
|
+
num_turns?: number;
|
|
36
|
+
duration_ms?: number;
|
|
37
|
+
}
|
|
38
|
+
interface PlaygroundErrorEvent {
|
|
39
|
+
type: "error";
|
|
40
|
+
error: string;
|
|
41
|
+
code?: string;
|
|
42
|
+
}
|
|
43
|
+
interface PlaygroundSessionCreatedEvent {
|
|
44
|
+
type: "session_created";
|
|
45
|
+
session_id: string;
|
|
46
|
+
}
|
|
47
|
+
type PlaygroundStreamEvent = PlaygroundTextDeltaEvent | PlaygroundRunStartedEvent | PlaygroundToolUseEvent | PlaygroundToolResultEvent | PlaygroundResultEvent | PlaygroundErrorEvent | PlaygroundSessionCreatedEvent | {
|
|
48
|
+
type: string;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
};
|
|
51
|
+
/** Async iterable stream of events (compatible with SDK RunStream). */
|
|
52
|
+
interface PlaygroundStream extends AsyncIterable<PlaygroundStreamEvent> {
|
|
53
|
+
run_id: string | null;
|
|
54
|
+
abort(reason?: unknown): void;
|
|
55
|
+
}
|
|
10
56
|
/**
|
|
11
57
|
* Structural interface for the AgentPlane SDK client.
|
|
12
58
|
* Declares all methods the UI actually uses, avoiding a hard compile-time
|
|
@@ -47,6 +93,17 @@ interface AgentPlaneClient {
|
|
|
47
93
|
list(params?: Record<string, unknown>): Promise<unknown>;
|
|
48
94
|
get(sessionId: string): Promise<unknown>;
|
|
49
95
|
stop(sessionId: string): Promise<unknown>;
|
|
96
|
+
create(params: {
|
|
97
|
+
agent_id: string;
|
|
98
|
+
prompt?: string;
|
|
99
|
+
}, options?: {
|
|
100
|
+
signal?: AbortSignal;
|
|
101
|
+
}): Promise<unknown | PlaygroundStream>;
|
|
102
|
+
sendMessage(sessionId: string, params: {
|
|
103
|
+
prompt: string;
|
|
104
|
+
}, options?: {
|
|
105
|
+
signal?: AbortSignal;
|
|
106
|
+
}): Promise<PlaygroundStream>;
|
|
50
107
|
};
|
|
51
108
|
connectors: {
|
|
52
109
|
list(agentId: string): Promise<unknown[]>;
|
|
@@ -632,6 +689,11 @@ interface Props$1 {
|
|
|
632
689
|
}
|
|
633
690
|
declare function AgentA2aInfo({ agentId, tenantSlug, agentSlug, baseUrl, initialEnabled, initialTags, onChanged, }: Props$1): react_jsx_runtime.JSX.Element;
|
|
634
691
|
|
|
692
|
+
interface PlaygroundPageProps {
|
|
693
|
+
agentId: string;
|
|
694
|
+
}
|
|
695
|
+
declare function PlaygroundPage({ agentId }: PlaygroundPageProps): react_jsx_runtime.JSX.Element;
|
|
696
|
+
|
|
635
697
|
interface ModelSelectorProps {
|
|
636
698
|
value: string;
|
|
637
699
|
onChange: (modelId: string) => void;
|
|
@@ -645,4 +707,4 @@ interface Props {
|
|
|
645
707
|
}
|
|
646
708
|
declare function ToolkitMultiselect({ value, onChange }: Props): react_jsx_runtime.JSX.Element;
|
|
647
709
|
|
|
648
|
-
export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, type AgentPlaneClient, AgentPlaneProvider, type AgentPlaneProviderProps, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardDescription, CardHeader, CardTitle, ConfirmDialog, CopyButton, DashboardPage, type DashboardPageProps, DetailPageHeader, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, EmptyRow, FormError, FormField, Input, type LinkComponentProps, LocalDate, McpServerListPage, type McpServerListPageProps, MetricCard, ModelSelector, type NavigationProps, PaginationBar, PluginDetailPage, type PluginDetailPageProps, PluginMarketplaceDetailPage, type PluginMarketplaceDetailPageProps, PluginMarketplaceListPage, type PluginMarketplaceListPageProps, RunDetailPage, type RunDetailPageProps, RunListPage, type RunListPageProps, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, type SettingsPageProps, Skeleton, Tabs, Textarea, type TextareaProps, Th, ToolkitMultiselect, TranscriptViewer, badgeVariants, buttonVariants, cn, parsePaginationParams, useAgentPlaneClient, useApi, useAuthError, useNavigation };
|
|
710
|
+
export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, type AgentPlaneClient, AgentPlaneProvider, type AgentPlaneProviderProps, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardDescription, CardHeader, CardTitle, ConfirmDialog, CopyButton, DashboardPage, type DashboardPageProps, DetailPageHeader, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, EmptyRow, FormError, FormField, Input, type LinkComponentProps, LocalDate, McpServerListPage, type McpServerListPageProps, MetricCard, ModelSelector, type NavigationProps, PaginationBar, PlaygroundPage, type PlaygroundPageProps, type PlaygroundStream, type PlaygroundStreamEvent, PluginDetailPage, type PluginDetailPageProps, PluginMarketplaceDetailPage, type PluginMarketplaceDetailPageProps, PluginMarketplaceListPage, type PluginMarketplaceListPageProps, RunDetailPage, type RunDetailPageProps, RunListPage, type RunListPageProps, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, type SettingsPageProps, Skeleton, Tabs, Textarea, type TextareaProps, Th, ToolkitMultiselect, TranscriptViewer, badgeVariants, buttonVariants, cn, parsePaginationParams, useAgentPlaneClient, useApi, useAuthError, useNavigation };
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,52 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
|
|
|
7
7
|
import { VariantProps } from 'class-variance-authority';
|
|
8
8
|
import { DailyAgentStat } from './charts.js';
|
|
9
9
|
|
|
10
|
+
/** Minimal stream event types used by the playground UI. */
|
|
11
|
+
interface PlaygroundTextDeltaEvent {
|
|
12
|
+
type: "text_delta";
|
|
13
|
+
text: string;
|
|
14
|
+
}
|
|
15
|
+
interface PlaygroundRunStartedEvent {
|
|
16
|
+
type: "run_started";
|
|
17
|
+
run_id: string;
|
|
18
|
+
agent_id: string;
|
|
19
|
+
model: string;
|
|
20
|
+
timestamp: string;
|
|
21
|
+
}
|
|
22
|
+
interface PlaygroundToolUseEvent {
|
|
23
|
+
type: "tool_use";
|
|
24
|
+
name?: string;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
interface PlaygroundToolResultEvent {
|
|
28
|
+
type: "tool_result";
|
|
29
|
+
[key: string]: unknown;
|
|
30
|
+
}
|
|
31
|
+
interface PlaygroundResultEvent {
|
|
32
|
+
type: "result";
|
|
33
|
+
subtype: string;
|
|
34
|
+
total_cost_usd?: number;
|
|
35
|
+
num_turns?: number;
|
|
36
|
+
duration_ms?: number;
|
|
37
|
+
}
|
|
38
|
+
interface PlaygroundErrorEvent {
|
|
39
|
+
type: "error";
|
|
40
|
+
error: string;
|
|
41
|
+
code?: string;
|
|
42
|
+
}
|
|
43
|
+
interface PlaygroundSessionCreatedEvent {
|
|
44
|
+
type: "session_created";
|
|
45
|
+
session_id: string;
|
|
46
|
+
}
|
|
47
|
+
type PlaygroundStreamEvent = PlaygroundTextDeltaEvent | PlaygroundRunStartedEvent | PlaygroundToolUseEvent | PlaygroundToolResultEvent | PlaygroundResultEvent | PlaygroundErrorEvent | PlaygroundSessionCreatedEvent | {
|
|
48
|
+
type: string;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
};
|
|
51
|
+
/** Async iterable stream of events (compatible with SDK RunStream). */
|
|
52
|
+
interface PlaygroundStream extends AsyncIterable<PlaygroundStreamEvent> {
|
|
53
|
+
run_id: string | null;
|
|
54
|
+
abort(reason?: unknown): void;
|
|
55
|
+
}
|
|
10
56
|
/**
|
|
11
57
|
* Structural interface for the AgentPlane SDK client.
|
|
12
58
|
* Declares all methods the UI actually uses, avoiding a hard compile-time
|
|
@@ -47,6 +93,17 @@ interface AgentPlaneClient {
|
|
|
47
93
|
list(params?: Record<string, unknown>): Promise<unknown>;
|
|
48
94
|
get(sessionId: string): Promise<unknown>;
|
|
49
95
|
stop(sessionId: string): Promise<unknown>;
|
|
96
|
+
create(params: {
|
|
97
|
+
agent_id: string;
|
|
98
|
+
prompt?: string;
|
|
99
|
+
}, options?: {
|
|
100
|
+
signal?: AbortSignal;
|
|
101
|
+
}): Promise<unknown | PlaygroundStream>;
|
|
102
|
+
sendMessage(sessionId: string, params: {
|
|
103
|
+
prompt: string;
|
|
104
|
+
}, options?: {
|
|
105
|
+
signal?: AbortSignal;
|
|
106
|
+
}): Promise<PlaygroundStream>;
|
|
50
107
|
};
|
|
51
108
|
connectors: {
|
|
52
109
|
list(agentId: string): Promise<unknown[]>;
|
|
@@ -632,6 +689,11 @@ interface Props$1 {
|
|
|
632
689
|
}
|
|
633
690
|
declare function AgentA2aInfo({ agentId, tenantSlug, agentSlug, baseUrl, initialEnabled, initialTags, onChanged, }: Props$1): react_jsx_runtime.JSX.Element;
|
|
634
691
|
|
|
692
|
+
interface PlaygroundPageProps {
|
|
693
|
+
agentId: string;
|
|
694
|
+
}
|
|
695
|
+
declare function PlaygroundPage({ agentId }: PlaygroundPageProps): react_jsx_runtime.JSX.Element;
|
|
696
|
+
|
|
635
697
|
interface ModelSelectorProps {
|
|
636
698
|
value: string;
|
|
637
699
|
onChange: (modelId: string) => void;
|
|
@@ -645,4 +707,4 @@ interface Props {
|
|
|
645
707
|
}
|
|
646
708
|
declare function ToolkitMultiselect({ value, onChange }: Props): react_jsx_runtime.JSX.Element;
|
|
647
709
|
|
|
648
|
-
export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, type AgentPlaneClient, AgentPlaneProvider, type AgentPlaneProviderProps, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardDescription, CardHeader, CardTitle, ConfirmDialog, CopyButton, DashboardPage, type DashboardPageProps, DetailPageHeader, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, EmptyRow, FormError, FormField, Input, type LinkComponentProps, LocalDate, McpServerListPage, type McpServerListPageProps, MetricCard, ModelSelector, type NavigationProps, PaginationBar, PluginDetailPage, type PluginDetailPageProps, PluginMarketplaceDetailPage, type PluginMarketplaceDetailPageProps, PluginMarketplaceListPage, type PluginMarketplaceListPageProps, RunDetailPage, type RunDetailPageProps, RunListPage, type RunListPageProps, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, type SettingsPageProps, Skeleton, Tabs, Textarea, type TextareaProps, Th, ToolkitMultiselect, TranscriptViewer, badgeVariants, buttonVariants, cn, parsePaginationParams, useAgentPlaneClient, useApi, useAuthError, useNavigation };
|
|
710
|
+
export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, type AgentPlaneClient, AgentPlaneProvider, type AgentPlaneProviderProps, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, Badge, type BadgeProps, Button, type ButtonProps, Card, CardContent, CardDescription, CardHeader, CardTitle, ConfirmDialog, CopyButton, DashboardPage, type DashboardPageProps, DetailPageHeader, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, EmptyRow, FormError, FormField, Input, type LinkComponentProps, LocalDate, McpServerListPage, type McpServerListPageProps, MetricCard, ModelSelector, type NavigationProps, PaginationBar, PlaygroundPage, type PlaygroundPageProps, type PlaygroundStream, type PlaygroundStreamEvent, PluginDetailPage, type PluginDetailPageProps, PluginMarketplaceDetailPage, type PluginMarketplaceDetailPageProps, PluginMarketplaceListPage, type PluginMarketplaceListPageProps, RunDetailPage, type RunDetailPageProps, RunListPage, type RunListPageProps, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, type SettingsPageProps, Skeleton, Tabs, Textarea, type TextareaProps, Th, ToolkitMultiselect, TranscriptViewer, badgeVariants, buttonVariants, cn, parsePaginationParams, useAgentPlaneClient, useApi, useAuthError, useNavigation };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import { useSWRConfig } from 'swr';
|
|
|
7
7
|
import ReactMarkdown from 'react-markdown';
|
|
8
8
|
import { Command } from 'cmdk';
|
|
9
9
|
import * as Popover from '@radix-ui/react-popover';
|
|
10
|
+
import remarkGfm from 'remark-gfm';
|
|
10
11
|
|
|
11
12
|
function Select({ className = "", ...props }) {
|
|
12
13
|
return /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
|
|
@@ -1674,14 +1675,6 @@ function PluginDetailPage({ marketplaceId, pluginName }) {
|
|
|
1674
1675
|
];
|
|
1675
1676
|
return /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
|
|
1676
1677
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1677
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-3 mb-1", children: /* @__PURE__ */ jsx(
|
|
1678
|
-
LinkComponent,
|
|
1679
|
-
{
|
|
1680
|
-
href: `${basePath}/plugin-marketplaces/${marketplaceId}`,
|
|
1681
|
-
className: "text-muted-foreground hover:text-foreground text-sm",
|
|
1682
|
-
children: "\u2190 Back to marketplace"
|
|
1683
|
-
}
|
|
1684
|
-
) }),
|
|
1685
1678
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1686
1679
|
/* @__PURE__ */ jsx("h1", { className: "text-2xl font-semibold", children: plugin.displayName }),
|
|
1687
1680
|
plugin.version && /* @__PURE__ */ jsxs(Badge, { variant: "outline", children: [
|
|
@@ -4370,5 +4363,442 @@ function ScheduleCard({
|
|
|
4370
4363
|
] })
|
|
4371
4364
|
] });
|
|
4372
4365
|
}
|
|
4366
|
+
function MarkdownContent({ children }) {
|
|
4367
|
+
return /* @__PURE__ */ jsx("div", { className: "text-sm text-foreground [&_p]:my-1 [&_h1]:text-lg [&_h1]:font-bold [&_h1]:my-2 [&_h2]:text-base [&_h2]:font-semibold [&_h2]:my-2 [&_h3]:text-sm [&_h3]:font-semibold [&_h3]:my-1 [&_ul]:list-disc [&_ul]:pl-5 [&_ul]:my-1 [&_ol]:list-decimal [&_ol]:pl-5 [&_ol]:my-1 [&_li]:my-0.5 [&_pre]:bg-muted [&_pre]:rounded-md [&_pre]:p-3 [&_pre]:overflow-x-auto [&_pre]:text-xs [&_pre]:my-2 [&_code:not(pre_code)]:bg-muted [&_code:not(pre_code)]:px-1 [&_code:not(pre_code)]:py-0.5 [&_code:not(pre_code)]:rounded [&_code:not(pre_code)]:text-xs [&_code:not(pre_code)]:font-mono [&_a]:text-blue-400 [&_a]:underline [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-3 [&_blockquote]:text-muted-foreground [&_blockquote]:my-2 [&_hr]:border-border [&_hr]:my-3 [&_table]:border-collapse [&_table]:text-xs [&_table]:w-full [&_th]:border [&_th]:border-border [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold [&_th]:bg-muted [&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1 [&_strong]:font-semibold [&_em]:italic", children: /* @__PURE__ */ jsx(
|
|
4368
|
+
ReactMarkdown,
|
|
4369
|
+
{
|
|
4370
|
+
remarkPlugins: [remarkGfm],
|
|
4371
|
+
components: {
|
|
4372
|
+
a: ({ href, children: linkChildren }) => /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children: linkChildren })
|
|
4373
|
+
},
|
|
4374
|
+
children
|
|
4375
|
+
}
|
|
4376
|
+
) });
|
|
4377
|
+
}
|
|
4378
|
+
function CollapsibleJson({ data, maxHeight = "12rem" }) {
|
|
4379
|
+
const [expanded, setExpanded] = useState(false);
|
|
4380
|
+
const json = typeof data === "string" ? data : JSON.stringify(data, null, 2);
|
|
4381
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
4382
|
+
/* @__PURE__ */ jsx(
|
|
4383
|
+
"pre",
|
|
4384
|
+
{
|
|
4385
|
+
className: `text-xs font-mono text-muted-foreground bg-muted/50 rounded-md p-2 overflow-x-auto whitespace-pre-wrap break-all ${expanded ? "" : "overflow-hidden"}`,
|
|
4386
|
+
style: expanded ? void 0 : { maxHeight },
|
|
4387
|
+
children: json
|
|
4388
|
+
}
|
|
4389
|
+
),
|
|
4390
|
+
json.length > 200 && /* @__PURE__ */ jsx(
|
|
4391
|
+
"button",
|
|
4392
|
+
{
|
|
4393
|
+
onClick: () => setExpanded(!expanded),
|
|
4394
|
+
className: "text-xs text-blue-400 hover:text-blue-300 mt-1",
|
|
4395
|
+
children: expanded ? "Collapse" : "Expand"
|
|
4396
|
+
}
|
|
4397
|
+
)
|
|
4398
|
+
] });
|
|
4399
|
+
}
|
|
4400
|
+
function renderEvent(event, idx) {
|
|
4401
|
+
if (event.type === "heartbeat") return null;
|
|
4402
|
+
if (event.type === "text_delta") return null;
|
|
4403
|
+
if (event.type === "session_created") return null;
|
|
4404
|
+
if (event.type === "session_info") return null;
|
|
4405
|
+
if (event.type === "mcp_status") return null;
|
|
4406
|
+
if (event.type === "rate_limit_event") return null;
|
|
4407
|
+
if (event.type === "user_message") {
|
|
4408
|
+
return /* @__PURE__ */ jsxs("div", { className: "border-t border-border pt-3 mt-1", children: [
|
|
4409
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-emerald-400 uppercase", children: "You" }),
|
|
4410
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground mt-1 whitespace-pre-wrap", children: String(event.text) })
|
|
4411
|
+
] }, idx);
|
|
4412
|
+
}
|
|
4413
|
+
if (event.type === "assistant") {
|
|
4414
|
+
const content = event.message;
|
|
4415
|
+
const blocks = content?.content ?? [];
|
|
4416
|
+
const textBlocks = blocks.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
4417
|
+
const toolUseBlocks = blocks.filter((c) => c.type === "tool_use");
|
|
4418
|
+
if (!textBlocks && toolUseBlocks.length === 0) return null;
|
|
4419
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
4420
|
+
textBlocks && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
4421
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-blue-400 uppercase", children: "Assistant" }),
|
|
4422
|
+
/* @__PURE__ */ jsx(MarkdownContent, { children: textBlocks })
|
|
4423
|
+
] }),
|
|
4424
|
+
toolUseBlocks.map((tool, ti) => /* @__PURE__ */ jsxs("div", { className: "space-y-1 ml-3 pl-3 border-l-2 border-yellow-800/50", children: [
|
|
4425
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs font-semibold text-yellow-400 uppercase", children: [
|
|
4426
|
+
"Tool Call: ",
|
|
4427
|
+
tool.name ?? "unknown"
|
|
4428
|
+
] }),
|
|
4429
|
+
tool.id && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground ml-2 font-mono", children: String(tool.id) }),
|
|
4430
|
+
tool.input != null && /* @__PURE__ */ jsx(CollapsibleJson, { data: tool.input })
|
|
4431
|
+
] }, ti))
|
|
4432
|
+
] }, idx);
|
|
4433
|
+
}
|
|
4434
|
+
if (event.type === "tool_use") {
|
|
4435
|
+
const toolName = String(event.tool_name ?? event.name ?? "unknown");
|
|
4436
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1 ml-3 pl-3 border-l-2 border-yellow-800/50", children: [
|
|
4437
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4438
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-yellow-400 uppercase", children: "Tool Call" }),
|
|
4439
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-yellow-400/80", children: toolName }),
|
|
4440
|
+
event.tool_use_id ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground font-mono", children: String(event.tool_use_id) }) : null
|
|
4441
|
+
] }),
|
|
4442
|
+
event.input != null ? /* @__PURE__ */ jsx(CollapsibleJson, { data: event.input }) : null
|
|
4443
|
+
] }, idx);
|
|
4444
|
+
}
|
|
4445
|
+
if (event.type === "tool_result") {
|
|
4446
|
+
const isError = event.is_error === true || event.error === true;
|
|
4447
|
+
const content = event.output ?? event.content ?? "";
|
|
4448
|
+
const contentStr = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
4449
|
+
return /* @__PURE__ */ jsxs("div", { className: `space-y-1 ml-3 pl-3 border-l-2 ${isError ? "border-red-800/50" : "border-green-800/50"}`, children: [
|
|
4450
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4451
|
+
/* @__PURE__ */ jsx("span", { className: `text-xs font-semibold uppercase ${isError ? "text-red-400" : "text-green-400"}`, children: isError ? "Tool Error" : "Tool Result" }),
|
|
4452
|
+
event.tool_name ? /* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-muted-foreground", children: String(event.tool_name) }) : null,
|
|
4453
|
+
event.tool_use_id ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground font-mono", children: String(event.tool_use_id) }) : null
|
|
4454
|
+
] }),
|
|
4455
|
+
contentStr ? /* @__PURE__ */ jsx(CollapsibleJson, { data: contentStr }) : null
|
|
4456
|
+
] }, idx);
|
|
4457
|
+
}
|
|
4458
|
+
if (event.type === "result") {
|
|
4459
|
+
const success = event.subtype === "success";
|
|
4460
|
+
const costUsd = event.cost_usd ?? event.total_cost_usd;
|
|
4461
|
+
return /* @__PURE__ */ jsxs("div", { className: `rounded-md px-3 py-2 flex items-center gap-3 ${success ? "bg-green-950 border border-green-900" : "bg-red-950 border border-red-900"}`, children: [
|
|
4462
|
+
/* @__PURE__ */ jsx("span", { className: `text-xs font-semibold ${success ? "text-green-400" : "text-red-400"}`, children: success ? "Completed" : "Failed" }),
|
|
4463
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-3 text-xs text-zinc-400", children: [
|
|
4464
|
+
event.num_turns != null && /* @__PURE__ */ jsxs("span", { children: [
|
|
4465
|
+
String(event.num_turns),
|
|
4466
|
+
" turns"
|
|
4467
|
+
] }),
|
|
4468
|
+
costUsd != null && Number(costUsd) > 0 && /* @__PURE__ */ jsxs("span", { children: [
|
|
4469
|
+
"$",
|
|
4470
|
+
Number(costUsd).toFixed(4)
|
|
4471
|
+
] }),
|
|
4472
|
+
event.duration_ms != null && /* @__PURE__ */ jsxs("span", { children: [
|
|
4473
|
+
(Number(event.duration_ms) / 1e3).toFixed(1),
|
|
4474
|
+
"s"
|
|
4475
|
+
] }),
|
|
4476
|
+
event.duration_api_ms != null && /* @__PURE__ */ jsxs("span", { children: [
|
|
4477
|
+
"API: ",
|
|
4478
|
+
(Number(event.duration_api_ms) / 1e3).toFixed(1),
|
|
4479
|
+
"s"
|
|
4480
|
+
] })
|
|
4481
|
+
] })
|
|
4482
|
+
] }, idx);
|
|
4483
|
+
}
|
|
4484
|
+
if (event.type === "error") {
|
|
4485
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-md p-3 bg-red-950 border border-red-800", children: [
|
|
4486
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4487
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm font-semibold text-red-400", children: "Error" }),
|
|
4488
|
+
event.code ? /* @__PURE__ */ jsx("span", { className: "text-xs font-mono text-red-400/70", children: String(event.code) }) : null
|
|
4489
|
+
] }),
|
|
4490
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground mt-1", children: String(event.error ?? "Unknown error") })
|
|
4491
|
+
] }, idx);
|
|
4492
|
+
}
|
|
4493
|
+
if (event.type === "stream_detached") {
|
|
4494
|
+
return /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground italic border-t border-border pt-2", children: [
|
|
4495
|
+
"Stream detached at ",
|
|
4496
|
+
event.timestamp ? new Date(String(event.timestamp)).toLocaleTimeString() : "unknown",
|
|
4497
|
+
" \u2014 run continues in background"
|
|
4498
|
+
] }, idx);
|
|
4499
|
+
}
|
|
4500
|
+
if (event.type === "queued") {
|
|
4501
|
+
return /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Queued\u2026" }, idx);
|
|
4502
|
+
}
|
|
4503
|
+
if (event.type === "sandbox_starting") {
|
|
4504
|
+
return /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: "Starting sandbox\u2026" }, idx);
|
|
4505
|
+
}
|
|
4506
|
+
if (event.type === "run_started") {
|
|
4507
|
+
return /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
|
|
4508
|
+
"Agent started",
|
|
4509
|
+
event.model ? /* @__PURE__ */ jsx("span", { className: "ml-2 font-mono text-foreground/60", children: String(event.model) }) : null,
|
|
4510
|
+
event.mcp_server_count != null && Number(event.mcp_server_count) > 0 && /* @__PURE__ */ jsxs("span", { className: "ml-2", children: [
|
|
4511
|
+
String(event.mcp_server_count),
|
|
4512
|
+
" MCP server",
|
|
4513
|
+
Number(event.mcp_server_count) !== 1 ? "s" : ""
|
|
4514
|
+
] })
|
|
4515
|
+
] }, idx);
|
|
4516
|
+
}
|
|
4517
|
+
if (event.type === "system") {
|
|
4518
|
+
return /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground italic", children: String(event.message ?? JSON.stringify(event)) }, idx);
|
|
4519
|
+
}
|
|
4520
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
4521
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-purple-400 uppercase", children: event.type }),
|
|
4522
|
+
/* @__PURE__ */ jsx(CollapsibleJson, { data: event, maxHeight: "8rem" })
|
|
4523
|
+
] }, idx);
|
|
4524
|
+
}
|
|
4525
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled", "timed_out"]);
|
|
4526
|
+
function PlaygroundPage({ agentId }) {
|
|
4527
|
+
const client = useAgentPlaneClient();
|
|
4528
|
+
const { LinkComponent, basePath } = useNavigation();
|
|
4529
|
+
const { data: agent, error: agentError, isLoading } = useApi(
|
|
4530
|
+
`agent-${agentId}`,
|
|
4531
|
+
(c) => c.agents.get(agentId)
|
|
4532
|
+
);
|
|
4533
|
+
const [prompt, setPrompt] = useState("");
|
|
4534
|
+
const [events, setEvents] = useState([]);
|
|
4535
|
+
const [streamingText, setStreamingText] = useState("");
|
|
4536
|
+
const [running, setRunning] = useState(false);
|
|
4537
|
+
const [polling, setPolling] = useState(false);
|
|
4538
|
+
const [error, setError] = useState(null);
|
|
4539
|
+
const [sessionId, setSessionId] = useState(null);
|
|
4540
|
+
const sessionIdRef = useRef(null);
|
|
4541
|
+
const abortRef = useRef(null);
|
|
4542
|
+
const runIdRef = useRef(null);
|
|
4543
|
+
const streamRef = useRef(null);
|
|
4544
|
+
const scrollRef = useRef(null);
|
|
4545
|
+
const textareaRef = useRef(null);
|
|
4546
|
+
useEffect(() => {
|
|
4547
|
+
const el = scrollRef.current;
|
|
4548
|
+
if (el) el.scrollTop = el.scrollHeight;
|
|
4549
|
+
}, [events, streamingText]);
|
|
4550
|
+
useEffect(() => {
|
|
4551
|
+
return () => {
|
|
4552
|
+
abortRef.current?.abort();
|
|
4553
|
+
streamRef.current?.abort();
|
|
4554
|
+
};
|
|
4555
|
+
}, []);
|
|
4556
|
+
const pollForFinalResult = useCallback(async (runId) => {
|
|
4557
|
+
setPolling(true);
|
|
4558
|
+
let delay = 3e3;
|
|
4559
|
+
const maxDelay = 1e4;
|
|
4560
|
+
try {
|
|
4561
|
+
while (true) {
|
|
4562
|
+
if (abortRef.current?.signal.aborted) break;
|
|
4563
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
4564
|
+
if (abortRef.current?.signal.aborted) break;
|
|
4565
|
+
try {
|
|
4566
|
+
const run = await client.runs.get(runId);
|
|
4567
|
+
if (TERMINAL_STATUSES.has(run.status)) {
|
|
4568
|
+
try {
|
|
4569
|
+
const transcriptEvents = await client.runs.transcriptArray(runId);
|
|
4570
|
+
if (transcriptEvents.length > 0) {
|
|
4571
|
+
const detachIdx = transcriptEvents.findIndex((ev) => ev.type === "stream_detached");
|
|
4572
|
+
const eventsAfterDetach = detachIdx >= 0 ? transcriptEvents.slice(detachIdx + 1) : [];
|
|
4573
|
+
const newEvents = eventsAfterDetach.filter(
|
|
4574
|
+
(ev) => ev.type !== "heartbeat" && ev.type !== "text_delta" && ev.type !== "run_started" && ev.type !== "queued" && ev.type !== "sandbox_starting"
|
|
4575
|
+
);
|
|
4576
|
+
if (newEvents.length > 0) {
|
|
4577
|
+
setEvents((prev) => [...prev, ...newEvents]);
|
|
4578
|
+
}
|
|
4579
|
+
}
|
|
4580
|
+
} catch {
|
|
4581
|
+
}
|
|
4582
|
+
setEvents((prev) => {
|
|
4583
|
+
if (prev.some((ev) => ev.type === "result")) return prev;
|
|
4584
|
+
const syntheticResult = {
|
|
4585
|
+
type: "result",
|
|
4586
|
+
subtype: run.status === "completed" ? "success" : "failed",
|
|
4587
|
+
cost_usd: run.cost_usd,
|
|
4588
|
+
num_turns: run.num_turns,
|
|
4589
|
+
duration_ms: run.duration_ms
|
|
4590
|
+
};
|
|
4591
|
+
if (run.error_type) {
|
|
4592
|
+
syntheticResult.result = run.error_type;
|
|
4593
|
+
}
|
|
4594
|
+
return [...prev, syntheticResult];
|
|
4595
|
+
});
|
|
4596
|
+
break;
|
|
4597
|
+
}
|
|
4598
|
+
delay = Math.min(delay * 2, maxDelay);
|
|
4599
|
+
} catch (err) {
|
|
4600
|
+
if (err?.name === "AbortError") break;
|
|
4601
|
+
delay = Math.min(delay * 2, maxDelay);
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
} finally {
|
|
4605
|
+
setPolling(false);
|
|
4606
|
+
setRunning(false);
|
|
4607
|
+
abortRef.current = null;
|
|
4608
|
+
runIdRef.current = null;
|
|
4609
|
+
streamRef.current = null;
|
|
4610
|
+
}
|
|
4611
|
+
}, [client]);
|
|
4612
|
+
const consumeStream = useCallback(async (stream) => {
|
|
4613
|
+
streamRef.current = stream;
|
|
4614
|
+
let handedOffToPoll = false;
|
|
4615
|
+
try {
|
|
4616
|
+
for await (const event of stream) {
|
|
4617
|
+
const ev = event;
|
|
4618
|
+
if (ev.type === "session_created" && ev.session_id) {
|
|
4619
|
+
const sid = ev.session_id;
|
|
4620
|
+
sessionIdRef.current = sid;
|
|
4621
|
+
setSessionId(sid);
|
|
4622
|
+
}
|
|
4623
|
+
if (ev.type === "run_started" && ev.run_id) {
|
|
4624
|
+
runIdRef.current = ev.run_id;
|
|
4625
|
+
}
|
|
4626
|
+
if (ev.type === "text_delta") {
|
|
4627
|
+
setStreamingText((prev) => prev + (ev.text ?? ""));
|
|
4628
|
+
} else if (ev.type === "stream_detached") {
|
|
4629
|
+
setStreamingText("");
|
|
4630
|
+
setEvents((prev) => [...prev, ev]);
|
|
4631
|
+
if (runIdRef.current) {
|
|
4632
|
+
handedOffToPoll = true;
|
|
4633
|
+
pollForFinalResult(runIdRef.current);
|
|
4634
|
+
return;
|
|
4635
|
+
}
|
|
4636
|
+
} else {
|
|
4637
|
+
if (ev.type === "assistant") setStreamingText("");
|
|
4638
|
+
setEvents((prev) => [...prev, ev]);
|
|
4639
|
+
}
|
|
4640
|
+
}
|
|
4641
|
+
} finally {
|
|
4642
|
+
if (!handedOffToPoll) {
|
|
4643
|
+
setRunning(false);
|
|
4644
|
+
abortRef.current = null;
|
|
4645
|
+
runIdRef.current = null;
|
|
4646
|
+
streamRef.current = null;
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
}, [pollForFinalResult]);
|
|
4650
|
+
const handleSend = useCallback(async () => {
|
|
4651
|
+
if (!prompt.trim() || running) return;
|
|
4652
|
+
const messageText = prompt.trim();
|
|
4653
|
+
setPrompt("");
|
|
4654
|
+
setRunning(true);
|
|
4655
|
+
setStreamingText("");
|
|
4656
|
+
setError(null);
|
|
4657
|
+
setPolling(false);
|
|
4658
|
+
setEvents((prev) => [...prev, { type: "user_message", text: messageText }]);
|
|
4659
|
+
const abort = new AbortController();
|
|
4660
|
+
abortRef.current = abort;
|
|
4661
|
+
try {
|
|
4662
|
+
let stream;
|
|
4663
|
+
const currentSessionId = sessionIdRef.current;
|
|
4664
|
+
if (currentSessionId) {
|
|
4665
|
+
stream = await client.sessions.sendMessage(
|
|
4666
|
+
currentSessionId,
|
|
4667
|
+
{ prompt: messageText },
|
|
4668
|
+
{ signal: abort.signal }
|
|
4669
|
+
);
|
|
4670
|
+
} else {
|
|
4671
|
+
stream = await client.sessions.create(
|
|
4672
|
+
{ agent_id: agentId, prompt: messageText },
|
|
4673
|
+
{ signal: abort.signal }
|
|
4674
|
+
);
|
|
4675
|
+
}
|
|
4676
|
+
await consumeStream(stream);
|
|
4677
|
+
} catch (err) {
|
|
4678
|
+
if (err?.name !== "AbortError") {
|
|
4679
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
4680
|
+
setError(msg);
|
|
4681
|
+
}
|
|
4682
|
+
setRunning(false);
|
|
4683
|
+
abortRef.current = null;
|
|
4684
|
+
runIdRef.current = null;
|
|
4685
|
+
streamRef.current = null;
|
|
4686
|
+
}
|
|
4687
|
+
}, [prompt, running, agentId, client, consumeStream]);
|
|
4688
|
+
function handleNewChat() {
|
|
4689
|
+
abortRef.current?.abort();
|
|
4690
|
+
streamRef.current?.abort();
|
|
4691
|
+
if (sessionId) {
|
|
4692
|
+
client.sessions.stop(sessionId).catch(() => {
|
|
4693
|
+
});
|
|
4694
|
+
}
|
|
4695
|
+
sessionIdRef.current = null;
|
|
4696
|
+
setSessionId(null);
|
|
4697
|
+
setEvents([]);
|
|
4698
|
+
setStreamingText("");
|
|
4699
|
+
setRunning(false);
|
|
4700
|
+
setPolling(false);
|
|
4701
|
+
setError(null);
|
|
4702
|
+
setPrompt("");
|
|
4703
|
+
runIdRef.current = null;
|
|
4704
|
+
abortRef.current = null;
|
|
4705
|
+
streamRef.current = null;
|
|
4706
|
+
textareaRef.current?.focus();
|
|
4707
|
+
}
|
|
4708
|
+
function handleStop() {
|
|
4709
|
+
abortRef.current?.abort();
|
|
4710
|
+
streamRef.current?.abort();
|
|
4711
|
+
const id = runIdRef.current;
|
|
4712
|
+
if (id) {
|
|
4713
|
+
runIdRef.current = null;
|
|
4714
|
+
client.runs.cancel(id).catch(() => {
|
|
4715
|
+
});
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4718
|
+
if (isLoading) {
|
|
4719
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-[calc(100vh-6rem)]", children: [
|
|
4720
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
4721
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-24" }),
|
|
4722
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-40" })
|
|
4723
|
+
] }),
|
|
4724
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "flex-1 rounded-lg" }),
|
|
4725
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-4 space-y-2", children: [
|
|
4726
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-24 w-full rounded-lg" }),
|
|
4727
|
+
/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })
|
|
4728
|
+
] })
|
|
4729
|
+
] });
|
|
4730
|
+
}
|
|
4731
|
+
if (agentError || !agent) {
|
|
4732
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center justify-center h-[calc(100vh-6rem)] gap-3", children: [
|
|
4733
|
+
/* @__PURE__ */ jsx("p", { className: "text-destructive text-sm", children: agentError?.status === 404 ? "Agent not found." : `Failed to load agent: ${agentError?.message ?? "Unknown error"}` }),
|
|
4734
|
+
/* @__PURE__ */ jsx(
|
|
4735
|
+
LinkComponent,
|
|
4736
|
+
{
|
|
4737
|
+
href: `${basePath}/agents`,
|
|
4738
|
+
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
4739
|
+
children: "\u2190 Back to agents"
|
|
4740
|
+
}
|
|
4741
|
+
)
|
|
4742
|
+
] });
|
|
4743
|
+
}
|
|
4744
|
+
const hasContent = events.length > 0 || running;
|
|
4745
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-[calc(100vh-6rem)]", children: [
|
|
4746
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 mb-4", children: [
|
|
4747
|
+
/* @__PURE__ */ jsxs(
|
|
4748
|
+
LinkComponent,
|
|
4749
|
+
{
|
|
4750
|
+
href: `${basePath}/agents/${agentId}`,
|
|
4751
|
+
className: "text-sm text-muted-foreground hover:text-foreground",
|
|
4752
|
+
children: [
|
|
4753
|
+
"\u2190 ",
|
|
4754
|
+
agent.name
|
|
4755
|
+
]
|
|
4756
|
+
}
|
|
4757
|
+
),
|
|
4758
|
+
(sessionId || events.length > 0) && /* @__PURE__ */ jsx(Button, { onClick: handleNewChat, variant: "outline", size: "sm", disabled: running, children: "New Chat" }),
|
|
4759
|
+
sessionId && /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground font-mono", children: [
|
|
4760
|
+
"Session: ",
|
|
4761
|
+
sessionId.slice(0, 12),
|
|
4762
|
+
"\u2026"
|
|
4763
|
+
] })
|
|
4764
|
+
] }),
|
|
4765
|
+
hasContent && /* @__PURE__ */ jsxs("div", { ref: scrollRef, className: "flex-1 min-h-0 overflow-y-auto rounded-lg border border-border bg-muted/20 p-4 space-y-4 mb-4", children: [
|
|
4766
|
+
events.map((ev, i) => renderEvent(ev, i)),
|
|
4767
|
+
streamingText && /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
4768
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-blue-400 uppercase", children: "Assistant" }),
|
|
4769
|
+
/* @__PURE__ */ jsx(MarkdownContent, { children: streamingText }),
|
|
4770
|
+
/* @__PURE__ */ jsx("span", { className: "inline-block w-0.5 h-4 bg-foreground animate-pulse align-text-bottom" })
|
|
4771
|
+
] }),
|
|
4772
|
+
running && !streamingText && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
|
|
4773
|
+
/* @__PURE__ */ jsx("span", { className: "animate-pulse", children: "\u25CF" }),
|
|
4774
|
+
" ",
|
|
4775
|
+
polling ? "Reconnected, streaming updates\u2026" : "Running\u2026"
|
|
4776
|
+
] })
|
|
4777
|
+
] }),
|
|
4778
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 shrink-0", children: [
|
|
4779
|
+
error && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: error }),
|
|
4780
|
+
/* @__PURE__ */ jsx(
|
|
4781
|
+
Textarea,
|
|
4782
|
+
{
|
|
4783
|
+
ref: textareaRef,
|
|
4784
|
+
placeholder: sessionId ? "Send a follow-up message\u2026" : "Enter your prompt\u2026",
|
|
4785
|
+
value: prompt,
|
|
4786
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
4787
|
+
rows: hasContent ? 3 : 12,
|
|
4788
|
+
disabled: running,
|
|
4789
|
+
className: "font-mono text-sm resize-none",
|
|
4790
|
+
onKeyDown: (e) => {
|
|
4791
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) handleSend();
|
|
4792
|
+
}
|
|
4793
|
+
}
|
|
4794
|
+
),
|
|
4795
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
4796
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleSend, disabled: running || !prompt.trim(), size: "sm", children: running ? "Running\u2026" : sessionId ? "Send" : "Run" }),
|
|
4797
|
+
running && /* @__PURE__ */ jsx(Button, { onClick: handleStop, variant: "outline", size: "sm", children: "Stop" }),
|
|
4798
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground ml-1", children: "\u2318+Enter to send" })
|
|
4799
|
+
] })
|
|
4800
|
+
] })
|
|
4801
|
+
] });
|
|
4802
|
+
}
|
|
4373
4803
|
|
|
4374
|
-
export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, ConfirmDialog, CopyButton, DashboardPage, DetailPageHeader, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, EmptyRow, FormError, FormField, LocalDate, McpServerListPage, MetricCard, ModelSelector, PaginationBar, PluginDetailPage, PluginMarketplaceDetailPage, PluginMarketplaceListPage, RunDetailPage, RunListPage, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, Tabs, Textarea, Th, ToolkitMultiselect, TranscriptViewer, parsePaginationParams };
|
|
4804
|
+
export { AdminTable, AdminTableHead, AdminTableRow, AgentA2aInfo, AgentConnectorsManager, AgentDetailPage, AgentEditForm, AgentListPage, AgentPluginManager, AgentRuns, AgentScheduleForm, AgentSkillManager, ConfirmDialog, CopyButton, DashboardPage, DetailPageHeader, Dialog, DialogBody, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, EmptyRow, FormError, FormField, LocalDate, McpServerListPage, MetricCard, ModelSelector, PaginationBar, PlaygroundPage, PluginDetailPage, PluginMarketplaceDetailPage, PluginMarketplaceListPage, RunDetailPage, RunListPage, RunSourceBadge, RunStatusBadge, SectionHeader, Select, SettingsPage, Tabs, Textarea, Th, ToolkitMultiselect, TranscriptViewer, parsePaginationParams };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@getcatalystiq/agent-plane-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Embeddable React component library for AgentPlane",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -61,12 +61,16 @@
|
|
|
61
61
|
"react-dom": "^18.0.0 || ^19.0.0",
|
|
62
62
|
"react-markdown": "^9.0.0",
|
|
63
63
|
"recharts": "^2.0.0",
|
|
64
|
+
"remark-gfm": "^4.0.0",
|
|
64
65
|
"swr": "^2.0.0"
|
|
65
66
|
},
|
|
66
67
|
"peerDependenciesMeta": {
|
|
67
68
|
"react-markdown": {
|
|
68
69
|
"optional": true
|
|
69
70
|
},
|
|
71
|
+
"remark-gfm": {
|
|
72
|
+
"optional": true
|
|
73
|
+
},
|
|
70
74
|
"recharts": {
|
|
71
75
|
"optional": true
|
|
72
76
|
},
|
|
@@ -96,6 +100,7 @@
|
|
|
96
100
|
"devDependencies": {
|
|
97
101
|
"@types/react": "^19",
|
|
98
102
|
"@types/react-dom": "^19",
|
|
103
|
+
"remark-gfm": "^4.0.1",
|
|
99
104
|
"swr": "^2.0.0",
|
|
100
105
|
"tsup": "^8",
|
|
101
106
|
"typescript": "^5"
|