@tetherto/mdk-ui-agent 0.0.0 → 0.12.1

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.
Files changed (217) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +310 -0
  3. package/dist/branding.d.ts +36 -0
  4. package/dist/branding.d.ts.map +1 -0
  5. package/dist/branding.js +37 -0
  6. package/dist/branding.js.map +1 -0
  7. package/dist/components/approval-card.d.ts +46 -0
  8. package/dist/components/approval-card.d.ts.map +1 -0
  9. package/dist/components/approval-card.js +84 -0
  10. package/dist/components/approval-card.js.map +1 -0
  11. package/dist/components/assistant-message.d.ts +25 -0
  12. package/dist/components/assistant-message.d.ts.map +1 -0
  13. package/dist/components/assistant-message.js +49 -0
  14. package/dist/components/assistant-message.js.map +1 -0
  15. package/dist/components/co-pilot-panel.d.ts +17 -0
  16. package/dist/components/co-pilot-panel.d.ts.map +1 -0
  17. package/dist/components/co-pilot-panel.js +33 -0
  18. package/dist/components/co-pilot-panel.js.map +1 -0
  19. package/dist/components/code-block.d.ts +17 -0
  20. package/dist/components/code-block.d.ts.map +1 -0
  21. package/dist/components/code-block.js +40 -0
  22. package/dist/components/code-block.js.map +1 -0
  23. package/dist/components/collapsible-answer.d.ts +26 -0
  24. package/dist/components/collapsible-answer.d.ts.map +1 -0
  25. package/dist/components/collapsible-answer.js +30 -0
  26. package/dist/components/collapsible-answer.js.map +1 -0
  27. package/dist/components/composer.d.ts +31 -0
  28. package/dist/components/composer.d.ts.map +1 -0
  29. package/dist/components/composer.js +82 -0
  30. package/dist/components/composer.js.map +1 -0
  31. package/dist/components/conversation-list.d.ts +21 -0
  32. package/dist/components/conversation-list.d.ts.map +1 -0
  33. package/dist/components/conversation-list.js +42 -0
  34. package/dist/components/conversation-list.js.map +1 -0
  35. package/dist/components/icons.d.ts +88 -0
  36. package/dist/components/icons.d.ts.map +1 -0
  37. package/dist/components/icons.js +112 -0
  38. package/dist/components/icons.js.map +1 -0
  39. package/dist/components/launcher-fab.d.ts +8 -0
  40. package/dist/components/launcher-fab.d.ts.map +1 -0
  41. package/dist/components/launcher-fab.js +6 -0
  42. package/dist/components/launcher-fab.js.map +1 -0
  43. package/dist/components/leaked-tool-call-notice.d.ts +18 -0
  44. package/dist/components/leaked-tool-call-notice.d.ts.map +1 -0
  45. package/dist/components/leaked-tool-call-notice.js +14 -0
  46. package/dist/components/leaked-tool-call-notice.js.map +1 -0
  47. package/dist/components/markdown-link.d.ts +17 -0
  48. package/dist/components/markdown-link.d.ts.map +1 -0
  49. package/dist/components/markdown-link.js +18 -0
  50. package/dist/components/markdown-link.js.map +1 -0
  51. package/dist/components/markdown-text.d.ts +26 -0
  52. package/dist/components/markdown-text.d.ts.map +1 -0
  53. package/dist/components/markdown-text.js +32 -0
  54. package/dist/components/markdown-text.js.map +1 -0
  55. package/dist/components/message-list.d.ts +24 -0
  56. package/dist/components/message-list.d.ts.map +1 -0
  57. package/dist/components/message-list.js +92 -0
  58. package/dist/components/message-list.js.map +1 -0
  59. package/dist/components/no-tools-note.d.ts +26 -0
  60. package/dist/components/no-tools-note.d.ts.map +1 -0
  61. package/dist/components/no-tools-note.js +27 -0
  62. package/dist/components/no-tools-note.js.map +1 -0
  63. package/dist/components/panel-header.d.ts +26 -0
  64. package/dist/components/panel-header.d.ts.map +1 -0
  65. package/dist/components/panel-header.js +13 -0
  66. package/dist/components/panel-header.js.map +1 -0
  67. package/dist/components/rehype-highlight-subset.d.ts +17 -0
  68. package/dist/components/rehype-highlight-subset.d.ts.map +1 -0
  69. package/dist/components/rehype-highlight-subset.js +77 -0
  70. package/dist/components/rehype-highlight-subset.js.map +1 -0
  71. package/dist/components/system-message.d.ts +15 -0
  72. package/dist/components/system-message.d.ts.map +1 -0
  73. package/dist/components/system-message.js +12 -0
  74. package/dist/components/system-message.js.map +1 -0
  75. package/dist/components/tool-chip.d.ts +19 -0
  76. package/dist/components/tool-chip.d.ts.map +1 -0
  77. package/dist/components/tool-chip.js +32 -0
  78. package/dist/components/tool-chip.js.map +1 -0
  79. package/dist/components/user-message.d.ts +9 -0
  80. package/dist/components/user-message.d.ts.map +1 -0
  81. package/dist/components/user-message.js +7 -0
  82. package/dist/components/user-message.js.map +1 -0
  83. package/dist/core/conversation-store.d.ts +107 -0
  84. package/dist/core/conversation-store.d.ts.map +1 -0
  85. package/dist/core/conversation-store.js +254 -0
  86. package/dist/core/conversation-store.js.map +1 -0
  87. package/dist/core/error-text.d.ts +19 -0
  88. package/dist/core/error-text.d.ts.map +1 -0
  89. package/dist/core/error-text.js +35 -0
  90. package/dist/core/error-text.js.map +1 -0
  91. package/dist/core/events.d.ts +98 -0
  92. package/dist/core/events.d.ts.map +1 -0
  93. package/dist/core/events.js +50 -0
  94. package/dist/core/events.js.map +1 -0
  95. package/dist/core/format.d.ts +23 -0
  96. package/dist/core/format.d.ts.map +1 -0
  97. package/dist/core/format.js +49 -0
  98. package/dist/core/format.js.map +1 -0
  99. package/dist/core/index.d.ts +27 -0
  100. package/dist/core/index.d.ts.map +1 -0
  101. package/dist/core/index.js +20 -0
  102. package/dist/core/index.js.map +1 -0
  103. package/dist/core/markdown.d.ts +26 -0
  104. package/dist/core/markdown.d.ts.map +1 -0
  105. package/dist/core/markdown.js +49 -0
  106. package/dist/core/markdown.js.map +1 -0
  107. package/dist/core/prose.d.ts +27 -0
  108. package/dist/core/prose.d.ts.map +1 -0
  109. package/dist/core/prose.js +79 -0
  110. package/dist/core/prose.js.map +1 -0
  111. package/dist/core/small-talk.d.ts +15 -0
  112. package/dist/core/small-talk.d.ts.map +1 -0
  113. package/dist/core/small-talk.js +42 -0
  114. package/dist/core/small-talk.js.map +1 -0
  115. package/dist/core/sse.d.ts +108 -0
  116. package/dist/core/sse.d.ts.map +1 -0
  117. package/dist/core/sse.js +236 -0
  118. package/dist/core/sse.js.map +1 -0
  119. package/dist/core/tool-label.d.ts +16 -0
  120. package/dist/core/tool-label.d.ts.map +1 -0
  121. package/dist/core/tool-label.js +31 -0
  122. package/dist/core/tool-label.js.map +1 -0
  123. package/dist/core/transport.d.ts +71 -0
  124. package/dist/core/transport.d.ts.map +1 -0
  125. package/dist/core/transport.js +147 -0
  126. package/dist/core/transport.js.map +1 -0
  127. package/dist/core/turn.d.ts +87 -0
  128. package/dist/core/turn.d.ts.map +1 -0
  129. package/dist/core/turn.js +232 -0
  130. package/dist/core/turn.js.map +1 -0
  131. package/dist/core/uuid.d.ts +21 -0
  132. package/dist/core/uuid.d.ts.map +1 -0
  133. package/dist/core/uuid.js +54 -0
  134. package/dist/core/uuid.js.map +1 -0
  135. package/dist/entries/chat-page.d.ts +28 -0
  136. package/dist/entries/chat-page.d.ts.map +1 -0
  137. package/dist/entries/chat-page.js +25 -0
  138. package/dist/entries/chat-page.js.map +1 -0
  139. package/dist/entries/co-pilot.d.ts +41 -0
  140. package/dist/entries/co-pilot.d.ts.map +1 -0
  141. package/dist/entries/co-pilot.js +39 -0
  142. package/dist/entries/co-pilot.js.map +1 -0
  143. package/dist/entries/lazy-panel.d.ts +15 -0
  144. package/dist/entries/lazy-panel.d.ts.map +1 -0
  145. package/dist/entries/lazy-panel.js +19 -0
  146. package/dist/entries/lazy-panel.js.map +1 -0
  147. package/dist/hooks/index.d.ts +7 -0
  148. package/dist/hooks/index.d.ts.map +1 -0
  149. package/dist/hooks/index.js +4 -0
  150. package/dist/hooks/index.js.map +1 -0
  151. package/dist/hooks/use-agent-chat.d.ts +46 -0
  152. package/dist/hooks/use-agent-chat.d.ts.map +1 -0
  153. package/dist/hooks/use-agent-chat.js +288 -0
  154. package/dist/hooks/use-agent-chat.js.map +1 -0
  155. package/dist/hooks/use-agent-config.d.ts +29 -0
  156. package/dist/hooks/use-agent-config.d.ts.map +1 -0
  157. package/dist/hooks/use-agent-config.js +45 -0
  158. package/dist/hooks/use-agent-config.js.map +1 -0
  159. package/dist/hooks/use-conversations.d.ts +19 -0
  160. package/dist/hooks/use-conversations.d.ts.map +1 -0
  161. package/dist/hooks/use-conversations.js +19 -0
  162. package/dist/hooks/use-conversations.js.map +1 -0
  163. package/dist/index.d.ts +28 -0
  164. package/dist/index.d.ts.map +1 -0
  165. package/dist/index.js +26 -0
  166. package/dist/index.js.map +1 -0
  167. package/dist/styles.css +1 -0
  168. package/package.json +105 -1
  169. package/src/branding.ts +40 -0
  170. package/src/components/approval-card.tsx +141 -0
  171. package/src/components/assistant-message.tsx +140 -0
  172. package/src/components/co-pilot-panel.tsx +109 -0
  173. package/src/components/code-block.tsx +63 -0
  174. package/src/components/collapsible-answer.tsx +55 -0
  175. package/src/components/composer.tsx +147 -0
  176. package/src/components/conversation-list.tsx +141 -0
  177. package/src/components/icons.tsx +189 -0
  178. package/src/components/launcher-fab.tsx +16 -0
  179. package/src/components/leaked-tool-call-notice.tsx +29 -0
  180. package/src/components/markdown-link.tsx +30 -0
  181. package/src/components/markdown-text.tsx +58 -0
  182. package/src/components/message-list.tsx +164 -0
  183. package/src/components/no-tools-note.tsx +33 -0
  184. package/src/components/panel-header.tsx +86 -0
  185. package/src/components/rehype-highlight-subset.ts +84 -0
  186. package/src/components/system-message.tsx +19 -0
  187. package/src/components/tool-chip.tsx +58 -0
  188. package/src/components/user-message.tsx +18 -0
  189. package/src/core/conversation-store.ts +342 -0
  190. package/src/core/error-text.ts +36 -0
  191. package/src/core/events.ts +127 -0
  192. package/src/core/format.ts +59 -0
  193. package/src/core/index.ts +115 -0
  194. package/src/core/markdown.ts +52 -0
  195. package/src/core/prose.ts +78 -0
  196. package/src/core/small-talk.ts +45 -0
  197. package/src/core/sse.ts +269 -0
  198. package/src/core/tool-label.ts +33 -0
  199. package/src/core/transport.ts +208 -0
  200. package/src/core/turn.ts +299 -0
  201. package/src/core/uuid.ts +59 -0
  202. package/src/entries/chat-page.tsx +56 -0
  203. package/src/entries/co-pilot.tsx +84 -0
  204. package/src/entries/lazy-panel.tsx +19 -0
  205. package/src/hooks/index.ts +8 -0
  206. package/src/hooks/use-agent-chat.ts +387 -0
  207. package/src/hooks/use-agent-config.ts +70 -0
  208. package/src/hooks/use-conversations.ts +39 -0
  209. package/src/index.ts +30 -0
  210. package/src/styles/_approval.scss +68 -0
  211. package/src/styles/_composer.scss +45 -0
  212. package/src/styles/_conversations.scss +160 -0
  213. package/src/styles/_messages.scss +444 -0
  214. package/src/styles/_mixins.scss +27 -0
  215. package/src/styles/_panel.scss +147 -0
  216. package/src/styles/_tokens.scss +30 -0
  217. package/src/styles.scss +16 -0
@@ -0,0 +1,84 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@tetherto/mdk-react-devkit/primitives';
3
+ import isNil from 'lodash/isNil';
4
+ import { AGENT_LABELS } from '../branding';
5
+ import { humanizeToolName, toolLabel } from '../core/tool-label';
6
+ /** Args the reference site tools use to name their target, most specific first. */
7
+ const TARGET_KEYS = ['ref', 'deviceId', 'device', 'id', 'name'];
8
+ /**
9
+ * Friendlier names for argument keys the reference tools use.
10
+ *
11
+ * `action` matters most: without it the card shows two rows both labelled
12
+ * "Action" — the tool itself, and the tool's `action` argument — which is what
13
+ * the design calls "Command". Anything not listed is humanized from its key.
14
+ */
15
+ const ARG_LABELS = {
16
+ action: 'Command',
17
+ mode: 'Mode',
18
+ family: 'Family',
19
+ state: 'State',
20
+ };
21
+ /** Shown for an argument the tool declared but sent no value for. */
22
+ const EMPTY_VALUE = '—';
23
+ const describeValue = (value) => {
24
+ if (isNil(value))
25
+ return EMPTY_VALUE;
26
+ if (typeof value === 'string')
27
+ return value;
28
+ if (typeof value === 'number' || typeof value === 'boolean')
29
+ return String(value);
30
+ return JSON.stringify(value);
31
+ };
32
+ /**
33
+ * Flattens the tool args into the Action / Device / Command rows the design
34
+ * shows.
35
+ *
36
+ * Tools are supplied by whichever MCP server the operator points the agent at,
37
+ * so no argument name is guaranteed. The target is looked up across the names
38
+ * the reference tools use and everything else is listed as-is, which degrades to
39
+ * a plain key/value dump for an unknown tool rather than to nothing.
40
+ */
41
+ export function describeApproval(approval, labels) {
42
+ const rows = [{ label: 'Action', value: toolLabel(approval.name, labels) }];
43
+ const targetKey = TARGET_KEYS.find((key) => key in approval.args);
44
+ if (targetKey)
45
+ rows.push({ label: 'Device', value: describeValue(approval.args[targetKey]) });
46
+ for (const [key, value] of Object.entries(approval.args)) {
47
+ if (key === targetKey)
48
+ continue;
49
+ rows.push({ label: ARG_LABELS[key] ?? humanizeToolName(key), value: describeValue(value) });
50
+ }
51
+ return rows;
52
+ }
53
+ /**
54
+ * The one-line "here is what you are about to allow", shown above the card.
55
+ *
56
+ * Synthesized rather than streamed: `pending_approval` arrives between a
57
+ * `tool_call` and its `tool_result`, and the model does not emit a single token
58
+ * until after the tool returns — so at the moment the operator is asked to
59
+ * decide, the agent has said nothing at all. The design shows a sentence there,
60
+ * and it has to be built from the call itself.
61
+ */
62
+ export function describeApprovalIntent(approval, labels) {
63
+ const action = toolLabel(approval.name, labels).toLowerCase();
64
+ const targetKey = TARGET_KEYS.find((key) => key in approval.args);
65
+ const target = targetKey ? describeValue(approval.args[targetKey]) : null;
66
+ return target
67
+ ? `This runs ${action} on ${target}. Review and approve to proceed.`
68
+ : `This runs ${action}. Review and approve to proceed.`;
69
+ }
70
+ /**
71
+ * The inline approval prompt. The stream is paused behind this.
72
+ *
73
+ * Rendered in the transcript rather than as a blocking modal, because it is not
74
+ * always the operator who resolves it: an approval left unanswered for
75
+ * `agent.approvalTimeoutMs` is auto-rejected server-side and the stream resumes
76
+ * on its own. The card must be able to disappear because the turn moved on — a
77
+ * modal that only closes on click would strand the operator on a dead prompt.
78
+ * Unmounting is driven by the reducer clearing `pendingApproval`.
79
+ */
80
+ export const ApprovalCard = ({ approval, toolLabels, pending = false, onDecide, }) => {
81
+ const rows = describeApproval(approval, toolLabels);
82
+ return (_jsxs("section", { className: "mdk-agent-approval", "aria-label": AGENT_LABELS.approvalRequired, children: [_jsx("h3", { className: "mdk-agent-approval__title", children: AGENT_LABELS.approvalRequired }), _jsx("dl", { className: "mdk-agent-approval__details", children: rows.map((row) => (_jsxs("div", { className: "mdk-agent-approval__row", children: [_jsx("dt", { className: "mdk-agent-approval__label", children: row.label }), _jsx("dd", { className: "mdk-agent-approval__value", children: row.value })] }, row.label))) }), _jsxs("div", { className: "mdk-agent-approval__actions", children: [_jsx(Button, { variant: "outline", size: "sm", disabled: pending, onClick: () => onDecide(false), children: "Reject" }), _jsx(Button, { variant: "primary", size: "sm", loading: pending, disabled: pending, onClick: () => onDecide(true), children: "Approve" })] })] }));
83
+ };
84
+ //# sourceMappingURL=approval-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-card.js","sourceRoot":"","sources":["../../src/components/approval-card.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { JSX } from 'react';
2
+ import type { ToolLabels } from '../core/tool-label';
3
+ import type { PendingApproval, ToolStep } from '../core/turn';
4
+ export type AssistantMessageProps = {
5
+ text: string;
6
+ /** The operator message this answers — only read to decide whether it was a fleet question. */
7
+ question?: string;
8
+ tools?: ToolStep[];
9
+ /** The `error` the turn ended on. A raw `ERR_*` code is mapped before it is shown. */
10
+ error?: string | null;
11
+ /** The turn was stopped before it finished, so this is a part of an answer. */
12
+ interrupted?: boolean;
13
+ /** The turn is still running: render plain text and the thinking indicator. */
14
+ streaming?: boolean;
15
+ toolLabels?: ToolLabels;
16
+ approval?: PendingApproval | null;
17
+ isDecisionPending?: boolean;
18
+ onDecide?: (approved: boolean) => void;
19
+ /** Offered on a failed turn, so the operator does not retype the question. */
20
+ onRetry?: VoidFunction;
21
+ };
22
+ declare const AssistantMessageView: ({ text, question, tools, error, interrupted, streaming, toolLabels, approval, isDecisionPending, onDecide, onRetry, }: AssistantMessageProps) => JSX.Element;
23
+ export declare const AssistantMessage: import("react").MemoExoticComponent<typeof AssistantMessageView>;
24
+ export {};
25
+ //# sourceMappingURL=assistant-message.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistant-message.d.ts","sourceRoot":"","sources":["../../src/components/assistant-message.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAGhC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAW7D,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,QAAQ,EAAE,CAAA;IAClB,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,QAAQ,CAAC,EAAE,eAAe,GAAG,IAAI,CAAA;IACjC,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,8EAA8E;IAC9E,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB,CAAA;AAED,QAAA,MAAM,oBAAoB,0HAYvB,qBAAqB,KAAG,GAAG,CAAC,OA0F9B,CAAA;AAED,eAAO,MAAM,gBAAgB,kEAA6B,CAAA"}
@@ -0,0 +1,49 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Loader } from '@tetherto/mdk-react-devkit/primitives';
3
+ import { memo, useMemo } from 'react';
4
+ import { AGENT_LABELS } from '../branding';
5
+ import { describeAgentError } from '../core/error-text';
6
+ import { parseLeakedToolCall } from '../core/prose';
7
+ import { isSmallTalk } from '../core/small-talk';
8
+ import { ApprovalCard, describeApprovalIntent } from './approval-card';
9
+ import { CollapsibleAnswer } from './collapsible-answer';
10
+ import { LeakedToolCallNotice } from './leaked-tool-call-notice';
11
+ import { NoToolsNote } from './no-tools-note';
12
+ import { ToolChip } from './tool-chip';
13
+ const AssistantMessageView = ({ text, question = '', tools = [], error = null, interrupted = false, streaming = false, toolLabels, approval = null, isDecisionPending = false, onDecide, onRetry, }) => {
14
+ // Only worth checking once the turn has settled — a partial answer can look
15
+ // like a bare JSON object simply because the rest has not arrived yet.
16
+ const leaked = useMemo(() => (streaming ? null : parseLeakedToolCall(text)), [streaming, text]);
17
+ const hasText = text.trim().length > 0;
18
+ const isThinking = streaming && !hasText && approval === null;
19
+ // The chip for the gated step is suppressed while its card is up: the card
20
+ // already names the action, the device and the command, so the chip would just
21
+ // restate it directly above.
22
+ const chips = approval ? tools.filter((step) => step.id !== approval.toolStepId) : tools;
23
+ // Stated only once the turn has settled — mid-stream the tools may simply not
24
+ // have been called *yet*. A leaked call and an errored turn already say their
25
+ // own thing, so the note would only add noise there. Nor is it said against a
26
+ // greeting: consulting nothing is the right answer to "hey", and the marker
27
+ // was appearing on every one of them.
28
+ const answeredWithoutTools = !streaming
29
+ && tools.length === 0
30
+ && hasText
31
+ && leaked === null
32
+ && !error
33
+ && !isSmallTalk(question);
34
+ return (_jsxs("div", { className: "mdk-agent-message mdk-agent-message--assistant", children: [_jsxs("p", { className: "mdk-agent-message__role", children: [_jsx("span", { className: "mdk-agent-message__dot", "aria-hidden": "true" }), AGENT_LABELS.name, answeredWithoutTools ? _jsx(NoToolsNote, {}) : null] }), chips.length > 0
35
+ ? (_jsx("div", { className: "mdk-agent-message__tools", children: chips.map((step) => (_jsx(ToolChip, { step: step, toolLabels: toolLabels }, step.id))) }))
36
+ : null, approval
37
+ ? (_jsx("p", { className: "mdk-agent-message__intent", children: describeApprovalIntent(approval, toolLabels) }))
38
+ : null, isThinking ? _jsx(Loader, { inline: true, size: 6, count: 3, color: "orange" }) : null, hasText && leaked === null ? _jsx(CollapsibleAnswer, { text: text, streaming: streaming }) : null, hasText && leaked !== null ? _jsx(LeakedToolCallNotice, { call: leaked }) : null, approval && onDecide
39
+ ? (_jsx(ApprovalCard, { approval: approval, toolLabels: toolLabels, pending: isDecisionPending, onDecide: onDecide }))
40
+ : null, interrupted && !error
41
+ ? _jsx("p", { className: "mdk-agent-message__note", children: "Stopped early \u2014 this is not the whole answer." })
42
+ : null, error
43
+ ? (_jsxs("p", { className: "mdk-agent-message__error", role: "alert", children: [describeAgentError(error), onRetry
44
+ ? (_jsx("button", { type: "button", className: "mdk-agent-message__retry", onClick: onRetry, children: "Try again" }))
45
+ : null] }))
46
+ : null] }));
47
+ };
48
+ export const AssistantMessage = memo(AssistantMessageView);
49
+ //# sourceMappingURL=assistant-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assistant-message.js","sourceRoot":"","sources":["../../src/components/assistant-message.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ import type { ToolLabels } from '../core/tool-label';
3
+ import type { UseAgentChatResult } from '../hooks/use-agent-chat';
4
+ export type CoPilotPanelProps = {
5
+ /** The single hook instance. Both entries own one and pass it down. */
6
+ chat: UseAgentChatResult;
7
+ title?: string;
8
+ status?: ReactNode;
9
+ toolLabels?: ToolLabels;
10
+ placeholder?: string;
11
+ /** Omitted by the route page, which has nothing to collapse into. */
12
+ onClose?: VoidFunction | undefined;
13
+ className?: string;
14
+ };
15
+ /** The panel body, shared by the docked overlay and the full-page route. */
16
+ export declare const CoPilotPanel: ({ chat, title, status, toolLabels, placeholder, onClose, className, }: CoPilotPanelProps) => JSX.Element;
17
+ //# sourceMappingURL=co-pilot-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"co-pilot-panel.d.ts","sourceRoot":"","sources":["../../src/components/co-pilot-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAG3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAA;AACpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AASjE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,uEAAuE;IACvE,IAAI,EAAE,kBAAkB,CAAA;IACxB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qEAAqE;IACrE,OAAO,CAAC,EAAE,YAAY,GAAG,SAAS,CAAA;IAClC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,4EAA4E;AAC5E,eAAO,MAAM,YAAY,0EAQtB,iBAAiB,KAAG,GAAG,CAAC,OA0E1B,CAAA"}
@@ -0,0 +1,33 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useState } from 'react';
3
+ import { AGENT_LABELS } from '../branding';
4
+ import { formatConversationSummary } from '../core/format';
5
+ import { Composer } from './composer';
6
+ import { ConversationList } from './conversation-list';
7
+ import { MessageList } from './message-list';
8
+ import { PANEL_VIEW, PanelHeader } from './panel-header';
9
+ /** The panel body, shared by the docked overlay and the full-page route. */
10
+ export const CoPilotPanel = ({ chat, title = AGENT_LABELS.name, status, toolLabels, placeholder, onClose, className, }) => {
11
+ const [view, setView] = useState(PANEL_VIEW.CHAT);
12
+ const toggleConversations = useCallback(() => {
13
+ setView((current) => (current === PANEL_VIEW.CHAT ? PANEL_VIEW.CONVERSATIONS : PANEL_VIEW.CHAT));
14
+ }, []);
15
+ const handleNewConversation = useCallback(() => {
16
+ chat.newConversation();
17
+ setView(PANEL_VIEW.CHAT);
18
+ }, [chat]);
19
+ const handleSelectConversation = useCallback((id) => {
20
+ chat.selectConversation(id);
21
+ setView(PANEL_VIEW.CHAT);
22
+ }, [chat]);
23
+ const isConversations = view === PANEL_VIEW.CONVERSATIONS;
24
+ // The conversations view describes the list rather than the connection — the
25
+ // host-supplied status is about the agent, which is not what is on screen.
26
+ const headerStatus = isConversations
27
+ ? formatConversationSummary(chat.conversations.length, chat.isStreaming)
28
+ : status;
29
+ return (_jsxs("section", { className: `mdk-agent-panel${className ? ` ${className}` : ''}`, "aria-label": title, children: [_jsx(PanelHeader, { view: view, title: isConversations ? AGENT_LABELS.conversations : title, status: headerStatus, actionsDisabled: chat.isStreaming, onNewConversation: handleNewConversation, onToggleConversations: toggleConversations, onClose: onClose }), isConversations
30
+ ? (_jsx(ConversationList, { conversations: chat.conversations, activeId: chat.active?.id ?? null, runningId: chat.isStreaming ? (chat.active?.id ?? null) : null, onSelect: handleSelectConversation, onCreate: handleNewConversation, onDelete: chat.removeConversation }))
31
+ : (_jsxs(_Fragment, { children: [_jsx(MessageList, { messages: chat.messages, live: chat.live, toolLabels: toolLabels, pendingApproval: chat.pendingApproval, isDecisionPending: chat.isDecisionPending, onDecide: chat.decide, onRetry: chat.retry }), _jsx(Composer, { disabled: !chat.canSend, isStreaming: chat.isStreaming, placeholder: placeholder, focusKey: chat.active?.id ?? null, onSend: chat.send, onStop: chat.abort })] }))] }));
32
+ };
33
+ //# sourceMappingURL=co-pilot-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"co-pilot-panel.js","sourceRoot":"","sources":["../../src/components/co-pilot-panel.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { ComponentPropsWithoutRef, JSX } from 'react';
2
+ import type { ExtraProps } from 'react-markdown';
3
+ export type CodeBlockProps = ComponentPropsWithoutRef<'pre'> & ExtraProps;
4
+ /**
5
+ * A fenced code block, with a copy button.
6
+ *
7
+ * What the panel puts in fences is mostly shell commands and JSON an operator
8
+ * wants to run or paste somewhere, so copying it is the common next action.
9
+ *
10
+ * The text is read off the rendered node rather than reassembled from the hast
11
+ * tree: the highlighter has already replaced the block's children with token
12
+ * spans, and `textContent` is exactly the source again. The button is absent
13
+ * where the Clipboard API is — it needs a secure context, and a gateway on a site
14
+ * LAN is served over plain http.
15
+ */
16
+ export declare const CodeBlock: ({ children, node, ...rest }: CodeBlockProps) => JSX.Element;
17
+ //# sourceMappingURL=code-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../../src/components/code-block.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAMhD,MAAM,MAAM,cAAc,GAAG,wBAAwB,CAAC,KAAK,CAAC,GAAG,UAAU,CAAA;AAEzE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,gCAAiC,cAAc,KAAG,GAAG,CAAC,OAyC3E,CAAA"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ /** How long the button confirms the copy before going back to its label. */
4
+ const COPIED_FEEDBACK_MS = 1500;
5
+ /**
6
+ * A fenced code block, with a copy button.
7
+ *
8
+ * What the panel puts in fences is mostly shell commands and JSON an operator
9
+ * wants to run or paste somewhere, so copying it is the common next action.
10
+ *
11
+ * The text is read off the rendered node rather than reassembled from the hast
12
+ * tree: the highlighter has already replaced the block's children with token
13
+ * spans, and `textContent` is exactly the source again. The button is absent
14
+ * where the Clipboard API is — it needs a secure context, and a gateway on a site
15
+ * LAN is served over plain http.
16
+ */
17
+ export const CodeBlock = ({ children, node, ...rest }) => {
18
+ const codeRef = useRef(null);
19
+ const [copied, setCopied] = useState(false);
20
+ const canCopy = typeof navigator?.clipboard?.writeText === 'function';
21
+ useEffect(() => {
22
+ if (!copied)
23
+ return;
24
+ const timer = setTimeout(() => setCopied(false), COPIED_FEEDBACK_MS);
25
+ return () => clearTimeout(timer);
26
+ }, [copied]);
27
+ const copy = () => {
28
+ const text = codeRef.current?.textContent ?? '';
29
+ if (!text)
30
+ return;
31
+ void navigator.clipboard.writeText(text).then(() => setCopied(true), () => {
32
+ // Denied by permissions policy, or the document is not focused. Nothing
33
+ // to report — the code is still on screen and selectable.
34
+ });
35
+ };
36
+ return (_jsxs("div", { className: "mdk-agent-code", children: [_jsx("pre", { ref: codeRef, ...rest, children: children }), canCopy
37
+ ? (_jsx("button", { type: "button", className: "mdk-agent-code__copy", "aria-label": copied ? 'Copied' : 'Copy code', onClick: copy, children: copied ? 'Copied' : 'Copy' }))
38
+ : null] }));
39
+ };
40
+ //# sourceMappingURL=code-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block.js","sourceRoot":"","sources":["../../src/components/code-block.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEnD,4EAA4E;AAC5E,MAAM,kBAAkB,GAAG,IAAI,CAAA;AAI/B;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,IAAI,EAAkB,EAAe,EAAE;IACpF,MAAM,OAAO,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAA;IAC5C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE3C,MAAM,OAAO,GAAG,OAAO,SAAS,EAAE,SAAS,EAAE,SAAS,KAAK,UAAU,CAAA;IAErE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,kBAAkB,CAAC,CAAA;QACpE,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAA;IAEZ,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,EAAE,WAAW,IAAI,EAAE,CAAA;QAC/C,IAAI,CAAC,IAAI;YAAE,OAAM;QACjB,KAAK,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAC3C,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EACrB,GAAG,EAAE;YACH,wEAAwE;YACxE,0DAA0D;QAC5D,CAAC,CACF,CAAA;IACH,CAAC,CAAA;IAED,OAAO,CACL,eAAK,SAAS,EAAC,gBAAgB,aAC7B,cAAK,GAAG,EAAE,OAAO,KAAM,IAAI,YAAG,QAAQ,GAAO,EAC5C,OAAO;gBACN,CAAC,CAAC,CACE,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,sBAAsB,gBACpB,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,EAC3C,OAAO,EAAE,IAAI,YAEZ,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,GACpB,CACV;gBACH,CAAC,CAAC,IAAI,IACJ,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,26 @@
1
+ import type { JSX } from 'react';
2
+ /**
3
+ * Where an answer stops being readable in a docked panel.
4
+ *
5
+ * The panel is 420×640, so a few thousand characters is already several screens
6
+ * of scrolling between one question and the next.
7
+ */
8
+ export declare const COLLAPSE_ABOVE_CHARS = 3000;
9
+ /** How much of it is shown collapsed. */
10
+ export declare const COLLAPSED_CHARS = 1500;
11
+ export type CollapsibleAnswerProps = {
12
+ text: string;
13
+ /** While the turn streams the answer is never collapsed: growth has to stay visible. */
14
+ streaming?: boolean;
15
+ };
16
+ /**
17
+ * An answer, collapsed behind a toggle when it is long enough to bury the rest of
18
+ * the transcript.
19
+ *
20
+ * Only ever collapsed once the turn has settled — mid-stream, hiding the tail
21
+ * would hide the very thing the operator is watching.
22
+ */
23
+ declare const CollapsibleAnswerView: ({ text, streaming }: CollapsibleAnswerProps) => JSX.Element;
24
+ export declare const CollapsibleAnswer: import("react").MemoExoticComponent<typeof CollapsibleAnswerView>;
25
+ export {};
26
+ //# sourceMappingURL=collapsible-answer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collapsible-answer.d.ts","sourceRoot":"","sources":["../../src/components/collapsible-answer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAMhC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,OAAO,CAAA;AACxC,yCAAyC;AACzC,eAAO,MAAM,eAAe,OAAO,CAAA;AAEnC,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;;;;;GAMG;AACH,QAAA,MAAM,qBAAqB,wBAAiC,sBAAsB,KAAG,GAAG,CAAC,OAuBxF,CAAA;AAED,eAAO,MAAM,iBAAiB,mEAA8B,CAAA"}
@@ -0,0 +1,30 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { memo, useState } from 'react';
3
+ import { clipToBoundary } from '../core/markdown';
4
+ import { MarkdownText } from './markdown-text';
5
+ /**
6
+ * Where an answer stops being readable in a docked panel.
7
+ *
8
+ * The panel is 420×640, so a few thousand characters is already several screens
9
+ * of scrolling between one question and the next.
10
+ */
11
+ export const COLLAPSE_ABOVE_CHARS = 3000;
12
+ /** How much of it is shown collapsed. */
13
+ export const COLLAPSED_CHARS = 1500;
14
+ /**
15
+ * An answer, collapsed behind a toggle when it is long enough to bury the rest of
16
+ * the transcript.
17
+ *
18
+ * Only ever collapsed once the turn has settled — mid-stream, hiding the tail
19
+ * would hide the very thing the operator is watching.
20
+ */
21
+ const CollapsibleAnswerView = ({ text, streaming = false }) => {
22
+ const [expanded, setExpanded] = useState(false);
23
+ const isLong = !streaming && text.length > COLLAPSE_ABOVE_CHARS;
24
+ const shown = isLong && !expanded ? clipToBoundary(text, COLLAPSED_CHARS) : text;
25
+ return (_jsxs(_Fragment, { children: [_jsx(MarkdownText, { text: shown, streaming: streaming }), isLong
26
+ ? (_jsx("button", { type: "button", className: "mdk-agent-markdown__more", "aria-expanded": expanded, onClick: () => setExpanded(!expanded), children: expanded ? 'Show less' : 'Show full answer' }))
27
+ : null] }));
28
+ };
29
+ export const CollapsibleAnswer = memo(CollapsibleAnswerView);
30
+ //# sourceMappingURL=collapsible-answer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collapsible-answer.js","sourceRoot":"","sources":["../../src/components/collapsible-answer.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEtC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAA;AACxC,yCAAyC;AACzC,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAA;AAQnC;;;;;;GAMG;AACH,MAAM,qBAAqB,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,GAAG,KAAK,EAA0B,EAAe,EAAE;IACjG,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE/C,MAAM,MAAM,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAA;IAC/D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAEhF,OAAO,CACL,8BACE,KAAC,YAAY,IAAC,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAI,EAClD,MAAM;gBACL,CAAC,CAAC,CACE,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,0BAA0B,mBACrB,QAAQ,EACvB,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,YAEpC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,kBAAkB,GACrC,CACV;gBACH,CAAC,CAAC,IAAI,IACP,CACJ,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,qBAAqB,CAAC,CAAA"}
@@ -0,0 +1,31 @@
1
+ import type { JSX } from 'react';
2
+ export type ComposerProps = {
3
+ disabled?: boolean;
4
+ /**
5
+ * A turn is running. Kept separate from `disabled` — which is about the input —
6
+ * because this swaps Send for Stop, and a composer disabled for any other reason
7
+ * must not offer to stop a turn that is not there.
8
+ */
9
+ isStreaming?: boolean;
10
+ placeholder?: string;
11
+ /**
12
+ * Changing this focuses the input — used when the panel switches conversation,
13
+ * so starting a new one lands the caret where you are about to type. Ignored on
14
+ * first render, so mounting the panel never steals focus from the host page.
15
+ */
16
+ focusKey?: string | number | null;
17
+ onSend: (text: string) => void;
18
+ /** Aborts the running turn. Without it a turn going wrong can only be escaped by reloading. */
19
+ onStop?: VoidFunction;
20
+ };
21
+ /**
22
+ * The input row: auto-growing, Enter sends, Shift+Enter breaks the line.
23
+ *
24
+ * `disabled` is driven by the session being busy, not by a local guard — the
25
+ * gateway allows one turn at a time per session and answers a second POST with
26
+ * a 409, and a turn paused on an approval still counts as busy.
27
+ */
28
+ declare const ComposerView: ({ disabled, isStreaming, placeholder, focusKey, onSend, onStop, }: ComposerProps) => JSX.Element;
29
+ export declare const Composer: import("react").MemoExoticComponent<typeof ComposerView>;
30
+ export {};
31
+ //# sourceMappingURL=composer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../src/components/composer.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,GAAG,EAAiB,MAAM,OAAO,CAAA;AAS1D,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;IACjC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,+FAA+F;IAC/F,MAAM,CAAC,EAAE,YAAY,CAAA;CACtB,CAAA;AAED;;;;;;GAMG;AACH,QAAA,MAAM,YAAY,sEAOf,aAAa,KAAG,GAAG,CAAC,OAoGtB,CAAA;AAED,eAAO,MAAM,QAAQ,0DAAqB,CAAA"}
@@ -0,0 +1,82 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@tetherto/mdk-react-devkit/primitives';
3
+ import { memo, useEffect, useLayoutEffect, useRef, useState } from 'react';
4
+ import { AGENT_LABELS } from '../branding';
5
+ import { SendIcon, StopIcon } from './icons';
6
+ /** Grows with the text up to this, then scrolls. Keeps the panel usable. */
7
+ const MAX_ROWS = 6;
8
+ /**
9
+ * The input row: auto-growing, Enter sends, Shift+Enter breaks the line.
10
+ *
11
+ * `disabled` is driven by the session being busy, not by a local guard — the
12
+ * gateway allows one turn at a time per session and answers a second POST with
13
+ * a 409, and a turn paused on an approval still counts as busy.
14
+ */
15
+ const ComposerView = ({ disabled = false, isStreaming = false, placeholder = AGENT_LABELS.placeholder, focusKey = null, onSend, onStop, }) => {
16
+ const [value, setValue] = useState('');
17
+ const textAreaRef = useRef(null);
18
+ const refocusRef = useRef(false);
19
+ /**
20
+ * Hands focus back when the turn releases the input.
21
+ *
22
+ * Disabling a focused `<textarea>` makes the browser blur it, so without this
23
+ * the caret is gone after every message and the next one needs a click. Armed
24
+ * only by an actual submit, so a turn finishing never steals focus from
25
+ * somewhere else the operator has moved to.
26
+ */
27
+ useEffect(() => {
28
+ if (disabled || !refocusRef.current)
29
+ return;
30
+ refocusRef.current = false;
31
+ textAreaRef.current?.focus();
32
+ }, [disabled]);
33
+ // Focus on a conversation change, but not on the first render — mounting the
34
+ // panel (or a route page) must not pull focus out of whatever the host had.
35
+ const lastFocusKeyRef = useRef(undefined);
36
+ useEffect(() => {
37
+ const previous = lastFocusKeyRef.current;
38
+ lastFocusKeyRef.current = focusKey;
39
+ // `disabled` is a dependency only so the focus lands after the input is
40
+ // usable again; a change to it alone must not count as a conversation
41
+ // switch, or every finished turn would grab focus.
42
+ if (previous === undefined || previous === focusKey || disabled)
43
+ return;
44
+ textAreaRef.current?.focus();
45
+ }, [focusKey, disabled]);
46
+ // The devkit `TextArea` is a plain `<textarea>` with no auto-grow, so the
47
+ // height is measured here: reset first, otherwise scrollHeight only ever
48
+ // grows and the box never shrinks back after a deletion.
49
+ useLayoutEffect(() => {
50
+ const node = textAreaRef.current;
51
+ if (!node)
52
+ return;
53
+ node.style.height = 'auto';
54
+ const lineHeight = Number.parseFloat(globalThis.getComputedStyle(node).lineHeight) || 20;
55
+ node.style.height = `${Math.min(node.scrollHeight, lineHeight * MAX_ROWS)}px`;
56
+ }, [value]);
57
+ const submit = () => {
58
+ const text = value.trim();
59
+ if (!text || disabled)
60
+ return;
61
+ setValue('');
62
+ refocusRef.current = true;
63
+ onSend(text);
64
+ };
65
+ const handleSubmit = (event) => {
66
+ event.preventDefault();
67
+ submit();
68
+ };
69
+ const handleKeyDown = (event) => {
70
+ // `isComposing` guards IME candidate selection, where Enter commits the
71
+ // candidate rather than the message.
72
+ if (event.key !== 'Enter' || event.shiftKey || event.nativeEvent.isComposing)
73
+ return;
74
+ event.preventDefault();
75
+ submit();
76
+ };
77
+ return (_jsxs("form", { className: "mdk-agent-composer", onSubmit: handleSubmit, children: [_jsx("textarea", { ref: textAreaRef, className: "mdk-agent-composer__input", rows: 1, value: value, placeholder: placeholder, "aria-label": AGENT_LABELS.composer, disabled: disabled, onChange: (event) => setValue(event.target.value), onKeyDown: handleKeyDown }), isStreaming && onStop
78
+ ? (_jsx(Button, { type: "button", variant: "primary", className: "mdk-agent-composer__send", "aria-label": "Stop", icon: _jsx(StopIcon, { size: 18 }), onClick: onStop }))
79
+ : (_jsx(Button, { type: "submit", variant: "primary", className: "mdk-agent-composer__send", "aria-label": "Send", disabled: disabled || value.trim().length === 0, icon: _jsx(SendIcon, { size: 18 }) }))] }));
80
+ };
81
+ export const Composer = memo(ComposerView);
82
+ //# sourceMappingURL=composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer.js","sourceRoot":"","sources":["../../src/components/composer.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { JSX } from 'react';
2
+ import type { Conversation } from '../core/conversation-store';
3
+ export type ConversationListProps = {
4
+ conversations: Conversation[];
5
+ activeId: string | null;
6
+ /** The conversation with a turn in flight, if any. */
7
+ runningId?: string | null;
8
+ onSelect: (id: string) => void;
9
+ onCreate: VoidFunction;
10
+ /** Omit to hide the delete affordance entirely. */
11
+ onDelete?: (id: string) => void;
12
+ };
13
+ /**
14
+ * Past conversations, newest first.
15
+ *
16
+ * "Running" is local truth, not server truth: the gateway keeps sessions in
17
+ * memory per process and exposes no way to list them, so the only turn this
18
+ * client can know about is the one it is streaming itself.
19
+ */
20
+ export declare const ConversationList: ({ conversations, activeId, runningId, onSelect, onCreate, onDelete, }: ConversationListProps) => JSX.Element;
21
+ //# sourceMappingURL=conversation-list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-list.d.ts","sourceRoot":"","sources":["../../src/components/conversation-list.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAGhC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAK9D,MAAM,MAAM,qBAAqB,GAAG;IAClC,aAAa,EAAE,YAAY,EAAE,CAAA;IAC7B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;IACvB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,QAAQ,EAAE,YAAY,CAAA;IACtB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAChC,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,0EAO1B,qBAAqB,KAAG,GAAG,CAAC,OA0G9B,CAAA"}
@@ -0,0 +1,42 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@tetherto/mdk-react-devkit/primitives';
3
+ import { useEffect, useState } from 'react';
4
+ import { AGENT_LABELS } from '../branding';
5
+ import { formatConversationMeta } from '../core/format';
6
+ import { MessagePlusIcon, TrashIcon } from './icons';
7
+ /**
8
+ * Past conversations, newest first.
9
+ *
10
+ * "Running" is local truth, not server truth: the gateway keeps sessions in
11
+ * memory per process and exposes no way to list them, so the only turn this
12
+ * client can know about is the one it is streaming itself.
13
+ */
14
+ export const ConversationList = ({ conversations, activeId, runningId = null, onSelect, onCreate, onDelete, }) => {
15
+ // Deleting drops a transcript that exists nowhere else — the gateway keeps no
16
+ // history — so it takes two clicks rather than a modal.
17
+ const [confirmingId, setConfirmingId] = useState(null);
18
+ // A conversation that disappears (deleted elsewhere, or storage cleared) must
19
+ // not leave the row behind it stuck in the confirming state.
20
+ useEffect(() => {
21
+ if (confirmingId && !conversations.some((c) => c.id === confirmingId))
22
+ setConfirmingId(null);
23
+ }, [conversations, confirmingId]);
24
+ return (_jsxs("div", { className: "mdk-agent-conversations", children: [_jsxs("div", { className: "mdk-agent-conversations__scroll", children: [conversations.length === 0
25
+ ? _jsx("p", { className: "mdk-agent-conversations__empty", children: "No conversations yet." })
26
+ : null, conversations.map((conversation) => {
27
+ const isRunning = conversation.id === runningId;
28
+ const isConfirming = conversation.id === confirmingId;
29
+ return (_jsxs("div", { className: `mdk-agent-conversations__row${conversation.id === activeId ? ' mdk-agent-conversations__row--active' : ''}`, children: [_jsxs("button", { type: "button", className: "mdk-agent-conversations__open", onClick: () => onSelect(conversation.id), children: [_jsx("span", { className: "mdk-agent-conversations__title", children: conversation.title }), _jsx("span", { className: "mdk-agent-conversations__meta", children: formatConversationMeta(conversation.updatedAt, conversation.messages.length) })] }), isConfirming
30
+ ? (_jsxs("div", { className: "mdk-agent-conversations__confirm", children: [_jsx("button", { type: "button", className: "mdk-agent-conversations__confirm-yes", onClick: () => {
31
+ setConfirmingId(null);
32
+ onDelete?.(conversation.id);
33
+ }, children: "Delete" }), _jsx("button", { type: "button", className: "mdk-agent-conversations__confirm-no", onClick: () => setConfirmingId(null), children: "Cancel" })] }))
34
+ : (_jsxs(_Fragment, { children: [_jsx("span", { className: `mdk-agent-conversations__badge mdk-agent-conversations__badge--${isRunning ? 'running' : 'idle'}`, children: isRunning ? 'Running' : 'Idle' }), onDelete
35
+ ? (_jsx("button", { type: "button", className: "mdk-agent-conversations__delete",
36
+ // Deleting the conversation whose turn is streaming would
37
+ // strand the open stream with nowhere to write its result.
38
+ disabled: isRunning, "aria-label": `Delete conversation: ${conversation.title}`, onClick: () => setConfirmingId(conversation.id), children: _jsx(TrashIcon, { size: 14 }) }))
39
+ : null] }))] }, conversation.id));
40
+ })] }), _jsx("div", { className: "mdk-agent-conversations__footer", children: _jsx(Button, { variant: "outline", size: "sm", fullWidth: true, icon: _jsx(MessagePlusIcon, { size: 16 }), onClick: onCreate, children: AGENT_LABELS.newConversation }) })] }));
41
+ };
42
+ //# sourceMappingURL=conversation-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation-list.js","sourceRoot":"","sources":["../../src/components/conversation-list.tsx"],"names":[],"mappings":"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"}