@windowkit/agent-chat 0.1.0 → 0.3.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/view/CodeBlock.tsx"],"names":[],"mappings":"AAIA,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAGvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKrD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,cAAc,GAAG,YAAY,CAwF1E"}
1
+ {"version":3,"file":"CodeBlock.d.ts","sourceRoot":"","sources":["../../src/view/CodeBlock.tsx"],"names":[],"mappings":"AAKA,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAGvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKrD,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,cAAc,GAAG,YAAY,CA8F1E"}
@@ -1,15 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react-x11/jsx-runtime";
2
2
  // A fenced code block with a header of actions: Copy by default, and
3
3
  // whatever the app's `codeActions` add. Nothing here runs code; an action
4
- // that does is the app's.
4
+ // that does is the app's. It is drawn as `<Markdown>` draws a fence, with
5
+ // the header inside the block's fill.
5
6
  import { useEffect, useRef, useState } from 'react';
6
7
  import { Button, useClipboard } from 'react-x11';
7
8
  import { Code } from '@react-x11/components/code';
8
9
  import { useChat } from './context.js';
9
- import { useLook } from './look.js';
10
+ import { useCodeLook, useLook } from './look.js';
10
11
  export function CodeBlock({ fence, message }) {
11
- const { codeActions, session } = useChat();
12
+ const { codeActions, session, fontSize } = useChat();
12
13
  const look = useLook();
14
+ const code = useCodeLook(fontSize);
13
15
  const clipboard = useClipboard();
14
16
  const [done, setDone] = useState(null);
15
17
  const timer = useRef(null);
@@ -40,21 +42,26 @@ export function CodeBlock({ fence, message }) {
40
42
  };
41
43
  return (_jsxs("box", { style: {
42
44
  flexDirection: 'column',
43
- borderWidth: 1,
44
- borderColor: look.border,
45
- borderRadius: 6,
45
+ backgroundColor: code.fill,
46
+ borderRadius: code.radius,
46
47
  overflow: 'hidden',
47
48
  }, children: [_jsxs("box", { style: {
48
49
  flexDirection: 'row',
49
50
  alignItems: 'center',
50
51
  gap: 4,
51
- paddingLeft: 10,
52
- paddingRight: 4,
52
+ paddingLeft: code.padding,
53
+ paddingRight: Math.round(code.padding / 3),
54
+ paddingTop: Math.round(code.padding / 3),
53
55
  minHeight: 26,
54
- borderBottomWidth: 1,
55
- borderBottomColor: look.border,
56
56
  }, children: [_jsx("text", { style: { color: look.muted, fontSize: 11, flexGrow: 1 }, children: fence.lang || 'text' }), actions.map((action) => (_jsx(Button, { size: "small", variant: "ghost", label: done === action.id
57
57
  ? (action.doneLabel ?? action.label)
58
- : action.label, onPress: () => run(action) }, action.id)))] }), _jsx(Code, { source: fence.text, ...(fence.lang ? { lang: fence.lang } : {}), wrap: true, style: { borderWidth: 0, borderRadius: 0 } })] }));
58
+ : action.label, onPress: () => run(action) }, action.id)))] }), _jsx(Code, { source: fence.text, ...(fence.lang ? { lang: fence.lang } : {}), fontSize: code.size, wrap: true,
59
+ // the frame holds the fill: the code's own, a tint, would lay a
60
+ // second over it
61
+ style: {
62
+ backgroundColor: 'transparent',
63
+ borderRadius: 0,
64
+ paddingTop: Math.round(code.padding / 3),
65
+ } })] }));
59
66
  }
60
67
  //# sourceMappingURL=CodeBlock.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodeBlock.js","sourceRoot":"","sources":["../../src/view/CodeBlock.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CodeBlock.js","sourceRoot":"","sources":["../../src/view/CodeBlock.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TextBlock.d.ts","sourceRoot":"","sources":["../../src/view/TextBlock.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAGzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAKrD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,eAAO,MAAM,SAAS,sEAInB,cAAc,KAAG,YAAY,CAoC9B,CAAC"}
1
+ {"version":3,"file":"TextBlock.d.ts","sourceRoot":"","sources":["../../src/view/TextBlock.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,OAAO,CAAC;AAGzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMrD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,YAAY,CAAC;CACvB;AAED,eAAO,MAAM,SAAS,sEAInB,cAAc,KAAG,YAAY,CAsC9B,CAAC"}
@@ -5,12 +5,15 @@ import { memo, useMemo } from 'react';
5
5
  import { Markdown } from '@react-x11/components/markdown';
6
6
  import { CodeBlock } from './CodeBlock.js';
7
7
  import { useChat } from './context.js';
8
+ import { useCodeLook } from './look.js';
8
9
  import { splitFences } from './fences.js';
9
10
  export const TextBlock = memo(function TextBlock({ text, streaming, message, }) {
10
11
  const { fences, components, onLink, fontSize } = useChat();
12
+ // segments alternate prose and fences: the gap is the space a fence keeps
13
+ const { spacing } = useCodeLook(fontSize);
11
14
  const segments = useMemo(() => splitFences(text, streaming), [text, streaming]);
12
15
  const link = useMemo(() => (onLink ? (href) => onLink(href) : undefined), [onLink]);
13
- return (_jsx("box", { style: { flexDirection: 'column', gap: 8 }, children: segments.map((s, i) => {
16
+ return (_jsx("box", { style: { flexDirection: 'column', gap: spacing }, children: segments.map((s, i) => {
14
17
  if (s.type === 'prose') {
15
18
  return (_jsx(Markdown, { source: s.text, partial: streaming && i === segments.length - 1, ...(fences ? { fences } : {}), ...(components ? { components } : {}), ...(link ? { onLink: link } : {}), ...(fontSize ? { fontSize } : {}) }, i));
16
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TextBlock.js","sourceRoot":"","sources":["../../src/view/TextBlock.tsx"],"names":[],"mappings":";AAAA,4EAA4E;AAC5E,mEAAmE;AAEnE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAqB,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ1C,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,SAAS,CAAC,EAC/C,IAAI,EACJ,SAAS,EACT,OAAO,GACQ;IACf,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IAC3D,MAAM,QAAQ,GAAG,OAAO,CACtB,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,EAClC,CAAC,IAAI,EAAE,SAAS,CAAC,CAClB,CAAC;IACF,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAC3D,CAAC,MAAM,CAAC,CACT,CAAC;IACF,OAAO,CACL,cAAK,KAAK,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,EAAE,YAC5C,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrB,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACvB,OAAO,CACL,KAAC,QAAQ,IAEP,MAAM,EAAE,CAAC,CAAC,IAAI,EACd,OAAO,EAAE,SAAS,IAAI,CAAC,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,KAC3C,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC1B,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAClC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC9B,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAN7B,CAAC,CAON,CACH,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACjE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChC,OAAO,MAAM,CAAC,CAAC,CAAC,CACd,wBAAc,MAAM,CAAC,KAAK,CAAC,IAAjB,CAAC,CAAuB,CACnC,CAAC,CAAC,CAAC,CACF,KAAC,SAAS,IAAS,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,IAAjC,CAAC,CAAoC,CACtD,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"TextBlock.js","sourceRoot":"","sources":["../../src/view/TextBlock.tsx"],"names":[],"mappings":";AAAA,4EAA4E;AAC5E,mEAAmE;AAEnE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAqB,MAAM,OAAO,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAG1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ1C,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,SAAS,CAAC,EAC/C,IAAI,EACJ,SAAS,EACT,OAAO,GACQ;IACf,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;IAC3D,0EAA0E;IAC1E,MAAM,EAAE,OAAO,EAAE,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,OAAO,CACtB,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,EAClC,CAAC,IAAI,EAAE,SAAS,CAAC,CAClB,CAAC;IACF,MAAM,IAAI,GAAG,OAAO,CAClB,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAC3D,CAAC,MAAM,CAAC,CACT,CAAC;IACF,OAAO,CACL,cAAK,KAAK,EAAE,EAAE,aAAa,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,YAClD,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrB,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACvB,OAAO,CACL,KAAC,QAAQ,IAEP,MAAM,EAAE,CAAC,CAAC,IAAI,EACd,OAAO,EAAE,SAAS,IAAI,CAAC,KAAK,QAAQ,CAAC,MAAM,GAAG,CAAC,KAC3C,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC1B,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAClC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAC9B,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,IAN7B,CAAC,CAON,CACH,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YACjE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChC,OAAO,MAAM,CAAC,CAAC,CAAC,CACd,wBAAc,MAAM,CAAC,KAAK,CAAC,IAAjB,CAAC,CAAuB,CACnC,CAAC,CAAC,CAAC,CACF,KAAC,SAAS,IAAS,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,IAAjC,CAAC,CAAoC,CACtD,CAAC;QACJ,CAAC,CAAC,GACE,CACP,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"Transcript.d.ts","sourceRoot":"","sources":["../../src/view/Transcript.tsx"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAWf,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,YAAY,CAsCzE"}
1
+ {"version":3,"file":"Transcript.d.ts","sourceRoot":"","sources":["../../src/view/Transcript.tsx"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAWf,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG,YAAY,CA6CzE"}
@@ -1,6 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react-x11/jsx-runtime";
2
2
  // The scrolling transcript. It follows the newest message while the reader
3
- // is at the bottom, and stops following once they scroll up to read.
3
+ // is at the bottom, and stops following once they scroll up to read. It
4
+ // follows content that grows after it was laid out too: a fence the app
5
+ // draws itself (a diagram compiled after mount) would otherwise push the end
6
+ // of the reply out of view.
4
7
  import { useLayoutEffect, useRef, } from 'react';
5
8
  import { useChat } from './context.js';
6
9
  import { useLook } from './look.js';
@@ -20,12 +23,18 @@ export function Transcript({ empty }) {
20
23
  if (stick.current)
21
24
  pane.current?.scrollTo(Infinity);
22
25
  }, [snap.messages, snap.status]);
26
+ // fires from layout whenever the content or viewport size changes, not
27
+ // only when the snapshot does
28
+ const onViewport = () => {
29
+ if (stick.current)
30
+ pane.current?.scrollTo(Infinity);
31
+ };
23
32
  const onScroll = (ev) => {
24
33
  stick.current =
25
34
  ev.scrollY + ev.viewportHeight >= ev.contentHeight - STICK_PX;
26
35
  };
27
36
  const activity = activityOf(snap.status, snap.messages);
28
- return (_jsx("box", { ref: pane, onScroll: onScroll, style: { flexGrow: 1, flexShrink: 1, minHeight: 0, overflow: 'scroll' }, "data-testname": "agent-chat-transcript", children: _jsxs("box", { style: { flexDirection: 'column', gap: 14, padding: 14 }, children: [snap.messages.length ? (_jsx(MessageList, { messages: snap.messages })) : ((empty ?? null)), activity ? (_jsx("text", { style: { color: look.muted, fontSize: 12 }, children: activity })) : null] }) }));
37
+ return (_jsx("box", { ref: pane, onScroll: onScroll, onViewport: onViewport, style: { flexGrow: 1, flexShrink: 1, minHeight: 0, overflow: 'scroll' }, "data-testname": "agent-chat-transcript", children: _jsxs("box", { style: { flexDirection: 'column', gap: 14, padding: 14 }, children: [snap.messages.length ? (_jsx(MessageList, { messages: snap.messages })) : ((empty ?? null)), activity ? (_jsx("text", { style: { color: look.muted, fontSize: 12 }, children: activity })) : null] }) }));
29
38
  }
30
39
  function activityOf(status, messages) {
31
40
  switch (status) {
@@ -1 +1 @@
1
- {"version":3,"file":"Transcript.js","sourceRoot":"","sources":["../../src/view/Transcript.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Transcript.js","sourceRoot":"","sources":["../../src/view/Transcript.tsx"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { type CodeBlockLook } from '@react-x11/components/codeblock';
1
2
  export interface ChatLook {
2
3
  text: string;
3
4
  muted: string;
@@ -13,6 +14,12 @@ export interface ChatLook {
13
14
  bubble: string;
14
15
  }
15
16
  export declare function useLook(): ChatLook;
17
+ /**
18
+ * What a block of code looks like here: what `<Markdown>` draws a fence
19
+ * with, at the chat's text size, so a fence the chat draws itself (to carry
20
+ * its actions) has the fill, radius, inset and spacing of one it does not.
21
+ */
22
+ export declare function useCodeLook(fontSize: number | undefined): CodeBlockLook;
16
23
  /** At most `max` lines: the first and last halves, and how many were cut. */
17
24
  export declare function clipLines(text: string, max?: number): string;
18
25
  //# sourceMappingURL=look.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"look.d.ts","sourceRoot":"","sources":["../../src/view/look.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,OAAO,IAAI,QAAQ,CAkBlC;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAM,GAAG,MAAM,CASzD"}
1
+ {"version":3,"file":"look.d.ts","sourceRoot":"","sources":["../../src/view/look.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,iCAAiC,CAAC;AAEzC,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,OAAO,IAAI,QAAQ,CAkBlC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAMvE;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAM,GAAG,MAAM,CASzD"}
package/dist/view/look.js CHANGED
@@ -3,6 +3,7 @@
3
3
  import { useMemo } from 'react';
4
4
  import { useTheme } from 'react-x11';
5
5
  import { tint } from 'react-x11/style';
6
+ import { codeBlockLook, } from '@react-x11/components/codeblock';
6
7
  export function useLook() {
7
8
  const theme = useTheme();
8
9
  return useMemo(() => {
@@ -22,6 +23,15 @@ export function useLook() {
22
23
  };
23
24
  }, [theme]);
24
25
  }
26
+ /**
27
+ * What a block of code looks like here: what `<Markdown>` draws a fence
28
+ * with, at the chat's text size, so a fence the chat draws itself (to carry
29
+ * its actions) has the fill, radius, inset and spacing of one it does not.
30
+ */
31
+ export function useCodeLook(fontSize) {
32
+ const theme = useTheme();
33
+ return useMemo(() => codeBlockLook(theme, fontSize ? { baseSize: fontSize } : {}), [theme, fontSize]);
34
+ }
25
35
  /** At most `max` lines: the first and last halves, and how many were cut. */
26
36
  export function clipLines(text, max = 200) {
27
37
  const lines = text.split('\n');
@@ -1 +1 @@
1
- {"version":3,"file":"look.js","sourceRoot":"","sources":["../../src/view/look.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+DAA+D;AAE/D,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAiBvC,MAAM,UAAU,OAAO;IACrB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;QAC7C,OAAO;YACL,IAAI;YACJ,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,SAAS,CAAC;YAC3C,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;YACzC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC;YAC3C,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,OAAO,CAAC;YAC/C,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;YACzC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;YACzC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC;YAC3C,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC;YAC3C,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,WAAW,CAAC;YAC7C,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;SACzB,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AACd,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,GAAG,GAAG,GAAG;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACjC,OAAO;QACL,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;QACvB,KAAK,KAAK,CAAC,MAAM,GAAG,GAAG,eAAe;QACtC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;KACtB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"look.js","sourceRoot":"","sources":["../../src/view/look.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,+DAA+D;AAE/D,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACvC,OAAO,EACL,aAAa,GAEd,MAAM,iCAAiC,CAAC;AAiBzC,MAAM,UAAU,OAAO;IACrB,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC,CAAC;QAC7C,OAAO;YACL,IAAI;YACJ,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS,IAAI,SAAS,CAAC;YAC3C,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;YACzC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC;YAC3C,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,OAAO,CAAC;YAC/C,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;YACzC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,SAAS,CAAC;YACzC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC;YAC3C,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,IAAI,SAAS,CAAC;YAC3C,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,WAAW,CAAC;YAC7C,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC;SACzB,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,QAA4B;IACtD,MAAM,KAAK,GAAG,QAAQ,EAAwC,CAAC;IAC/D,OAAO,OAAO,CACZ,GAAG,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAClE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAClB,CAAC;AACJ,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,GAAG,GAAG,GAAG;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACjC,OAAO;QACL,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC;QACvB,KAAK,KAAK,CAAC,MAAM,GAAG,GAAG,eAAe;QACtC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC;KACtB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windowkit/agent-chat",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "An embeddable chat UI for local AI agent harnesses, for react-x11: the Claude Agent SDK first, your own tools as functions, your own renderers, and every action interceptable.",
5
5
  "keywords": [
6
6
  "react-x11",
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "peerDependencies": {
70
70
  "@anthropic-ai/claude-agent-sdk": ">=0.3.300 <0.4.0",
71
- "@react-x11/components": ">=0.38.0 <0.44.0",
71
+ "@react-x11/components": "^0.44.0",
72
72
  "react": "^19.0.0",
73
73
  "react-x11": "^2.56.3"
74
74
  },
@@ -79,7 +79,7 @@
79
79
  },
80
80
  "devDependencies": {
81
81
  "@anthropic-ai/claude-agent-sdk": "^0.3.319",
82
- "@react-x11/components": "^0.43.0",
82
+ "@react-x11/components": "^0.44.0",
83
83
  "@types/node": "^26.2.0",
84
84
  "@types/pngjs": "^6.0.5",
85
85
  "@types/react": "^19.2.17",
@@ -1,6 +1,7 @@
1
1
  // A fenced code block with a header of actions: Copy by default, and
2
2
  // whatever the app's `codeActions` add. Nothing here runs code; an action
3
- // that does is the app's.
3
+ // that does is the app's. It is drawn as `<Markdown>` draws a fence, with
4
+ // the header inside the block's fill.
4
5
 
5
6
  import { useEffect, useRef, useState, type ReactElement } from 'react';
6
7
  import { Button, useClipboard } from 'react-x11';
@@ -9,7 +10,7 @@ import type { FenceInfo } from '@react-x11/components/markdown';
9
10
 
10
11
  import type { AgentMessage } from '../core/types.js';
11
12
  import { useChat } from './context.js';
12
- import { useLook } from './look.js';
13
+ import { useCodeLook, useLook } from './look.js';
13
14
  import type { CodeAction, CodeActionContext } from './types.js';
14
15
 
15
16
  export interface CodeBlockProps {
@@ -18,8 +19,9 @@ export interface CodeBlockProps {
18
19
  }
19
20
 
20
21
  export function CodeBlock({ fence, message }: CodeBlockProps): ReactElement {
21
- const { codeActions, session } = useChat();
22
+ const { codeActions, session, fontSize } = useChat();
22
23
  const look = useLook();
24
+ const code = useCodeLook(fontSize);
23
25
  const clipboard = useClipboard();
24
26
  const [done, setDone] = useState<string | null>(null);
25
27
  const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
@@ -62,9 +64,8 @@ export function CodeBlock({ fence, message }: CodeBlockProps): ReactElement {
62
64
  <box
63
65
  style={{
64
66
  flexDirection: 'column',
65
- borderWidth: 1,
66
- borderColor: look.border,
67
- borderRadius: 6,
67
+ backgroundColor: code.fill,
68
+ borderRadius: code.radius,
68
69
  overflow: 'hidden',
69
70
  }}
70
71
  >
@@ -73,11 +74,10 @@ export function CodeBlock({ fence, message }: CodeBlockProps): ReactElement {
73
74
  flexDirection: 'row',
74
75
  alignItems: 'center',
75
76
  gap: 4,
76
- paddingLeft: 10,
77
- paddingRight: 4,
77
+ paddingLeft: code.padding,
78
+ paddingRight: Math.round(code.padding / 3),
79
+ paddingTop: Math.round(code.padding / 3),
78
80
  minHeight: 26,
79
- borderBottomWidth: 1,
80
- borderBottomColor: look.border,
81
81
  }}
82
82
  >
83
83
  <text style={{ color: look.muted, fontSize: 11, flexGrow: 1 }}>
@@ -100,8 +100,15 @@ export function CodeBlock({ fence, message }: CodeBlockProps): ReactElement {
100
100
  <Code
101
101
  source={fence.text}
102
102
  {...(fence.lang ? { lang: fence.lang } : {})}
103
+ fontSize={code.size}
103
104
  wrap
104
- style={{ borderWidth: 0, borderRadius: 0 }}
105
+ // the frame holds the fill: the code's own, a tint, would lay a
106
+ // second over it
107
+ style={{
108
+ backgroundColor: 'transparent',
109
+ borderRadius: 0,
110
+ paddingTop: Math.round(code.padding / 3),
111
+ }}
105
112
  />
106
113
  </box>
107
114
  );
@@ -7,6 +7,7 @@ import { Markdown } from '@react-x11/components/markdown';
7
7
  import type { AgentMessage } from '../core/types.js';
8
8
  import { CodeBlock } from './CodeBlock.js';
9
9
  import { useChat } from './context.js';
10
+ import { useCodeLook } from './look.js';
10
11
  import { splitFences } from './fences.js';
11
12
 
12
13
  export interface TextBlockProps {
@@ -21,6 +22,8 @@ export const TextBlock = memo(function TextBlock({
21
22
  message,
22
23
  }: TextBlockProps): ReactElement {
23
24
  const { fences, components, onLink, fontSize } = useChat();
25
+ // segments alternate prose and fences: the gap is the space a fence keeps
26
+ const { spacing } = useCodeLook(fontSize);
24
27
  const segments = useMemo(
25
28
  () => splitFences(text, streaming),
26
29
  [text, streaming],
@@ -30,7 +33,7 @@ export const TextBlock = memo(function TextBlock({
30
33
  [onLink],
31
34
  );
32
35
  return (
33
- <box style={{ flexDirection: 'column', gap: 8 }}>
36
+ <box style={{ flexDirection: 'column', gap: spacing }}>
34
37
  {segments.map((s, i) => {
35
38
  if (s.type === 'prose') {
36
39
  return (
@@ -1,5 +1,8 @@
1
1
  // The scrolling transcript. It follows the newest message while the reader
2
- // is at the bottom, and stops following once they scroll up to read.
2
+ // is at the bottom, and stops following once they scroll up to read. It
3
+ // follows content that grows after it was laid out too: a fence the app
4
+ // draws itself (a diagram compiled after mount) would otherwise push the end
5
+ // of the reply out of view.
3
6
 
4
7
  import {
5
8
  useLayoutEffect,
@@ -30,6 +33,12 @@ export function Transcript({ empty }: { empty?: ReactNode }): ReactElement {
30
33
  if (stick.current) pane.current?.scrollTo(Infinity);
31
34
  }, [snap.messages, snap.status]);
32
35
 
36
+ // fires from layout whenever the content or viewport size changes, not
37
+ // only when the snapshot does
38
+ const onViewport = () => {
39
+ if (stick.current) pane.current?.scrollTo(Infinity);
40
+ };
41
+
33
42
  const onScroll = (ev: ScrollEvent) => {
34
43
  stick.current =
35
44
  ev.scrollY + ev.viewportHeight >= ev.contentHeight - STICK_PX;
@@ -40,6 +49,7 @@ export function Transcript({ empty }: { empty?: ReactNode }): ReactElement {
40
49
  <box
41
50
  ref={pane}
42
51
  onScroll={onScroll}
52
+ onViewport={onViewport}
43
53
  style={{ flexGrow: 1, flexShrink: 1, minHeight: 0, overflow: 'scroll' }}
44
54
  data-testname="agent-chat-transcript"
45
55
  >
package/src/view/look.ts CHANGED
@@ -4,6 +4,10 @@
4
4
  import { useMemo } from 'react';
5
5
  import { useTheme } from 'react-x11';
6
6
  import { tint } from 'react-x11/style';
7
+ import {
8
+ codeBlockLook,
9
+ type CodeBlockLook,
10
+ } from '@react-x11/components/codeblock';
7
11
 
8
12
  export interface ChatLook {
9
13
  text: string;
@@ -40,6 +44,19 @@ export function useLook(): ChatLook {
40
44
  }, [theme]);
41
45
  }
42
46
 
47
+ /**
48
+ * What a block of code looks like here: what `<Markdown>` draws a fence
49
+ * with, at the chat's text size, so a fence the chat draws itself (to carry
50
+ * its actions) has the fill, radius, inset and spacing of one it does not.
51
+ */
52
+ export function useCodeLook(fontSize: number | undefined): CodeBlockLook {
53
+ const theme = useTheme() as unknown as Record<string, unknown>;
54
+ return useMemo(
55
+ () => codeBlockLook(theme, fontSize ? { baseSize: fontSize } : {}),
56
+ [theme, fontSize],
57
+ );
58
+ }
59
+
43
60
  /** At most `max` lines: the first and last halves, and how many were cut. */
44
61
  export function clipLines(text: string, max = 200): string {
45
62
  const lines = text.split('\n');