@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,87 @@
1
+ /**
2
+ * Folds the event stream of one turn into a render model.
3
+ *
4
+ * Pure and synchronous: no fetch, no React, no timers. Every branch here is
5
+ * driven by a contract invariant, so the fixtures in `src/test-utils/fixtures`
6
+ * exercise it directly.
7
+ */
8
+ import type { ToolArgs, WireEvent } from './events';
9
+ export declare const TURN_STATUS: {
10
+ readonly IDLE: 'idle';
11
+ readonly STREAMING: 'streaming';
12
+ readonly AWAITING_APPROVAL: 'awaiting-approval';
13
+ readonly COMPLETE: 'complete';
14
+ readonly ERROR: 'error';
15
+ };
16
+ export type TurnStatus = (typeof TURN_STATUS)[keyof typeof TURN_STATUS];
17
+ export declare const TOOL_STATUS: {
18
+ readonly RUNNING: 'running';
19
+ readonly AWAITING_APPROVAL: 'awaiting-approval';
20
+ readonly OK: 'ok';
21
+ /** Refused — by the operator, or by the approval timing out. Not an error. */
22
+ readonly REJECTED: 'rejected';
23
+ readonly ERROR: 'error';
24
+ /**
25
+ * The turn ended before the tool reported back — an `error` event, a lost
26
+ * connection, or the operator stopping the turn. Whether the tool ran is
27
+ * genuinely unknown, which is why it is neither `ok` nor `error`.
28
+ */
29
+ readonly INTERRUPTED: 'interrupted';
30
+ };
31
+ export type ToolStatus = (typeof TOOL_STATUS)[keyof typeof TOOL_STATUS];
32
+ export declare function isRejectionResult(text: string): boolean;
33
+ export type ToolStep = {
34
+ id: string;
35
+ name: string;
36
+ args: ToolArgs;
37
+ status: ToolStatus;
38
+ /** The tool's answer, once it has one. */
39
+ text?: string;
40
+ /** The call itself failed. */
41
+ isError?: boolean;
42
+ /** The tool answered, but the answer broke its verb's contract. Implies `isError`. */
43
+ contractViolation?: string;
44
+ startedAt: number;
45
+ endedAt?: number;
46
+ /** What renders as `· 0.4s` on the chip. */
47
+ durationMs?: number;
48
+ };
49
+ export type PendingApproval = {
50
+ approvalId: string;
51
+ name: string;
52
+ args: ToolArgs;
53
+ /** The `ToolStep` this approval gates. */
54
+ toolStepId: string;
55
+ at: number;
56
+ };
57
+ export type AgentTurnState = {
58
+ turnId: string | null;
59
+ tools: ToolStep[];
60
+ text: string;
61
+ status: TurnStatus;
62
+ error: string | null;
63
+ pendingApproval: PendingApproval | null;
64
+ usage: Record<string, unknown> | null;
65
+ };
66
+ export declare function createTurnState(): AgentTurnState;
67
+ export declare function isTurnSettled(state: AgentTurnState): boolean;
68
+ /**
69
+ * Ends a turn from outside the event stream: a transport failure, an idle
70
+ * connection, or an unmount. `reduceTurn` handles the producer's own `error`
71
+ * event; this is the same closing-down for the cases that never reach it.
72
+ */
73
+ export declare function failTurn(state: AgentTurnState, error: string, at?: number): AgentTurnState;
74
+ /**
75
+ * Ends a turn the operator stopped. Not an error — they meant it — so whatever
76
+ * streamed is kept and no error is recorded, but an outstanding call is still
77
+ * closed: it did not report back and now never will.
78
+ */
79
+ export declare function abortTurn(state: AgentTurnState, at?: number): AgentTurnState;
80
+ /**
81
+ * Applies one event. Returns a new state; never mutates the one passed in.
82
+ *
83
+ * Unknown event types fall through unchanged (invariant 5) — the caller has
84
+ * usually filtered them already, but this must not throw either way.
85
+ */
86
+ export declare function reduceTurn(state: AgentTurnState, event: WireEvent): AgentTurnState;
87
+ //# sourceMappingURL=turn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../src/core/turn.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAGnD,eAAO,MAAM,WAAW;aACtB,IAAI,EAAE,MAAM;aACZ,SAAS,EAAE,WAAW;aACtB,iBAAiB,EAAE,mBAAmB;aACtC,QAAQ,EAAE,UAAU;aACpB,KAAK,EAAE,OAAO;CACN,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAEvE,eAAO,MAAM,WAAW;aACtB,OAAO,EAAE,SAAS;aAClB,iBAAiB,EAAE,mBAAmB;aACtC,EAAE,EAAE,IAAI;IACR,8EAA8E;aAC9E,QAAQ,EAAE,UAAU;aACpB,KAAK,EAAE,OAAO;IACd;;;;OAIG;aACH,WAAW,EAAE,aAAa;CAClB,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,CAAA;AAevE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED,MAAM,MAAM,QAAQ,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,UAAU,CAAA;IAClB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,8BAA8B;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,4CAA4C;IAC5C,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,QAAQ,CAAA;IACd,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,KAAK,EAAE,QAAQ,EAAE,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,UAAU,CAAA;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,eAAe,EAAE,eAAe,GAAG,IAAI,CAAA;IACvC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CACtC,CAAA;AAED,wBAAgB,eAAe,IAAI,cAAc,CAUhD;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAE5D;AAqCD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,SAAa,GAAG,cAAc,CAQ9F;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,cAAc,EAAE,EAAE,SAAa,GAAG,cAAc,CAMhF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,GAAG,cAAc,CA0HlF"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Folds the event stream of one turn into a render model.
3
+ *
4
+ * Pure and synchronous: no fetch, no React, no timers. Every branch here is
5
+ * driven by a contract invariant, so the fixtures in `src/test-utils/fixtures`
6
+ * exercise it directly.
7
+ */
8
+ import { EVENT } from './events';
9
+ export const TURN_STATUS = {
10
+ IDLE: 'idle',
11
+ STREAMING: 'streaming',
12
+ AWAITING_APPROVAL: 'awaiting-approval',
13
+ COMPLETE: 'complete',
14
+ ERROR: 'error',
15
+ };
16
+ export const TOOL_STATUS = {
17
+ RUNNING: 'running',
18
+ AWAITING_APPROVAL: 'awaiting-approval',
19
+ OK: 'ok',
20
+ /** Refused — by the operator, or by the approval timing out. Not an error. */
21
+ REJECTED: 'rejected',
22
+ ERROR: 'error',
23
+ /**
24
+ * The turn ended before the tool reported back — an `error` event, a lost
25
+ * connection, or the operator stopping the turn. Whether the tool ran is
26
+ * genuinely unknown, which is why it is neither `ok` nor `error`.
27
+ */
28
+ INTERRUPTED: 'interrupted',
29
+ };
30
+ /**
31
+ * How a refused write comes back.
32
+ *
33
+ * The producer answers a declined approval with an ordinary `tool_result` and
34
+ * **no `isError`** (`backend/core/agent/src/loop.js`), so without this a
35
+ * rejected write renders with the same green tick as one that ran — telling the
36
+ * operator their refusal succeeded in doing the thing they refused.
37
+ *
38
+ * It is a bare string literal over there, not an exported constant, so this is
39
+ * matched on a prefix and pinned by `turn.contract.test.ts`.
40
+ */
41
+ const REJECTED_RESULT_PREFIX = '(rejected by operator';
42
+ export function isRejectionResult(text) {
43
+ return text.startsWith(REJECTED_RESULT_PREFIX);
44
+ }
45
+ export function createTurnState() {
46
+ return {
47
+ turnId: null,
48
+ tools: [],
49
+ text: '',
50
+ status: TURN_STATUS.IDLE,
51
+ error: null,
52
+ pendingApproval: null,
53
+ usage: null,
54
+ };
55
+ }
56
+ export function isTurnSettled(state) {
57
+ return state.status === TURN_STATUS.COMPLETE || state.status === TURN_STATUS.ERROR;
58
+ }
59
+ function isOpen(step) {
60
+ return step.status === TOOL_STATUS.RUNNING || step.status === TOOL_STATUS.AWAITING_APPROVAL;
61
+ }
62
+ /**
63
+ * The OLDEST step of that name still waiting on its `tool_result`.
64
+ *
65
+ * The wire carries no id linking a result to its call, so attribution is by call
66
+ * order: the producer runs tools one at a time and emits each result in the order
67
+ * the calls were made, so the first unanswered call of a name is the one this
68
+ * result belongs to. Matching the newest instead crossed durations and outputs
69
+ * over as soon as a turn called the same tool twice.
70
+ */
71
+ function findOpenStep(tools, name) {
72
+ return tools.find((step) => isOpen(step) && step.name === name);
73
+ }
74
+ function replaceStep(tools, id, next) {
75
+ return tools.map((step) => (step.id === id ? next : step));
76
+ }
77
+ /**
78
+ * Closes every step still waiting on a result.
79
+ *
80
+ * A turn can end while a call is outstanding — an `error` event, a dropped
81
+ * socket, the operator pressing stop — and a step left `running` renders as a
82
+ * spinner that never resolves, which then gets persisted into the transcript and
83
+ * read back as a turn still in flight.
84
+ */
85
+ function settleOpenSteps(tools, at) {
86
+ return tools.map((step) => isOpen(step) ? { ...step, status: TOOL_STATUS.INTERRUPTED, endedAt: at } : step);
87
+ }
88
+ /**
89
+ * Ends a turn from outside the event stream: a transport failure, an idle
90
+ * connection, or an unmount. `reduceTurn` handles the producer's own `error`
91
+ * event; this is the same closing-down for the cases that never reach it.
92
+ */
93
+ export function failTurn(state, error, at = Date.now()) {
94
+ return {
95
+ ...state,
96
+ status: TURN_STATUS.ERROR,
97
+ error,
98
+ pendingApproval: null,
99
+ tools: settleOpenSteps(state.tools, at),
100
+ };
101
+ }
102
+ /**
103
+ * Ends a turn the operator stopped. Not an error — they meant it — so whatever
104
+ * streamed is kept and no error is recorded, but an outstanding call is still
105
+ * closed: it did not report back and now never will.
106
+ */
107
+ export function abortTurn(state, at = Date.now()) {
108
+ return {
109
+ ...state,
110
+ pendingApproval: null,
111
+ tools: settleOpenSteps(state.tools, at),
112
+ };
113
+ }
114
+ /**
115
+ * Applies one event. Returns a new state; never mutates the one passed in.
116
+ *
117
+ * Unknown event types fall through unchanged (invariant 5) — the caller has
118
+ * usually filtered them already, but this must not throw either way.
119
+ */
120
+ export function reduceTurn(state, event) {
121
+ const turnId = state.turnId ?? event.turnId;
122
+ switch (event.type) {
123
+ case EVENT.TOKEN:
124
+ return {
125
+ ...state,
126
+ turnId,
127
+ text: state.text + event.text,
128
+ status: TURN_STATUS.STREAMING,
129
+ };
130
+ case EVENT.TOOL_CALL:
131
+ return {
132
+ ...state,
133
+ turnId,
134
+ status: TURN_STATUS.STREAMING,
135
+ tools: [
136
+ ...state.tools,
137
+ {
138
+ id: `${event.turnId}:${event.seq}`,
139
+ name: event.name,
140
+ args: event.args,
141
+ status: TOOL_STATUS.RUNNING,
142
+ startedAt: event.ts,
143
+ },
144
+ ],
145
+ };
146
+ case EVENT.PENDING_APPROVAL: {
147
+ // Only ever emitted between a `tool_call` and its `tool_result`
148
+ // (invariant 3), so the gated step is the open one with the same name.
149
+ const step = findOpenStep(state.tools, event.name);
150
+ if (!step || !event.approvalId)
151
+ return { ...state, turnId };
152
+ return {
153
+ ...state,
154
+ turnId,
155
+ status: TURN_STATUS.AWAITING_APPROVAL,
156
+ tools: replaceStep(state.tools, step.id, {
157
+ ...step,
158
+ status: TOOL_STATUS.AWAITING_APPROVAL,
159
+ }),
160
+ pendingApproval: {
161
+ approvalId: event.approvalId,
162
+ name: event.name,
163
+ args: event.args,
164
+ toolStepId: step.id,
165
+ at: event.ts,
166
+ },
167
+ };
168
+ }
169
+ case EVENT.TOOL_RESULT: {
170
+ const step = findOpenStep(state.tools, event.name);
171
+ if (!step)
172
+ return { ...state, turnId };
173
+ // A refusal only reaches us as this text — the decision is sent
174
+ // out-of-band, and an approval that timed out server-side was never
175
+ // decided here at all.
176
+ const wasRefused = step.status === TOOL_STATUS.AWAITING_APPROVAL && isRejectionResult(event.text);
177
+ const settled = {
178
+ ...step,
179
+ status: event.isError
180
+ ? TOOL_STATUS.ERROR
181
+ : wasRefused
182
+ ? TOOL_STATUS.REJECTED
183
+ : TOOL_STATUS.OK,
184
+ text: event.text,
185
+ endedAt: event.ts,
186
+ // The operator's own deliberation is not the tool's runtime. On a gated call the
187
+ // producer says how long the prompt was up, and it comes back off the clock.
188
+ durationMs: Math.max(0, event.ts - step.startedAt - (event.approvalWaitMs ?? 0)),
189
+ ...(event.isError === undefined ? {} : { isError: event.isError }),
190
+ ...(event.contractViolation === undefined
191
+ ? {}
192
+ : { contractViolation: event.contractViolation }),
193
+ };
194
+ // Clears the approval whether the operator answered, the approval timed
195
+ // out server-side, or the turn was declined — in every case the stream has
196
+ // moved on and the prompt must stop being shown.
197
+ const stillPending = state.pendingApproval && state.pendingApproval.toolStepId !== step.id
198
+ ? state.pendingApproval
199
+ : null;
200
+ return {
201
+ ...state,
202
+ turnId,
203
+ tools: replaceStep(state.tools, step.id, settled),
204
+ pendingApproval: stillPending,
205
+ status: stillPending ? TURN_STATUS.AWAITING_APPROVAL : TURN_STATUS.STREAMING,
206
+ };
207
+ }
208
+ case EVENT.ERROR:
209
+ return {
210
+ ...state,
211
+ turnId,
212
+ status: TURN_STATUS.ERROR,
213
+ error: event.error,
214
+ pendingApproval: null,
215
+ tools: settleOpenSteps(state.tools, event.ts),
216
+ };
217
+ case EVENT.DONE:
218
+ return {
219
+ ...state,
220
+ turnId,
221
+ status: TURN_STATUS.COMPLETE,
222
+ pendingApproval: null,
223
+ // `done` may carry the whole answer. Only used when nothing streamed,
224
+ // otherwise it would duplicate the text already accumulated.
225
+ text: state.text === '' && event.text ? event.text : state.text,
226
+ usage: event.usage ?? state.usage,
227
+ };
228
+ default:
229
+ return state;
230
+ }
231
+ }
232
+ //# sourceMappingURL=turn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"turn.js","sourceRoot":"","sources":["../../src/core/turn.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Ids for conversations and messages.
3
+ *
4
+ * `crypto.randomUUID` is defined only in a secure context, and a gateway on a
5
+ * site LAN is routinely reached over plain http — the UI is served from the
6
+ * gateway's own `staticRootPath`, so `http://10.0.0.4:3000` is an ordinary
7
+ * deployment rather than an edge case. There `randomUUID` is undefined, and
8
+ * calling it would throw on conversation creation and on every send, i.e. the
9
+ * panel would be dead on arrival. `getRandomValues` is available in insecure
10
+ * contexts, so the v4 shape is assembled from it instead.
11
+ */
12
+ /**
13
+ * A v4 UUID where the platform offers one, and a v4-shaped id built from
14
+ * `getRandomValues` where it does not.
15
+ *
16
+ * These ids never leave the browser — they key conversations and messages in
17
+ * localStorage and React lists — so the only requirement is that two of them
18
+ * never collide within one browser.
19
+ */
20
+ export declare function uuid(): string;
21
+ //# sourceMappingURL=uuid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../../src/core/uuid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAyBH;;;;;;;GAOG;AACH,wBAAgB,IAAI,IAAI,MAAM,CAe7B"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Ids for conversations and messages.
3
+ *
4
+ * `crypto.randomUUID` is defined only in a secure context, and a gateway on a
5
+ * site LAN is routinely reached over plain http — the UI is served from the
6
+ * gateway's own `staticRootPath`, so `http://10.0.0.4:3000` is an ordinary
7
+ * deployment rather than an edge case. There `randomUUID` is undefined, and
8
+ * calling it would throw on conversation creation and on every send, i.e. the
9
+ * panel would be dead on arrival. `getRandomValues` is available in insecure
10
+ * contexts, so the v4 shape is assembled from it instead.
11
+ */
12
+ /** Version and variant bits, per RFC 4122 §4.4. */
13
+ const VERSION_BYTE = 6;
14
+ const VARIANT_BYTE = 8;
15
+ function hex(bytes) {
16
+ return [...bytes].map((byte) => byte.toString(16).padStart(2, '0')).join('');
17
+ }
18
+ function uuidFromBytes(bytes) {
19
+ const stamped = Uint8Array.from(bytes);
20
+ stamped[VERSION_BYTE] = ((stamped[VERSION_BYTE] ?? 0) & 0x0F) | 0x40;
21
+ stamped[VARIANT_BYTE] = ((stamped[VARIANT_BYTE] ?? 0) & 0x3F) | 0x80;
22
+ const digits = hex(stamped);
23
+ return [
24
+ digits.slice(0, 8),
25
+ digits.slice(8, 12),
26
+ digits.slice(12, 16),
27
+ digits.slice(16, 20),
28
+ digits.slice(20, 32),
29
+ ].join('-');
30
+ }
31
+ /**
32
+ * A v4 UUID where the platform offers one, and a v4-shaped id built from
33
+ * `getRandomValues` where it does not.
34
+ *
35
+ * These ids never leave the browser — they key conversations and messages in
36
+ * localStorage and React lists — so the only requirement is that two of them
37
+ * never collide within one browser.
38
+ */
39
+ export function uuid() {
40
+ const source = globalThis.crypto;
41
+ if (typeof source?.randomUUID === 'function')
42
+ return source.randomUUID();
43
+ if (typeof source?.getRandomValues === 'function') {
44
+ return uuidFromBytes(source.getRandomValues(new Uint8Array(16)));
45
+ }
46
+ // No WebCrypto at all: a very old browser, or a stripped non-browser global.
47
+ // Uniqueness within one tab is all these ids are asked for.
48
+ const bytes = new Uint8Array(16);
49
+ for (let index = 0; index < bytes.length; index += 1) {
50
+ bytes[index] = Math.floor(Math.random() * 256);
51
+ }
52
+ return uuidFromBytes(bytes);
53
+ }
54
+ //# sourceMappingURL=uuid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../src/core/uuid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,mDAAmD;AACnD,MAAM,YAAY,GAAG,CAAC,CAAA;AACtB,MAAM,YAAY,GAAG,CAAC,CAAA;AAEtB,SAAS,GAAG,CAAC,KAAiB;IAC5B,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC9E,CAAC;AAED,SAAS,aAAa,CAAC,KAAiB;IACtC,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IACtC,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IACpE,OAAO,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAEpE,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,CAAA;IAC3B,OAAO;QACL,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QAClB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;QACnB,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACpB,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QACpB,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;KACrB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AACb,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,IAAI;IAClB,MAAM,MAAM,GAAG,UAAU,CAAC,MAA4B,CAAA;IAEtD,IAAI,OAAO,MAAM,EAAE,UAAU,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC,UAAU,EAAE,CAAA;IACxE,IAAI,OAAO,MAAM,EAAE,eAAe,KAAK,UAAU,EAAE,CAAC;QAClD,OAAO,aAAa,CAAC,MAAM,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAClE,CAAC;IAED,6EAA6E;IAC7E,4DAA4D;IAC5D,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IAChC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAA;IAChD,CAAC;IACD,OAAO,aAAa,CAAC,KAAK,CAAC,CAAA;AAC7B,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ import type { ToolLabels } from '../core/tool-label';
3
+ import type { UseAgentChatOptions } from '../hooks/use-agent-chat';
4
+ export type ChatUIEntryProps = UseAgentChatOptions & {
5
+ title?: string;
6
+ status?: ReactNode;
7
+ toolLabels?: ToolLabels;
8
+ placeholder?: string;
9
+ className?: string;
10
+ };
11
+ /**
12
+ * The same conversation as {@link CoPilot}, rendered as a full-height page
13
+ * instead of a docked overlay.
14
+ *
15
+ * Zero required props and a default export, so it drops straight into the
16
+ * shell's lazy route registry:
17
+ *
18
+ * ```ts
19
+ * { path: '/chat', label: 'Co-pilot', page: () => import('@tetherto/mdk-ui-agent/chat-page') }
20
+ * ```
21
+ *
22
+ * The panel is loaded through the shared lazy boundary rather than imported
23
+ * directly — a static edge here would pull the transcript and its markdown
24
+ * renderer into the root barrel, undoing the split for `CoPilot` as well.
25
+ */
26
+ export declare const ChatUIEntry: ({ title, status, toolLabels, placeholder, className, ...chatOptions }: ChatUIEntryProps) => JSX.Element;
27
+ export default ChatUIEntry;
28
+ //# sourceMappingURL=chat-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-page.d.ts","sourceRoot":"","sources":["../../src/entries/chat-page.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,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAIlE,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,GAAG;IACnD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,0EAOrB,gBAAgB,KAAG,GAAG,CAAC,OAezB,CAAA;eAEc,WAAW"}
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Suspense } from 'react';
3
+ import { useAgentChat } from '../hooks/use-agent-chat';
4
+ import { LazyCoPilotPanel } from './lazy-panel';
5
+ /**
6
+ * The same conversation as {@link CoPilot}, rendered as a full-height page
7
+ * instead of a docked overlay.
8
+ *
9
+ * Zero required props and a default export, so it drops straight into the
10
+ * shell's lazy route registry:
11
+ *
12
+ * ```ts
13
+ * { path: '/chat', label: 'Co-pilot', page: () => import('@tetherto/mdk-ui-agent/chat-page') }
14
+ * ```
15
+ *
16
+ * The panel is loaded through the shared lazy boundary rather than imported
17
+ * directly — a static edge here would pull the transcript and its markdown
18
+ * renderer into the root barrel, undoing the split for `CoPilot` as well.
19
+ */
20
+ export const ChatUIEntry = ({ title, status, toolLabels, placeholder, className, ...chatOptions }) => {
21
+ const chat = useAgentChat(chatOptions);
22
+ return (_jsx(Suspense, { fallback: _jsx("div", { className: "mdk-agent-panel mdk-agent-panel--page" }), children: _jsx(LazyCoPilotPanel, { chat: chat, title: title, status: status, toolLabels: toolLabels, placeholder: placeholder, className: `mdk-agent-panel--page${className ? ` ${className}` : ''}` }) }));
23
+ };
24
+ export default ChatUIEntry;
25
+ //# sourceMappingURL=chat-page.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chat-page.js","sourceRoot":"","sources":["../../src/entries/chat-page.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAIhC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAU/C;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,EAC1B,KAAK,EACL,MAAM,EACN,UAAU,EACV,WAAW,EACX,SAAS,EACT,GAAG,WAAW,EACG,EAAe,EAAE;IAClC,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;IAEtC,OAAO,CACL,KAAC,QAAQ,IAAC,QAAQ,EAAE,cAAK,SAAS,EAAC,uCAAuC,GAAG,YAC3E,KAAC,gBAAgB,IACf,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,wBAAwB,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,GACrE,GACO,CACZ,CAAA;AACH,CAAC,CAAA;AAED,eAAe,WAAW,CAAA"}
@@ -0,0 +1,41 @@
1
+ import type { JSX, ReactNode } from 'react';
2
+ import type { ToolLabels } from '../core/tool-label';
3
+ import type { UseAgentChatOptions } from '../hooks/use-agent-chat';
4
+ export declare const COPILOT_POSITION: {
5
+ readonly BOTTOM_RIGHT: 'bottom-right';
6
+ readonly BOTTOM_LEFT: 'bottom-left';
7
+ };
8
+ export type CoPilotPosition = (typeof COPILOT_POSITION)[keyof typeof COPILOT_POSITION];
9
+ export type CoPilotProps = UseAgentChatOptions & {
10
+ title?: string;
11
+ /** The line under the title, e.g. `Local model · 6 tools`. */
12
+ status?: ReactNode;
13
+ /** Human labels for tool chips, keyed by the MCP tool name. */
14
+ toolLabels?: ToolLabels;
15
+ placeholder?: string;
16
+ defaultOpen?: boolean;
17
+ position?: CoPilotPosition;
18
+ className?: string;
19
+ };
20
+ /**
21
+ * The Co-pilot as a docked overlay: a launcher in the corner that opens the
22
+ * panel over whatever page is showing.
23
+ *
24
+ * Mount it once, in the app root, next to the router outlet:
25
+ *
26
+ * ```tsx
27
+ * import { CoPilot } from '@tetherto/mdk-ui-agent'
28
+ *
29
+ * <div className="app-root">
30
+ * …
31
+ * <CoPilot />
32
+ * </div>
33
+ * ```
34
+ *
35
+ * Everything is optional. Inside an `MdkProvider` it picks up the gateway base
36
+ * URL and the bearer token from the provider's auth seam; outside one it falls
37
+ * back to relative URLs and no token, which is what a gateway running without an
38
+ * auth plugin serves anyway.
39
+ */
40
+ export declare const CoPilot: ({ title, status, toolLabels, placeholder, defaultOpen, position, className, ...chatOptions }: CoPilotProps) => JSX.Element;
41
+ //# sourceMappingURL=co-pilot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"co-pilot.d.ts","sourceRoot":"","sources":["../../src/entries/co-pilot.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,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAKlE,eAAO,MAAM,gBAAgB;aAC3B,YAAY,EAAE,cAAc;aAC5B,WAAW,EAAE,aAAa;CAClB,CAAA;AAEV,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,CAAA;AAEtF,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,MAAM,CAAC,EAAE,SAAS,CAAA;IAClB,+DAA+D;IAC/D,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,OAAO,iGASjB,YAAY,KAAG,GAAG,CAAC,OA0BrB,CAAA"}
@@ -0,0 +1,39 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Suspense, useCallback, useState } from 'react';
3
+ import { LauncherFab } from '../components/launcher-fab';
4
+ import { useAgentChat } from '../hooks/use-agent-chat';
5
+ import { LazyCoPilotPanel } from './lazy-panel';
6
+ export const COPILOT_POSITION = {
7
+ BOTTOM_RIGHT: 'bottom-right',
8
+ BOTTOM_LEFT: 'bottom-left',
9
+ };
10
+ /**
11
+ * The Co-pilot as a docked overlay: a launcher in the corner that opens the
12
+ * panel over whatever page is showing.
13
+ *
14
+ * Mount it once, in the app root, next to the router outlet:
15
+ *
16
+ * ```tsx
17
+ * import { CoPilot } from '@tetherto/mdk-ui-agent'
18
+ *
19
+ * <div className="app-root">
20
+ * …
21
+ * <CoPilot />
22
+ * </div>
23
+ * ```
24
+ *
25
+ * Everything is optional. Inside an `MdkProvider` it picks up the gateway base
26
+ * URL and the bearer token from the provider's auth seam; outside one it falls
27
+ * back to relative URLs and no token, which is what a gateway running without an
28
+ * auth plugin serves anyway.
29
+ */
30
+ export const CoPilot = ({ title, status, toolLabels, placeholder, defaultOpen = false, position = COPILOT_POSITION.BOTTOM_RIGHT, className, ...chatOptions }) => {
31
+ const [open, setOpen] = useState(defaultOpen);
32
+ const chat = useAgentChat(chatOptions);
33
+ const close = useCallback(() => setOpen(false), []);
34
+ const openPanel = useCallback(() => setOpen(true), []);
35
+ return (_jsx("div", { className: `mdk-agent-root mdk-agent-root--${position}${className ? ` ${className}` : ''}`, children: open
36
+ ? (_jsx(Suspense, { fallback: _jsx("div", { className: "mdk-agent-panel mdk-agent-panel--docked" }), children: _jsx(LazyCoPilotPanel, { chat: chat, title: title, status: status, toolLabels: toolLabels, placeholder: placeholder, onClose: close, className: "mdk-agent-panel--docked" }) }))
37
+ : _jsx(LauncherFab, { onClick: openPanel }) }));
38
+ };
39
+ //# sourceMappingURL=co-pilot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"co-pilot.js","sourceRoot":"","sources":["../../src/entries/co-pilot.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAIvD,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAE/C,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,YAAY,EAAE,cAAc;IAC5B,WAAW,EAAE,aAAa;CAClB,CAAA;AAgBV;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,KAAK,EACL,MAAM,EACN,UAAU,EACV,WAAW,EACX,WAAW,GAAG,KAAK,EACnB,QAAQ,GAAG,gBAAgB,CAAC,YAAY,EACxC,SAAS,EACT,GAAG,WAAW,EACD,EAAe,EAAE;IAC9B,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,WAAW,CAAC,CAAA;IAC7C,MAAM,IAAI,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;IAEtC,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAA;IACnD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAA;IAEtD,OAAO,CACL,cAAK,SAAS,EAAE,kCAAkC,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,YAC5F,IAAI;YACH,CAAC,CAAC,CACE,KAAC,QAAQ,IAAC,QAAQ,EAAE,cAAK,SAAS,EAAC,yCAAyC,GAAG,YAC7E,KAAC,gBAAgB,IACf,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,KAAK,EACZ,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,UAAU,EACtB,WAAW,EAAE,WAAW,EACxB,OAAO,EAAE,KAAK,EACd,SAAS,EAAC,yBAAyB,GACnC,GACO,CACZ;YACH,CAAC,CAAC,KAAC,WAAW,IAAC,OAAO,EAAE,SAAS,GAAI,GACnC,CACP,CAAA;AACH,CAAC,CAAA"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The panel, split off from whatever mounts it.
3
+ *
4
+ * Both entries load it this way, and nothing in the package's root barrel may
5
+ * import `co-pilot-panel` statically — one static edge anywhere in the graph
6
+ * collapses the split back into the caller's main chunk, which bundlers report
7
+ * as an ineffective dynamic import. That is why `CoPilotPanel` is reachable only
8
+ * from the `./panel` subpath and not from the root export.
9
+ *
10
+ * What sits behind the boundary is the transcript: the markdown renderer and the
11
+ * syntax highlighter. Eagerly bundled, they made the generated shell's main
12
+ * chunk 80% larger before anyone had opened the panel.
13
+ */
14
+ export declare const LazyCoPilotPanel: import("react").LazyExoticComponent<typeof import("../components/co-pilot-panel").CoPilotPanel>;
15
+ //# sourceMappingURL=lazy-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-panel.d.ts","sourceRoot":"","sources":["../../src/entries/lazy-panel.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,iGAG3B,CAAA"}
@@ -0,0 +1,19 @@
1
+ import { lazy } from 'react';
2
+ /**
3
+ * The panel, split off from whatever mounts it.
4
+ *
5
+ * Both entries load it this way, and nothing in the package's root barrel may
6
+ * import `co-pilot-panel` statically — one static edge anywhere in the graph
7
+ * collapses the split back into the caller's main chunk, which bundlers report
8
+ * as an ineffective dynamic import. That is why `CoPilotPanel` is reachable only
9
+ * from the `./panel` subpath and not from the root export.
10
+ *
11
+ * What sits behind the boundary is the transcript: the markdown renderer and the
12
+ * syntax highlighter. Eagerly bundled, they made the generated shell's main
13
+ * chunk 80% larger before anyone had opened the panel.
14
+ */
15
+ export const LazyCoPilotPanel = lazy(async () => {
16
+ const module = await import('../components/co-pilot-panel');
17
+ return { default: module.CoPilotPanel };
18
+ });
19
+ //# sourceMappingURL=lazy-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lazy-panel.js","sourceRoot":"","sources":["../../src/entries/lazy-panel.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAE5B;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE;IAC9C,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,8BAA8B,CAAC,CAAA;IAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,YAAY,EAAE,CAAA;AACzC,CAAC,CAAC,CAAA"}
@@ -0,0 +1,7 @@
1
+ export type { UseAgentChatOptions, UseAgentChatResult } from './use-agent-chat';
2
+ export { useAgentChat } from './use-agent-chat';
3
+ export type { AgentConfigOptions } from './use-agent-config';
4
+ export { useAgentConfig } from './use-agent-config';
5
+ export type { UseConversationsResult } from './use-conversations';
6
+ export { useConversations } from './use-conversations';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAE/C,YAAY,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnD,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA"}
@@ -0,0 +1,4 @@
1
+ export { useAgentChat } from './use-agent-chat';
2
+ export { useAgentConfig } from './use-agent-config';
3
+ export { useConversations } from './use-conversations';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAG/C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAGnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA"}