@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 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.14",
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"