@agentshouse/mdruntime 0.1.0-ca9afacd5aebd → 0.1.0-caee7332d2235

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 (155) hide show
  1. package/AGENTS.md +271 -290
  2. package/README.md +8 -8
  3. package/dist/adapter.d.ts +52 -10
  4. package/dist/adapter.d.ts.map +1 -1
  5. package/dist/attempt.d.ts.map +1 -1
  6. package/dist/attempt.js +14 -1
  7. package/dist/bootstrap.d.ts +3 -2
  8. package/dist/bootstrap.d.ts.map +1 -1
  9. package/dist/bootstrap.js +33 -7
  10. package/dist/change-set.d.ts +7 -2
  11. package/dist/change-set.d.ts.map +1 -1
  12. package/dist/change-set.js +41 -10
  13. package/dist/chat/acts.d.ts +3 -4
  14. package/dist/chat/acts.d.ts.map +1 -1
  15. package/dist/chat/acts.js +10 -10
  16. package/dist/chat/earlier.d.ts +10 -0
  17. package/dist/chat/earlier.d.ts.map +1 -0
  18. package/dist/chat/earlier.js +54 -0
  19. package/dist/chat/kit.d.ts +2 -1
  20. package/dist/chat/kit.d.ts.map +1 -1
  21. package/dist/chat/kit.js +3 -3
  22. package/dist/chat/list.d.ts +8 -1
  23. package/dist/chat/list.d.ts.map +1 -1
  24. package/dist/chat/list.js +48 -8
  25. package/dist/chat/markdown.d.ts +3 -1
  26. package/dist/chat/markdown.d.ts.map +1 -1
  27. package/dist/chat/markdown.js +85 -26
  28. package/dist/chat/message.d.ts.map +1 -1
  29. package/dist/chat/message.js +3 -3
  30. package/dist/chat/messages.d.ts +1 -0
  31. package/dist/chat/messages.d.ts.map +1 -1
  32. package/dist/chat/messages.js +35 -15
  33. package/dist/chat/pieces.d.ts +62 -0
  34. package/dist/chat/pieces.d.ts.map +1 -0
  35. package/dist/chat/pieces.js +1110 -0
  36. package/dist/chat/provider.d.ts +1 -1
  37. package/dist/chat/provider.d.ts.map +1 -1
  38. package/dist/chat/provider.js +65 -80
  39. package/dist/chat/question.d.ts +1 -1
  40. package/dist/chat/question.d.ts.map +1 -1
  41. package/dist/chat/question.js +7 -18
  42. package/dist/chat/ready.d.ts +1 -0
  43. package/dist/chat/ready.d.ts.map +1 -1
  44. package/dist/chat/ready.js +4 -4
  45. package/dist/chat/steady.d.ts +3 -0
  46. package/dist/chat/steady.d.ts.map +1 -0
  47. package/dist/chat/steady.js +26 -0
  48. package/dist/chat/style.js +4 -4
  49. package/dist/chat.d.ts +1 -1
  50. package/dist/chat.d.ts.map +1 -1
  51. package/dist/chat.js +1 -1
  52. package/dist/client.d.ts +17 -9
  53. package/dist/client.d.ts.map +1 -1
  54. package/dist/client.js +19 -6
  55. package/dist/collection.d.ts +20 -5
  56. package/dist/collection.d.ts.map +1 -1
  57. package/dist/collection.js +309 -33
  58. package/dist/connection.d.ts +31 -9
  59. package/dist/connection.d.ts.map +1 -1
  60. package/dist/connection.js +1602 -386
  61. package/dist/conversation.d.ts +20 -7
  62. package/dist/conversation.d.ts.map +1 -1
  63. package/dist/conversation.js +474 -163
  64. package/dist/durability.d.ts +7 -1
  65. package/dist/durability.d.ts.map +1 -1
  66. package/dist/entry.d.ts +17 -0
  67. package/dist/entry.d.ts.map +1 -0
  68. package/dist/entry.js +157 -0
  69. package/dist/fence.d.ts +6 -0
  70. package/dist/fence.d.ts.map +1 -0
  71. package/dist/fence.js +10 -0
  72. package/dist/host.d.ts +15 -3
  73. package/dist/host.d.ts.map +1 -1
  74. package/dist/host.js +94 -12
  75. package/dist/identity.d.ts +2 -0
  76. package/dist/identity.d.ts.map +1 -1
  77. package/dist/identity.js +6 -0
  78. package/dist/index.d.ts +10 -7
  79. package/dist/index.d.ts.map +1 -1
  80. package/dist/index.js +2 -0
  81. package/dist/memory.d.ts +8 -2
  82. package/dist/memory.d.ts.map +1 -1
  83. package/dist/memory.js +33 -6
  84. package/dist/model.d.ts +4 -2
  85. package/dist/model.d.ts.map +1 -1
  86. package/dist/model.js +10 -1
  87. package/dist/observation.d.ts +7 -2
  88. package/dist/observation.d.ts.map +1 -1
  89. package/dist/observation.js +29 -12
  90. package/dist/outcome.d.ts +12 -2
  91. package/dist/outcome.d.ts.map +1 -1
  92. package/dist/outcome.js +4 -0
  93. package/dist/overlay.d.ts +5 -3
  94. package/dist/overlay.d.ts.map +1 -1
  95. package/dist/overlay.js +203 -159
  96. package/dist/query.d.ts +56 -4
  97. package/dist/query.d.ts.map +1 -1
  98. package/dist/query.js +36 -7
  99. package/dist/reach.d.ts +6 -3
  100. package/dist/reach.d.ts.map +1 -1
  101. package/dist/reach.js +30 -5
  102. package/dist/react.d.ts +8 -6
  103. package/dist/react.d.ts.map +1 -1
  104. package/dist/react.js +7 -17
  105. package/dist/read-side.d.ts +16 -7
  106. package/dist/read-side.d.ts.map +1 -1
  107. package/dist/read-side.js +486 -100
  108. package/dist/readiness.d.ts +53 -0
  109. package/dist/readiness.d.ts.map +1 -0
  110. package/dist/readiness.js +33 -0
  111. package/dist/reads.d.ts +11 -0
  112. package/dist/reads.d.ts.map +1 -0
  113. package/dist/reads.js +98 -0
  114. package/dist/recovery.d.ts +25 -0
  115. package/dist/recovery.d.ts.map +1 -0
  116. package/dist/recovery.js +197 -0
  117. package/dist/refresh.d.ts +4 -4
  118. package/dist/refresh.d.ts.map +1 -1
  119. package/dist/refresh.js +44 -18
  120. package/dist/replica.d.ts +11 -5
  121. package/dist/replica.d.ts.map +1 -1
  122. package/dist/replica.js +111 -56
  123. package/dist/room-draft.d.ts +13 -1
  124. package/dist/room-draft.d.ts.map +1 -1
  125. package/dist/room-draft.js +11 -12
  126. package/dist/rows.d.ts +6 -13
  127. package/dist/rows.d.ts.map +1 -1
  128. package/dist/rows.js +10 -13
  129. package/dist/save.d.ts +10 -4
  130. package/dist/save.d.ts.map +1 -1
  131. package/dist/save.js +216 -108
  132. package/dist/search.d.ts +49 -6
  133. package/dist/search.d.ts.map +1 -1
  134. package/dist/search.js +192 -47
  135. package/dist/seed.d.ts +16 -0
  136. package/dist/seed.d.ts.map +1 -0
  137. package/dist/seed.js +75 -0
  138. package/dist/shared.d.ts +15 -0
  139. package/dist/shared.d.ts.map +1 -0
  140. package/dist/shared.js +398 -0
  141. package/dist/status.d.ts +4 -0
  142. package/dist/status.d.ts.map +1 -1
  143. package/dist/store.d.ts +61 -12
  144. package/dist/store.d.ts.map +1 -1
  145. package/dist/store.js +580 -268
  146. package/dist/turn.d.ts +9 -0
  147. package/dist/turn.d.ts.map +1 -0
  148. package/dist/turn.js +64 -0
  149. package/dist/windows.d.ts +26 -0
  150. package/dist/windows.d.ts.map +1 -0
  151. package/dist/windows.js +93 -0
  152. package/dist/wire.d.ts +152 -32
  153. package/dist/wire.d.ts.map +1 -1
  154. package/dist/wire.js +52 -31
  155. package/package.json +12 -8
@@ -0,0 +1,54 @@
1
+ import { useCallback, useMemo, useState } from 'react';
2
+ export const CHAT_WINDOW = 50;
3
+ function slidOut(before, after) {
4
+ if (before === null || before.conversation !== after.conversation)
5
+ return [];
6
+ const kept = new Set(after.messages.map((one) => one.identity));
7
+ const left = [];
8
+ for (const message of before.messages) {
9
+ if (kept.has(message.identity))
10
+ break;
11
+ left.push(message);
12
+ }
13
+ return left;
14
+ }
15
+ function joined(held, earlier) {
16
+ const { next: _live, ...view } = held;
17
+ const live = new Set(held.messages.map((one) => one.identity));
18
+ return {
19
+ ...view,
20
+ messages: [...earlier.messages.filter((one) => !live.has(one.identity)), ...held.messages],
21
+ ...(earlier.next === undefined ? {} : { next: earlier.next }),
22
+ };
23
+ }
24
+ export function useEarlier(client, thread, held) {
25
+ const [earlier, setEarlier] = useState(null);
26
+ const [seen, setSeen] = useState(held);
27
+ const whole = held !== null && held.next === undefined;
28
+ let current = earlier !== null && earlier.thread === thread && !whole ? earlier : null;
29
+ if (current !== earlier)
30
+ setEarlier(current);
31
+ if (seen !== held) {
32
+ setSeen(held);
33
+ const carried = held === null ? [] : slidOut(seen, held);
34
+ if (thread !== null && carried.length > 0) {
35
+ const base = current ?? { thread, messages: [], next: seen?.next };
36
+ current = { ...base, messages: [...base.messages, ...carried] };
37
+ setEarlier(current);
38
+ }
39
+ }
40
+ const view = useMemo(() => (held === null || current === null ? held : joined(held, current)), [held, current]);
41
+ const next = current === null ? held?.next : current.next;
42
+ const loadEarlier = useCallback(async () => {
43
+ if (thread === null || next === undefined)
44
+ return;
45
+ const older = await client.conversation.read(thread, { limit: CHAT_WINDOW, after: next });
46
+ setEarlier((now) => {
47
+ const base = now !== null && now.thread === thread ? now : { thread, messages: [], next };
48
+ if (base.next !== next)
49
+ return now;
50
+ return { thread, messages: [...older.messages, ...base.messages], next: older.next };
51
+ });
52
+ }, [client, thread, next]);
53
+ return { view, hasEarlier: next !== undefined, loadEarlier };
54
+ }
@@ -48,7 +48,8 @@ export declare function ItemRow({ lead, title, sub, trailing, }: {
48
48
  sub: ReactNode;
49
49
  trailing: ReactNode;
50
50
  }): ReactElement;
51
- export declare function Working({ step }: {
51
+ export declare function Working({ label, step, }: {
52
+ label?: string;
52
53
  step?: string | undefined;
53
54
  }): ReactElement;
54
55
  export type ChatNoteProps = {
@@ -1 +1 @@
1
- {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/chat/kit.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kit.d.ts","sourceRoot":"","sources":["../../src/chat/kit.tsx"],"names":[],"mappings":"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"}
package/dist/chat/kit.js CHANGED
@@ -94,7 +94,7 @@ export function ItemRow({ lead, title, sub, trailing, }) {
94
94
  function elapsed(seconds) {
95
95
  return seconds >= 60 ? `${Math.floor(seconds / 60)}m ${seconds % 60}s` : `${seconds}s`;
96
96
  }
97
- export function Working({ step }) {
97
+ export function Working({ label = 'Working', step, }) {
98
98
  const [from] = useState(() => Date.now());
99
99
  const [now, setNow] = useState(from);
100
100
  useEffect(() => {
@@ -102,11 +102,11 @@ export function Working({ step }) {
102
102
  const tick = setInterval(() => setNow(Date.now()), 1000);
103
103
  return () => clearInterval(tick);
104
104
  }, []);
105
- return (_jsxs("div", { className: "ahc-toolline ahc-working", role: "status", children: [_jsx("span", { className: "ahc-shimmer", children: "Working" }), _jsx("span", { className: "ahc-figure", "aria-hidden": "true", children: elapsed(Math.floor((now - from) / 1000)) }), step === undefined ? null : _jsx("span", { children: step })] }));
105
+ return (_jsxs("div", { className: "ahc-toolline ahc-working", role: "status", children: [_jsx("span", { className: "ahc-shimmer", children: label }), _jsx("span", { className: "ahc-figure", "aria-hidden": "true", children: elapsed(Math.floor((now - from) / 1000)) }), step === undefined ? null : _jsx("span", { children: step })] }));
106
106
  }
107
107
  const SAID = {
108
108
  sending: 'Sending…',
109
- offline: 'You are offline. Nothing was sent.',
109
+ offline: 'House can’t be reached. Nothing was sent.',
110
110
  };
111
111
  const UNANSWERED = 'House did not answer.';
112
112
  export function ChatNote({ outcome, again }) {
@@ -1,5 +1,11 @@
1
1
  import { type ComponentType, type ReactElement, type ReactNode } from 'react';
2
2
  export type AgentLook = {
3
+ readonly AgentLink?: ComponentType<{
4
+ agent: string;
5
+ className: string;
6
+ children: ReactNode;
7
+ 'aria-current': 'true' | undefined;
8
+ }> | undefined;
3
9
  readonly agentMark?: ((agent: string, size: number) => ReactNode) | undefined;
4
10
  readonly agentDetail?: ((agent: string) => string) | undefined;
5
11
  };
@@ -11,9 +17,10 @@ export type ChatMessageListProps = {
11
17
  };
12
18
  readonly onLink?: (href: string) => void;
13
19
  readonly footer?: ReactNode;
20
+ readonly waiting?: string | null;
14
21
  readonly children?: ReactNode;
15
22
  };
16
- export declare function ChatMessageList({ components, onLink, footer, children, }: ChatMessageListProps): ReactElement;
23
+ export declare function ChatMessageList({ components, onLink, footer, waiting, children, }: ChatMessageListProps): ReactElement;
17
24
  export declare function ChatList({ onChoose }: {
18
25
  onChoose: () => void;
19
26
  }): ReactElement;
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/chat/list.tsx"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CAChE,CAAC;AAEF,eAAO,MAAM,SAAS,oCAA+B,CAAC;AAmDtD,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE;QACpB,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC;QACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,aAAa,CAAC;KAC3C,CAAC;IACF,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAC9B,UAAe,EACf,MAAM,EACN,MAAM,EACN,QAAQ,GACT,EAAE,oBAAoB,GAAG,YAAY,CAmCrC;AAoBD,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,GAAG,YAAY,CAkD7E"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/chat/list.tsx"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAaf,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,SAAS,CAAC,EACf,aAAa,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,SAAS,CAAC;QACpB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;KACpC,CAAC,GACF,SAAS,CAAC;IACd,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,SAAS,CAAC,GAAG,SAAS,CAAC;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CAChE,CAAC;AAEF,eAAO,MAAM,SAAS,oCAA+B,CAAC;AAkEtD,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE;QACpB,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC;QACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,aAAa,CAAC;KAC3C,CAAC;IACF,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAC9B,UAAe,EACf,MAAM,EACN,MAAM,EACN,OAAO,EACP,QAAQ,GACT,EAAE,oBAAoB,GAAG,YAAY,CAsErC;AAoBD,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,MAAM,IAAI,CAAA;CAAE,GAAG,YAAY,CAkD7E"}
package/dist/chat/list.js CHANGED
@@ -1,33 +1,73 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { createContext, useContext, } from 'react';
3
- import { ThreadPrimitive } from '@assistant-ui/react';
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { createContext, useContext, useEffect, useRef, } from 'react';
3
+ import { ThreadPrimitive, useAui } from '@assistant-ui/react';
4
4
  import Check from 'lucide-react/dist/esm/icons/check.mjs';
5
5
  import MessageSquare from 'lucide-react/dist/esm/icons/message-square.mjs';
6
6
  import SquarePen from 'lucide-react/dist/esm/icons/square-pen.mjs';
7
- import { Name, Scoped } from './kit.js';
7
+ import { Name, Scoped, Working } from './kit.js';
8
8
  import { AssistantMessage, Linked, UserMessage } from './message.js';
9
+ import { awaitsTurn } from './messages.js';
9
10
  import { ChatName } from './name.js';
10
11
  import { useOpened } from './opened.js';
11
12
  import { ChatQuestionCard } from './question.js';
12
13
  export const Described = createContext({});
14
+ const EARLIER_MARGIN = 240;
13
15
  function Chip({ agent, name, on, start, }) {
14
- const { agentMark, agentDetail } = useContext(Described);
15
- return (_jsxs("button", { type: "button", className: "ahc-btn ahc-agent", "aria-pressed": on, onClick: () => start(agent), children: [agentMark?.(agent, 16), _jsx(Name, { text: name }), agentDetail === undefined ? null : _jsx(Name, { text: agentDetail(agent), className: "ahc-meta" })] }));
16
+ const { agentMark, agentDetail, AgentLink } = useContext(Described);
17
+ const content = (_jsxs(_Fragment, { children: [agentMark?.(agent, 16), _jsx(Name, { text: name }), agentDetail === undefined ? null : _jsx(Name, { text: agentDetail(agent), className: "ahc-meta" })] }));
18
+ if (AgentLink !== undefined)
19
+ return (_jsx(AgentLink, { agent: agent, className: "ahc-btn ahc-agent", "aria-current": on ? 'true' : undefined, children: content }));
20
+ return (_jsx("button", { type: "button", className: "ahc-btn ahc-agent", "aria-pressed": on, onClick: () => start(agent), children: content }));
16
21
  }
17
22
  function Empty() {
18
23
  const chat = useOpened();
19
24
  return (_jsxs("div", { className: "ahc-empty", children: [_jsx("h2", { className: "ahc-empty__title", children: "What should we work on?" }), chat.conversation === null &&
20
25
  (chat.agents.length > 1 || !chat.agents.some((one) => one.identity === chat.by)) ? (_jsx("div", { role: "group", "aria-label": "Agent", className: "ahc-agents", children: chat.agents.map((one) => (_jsx(Chip, { agent: one.identity, name: one.name, on: one.identity === chat.by, start: chat.start }, one.identity))) })) : null] }));
21
26
  }
22
- export function ChatMessageList({ components = {}, onLink, footer, children, }) {
27
+ export function ChatMessageList({ components = {}, onLink, footer, waiting, children, }) {
23
28
  const chat = useOpened();
24
29
  const linked = useContext(Linked);
30
+ const aui = useAui();
31
+ const viewport = useRef(null);
32
+ const content = useRef(null);
33
+ const anchor = useRef(null);
34
+ const first = chat.view?.messages[0]?.identity;
35
+ const shownFirst = useRef(first);
36
+ shownFirst.current = first;
37
+ useEffect(() => {
38
+ const element = viewport.current;
39
+ const inner = content.current;
40
+ if (element === null || inner === null)
41
+ return;
42
+ const kept = new ResizeObserver(() => {
43
+ const held = anchor.current;
44
+ if (held === null || held.first === shownFirst.current)
45
+ return;
46
+ if (element.scrollHeight === held.height)
47
+ return;
48
+ anchor.current = null;
49
+ element.scrollTop += element.scrollHeight - held.height;
50
+ });
51
+ kept.observe(inner);
52
+ return () => kept.disconnect();
53
+ }, []);
54
+ const earlier = () => {
55
+ const element = viewport.current;
56
+ if (element === null || element.scrollTop > EARLIER_MARGIN)
57
+ return;
58
+ const thread = aui.thread();
59
+ const state = thread.getState();
60
+ if (!state.hasEarlier || state.isLoadingEarlier)
61
+ return;
62
+ anchor.current = { height: element.scrollHeight, first };
63
+ void thread.loadEarlier();
64
+ };
25
65
  const User = components.UserMessage ?? UserMessage;
26
66
  const Assistant = components.AssistantMessage ?? AssistantMessage;
27
67
  const silent = chat.view === null
28
68
  ? chat.conversation === null
29
69
  : chat.view.messages.length === 0 && chat.view.turn === null;
30
- return (_jsx(Scoped, { children: _jsx(Linked.Provider, { value: onLink ?? linked, children: _jsx(ThreadPrimitive.Root, { className: "ahc-thread", children: _jsxs(ThreadPrimitive.Viewport, { className: "ahc-viewport", children: [_jsxs("div", { className: "ahc-column ahc-messages", children: [silent ? _jsx(Empty, {}) : null, _jsx(ThreadPrimitive.Messages, { children: ({ message }) => (message.role === 'user' ? _jsx(User, {}) : _jsx(Assistant, {})) }), children === undefined
70
+ return (_jsx(Scoped, { children: _jsx(Linked.Provider, { value: onLink ?? linked, children: _jsx(ThreadPrimitive.Root, { className: "ahc-thread", children: _jsxs(ThreadPrimitive.Viewport, { className: "ahc-viewport", ref: viewport, onScroll: earlier, children: [_jsxs("div", { className: "ahc-column ahc-messages", ref: content, children: [silent ? _jsx(Empty, {}) : null, _jsx(ThreadPrimitive.Messages, { components: { UserMessage: User, AssistantMessage: Assistant } }), waiting == null || !awaitsTurn(chat.view) ? null : (_jsx("div", { className: "ahc-turn", children: _jsx(Working, { label: waiting }) })), children === undefined
31
71
  ? chat.questions.map((question) => (_jsx(ChatQuestionCard, { question: question }, question.interaction)))
32
72
  : children] }), footer === undefined ? null : (_jsx(ThreadPrimitive.ViewportFooter, { className: "ahc-column ahc-footer", children: footer }))] }) }) }) }));
33
73
  }
@@ -1,7 +1,8 @@
1
1
  import { type ReactElement, type ReactNode } from 'react';
2
2
  export interface FileReference {
3
3
  readonly pattern: RegExp;
4
- readonly draw: (reference: string, label: string) => ReactNode;
4
+ readonly names?: (destination: string) => boolean;
5
+ readonly draw: (reference: string, label: string, image: boolean) => ReactNode;
5
6
  }
6
7
  interface MarkdownOptions {
7
8
  readonly className?: string;
@@ -10,6 +11,7 @@ interface MarkdownOptions {
10
11
  }
11
12
  export declare function slugOf(text: string): string;
12
13
  export declare function anchorOf(fragment: string): string;
14
+ export declare function revealed(anchor: string): HTMLElement | null;
13
15
  export declare function plainText(text: string): string;
14
16
  export type MarkdownProps = MarkdownOptions & {
15
17
  readonly text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/chat/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,YAAY,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKnF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;CAChE;AAED,UAAU,eAAe;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC;CAC/B;AAYD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3C;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjD;AAiND,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,EAAE,aAAa,GAAG,YAAY,CAOrF"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/chat/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,YAAY,EACjB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAYf,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;IAClD,QAAQ,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,SAAS,CAAC;CAChF;AAED,UAAU,eAAe;IACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC;CAC/B;AAYD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM3C;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjD;AAkED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAK3D;AA4JD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExE,wBAAgB,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,EAAE,EAAE,aAAa,GAAG,YAAY,CAgDrF"}
@@ -1,10 +1,9 @@
1
- import { createElement, Fragment } from 'react';
2
- import { fromMarkdown } from 'mdast-util-from-markdown';
3
- import { gfmFromMarkdown } from 'mdast-util-gfm';
4
- import { gfm } from 'micromark-extension-gfm';
1
+ import { createElement, Fragment, useEffect, useMemo, useRef, useState, } from 'react';
2
+ import { flushSync } from 'react-dom';
3
+ import { drawn, longOf, parseMarkdown, pieceAt, remaining, } from './pieces.js';
5
4
  function unfiled(options) {
6
- const { definitions, slugs, onLink } = options;
7
- return onLink === undefined ? { definitions, slugs } : { definitions, slugs, onLink };
5
+ const { definitions, ids, onLink } = options;
6
+ return onLink === undefined ? { definitions, ids } : { definitions, ids, onLink };
8
7
  }
9
8
  export function slugOf(text) {
10
9
  return text
@@ -23,7 +22,8 @@ function headingId(slugs, text) {
23
22
  return anchorOf(seen === 0 ? slug : `${slug}-${seen}`);
24
23
  }
25
24
  function whole(file, text) {
26
- return file !== undefined && [...text.matchAll(file.pattern)].some((one) => one[0] === text);
25
+ return (file !== undefined &&
26
+ ([...text.matchAll(file.pattern)].some((one) => one[0] === text) || file.names?.(text) === true));
27
27
  }
28
28
  function referenced(file, text, key) {
29
29
  const parts = [];
@@ -32,7 +32,7 @@ function referenced(file, text, key) {
32
32
  const at = found.index;
33
33
  if (at > from)
34
34
  parts.push(text.slice(from, at));
35
- parts.push(createElement(Fragment, { key: at }, file.draw(found[0], found[0])));
35
+ parts.push(createElement(Fragment, { key: at }, file.draw(found[0], found[0], false)));
36
36
  from = at + found[0].length;
37
37
  }
38
38
  if (from === 0)
@@ -41,9 +41,6 @@ function referenced(file, text, key) {
41
41
  parts.push(text.slice(from));
42
42
  return createElement(Fragment, { key }, ...parts);
43
43
  }
44
- function parseMarkdown(text) {
45
- return fromMarkdown(text, { extensions: [gfm()], mdastExtensions: [gfmFromMarkdown()] });
46
- }
47
44
  function safeHref(url) {
48
45
  const href = url.replace(/[\t\n\r]/g, '').replace(/^[\u0000-\u0020]+|[\u0000-\u0020]+$/g, '');
49
46
  if (href === '' || /^[\\/]{2}/.test(href))
@@ -64,17 +61,36 @@ function textOf(node) {
64
61
  return node.children.map(textOf).join('');
65
62
  return '';
66
63
  }
67
- function definitionsOf(node, found = new Map()) {
68
- if (node.type === 'definition' && !found.has(node.identifier))
69
- found.set(node.identifier, node.url);
70
- if ('children' in node)
71
- for (const child of node.children)
72
- definitionsOf(child, found);
73
- return found;
64
+ function headingIds(nodes, slugs, ids) {
65
+ for (const node of nodes) {
66
+ if (node.type === 'heading')
67
+ ids.set(node, headingId(slugs, textOf(node)));
68
+ else if (node.type === 'blockquote' || node.type === 'list' || node.type === 'listItem') {
69
+ headingIds(node.children, slugs, ids);
70
+ }
71
+ }
72
+ }
73
+ const revealers = new Set();
74
+ export function revealed(anchor) {
75
+ const heading = document.getElementById(anchor);
76
+ if (heading !== null)
77
+ return heading;
78
+ for (const reveal of revealers)
79
+ if (reveal(anchor))
80
+ return document.getElementById(anchor);
81
+ return null;
82
+ }
83
+ function fragmentOf(href) {
84
+ try {
85
+ return decodeURIComponent(href.slice(1));
86
+ }
87
+ catch {
88
+ return href.slice(1);
89
+ }
74
90
  }
75
91
  function link(url, node, key, options) {
76
- if (options.file !== undefined && whole(options.file, url)) {
77
- return createElement(Fragment, { key }, options.file.draw(url, textOf(node) || url));
92
+ if (whole(options.file, url)) {
93
+ return createElement(Fragment, { key }, options.file.draw(url, textOf(node) || url, false));
78
94
  }
79
95
  const inside = node.children.map((child, at) => render(child, at, unfiled(options)));
80
96
  const href = safeHref(url);
@@ -82,7 +98,8 @@ function link(url, node, key, options) {
82
98
  return createElement(Fragment, { key }, ...inside);
83
99
  const onLink = options.onLink;
84
100
  if (external(href) || onLink === undefined) {
85
- return createElement('a', { key, href, rel: 'noreferrer' }, ...inside);
101
+ const onClick = href.startsWith('#') ? () => revealed(fragmentOf(href)) : undefined;
102
+ return createElement('a', { key, href, rel: 'noreferrer', onClick }, ...inside);
86
103
  }
87
104
  return createElement('a', {
88
105
  key,
@@ -103,7 +120,7 @@ function render(node, key, options, header = false) {
103
120
  case 'paragraph':
104
121
  return createElement('p', { key }, ...children());
105
122
  case 'heading':
106
- return createElement(`h${node.depth}`, { key, id: headingId(options.slugs, textOf(node)) }, ...children());
123
+ return createElement(`h${node.depth}`, { key, id: options.ids.get(node) }, ...children());
107
124
  case 'text':
108
125
  return options.file === undefined ? node.value : referenced(options.file, node.value, key);
109
126
  case 'emphasis':
@@ -139,8 +156,8 @@ function render(node, key, options, header = false) {
139
156
  case 'linkReference':
140
157
  return link(options.definitions.get(node.identifier) ?? '', node, key, options);
141
158
  case 'image':
142
- return options.file !== undefined && whole(options.file, node.url)
143
- ? createElement(Fragment, { key }, options.file.draw(node.url, node.alt || node.url))
159
+ return whole(options.file, node.url)
160
+ ? createElement(Fragment, { key }, options.file.draw(node.url, node.alt || node.url, true))
144
161
  : (node.alt ?? '');
145
162
  case 'html':
146
163
  return node.value;
@@ -182,6 +199,48 @@ export function plainText(text) {
182
199
  return spokenOf(parseMarkdown(text)).replace(/\s+/g, ' ').trim();
183
200
  }
184
201
  export function Markdown({ text, className, ...options }) {
185
- const root = parseMarkdown(text);
186
- return createElement('div', { className }, render(root, 0, { ...options, definitions: definitionsOf(root), slugs: new Map() }));
202
+ const long = useMemo(() => longOf(text), [text]);
203
+ const [shown, setShown] = useState(1);
204
+ const more = useRef(null);
205
+ const nodes = drawn(long, shown);
206
+ const showing = Math.min(shown, long.pieces.length);
207
+ const rest = remaining(long, showing);
208
+ useEffect(() => {
209
+ const sentinel = more.current;
210
+ if (sentinel === null)
211
+ return;
212
+ const watcher = new IntersectionObserver((seen) => {
213
+ if (seen.some((one) => one.isIntersecting))
214
+ setShown(showing + 1);
215
+ }, { rootMargin: '0px 0px 100% 0px' });
216
+ watcher.observe(sentinel);
217
+ return () => watcher.disconnect();
218
+ }, [showing, long]);
219
+ useEffect(() => {
220
+ if (!rest)
221
+ return;
222
+ const reveal = (anchor) => {
223
+ const slugs = new Map();
224
+ for (let index = 0;; index += 1) {
225
+ const piece = pieceAt(long, index);
226
+ if (piece === null)
227
+ return false;
228
+ const ids = new Map();
229
+ headingIds(piece.nodes, slugs, ids);
230
+ if ([...ids.values()].includes(anchor)) {
231
+ if (index >= showing)
232
+ flushSync(() => setShown(index + 1));
233
+ return true;
234
+ }
235
+ }
236
+ };
237
+ revealers.add(reveal);
238
+ return () => {
239
+ revealers.delete(reveal);
240
+ };
241
+ }, [showing, long, rest]);
242
+ const ids = new Map();
243
+ headingIds(nodes, new Map(), ids);
244
+ const rendering = { ...options, definitions: long.urls, ids };
245
+ return createElement('div', { className }, ...nodes.map((node, at) => render(node, at, rendering)), rest ? createElement('div', { key: 'more', ref: more }) : null);
187
246
  }
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/chat/message.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EAElB,MAAM,OAAO,CAAC;AAkCf,eAAO,MAAM,MAAM,kCAAyB,MAAM,KAAK,IAAI,SAAe,CAAC;AA4O3E,wBAAgB,WAAW,IAAI,YAAY,CA4B1C;AAED,wBAAgB,WAAW,IAAI,YAAY,CAE1C;AAED,wBAAgB,gBAAgB,IAAI,YAAY,CA0F/C"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../src/chat/message.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,YAAY,EAElB,MAAM,OAAO,CAAC;AAmCf,eAAO,MAAM,MAAM,kCAAyB,MAAM,KAAK,IAAI,SAAe,CAAC;AA2O3E,wBAAgB,WAAW,IAAI,YAAY,CA4B1C;AAED,wBAAgB,WAAW,IAAI,YAAY,CAE1C;AAED,wBAAgB,gBAAgB,IAAI,YAAY,CA0F/C"}
@@ -20,6 +20,7 @@ import RotateCw from 'lucide-react/dist/esm/icons/rotate-cw.mjs';
20
20
  import Send from 'lucide-react/dist/esm/icons/send.mjs';
21
21
  import SlidersHorizontal from 'lucide-react/dist/esm/icons/sliders-horizontal.mjs';
22
22
  import Terminal from 'lucide-react/dist/esm/icons/terminal.mjs';
23
+ import { SESSION_STARTED } from '../conversation.js';
23
24
  import { buttonClass, Name, Working } from './kit.js';
24
25
  import { StillRunning } from './lasting.js';
25
26
  import { list, record, text } from './read.js';
@@ -29,7 +30,6 @@ const groupBy = groupPartByType({
29
30
  'tool-call': ['group-thought'],
30
31
  });
31
32
  const GFM = [remarkGfm];
32
- const STARTED = 'Session started';
33
33
  const SENT = {
34
34
  send_routine_request: 'Sent a request',
35
35
  cancel_routine_request: 'Cancelled a request',
@@ -148,7 +148,7 @@ function Anchor({ node: _node, href = '', ...rest }) {
148
148
  const LINKED = { a: Anchor };
149
149
  const THOUGHT = { className: 'ahc-thought' };
150
150
  function Said({ thought = false }) {
151
- return (_jsx(MarkdownTextPrimitive, { className: "ahc-text ahc-markdown", containerProps: thought ? THOUGHT : undefined, remarkPlugins: GFM, components: LINKED }));
151
+ return (_jsx(MarkdownTextPrimitive, { className: "ahc-text ahc-markdown", containerProps: thought ? THOUGHT : undefined, remarkPlugins: GFM, components: LINKED, smooth: false }));
152
152
  }
153
153
  function UserText() {
154
154
  return _jsx(MessagePartPrimitive.Text, { className: "ahc-said" });
@@ -184,7 +184,7 @@ export function AssistantMessage() {
184
184
  case 'file':
185
185
  return (_jsxs("div", { className: "ahc-toolline ahc-quiet", children: [_jsx(ImageGlyph, { "aria-hidden": "true" }), _jsx("span", { className: "ahc-clipped", children: part.filename })] }));
186
186
  case 'indicator':
187
- return _jsx(Working, { step: started ? STARTED : undefined });
187
+ return _jsx(Working, { step: started ? SESSION_STARTED : undefined });
188
188
  default:
189
189
  return null;
190
190
  }
@@ -14,6 +14,7 @@ export type Said = {
14
14
  readonly files: readonly string[];
15
15
  };
16
16
  export declare function saidOf(entry: Entry): Said;
17
+ export declare function awaitsTurn(view: ConversationView | null): boolean;
17
18
  export declare function askedBefore(view: ConversationView | null, id: string | null): string | null;
18
19
  export declare function chatMessages(view: ConversationView | null): ThreadMessageLike[];
19
20
  export declare function contextOf(view: ConversationView | null): TurnContext | null;
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/chat/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAA0D,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAO/F,KAAK,KAAK,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAYzC;AAkED,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAO3F;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,GAAG,iBAAiB,EAAE,CAsD/E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAS3E"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/chat/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAA0D,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAO/F,KAAK,KAAK,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAElD,MAAM,MAAM,IAAI,GAAG;IACjB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAYF,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAgBzC;AA2FD,wBAAgB,UAAU,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAGjE;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAO3F;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,GAAG,iBAAiB,EAAE,CAkD/E;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,GAAG,WAAW,GAAG,IAAI,CAS3E"}
@@ -1,8 +1,13 @@
1
1
  import { contextIn, jobOf, partsOf, stillRunning } from './parts.js';
2
2
  import { list, record, text } from './read.js';
3
+ const SAID = new WeakMap();
4
+ const CONVERTED = new WeakMap();
3
5
  export function saidOf(entry) {
6
+ const held = SAID.get(entry);
7
+ if (held !== undefined)
8
+ return held;
4
9
  const message = record(entry.message);
5
- return {
10
+ const said = {
6
11
  turn: text(message, 'turn_id') ?? entry.turn,
7
12
  user: text(message, 'role') === 'user',
8
13
  text: text(message, 'text') ?? '',
@@ -12,6 +17,21 @@ export function saidOf(entry) {
12
17
  undelivered: message.telegram_undelivered === true,
13
18
  files: list(message, 'files').flatMap((one) => text(record(one), 'name') ?? []),
14
19
  };
20
+ SAID.set(entry, said);
21
+ return said;
22
+ }
23
+ function sameWork(held, now) {
24
+ return (held.length === now.length &&
25
+ held.every((one, at) => one.kind === now[at].kind && one.title === now[at].title && one.next === now[at].next));
26
+ }
27
+ function converted(entry, lasting, again, convert) {
28
+ const held = CONVERTED.get(entry);
29
+ if (held !== undefined && held.again === again && sameWork(held.lasting, lasting)) {
30
+ return held.message;
31
+ }
32
+ const message = convert();
33
+ CONVERTED.set(entry, { lasting, again, message });
34
+ return message;
15
35
  }
16
36
  function markerArgs(part) {
17
37
  if (part.marker !== 'job')
@@ -73,6 +93,10 @@ function leftRunning(view) {
73
93
  ? turns
74
94
  : [...turns, { turn: view.turn.turn, parts: partsOf(view.turn.parts), ended: false }]);
75
95
  }
96
+ export function awaitsTurn(view) {
97
+ const newest = view?.messages.at(-1);
98
+ return view?.turn === null && newest !== undefined && saidOf(newest).user;
99
+ }
76
100
  export function askedBefore(view, id) {
77
101
  const said = (view?.messages ?? []).map((entry) => ({ ...saidOf(entry), id: entry.identity }));
78
102
  const asked = said
@@ -89,7 +113,7 @@ export function chatMessages(view) {
89
113
  const one = saidOf(entry);
90
114
  const custom = { undelivered: one.undelivered };
91
115
  if (one.user) {
92
- return {
116
+ return converted(entry, [], false, () => ({
93
117
  id: entry.identity,
94
118
  role: 'user',
95
119
  content: [{ type: 'text', text: one.text }],
@@ -101,27 +125,23 @@ export function chatMessages(view) {
101
125
  content: [],
102
126
  })),
103
127
  metadata: { custom },
104
- };
128
+ }));
105
129
  }
106
130
  const failed = one.failure === null
107
131
  ? undefined
108
132
  : { type: 'incomplete', reason: 'error', error: one.failure };
109
- return {
133
+ const working = lasting.get(one.turn) ?? [];
134
+ const again = failed !== undefined &&
135
+ view.turn === null &&
136
+ at === view.messages.length - 1 &&
137
+ askedBefore(view, view.messages[at - 1]?.identity ?? null) !== null;
138
+ return converted(entry, working, again, () => ({
110
139
  id: entry.identity,
111
140
  role: 'assistant',
112
141
  content: contentOf(entry.identity, one.parts, false),
113
142
  status: failed,
114
- metadata: {
115
- custom: {
116
- ...custom,
117
- lasting: lasting.get(one.turn) ?? [],
118
- again: failed !== undefined &&
119
- view.turn === null &&
120
- at === view.messages.length - 1 &&
121
- askedBefore(view, view.messages[at - 1]?.identity ?? null) !== null,
122
- },
123
- },
124
- };
143
+ metadata: { custom: { ...custom, lasting: working, again } },
144
+ }));
125
145
  });
126
146
  if (view.turn === null)
127
147
  return said;
@@ -0,0 +1,62 @@
1
+ import { fromMarkdown } from 'mdast-util-from-markdown';
2
+ export type Root = ReturnType<typeof fromMarkdown>;
3
+ export type Block = Root['children'][number];
4
+ export declare function parseMarkdown(text: string): Root;
5
+ export type Step = 'list' | 'item' | 'footnote' | 'table' | 'blockquote' | 'paragraph';
6
+ export interface Piece {
7
+ readonly nodes: readonly Block[];
8
+ readonly path: readonly Step[];
9
+ readonly join: string;
10
+ }
11
+ interface Level {
12
+ readonly kind: 'quote' | 'item' | 'note';
13
+ readonly line: number;
14
+ readonly column: number;
15
+ readonly size: number;
16
+ readonly carry: string;
17
+ readonly spread: boolean;
18
+ }
19
+ interface Next {
20
+ readonly start: number;
21
+ readonly path: readonly Step[];
22
+ readonly join: string;
23
+ readonly carry: string;
24
+ readonly levels: readonly Level[];
25
+ }
26
+ interface Found {
27
+ readonly key: string;
28
+ readonly at: number;
29
+ readonly url: string;
30
+ }
31
+ interface Region {
32
+ readonly from: number;
33
+ readonly looks: readonly number[];
34
+ readonly last: ReadonlyMap<string, number>;
35
+ readonly runs: ReadonlyMap<number, number>;
36
+ }
37
+ interface Discovery {
38
+ readonly found: Found[];
39
+ next: Next | null;
40
+ }
41
+ export interface Long {
42
+ readonly text: string;
43
+ readonly starts: Int32Array;
44
+ readonly breaks: Int32Array;
45
+ readonly quoteBreaks: Int32Array;
46
+ readonly anchors: readonly number[];
47
+ readonly candidates: ReadonlyMap<string, readonly number[]>;
48
+ readonly pieces: Piece[];
49
+ next: Next | null;
50
+ readonly urls: Map<string, string>;
51
+ readonly spans: Map<string, readonly Found[]>;
52
+ readonly discoveries: Map<number, Discovery>;
53
+ readonly regions: Map<string, Region>;
54
+ readonly spreads: Map<number, boolean | null>;
55
+ }
56
+ export declare function identifierOf(label: string): string;
57
+ export declare function longOf(text: string): Long;
58
+ export declare function pieceAt(long: Long, index: number): Piece | null;
59
+ export declare function drawn(long: Long, count: number): Block[];
60
+ export declare function remaining(long: Long, count: number): boolean;
61
+ export {};
62
+ //# sourceMappingURL=pieces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pieces.d.ts","sourceRoot":"","sources":["../../src/chat/pieces.ts"],"names":[],"mappings":"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"}