@jini-ai/chat 0.3.11 → 0.5.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 (205) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +152 -6
  3. package/dist/core/ag-ui/entry.d.ts +53 -0
  4. package/dist/core/ag-ui/entry.js +135 -0
  5. package/dist/core/agentic/chat-capabilities.d.ts +1 -1
  6. package/dist/core/agentic/index.d.ts +1 -1
  7. package/dist/core/agentic/index.js +1 -1
  8. package/dist/core/assistant-content.d.ts +6 -2
  9. package/dist/core/assistant-content.js +2 -2
  10. package/dist/core/compact-events.d.ts +3 -1
  11. package/dist/core/compact-events.js +1 -1
  12. package/dist/core/events.d.ts +1 -1
  13. package/dist/core/events.js +1 -1
  14. package/dist/core/index.d.ts +3 -3
  15. package/dist/core/index.js +3 -3
  16. package/dist/core/messages.d.ts +4 -2
  17. package/dist/core/messages.js +2 -2
  18. package/dist/core/partial-json.d.ts +6 -2
  19. package/dist/core/partial-json.js +3 -3
  20. package/dist/core/persistence/index.d.ts +1 -1
  21. package/dist/core/persistence/index.js +1 -1
  22. package/dist/core/persistence/ports.d.ts +2 -123
  23. package/dist/core/persistence/title.d.ts +3 -1
  24. package/dist/core/persistence/title.js +1 -1
  25. package/dist/core/question-form/format.d.ts +16 -7
  26. package/dist/core/question-form/format.js +3 -3
  27. package/dist/core/question-form/normalize.d.ts +7 -2
  28. package/dist/core/question-form/normalize.js +5 -5
  29. package/dist/core/question-form/scan.d.ts +18 -6
  30. package/dist/core/question-form/scan.js +14 -14
  31. package/dist/core/run-activity.d.ts +16 -4
  32. package/dist/core/run-activity.js +11 -11
  33. package/dist/core/run-events/entry.d.ts +121 -0
  34. package/dist/core/run-events/entry.js +290 -0
  35. package/dist/core/todos.d.ts +20 -8
  36. package/dist/core/todos.js +11 -11
  37. package/dist/core/tool-events.d.ts +3 -1
  38. package/dist/core/tool-events.js +1 -1
  39. package/dist/core/tool-output.d.ts +3 -1
  40. package/dist/core/tool-output.js +1 -1
  41. package/dist/core/tools.d.ts +14 -3
  42. package/dist/core/tools.js +3 -3
  43. package/dist/core/transcript.d.ts +13 -5
  44. package/dist/core/transcript.js +5 -5
  45. package/dist/core/util/manifest.d.ts +9 -3
  46. package/dist/core/util/manifest.js +3 -3
  47. package/dist/core/util/markdown-context.d.ts +11 -3
  48. package/dist/core/util/markdown-context.js +3 -3
  49. package/dist/core/util/markup-attributes.d.ts +3 -1
  50. package/dist/core/util/markup-attributes.js +1 -1
  51. package/dist/core/util/parser.d.ts +9 -5
  52. package/dist/core/util/parser.js +13 -13
  53. package/dist/core/util/recover.d.ts +6 -2
  54. package/dist/core/util/recover.js +6 -6
  55. package/dist/core/util/strip.d.ts +19 -5
  56. package/dist/core/util/strip.js +17 -17
  57. package/dist/core/util/validate.d.ts +3 -1
  58. package/dist/core/util/validate.js +1 -1
  59. package/dist/embed-widget/browser/page-actions.d.ts +121 -0
  60. package/dist/embed-widget/browser/page-actions.js +113 -0
  61. package/dist/embed-widget/browser/session-store.d.ts +44 -0
  62. package/dist/embed-widget/browser/session-store.js +103 -0
  63. package/dist/embed-widget/react/embed.d.ts +45 -0
  64. package/dist/embed-widget/react/embed.js +87 -0
  65. package/dist/embed-widget/react/header.d.ts +21 -0
  66. package/dist/embed-widget/react/header.js +18 -0
  67. package/dist/embed-widget/transports/fetch-sse.d.ts +75 -0
  68. package/dist/embed-widget/transports/fetch-sse.js +175 -0
  69. package/dist/react/agent-bridge/frontend-session-bridge.d.ts +15 -3
  70. package/dist/react/agent-bridge/frontend-session-bridge.js +13 -6
  71. package/dist/react/artifact-types.d.ts +3 -3
  72. package/dist/react/artifact-types.js +3 -3
  73. package/dist/react/components/A2uiSurfaceCard.js +34 -13
  74. package/dist/react/components/AttachmentPreviewModal.hooks.d.ts +7 -2
  75. package/dist/react/components/AttachmentPreviewModal.hooks.js +5 -5
  76. package/dist/react/components/AttachmentPreviewModal.js +2 -2
  77. package/dist/react/components/AttachmentTray.d.ts +3 -1
  78. package/dist/react/components/AttachmentTray.js +2 -2
  79. package/dist/react/components/ChatFab.js +1 -1
  80. package/dist/react/components/Composer.js +9 -9
  81. package/dist/react/components/ConversationList.js +1 -1
  82. package/dist/react/components/McpUiSurfaceCard.d.ts +4 -2
  83. package/dist/react/components/McpUiSurfaceCard.js +5 -5
  84. package/dist/react/components/MessageList.js +1 -1
  85. package/dist/react/components/MessageRow.js +9 -9
  86. package/dist/react/components/QuestionForm.js +5 -5
  87. package/dist/react/components/ToolCard.js +9 -9
  88. package/dist/react/components/composer-discovery.d.ts +29 -8
  89. package/dist/react/components/composer-discovery.js +10 -10
  90. package/dist/react/ext-event-renderer-registry.d.ts +15 -5
  91. package/dist/react/ext-event-renderer-registry.js +4 -4
  92. package/dist/react/features/chat-pane/components/AgentRuntimePicker.d.ts +3 -1
  93. package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +3 -3
  94. package/dist/react/features/chat-pane/components/ChatPane.js +43 -43
  95. package/dist/react/features/chat-pane/create-daemon-attachment-uploader.d.ts +4 -1
  96. package/dist/react/features/chat-pane/create-daemon-attachment-uploader.js +5 -35
  97. package/dist/react/features/chat-pane/create-mcp-ui-tool-caller.d.ts +5 -2
  98. package/dist/react/features/chat-pane/create-mcp-ui-tool-caller.js +1 -1
  99. package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.d.ts +38 -10
  100. package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +15 -15
  101. package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +31 -31
  102. package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.d.ts +3 -1
  103. package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.js +3 -3
  104. package/dist/react/features/chat-pane/hooks/useChatPaneComposerPlaceholder.hooks.d.ts +4 -1
  105. package/dist/react/features/chat-pane/hooks/useChatPaneComposerPlaceholder.hooks.js +1 -1
  106. package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.js +30 -30
  107. package/dist/react/features/chat-pane/hooks/useChatPaneWorkingDirectory.hooks.js +57 -57
  108. package/dist/react/features/chat-pane/rules.d.ts +13 -4
  109. package/dist/react/features/chat-pane/rules.js +5 -5
  110. package/dist/react/features/chat-pane/types.d.ts +1 -1
  111. package/dist/react/hooks/attachment-preview-cache.d.ts +7 -2
  112. package/dist/react/hooks/attachment-preview-cache.js +2 -2
  113. package/dist/react/hooks/composer-draft-cache.d.ts +17 -5
  114. package/dist/react/hooks/composer-draft-cache.js +6 -6
  115. package/dist/react/hooks/useArtifactStream.d.ts +5 -1
  116. package/dist/react/hooks/useArtifactStream.js +3 -3
  117. package/dist/react/hooks/useChatFabDrag.d.ts +9 -4
  118. package/dist/react/hooks/useChatFabDrag.js +4 -4
  119. package/dist/react/hooks/useComposer.js +8 -8
  120. package/dist/react/hooks/useConversation.js +56 -4
  121. package/dist/react/hooks/useExtEventGroups.d.ts +5 -1
  122. package/dist/react/hooks/useExtEventGroups.js +1 -1
  123. package/dist/react/hooks/useLatestOperation.d.ts +8 -3
  124. package/dist/react/hooks/useLatestOperation.js +4 -4
  125. package/dist/react/hooks/usePinnedTodos.d.ts +3 -1
  126. package/dist/react/hooks/usePinnedTodos.js +3 -3
  127. package/dist/react/hooks/useQuestionForms.d.ts +7 -2
  128. package/dist/react/hooks/useQuestionForms.js +7 -7
  129. package/dist/react/hooks/useRunActivity.d.ts +6 -1
  130. package/dist/react/hooks/useRunActivity.js +3 -3
  131. package/dist/react/hooks/useRunStream.d.ts +3 -1
  132. package/dist/react/hooks/useRunStream.js +1 -1
  133. package/dist/react/hooks/useToolTimeline.d.ts +3 -1
  134. package/dist/react/hooks/useToolTimeline.js +3 -3
  135. package/dist/react/index.d.ts +4 -4
  136. package/dist/react/index.js +6 -6
  137. package/dist/react/message-blocks.d.ts +10 -4
  138. package/dist/react/message-blocks.js +2 -2
  139. package/dist/react/styles/reference.css +3 -3
  140. package/dist/react/tool-renderer-registry.d.ts +8 -3
  141. package/dist/react/tool-renderer-registry.js +3 -3
  142. package/dist/react/util/defined-props.d.ts +3 -1
  143. package/dist/react/util/defined-props.js +1 -1
  144. package/dist/server/run-finalizer/entry.d.ts +47 -0
  145. package/dist/server/run-finalizer/entry.js +156 -0
  146. package/dist/server/run-finalizer/ports.d.ts +52 -0
  147. package/dist/store/contracts/index.d.ts +5 -0
  148. package/dist/store/contracts/index.js +5 -0
  149. package/dist/store/errors.d.ts +12 -0
  150. package/dist/store/errors.js +18 -0
  151. package/dist/store/index.d.ts +4 -0
  152. package/dist/store/index.js +2 -0
  153. package/dist/store/legacy/index.d.ts +3 -0
  154. package/dist/store/legacy/index.js +2 -0
  155. package/dist/store/legacy/sqlite/conversations.d.ts +129 -0
  156. package/dist/store/legacy/sqlite/conversations.js +274 -0
  157. package/dist/store/legacy/sqlite/index.d.ts +6 -0
  158. package/dist/store/legacy/sqlite/index.js +5 -0
  159. package/dist/store/legacy/sqlite/messages.d.ts +156 -0
  160. package/dist/store/legacy/sqlite/messages.js +246 -0
  161. package/dist/store/legacy/sqlite/schema.d.ts +3 -0
  162. package/dist/store/legacy/sqlite/schema.js +40 -0
  163. package/dist/store/pglite/index.d.ts +21 -0
  164. package/dist/store/pglite/index.js +17 -0
  165. package/dist/store/ports.d.ts +121 -0
  166. package/dist/store/ports.js +2 -0
  167. package/dist/store/postgres/index.d.ts +21 -0
  168. package/dist/store/postgres/index.js +17 -0
  169. package/dist/store/sql/boundary.d.ts +28 -0
  170. package/dist/store/sql/boundary.js +32 -0
  171. package/dist/store/sql/cursor.d.ts +24 -0
  172. package/dist/store/sql/cursor.js +49 -0
  173. package/dist/store/sql/maintenance.d.ts +9 -0
  174. package/dist/store/sql/maintenance.js +16 -0
  175. package/dist/store/sql/store.d.ts +22 -0
  176. package/dist/store/sql/store.js +340 -0
  177. package/dist/store/sql/tables.d.ts +34 -0
  178. package/dist/store/sql/tables.js +2 -0
  179. package/dist/store/sqlite/index.d.ts +36 -0
  180. package/dist/store/sqlite/index.js +29 -0
  181. package/dist/store/sqlite/schema.d.ts +49 -0
  182. package/dist/store/sqlite/schema.js +80 -0
  183. package/package.json +211 -14
  184. package/dist/react/features/model-picker/components/CredentialStatusBadge.d.ts +0 -7
  185. package/dist/react/features/model-picker/components/CredentialStatusBadge.js +0 -20
  186. package/dist/react/features/model-picker/components/ModelPicker.d.ts +0 -9
  187. package/dist/react/features/model-picker/components/ModelPicker.js +0 -34
  188. package/dist/react/features/model-picker/constants.d.ts +0 -6
  189. package/dist/react/features/model-picker/constants.js +0 -9
  190. package/dist/react/features/model-picker/dependencies.d.ts +0 -11
  191. package/dist/react/features/model-picker/dependencies.js +0 -10
  192. package/dist/react/features/model-picker/hooks/useModelPicker.hooks.d.ts +0 -27
  193. package/dist/react/features/model-picker/hooks/useModelPicker.hooks.js +0 -62
  194. package/dist/react/features/model-picker/index.d.ts +0 -32
  195. package/dist/react/features/model-picker/index.js +0 -29
  196. package/dist/react/features/model-picker/ports.d.ts +0 -11
  197. package/dist/react/features/model-picker/rules.d.ts +0 -26
  198. package/dist/react/features/model-picker/rules.js +0 -84
  199. package/dist/react/features/model-picker/types.d.ts +0 -38
  200. package/dist/react/features/model-picker/types.js +0 -2
  201. package/dist/react/poc-mcp-ui-official/PocMcpUiCard.d.ts +0 -9
  202. package/dist/react/poc-mcp-ui-official/PocMcpUiCard.js +0 -29
  203. package/dist/react/poc-mcp-ui-official/create-poc-resource.d.ts +0 -30
  204. package/dist/react/poc-mcp-ui-official/create-poc-resource.js +0 -44
  205. /package/dist/{react/features/model-picker → server/run-finalizer}/ports.js +0 -0
@@ -24,7 +24,7 @@ export function useConversation(options) {
24
24
  const { transport, conversationId = null, agentId, createMessageId = defaultCreateMessageId } = options;
25
25
  const [messages, setMessagesState] = useState(options.initialMessages ?? []);
26
26
  const [scrollIntent, setScrollIntent] = useState(false);
27
- const run = useRunStream(transport);
27
+ const run = useRunStream({ transport });
28
28
  // The assistant message id the currently-active run is writing into.
29
29
  const activeAssistantIdRef = useRef(null);
30
30
  const messagesRef = useRef(messages);
@@ -32,6 +32,58 @@ export function useConversation(options) {
32
32
  const setMessages = useCallback((updater) => {
33
33
  setMessagesState((prev) => (typeof updater === 'function' ? updater(prev) : updater));
34
34
  }, []);
35
+ /**
36
+ * The mount-time snapshot of `initialMessages`, captured once — the same "read once, never react
37
+ * to a later identity change" contract `messages`'s own `useState` initializer above already has
38
+ * for this same prop. A host's `initialMessages` array is expected to be a fresh identity on every
39
+ * render (`ChatPane` remounts the whole pane with a fresh `key` on a real conversation switch
40
+ * rather than pushing a new array into a live one), so depending on it directly in the effect below
41
+ * would re-fire on every render of a host that does not itself memoize the prop.
42
+ */
43
+ const initialMessagesRef = useRef(options.initialMessages);
44
+ /**
45
+ * Resumes an interrupted run on mount instead of leaving it frozen forever.
46
+ *
47
+ * `run.reattach` (`useRunStream.ts`) has existed since 2026-07-29 and is fully implemented —
48
+ * generation-guarded against double-subscription, abortable, race-safe — but until this effect,
49
+ * nothing in this package or any host ever called it. The gap it left: once a browser's live
50
+ * subscription to a run is torn down for ANY reason (this hook unmounting, a host remount, an HMR
51
+ * reload, a daemon restart), the run keeps going server-side and nothing ever tells the browser
52
+ * about it again — no more events, no more persistence, no error, just a frozen pane. The 2026-09-11 incident showed that teardown without remount reattachment
53
+ * leaves a running server task invisible to the browser. Reattaching needs a durably-recorded, non-terminal `runId` to find
54
+ * in `initialMessages` in the first place — the host is responsible for that half by persisting the run stub before starting the subscription.
55
+ *
56
+ * Mount-only (`[]` deps), by design: `useConversation` owns exactly one `useRunStream` instance for
57
+ * its whole lifetime, and a host that wants a different transcript remounts the pane with a fresh
58
+ * `key` rather than pushing a new `initialMessages` into a live one (see `initialMessagesRef`'s own
59
+ * doc) — so "the moment this hook mounts" IS "the moment a stale subscription needs recovering",
60
+ * and there is no later point in this hook's life that also needs this check.
61
+ *
62
+ * `activeAssistantIdRef.current` is set BEFORE calling `reattach`, not after: the reconciliation
63
+ * effect below (`applyRunToAssistantMessage`) no-ops whenever that ref is `null` — a reattach whose
64
+ * first event arrived before this assignment landed would be silently dropped on the floor instead
65
+ * of reaching the message it belongs to.
66
+ *
67
+ * A message with a `runId` but no `runStatus` at all is treated as nothing to reattach to, not as
68
+ * "assume non-terminal" — `useConversation`'s own reconciliation always writes both together, so
69
+ * the combination only arises from data this hook did not itself produce (a host's legacy rows, a
70
+ * different producer entirely), and there is no positive evidence there of an in-flight run worth
71
+ * the network round trip.
72
+ */
73
+ useEffect(() => {
74
+ const last = initialMessagesRef.current?.at(-1);
75
+ if (!last || last.role !== 'assistant')
76
+ return;
77
+ if (last.runId === undefined || last.runStatus === undefined)
78
+ return;
79
+ if (isTerminalRunStatus({ status: last.runStatus }))
80
+ return;
81
+ activeAssistantIdRef.current = last.id;
82
+ void run.reattach(last.runId, last.events);
83
+ // Mount-only: see this effect's own doc for why `run` is deliberately not listed — it is a
84
+ // `useCallback` (`useRunStream.ts`), stable for this hook instance's whole lifetime, so omitting
85
+ // it changes nothing about correctness.
86
+ }, []);
35
87
  const applyRunToAssistantMessage = useCallback(() => {
36
88
  const assistantId = activeAssistantIdRef.current;
37
89
  if (!assistantId)
@@ -62,9 +114,9 @@ export function useConversation(options) {
62
114
  ...m,
63
115
  ...(nextRunId !== undefined ? { runId: nextRunId } : {}),
64
116
  events: run.events,
65
- content: assistantContentFromEvents(run.events),
117
+ content: assistantContentFromEvents({ events: run.events }),
66
118
  runStatus,
67
- ...(isTerminalRunStatus(runStatus) ? { endedAt: Date.now() } : {}),
119
+ ...(isTerminalRunStatus({ status: runStatus }) ? { endedAt: Date.now() } : {}),
68
120
  };
69
121
  }));
70
122
  setScrollIntent(true);
@@ -104,7 +156,7 @@ export function useConversation(options) {
104
156
  // the same commit as the reconciliation effect that just marked the previous turn terminal.
105
157
  // Replacing the array with the snapshot threw that pending update away, leaving the finished
106
158
  // turn `running` forever — and never persisted, since hosts persist only terminal turns
107
- // (Tovu stuck-chat investigation, 2026-09-27).
159
+ // (host stuck-chat investigation, 2026-09-27).
108
160
  setMessagesState((prev) => [...prev, userMessage, assistantMessage]);
109
161
  setScrollIntent(true);
110
162
  await run.start({
@@ -15,5 +15,9 @@ export interface ExtEventGroup {
15
15
  * @param slotOf - Which render slot an event belongs to. Defaults to its `name`, the one-slot-per-name
16
16
  * grouping this hook always had; `MessageRow` passes the registry's `extEventSlot`.
17
17
  */
18
- export declare function useExtEventGroups(events: AgentEvent[] | undefined, slotOf?: (name: string, data: unknown) => string): ExtEventGroup[];
18
+ export declare function useExtEventGroups({ events }: {
19
+ events: AgentEvent[] | undefined;
20
+ }, { slotOf }?: {
21
+ slotOf?: ((name: string, data: unknown) => string) | undefined;
22
+ }): ExtEventGroup[];
19
23
  //# sourceMappingURL=useExtEventGroups.d.ts.map
@@ -15,7 +15,7 @@ import { useMemo } from 'react';
15
15
  * @param slotOf - Which render slot an event belongs to. Defaults to its `name`, the one-slot-per-name
16
16
  * grouping this hook always had; `MessageRow` passes the registry's `extEventSlot`.
17
17
  */
18
- export function useExtEventGroups(events, slotOf = (name) => name) {
18
+ export function useExtEventGroups({ events }, { slotOf = (name) => name } = {}) {
19
19
  return useMemo(() => {
20
20
  const order = [];
21
21
  const bySlot = new Map();
@@ -14,12 +14,17 @@ export interface LatestOperation {
14
14
  * `onError` is invoked only for a genuine failure of an operation that is *still* current — a
15
15
  * superseded or unmounted one is discarded silently, which is what the hand-written guards did.
16
16
  */
17
- run(body: (token: OperationToken) => Promise<void>, onError: (error: Error) => void): Promise<void>;
17
+ run(args: {
18
+ body: (token: OperationToken) => Promise<void>;
19
+ onError: (error: Error) => void;
20
+ }): Promise<void>;
18
21
  /** Supersedes whatever is in flight without starting a new operation. */
19
22
  supersede(): void;
20
23
  }
21
24
  /** Preserves native Error objects while normalizing opaque host-bridge rejections. */
22
- export declare function normalizeOperationError(error: unknown): Error;
25
+ export declare function normalizeOperationError({ error }: {
26
+ error: unknown;
27
+ }): Error;
23
28
  /**
24
29
  * Owns the mounted flag and the generation counter that decide which async attempt is allowed to
25
30
  * write state. One instance per hook: every operation started through it supersedes the previous
@@ -27,5 +32,5 @@ export declare function normalizeOperationError(error: unknown): Error;
27
32
  *
28
33
  * @complexity Time/space: O(1).
29
34
  */
30
- export declare function useLatestOperation(): LatestOperation;
35
+ export declare function useLatestOperation(_requiredArgs: Record<string, never>): LatestOperation;
31
36
  //# sourceMappingURL=useLatestOperation.d.ts.map
@@ -24,7 +24,7 @@ class SupersededOperation extends Error {
24
24
  }
25
25
  }
26
26
  /** Preserves native Error objects while normalizing opaque host-bridge rejections. */
27
- export function normalizeOperationError(error) {
27
+ export function normalizeOperationError({ error }) {
28
28
  return error instanceof Error ? error : new Error(String(error));
29
29
  }
30
30
  /**
@@ -34,7 +34,7 @@ export function normalizeOperationError(error) {
34
34
  *
35
35
  * @complexity Time/space: O(1).
36
36
  */
37
- export function useLatestOperation() {
37
+ export function useLatestOperation(_requiredArgs) {
38
38
  const mountedRef = useRef(true);
39
39
  const generationRef = useRef(0);
40
40
  useEffect(() => {
@@ -47,7 +47,7 @@ export function useLatestOperation() {
47
47
  const supersede = useCallback(() => {
48
48
  generationRef.current += 1;
49
49
  }, []);
50
- const run = useCallback(async (body, onError) => {
50
+ const run = useCallback(async ({ body, onError }) => {
51
51
  const generation = ++generationRef.current;
52
52
  const isCurrent = () => mountedRef.current && generation === generationRef.current;
53
53
  const token = {
@@ -66,7 +66,7 @@ export function useLatestOperation() {
66
66
  catch (error) {
67
67
  if (!isCurrent())
68
68
  return;
69
- onError(normalizeOperationError(error));
69
+ onError(normalizeOperationError({ error: error }));
70
70
  }
71
71
  }, []);
72
72
  return useMemo(() => ({ run, supersede }), [run, supersede]);
@@ -11,5 +11,7 @@ export interface UsePinnedTodosResult {
11
11
  /** Dismisses the currently-pinned card. Only meaningful once `allComplete`; re-appears automatically once the plan changes again. */
12
12
  dismiss: () => void;
13
13
  }
14
- export declare function usePinnedTodos(messages: ReadonlyArray<ChatMessage> | undefined): UsePinnedTodosResult;
14
+ export declare function usePinnedTodos({ messages }: {
15
+ messages: ReadonlyArray<ChatMessage> | undefined;
16
+ }): UsePinnedTodosResult;
15
17
  //# sourceMappingURL=usePinnedTodos.d.ts.map
@@ -12,10 +12,10 @@
12
12
  */
13
13
  import { useCallback, useMemo, useState } from 'react';
14
14
  import { latestTodoWriteInputForPinnedCard, parseTodoWriteInput } from '../../core/index.js';
15
- export function usePinnedTodos(messages) {
15
+ export function usePinnedTodos({ messages }) {
16
16
  const [dismissedKey, setDismissedKey] = useState(null);
17
- const rawInput = useMemo(() => latestTodoWriteInputForPinnedCard(messages), [messages]);
18
- const todos = useMemo(() => parseTodoWriteInput(rawInput), [rawInput]);
17
+ const rawInput = useMemo(() => latestTodoWriteInputForPinnedCard({ messages: messages }), [messages]);
18
+ const todos = useMemo(() => parseTodoWriteInput({ input: rawInput }), [rawInput]);
19
19
  const key = useMemo(() => (rawInput === null ? null : safeStableKey(rawInput)), [rawInput]);
20
20
  const total = todos.length;
21
21
  const completed = todos.filter((t) => t.status === 'completed').length;
@@ -18,11 +18,16 @@ export interface UseQuestionFormsResult {
18
18
  /** Formats `answers` into the prose user-message text the host sends back. */
19
19
  buildSubmission: (form: QuestionForm, answers: QuestionFormAnswers) => string;
20
20
  }
21
- export declare function useQuestionForms(messages: ReadonlyArray<ChatMessage> | undefined): UseQuestionFormsResult;
21
+ export declare function useQuestionForms({ messages }: {
22
+ messages: ReadonlyArray<ChatMessage> | undefined;
23
+ }): UseQuestionFormsResult;
22
24
  /**
23
25
  * Reverse of `formatFormAnswers` — given the user message that (maybe)
24
26
  * answered `form`, recover the answers map so the form can render in its
25
27
  * locked "answered" state with the user's picks visible.
26
28
  */
27
- export declare function parseSubmittedAnswers(form: QuestionForm, userMessageContent: string): QuestionFormAnswers | null;
29
+ export declare function parseSubmittedAnswers({ form, userMessageContent }: {
30
+ form: QuestionForm;
31
+ userMessageContent: string;
32
+ }): QuestionFormAnswers | null;
28
33
  //# sourceMappingURL=useQuestionForms.d.ts.map
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import { useCallback, useMemo } from 'react';
19
19
  import { findFirstQuestionForm, formOptionValueForLabel, formatFormAnswers } from '../../core/index.js';
20
- export function useQuestionForms(messages) {
20
+ export function useQuestionForms({ messages }) {
21
21
  const forms = useMemo(() => {
22
22
  if (!messages || messages.length === 0)
23
23
  return [];
@@ -26,11 +26,11 @@ export function useQuestionForms(messages) {
26
26
  const message = messages[i];
27
27
  if (!message || message.role !== 'assistant')
28
28
  continue;
29
- const found = findFirstQuestionForm(message.content);
29
+ const found = findFirstQuestionForm({ input: message.content });
30
30
  if (!found)
31
31
  continue;
32
32
  const nextMessage = messages[i + 1];
33
- const submittedAnswers = nextMessage && nextMessage.role === 'user' ? parseSubmittedAnswers(found.form, nextMessage.content) ?? undefined : undefined;
33
+ const submittedAnswers = nextMessage && nextMessage.role === 'user' ? parseSubmittedAnswers({ form: found.form, userMessageContent: nextMessage.content }) ?? undefined : undefined;
34
34
  const interactive = submittedAnswers === undefined && i === messages.length - 1;
35
35
  out.push({ form: found.form, raw: found.raw, messageId: message.id, interactive, submittedAnswers });
36
36
  }
@@ -44,7 +44,7 @@ export function useQuestionForms(messages) {
44
44
  }
45
45
  return null;
46
46
  }, [forms]);
47
- const buildSubmission = useCallback((form, answers) => formatFormAnswers(form, answers), []);
47
+ const buildSubmission = useCallback((form, answers) => formatFormAnswers({ form: form, answers: answers }), []);
48
48
  return { forms, activeForm, buildSubmission };
49
49
  }
50
50
  /**
@@ -52,7 +52,7 @@ export function useQuestionForms(messages) {
52
52
  * answered `form`, recover the answers map so the form can render in its
53
53
  * locked "answered" state with the user's picks visible.
54
54
  */
55
- export function parseSubmittedAnswers(form, userMessageContent) {
55
+ export function parseSubmittedAnswers({ form, userMessageContent }) {
56
56
  // `String.prototype.split` always returns an array of length >= 1 (even
57
57
  // `''.split('\n')` is `['']`), so `lines` can never be empty here — no
58
58
  // `lines.length === 0` guard is needed (removed as provably-dead). Index 0
@@ -97,9 +97,9 @@ function decodeAnswerValue(question, value) {
97
97
  .split(',')
98
98
  .map((s) => s.trim())
99
99
  .filter((s) => s.length > 0 && s.toLowerCase() !== '(skipped)')
100
- .map((s) => formOptionValueForLabel(question, parseSubmittedOptionToken(s)));
100
+ .map((s) => formOptionValueForLabel({ question: question, labelOrValue: parseSubmittedOptionToken(s) }));
101
101
  }
102
- return value.toLowerCase() === '(skipped)' ? '' : formOptionValueForLabel(question, parseSubmittedOptionToken(value));
102
+ return value.toLowerCase() === '(skipped)' ? '' : formOptionValueForLabel({ question: question, labelOrValue: parseSubmittedOptionToken(value) });
103
103
  }
104
104
  function parseSubmittedOptionToken(raw) {
105
105
  const match = /\s+\[value:\s*([^\]]+)\]\s*$/i.exec(raw);
@@ -8,5 +8,10 @@ export type NowFn = () => number;
8
8
  * @returns The activity line's text, or `null` when `active` is false.
9
9
  * @complexity O(n) in events per render (memoized on the events array).
10
10
  */
11
- export declare function useRunActivity(events: readonly AgentEvent[] | undefined, active: boolean, now?: NowFn): string | null;
11
+ export declare function useRunActivity({ events, active }: {
12
+ events: readonly AgentEvent[] | undefined;
13
+ active: boolean;
14
+ }, { now }?: {
15
+ now?: (NowFn) | undefined;
16
+ }): string | null;
12
17
  //# sourceMappingURL=useRunActivity.d.ts.map
@@ -15,9 +15,9 @@ import { useT } from './context.js';
15
15
  * @returns The activity line's text, or `null` when `active` is false.
16
16
  * @complexity O(n) in events per render (memoized on the events array).
17
17
  */
18
- export function useRunActivity(events, active, now = Date.now) {
18
+ export function useRunActivity({ events, active }, { now = Date.now } = {}) {
19
19
  const t = useT();
20
- const state = useMemo(() => deriveRunActivity(events), [events]);
20
+ const state = useMemo(() => deriveRunActivity({ events: events }), [events]);
21
21
  const [, setTick] = useState(0);
22
22
  const signal = useRef(null);
23
23
  const visible = useRef(null);
@@ -39,6 +39,6 @@ export function useRunActivity(events, active, now = Date.now) {
39
39
  visible.current = { count: state.visibleCount, at };
40
40
  const localSeconds = (at - signal.current.at) / 1000;
41
41
  const reported = state.activity.kind === 'running-tool' ? (state.activity.reportedSeconds ?? 0) : 0;
42
- return describeRunActivity(state.activity, { seconds: Math.max(localSeconds, reported), idleMs: at - visible.current.at }, t);
42
+ return describeRunActivity({ activity: state.activity, clock: { seconds: Math.max(localSeconds, reported), idleMs: at - visible.current.at }, t: t });
43
43
  }
44
44
  //# sourceMappingURL=useRunActivity.js.map
@@ -23,5 +23,7 @@ export interface UseRunStreamResult extends RunStreamState {
23
23
  /** Clears all state back to `idle` without touching the transport (e.g. moving to a fresh turn). */
24
24
  reset: () => void;
25
25
  }
26
- export declare function useRunStream(transport: ChatTransport): UseRunStreamResult;
26
+ export declare function useRunStream({ transport }: {
27
+ transport: ChatTransport;
28
+ }): UseRunStreamResult;
27
29
  //# sourceMappingURL=useRunStream.d.ts.map
@@ -48,7 +48,7 @@ const INITIAL_STATE = {
48
48
  error: null,
49
49
  toolInputDeltas: {},
50
50
  };
51
- export function useRunStream(transport) {
51
+ export function useRunStream({ transport }) {
52
52
  const [state, setState] = useState(INITIAL_STATE);
53
53
  const subscriptionAbortRef = useRef(null);
54
54
  const cancelAbortRef = useRef(null);
@@ -28,6 +28,8 @@ export interface UseToolTimelineResult {
28
28
  expandAll: () => void;
29
29
  collapseAll: () => void;
30
30
  }
31
- export declare function useToolTimeline(events: AgentEvent[] | undefined, options?: UseToolTimelineOptions): UseToolTimelineResult;
31
+ export declare function useToolTimeline({ events }: {
32
+ events: AgentEvent[] | undefined;
33
+ }, options?: UseToolTimelineOptions): UseToolTimelineResult;
32
34
  export {};
33
35
  //# sourceMappingURL=useToolTimeline.d.ts.map
@@ -10,17 +10,17 @@
10
10
  */
11
11
  import { useCallback, useMemo, useState } from 'react';
12
12
  import { dedupeToolUsesById, deriveToolStatus } from '../../core/index.js';
13
- export function useToolTimeline(events, options = {}) {
13
+ export function useToolTimeline({ events }, options = {}) {
14
14
  const { runStreaming = false, runSucceeded = false, defaultExpanded = false } = options;
15
15
  const [overrides, setOverrides] = useState({});
16
- const deduped = useMemo(() => dedupeToolUsesById(events), [events]);
16
+ const deduped = useMemo(() => dedupeToolUsesById({ events: events }), [events]);
17
17
  const rows = useMemo(() => {
18
18
  const out = [];
19
19
  for (const ev of deduped) {
20
20
  if (ev.kind !== 'tool_use')
21
21
  continue;
22
22
  const result = deduped.find((r) => r.kind === 'tool_result' && r.toolUseId === ev.id);
23
- const status = deriveToolStatus(result, runStreaming, runSucceeded);
23
+ const status = deriveToolStatus({ result: result, runStreaming: runStreaming }, { runSucceeded: runSucceeded });
24
24
  out.push({
25
25
  id: ev.id,
26
26
  name: ev.name,
@@ -2,11 +2,11 @@
2
2
  * @jini-ai/chat-react — headless hooks + presentational components + slots for
3
3
  * a chat/artifact frontend, built on `@jini-ai/chat/core`'s framework-free
4
4
  * vocabulary. See ADS-memory/reports/jini-port/recon/r4b-webui-design.md §1/§2/§4 for the
5
- * spec this package implements, and source-map.md for provenance.
5
+ * spec this package implements, and archived provenance ledger for provenance.
6
6
  *
7
7
  * This barrel is filled in incrementally as each layer lands (hooks first,
8
8
  * then presentational components, then the `<JiniChatProvider>` composition
9
- * root) — see source-map.md's "Status" section for what's shipped so far.
9
+ * root) — see archived provenance ledger's "Status" section for what's shipped so far.
10
10
  *
11
11
  * ## Every export here is explicit. Do not reintroduce `export *`.
12
12
  *
@@ -104,7 +104,7 @@ export { TodoCard } from './components/TodoCard.js';
104
104
  export type { TodoCardProps } from './components/TodoCard.js';
105
105
  /**
106
106
  * The conversation switcher — new / select / delete / search / rename-on-double-click. Storage
107
- * agnostic: it takes data plus callbacks, so a host backs it with `@jini-ai/sqlite`'s
107
+ * agnostic: it takes data plus callbacks, so a host backs it with `@jini-ai/sqlite-chat`'s
108
108
  * `ChatHistoryStore`, an HTTP endpoint, or a plain array. Drop it into `ChatPane`'s
109
109
  * `leadingAccessory` slot; it needs no changes to `ChatPane` itself.
110
110
  */
@@ -153,6 +153,6 @@ export type { JiniChatProviderProps, JiniChatSlots } from './components/JiniChat
153
153
  * extraction — re-exported here so existing `@jini-ai/chat-react` importers keep working.
154
154
  */
155
155
  export { createFrontendSessionBridge } from './agent-bridge/frontend-session-bridge.js';
156
- export type { FrontendSessionBridge, FrontendSessionBridgeOptions, } from './agent-bridge/frontend-session-bridge.js';
156
+ export type { FrontendSessionBridge, FrontendSessionBridgeArgs, FrontendSessionBridgeOptions, } from './agent-bridge/frontend-session-bridge.js';
157
157
  export { createDomPageDriver, currentAgentPage, type DomPageDriverOptions } from '@jini-ai/agentic/dom';
158
158
  //# sourceMappingURL=index.d.ts.map
@@ -14,11 +14,11 @@ export { clearExtEventRenderers, extEventSlot, getExtEventRenderer, registerExtE
14
14
  // this package's re-export. See ADS-memory/reports/refactor/2026-08-05-ref-001-steps-bcd-proposal.md
15
15
  // §2.4 for the full trace and §9 for the re-confirmation against the post-BYOK tree.
16
16
  //
17
- // The feature itself is not deleted — `./features/model-picker/index.js` still exists and still
18
- // works for anything inside this package that wants it (nothing currently does). This removes only
19
- // the root barrel's re-export of it. A future consumer that genuinely needs it gets a real ADR-worthy
20
- // decision (its own subpath, most likely, following Step C's pattern) instead of a standing
21
- // "just in case" export nobody asked for.
17
+ // The unused feature was deleted on 2026-10-02 after re-confirming that no import or export
18
+ // outside its own tests reached it. Model/provider selection belongs to the host-injected
19
+ // `ModelAgentPickerSlot`, not chat's domain. A future standalone picker needs a real consumer
20
+ // and an explicit API decision (its own subpath, most likely, following Step C's pattern)
21
+ // instead of a standing "just in case" export nobody asked for.
22
22
  /**
23
23
  * @deprecated REF-001 Step C (2026-08-05): `ChatPane` and its companions moved to their own
24
24
  * subpath, `@jini-ai/chat/react/chat-pane` — import from there in new code. Re-exported here,
@@ -80,7 +80,7 @@ export { interleaveMessageBlocks } from './message-blocks.js';
80
80
  export { TodoCard } from './components/TodoCard.js';
81
81
  /**
82
82
  * The conversation switcher — new / select / delete / search / rename-on-double-click. Storage
83
- * agnostic: it takes data plus callbacks, so a host backs it with `@jini-ai/sqlite`'s
83
+ * agnostic: it takes data plus callbacks, so a host backs it with `@jini-ai/sqlite-chat`'s
84
84
  * `ChatHistoryStore`, an HTTP endpoint, or a plain array. Drop it into `ChatPane`'s
85
85
  * `leadingAccessory` slot; it needs no changes to `ChatPane` itself.
86
86
  */
@@ -84,8 +84,14 @@ export type MessageBlock<Row> = {
84
84
  */
85
85
  export declare function interleaveMessageBlocks<Row extends {
86
86
  id: string;
87
- }>(events: readonly AgentEvent[] | undefined, content: string, rows: readonly Row[], slotOf?: (ev: {
88
- readonly name: string;
89
- readonly data: unknown;
90
- }) => string): MessageBlock<Row>[] | null;
87
+ }>({ events, content, rows }: {
88
+ events: readonly AgentEvent[] | undefined;
89
+ content: string;
90
+ rows: readonly Row[];
91
+ }, { slotOf }?: {
92
+ slotOf?: (ev: {
93
+ readonly name: string;
94
+ readonly data: unknown;
95
+ }) => string;
96
+ }): MessageBlock<Row>[] | null;
91
97
  //# sourceMappingURL=message-blocks.d.ts.map
@@ -11,7 +11,7 @@ import { assistantContentFromEvents, legacyAssistantContentFromEvents } from '..
11
11
  * @returns Ordered blocks, or `null` to signal "render the flat layout instead".
12
12
  * @complexity O(n + m) in the event and row counts.
13
13
  */
14
- export function interleaveMessageBlocks(events, content, rows, slotOf = (ev) => ev.name) {
14
+ export function interleaveMessageBlocks({ events, content, rows }, { slotOf = (ev) => ev.name } = {}) {
15
15
  if (!events || events.length === 0)
16
16
  return null;
17
17
  const hasExtEvent = events.some((ev) => ev.kind === 'ext');
@@ -21,7 +21,7 @@ export function interleaveMessageBlocks(events, content, rows, slotOf = (ev) =>
21
21
  // was built from. Anything else and the offsets below are fiction.
22
22
  // Both producers' shapes count: today's (a paragraph break between steps, see
23
23
  // `assistantContentFromEvents`) and the old plain concatenation older saved rows carry.
24
- if (content !== assistantContentFromEvents(events) && content !== legacyAssistantContentFromEvents(events))
24
+ if (content !== assistantContentFromEvents({ events }) && content !== legacyAssistantContentFromEvents({ events: events }))
25
25
  return null;
26
26
  const rowById = new Map(rows.map((row) => [row.id, row]));
27
27
  const blocks = [];
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * @jini-ai/chat-react reference stylesheet — structural layout only.
3
3
  *
4
- * NOT applied by default and not exported by package.json — see this package's README for why.
4
+ * Not applied by default; exported for opt-in use — see this package's README for why.
5
5
  * Kept here as a documented starting point for a host writing their own CSS against this
6
- * package's `jini-*` class names, not as something to `import` as-is.
6
+ * package's `jini-*` class names. Hosts may import it explicitly for structural layout.
7
7
  *
8
8
  * Every rule here exists because, without it, a plain-HTML default (inline elements that don't
9
9
  * stack, an inline-block that doesn't shrink to fit a narrow parent, a block box that forces a
@@ -153,7 +153,7 @@
153
153
  /* ---- ChatPane (features/chat-pane/react/components/ChatPane.tsx) ---- */
154
154
 
155
155
  /*
156
- * The two traps from tovu-learnings.md §7:
156
+ * The two layout traps recorded during host integration (§7 of the original learning notes):
157
157
  *
158
158
  * __controls wraps the suggestions row, status banners, and composer area (via
159
159
  * ChatPaneComposerArea's fragment) as siblings. It renders with no inline style at all, so a
@@ -34,8 +34,13 @@ export type ToolRenderer = (props: ToolRenderProps) => ReactNode;
34
34
  * against `tool_use.name`. Re-registering the same name overwrites — last
35
35
  * writer wins.
36
36
  */
37
- export declare function registerToolRenderer(name: string, renderer: ToolRenderer): () => void;
38
- export declare function getToolRenderer(name: string): ToolRenderer | undefined;
37
+ export declare function registerToolRenderer({ name, renderer }: {
38
+ name: string;
39
+ renderer: ToolRenderer;
40
+ }): () => void;
41
+ export declare function getToolRenderer({ name }: {
42
+ name: string;
43
+ }): ToolRenderer | undefined;
39
44
  /** Visible mainly for tests. */
40
- export declare function clearToolRenderers(): void;
45
+ export declare function clearToolRenderers(_requiredArgs: Record<string, never>): void;
41
46
  //# sourceMappingURL=tool-renderer-registry.d.ts.map
@@ -5,18 +5,18 @@ const renderers = new Map();
5
5
  * against `tool_use.name`. Re-registering the same name overwrites — last
6
6
  * writer wins.
7
7
  */
8
- export function registerToolRenderer(name, renderer) {
8
+ export function registerToolRenderer({ name, renderer }) {
9
9
  renderers.set(name, renderer);
10
10
  return () => {
11
11
  if (renderers.get(name) === renderer)
12
12
  renderers.delete(name);
13
13
  };
14
14
  }
15
- export function getToolRenderer(name) {
15
+ export function getToolRenderer({ name }) {
16
16
  return renderers.get(name);
17
17
  }
18
18
  /** Visible mainly for tests. */
19
- export function clearToolRenderers() {
19
+ export function clearToolRenderers(_requiredArgs) {
20
20
  renderers.clear();
21
21
  }
22
22
  //# sourceMappingURL=tool-renderer-registry.js.map
@@ -27,5 +27,7 @@ export type DefinedProps<T> = {
27
27
  *
28
28
  * @complexity Time: O(n) in the key count; space: O(n) for the returned object.
29
29
  */
30
- export declare function definedProps<T extends object>(source: T): DefinedProps<T>;
30
+ export declare function definedProps<T extends object>({ source }: {
31
+ source: T;
32
+ }): DefinedProps<T>;
31
33
  //# sourceMappingURL=defined-props.d.ts.map
@@ -17,7 +17,7 @@
17
17
  *
18
18
  * @complexity Time: O(n) in the key count; space: O(n) for the returned object.
19
19
  */
20
- export function definedProps(source) {
20
+ export function definedProps({ source }) {
21
21
  const result = {};
22
22
  for (const [key, value] of Object.entries(source)) {
23
23
  if (value !== undefined)
@@ -0,0 +1,47 @@
1
+ import type { Clock } from '@jini-ai/core/primitives';
2
+ /** Saves completed run output independently of a connected client, through host ports. */
3
+ import type { ChatMessage } from '../../core/messages.js';
4
+ import { type RunNotices } from '../../core/run-events/entry.js';
5
+ import type { RunDaemonClient, RunLedger, Scheduler, RunIdClassifier } from './ports.js';
6
+ export type { RunDaemonClient, RunLedger, Scheduler, RunIdClassifier, RunRef, RunProgress, RunSettlement } from './ports.js';
7
+ /** All infrastructure and host messages are explicit; this factory opens no storage. */
8
+ export interface AssistantRunFinalizerArgs {
9
+ readonly ledger: RunLedger;
10
+ readonly daemon: RunDaemonClient;
11
+ readonly clock: Clock;
12
+ readonly scheduler: Scheduler;
13
+ readonly runIdClassifier: RunIdClassifier;
14
+ readonly notices: RunNotices;
15
+ readonly onError: (args: {
16
+ operation: 'checkpoint' | 'watch';
17
+ runId: string;
18
+ error: unknown;
19
+ }) => void;
20
+ }
21
+ /** Reconnect delay: 2000ms; retry count: 30; checkpoint interval: 1000ms. */
22
+ export interface AssistantRunFinalizerOptions {
23
+ readonly reconnectDelayMs?: number;
24
+ readonly maxReconnects?: number;
25
+ readonly checkpointIntervalMs?: number;
26
+ }
27
+ export interface AssistantRunFinalizer {
28
+ /** Ignore non-assistant, terminal, missing-status and externally held runs; deduplicate by run ID. */
29
+ watch(input: {
30
+ principalId: string;
31
+ conversationId: string;
32
+ message: ChatMessage;
33
+ }): void;
34
+ /** Wait for current watches to finish; terminal writes may overtake pending checkpoints. */
35
+ idle(args: Record<string, never>): Promise<void>;
36
+ activeCount(args: Record<string, never>): number;
37
+ }
38
+ /** Follow replayable run streams and save through atomic host ledger operations.
39
+ * The host retains authorization, owner scope, kernel transactions, boot reconciliation, HTTP
40
+ * credentials and excluded run-ID prefixes. Replay starts at zero; error-before-success and
41
+ * reconnect exhaustion must not falsely settle a run. Checkpoints are throttled with a trailing
42
+ * write, and checkpoint/settle atomically reject other runs or terminal rows: first terminal wins.
43
+ * Frame vocabulary, paragraph boundaries and compaction are shared with the run-event reducer.
44
+ * Non-success bodies are cancelled and progress scheduling stops at completion. Real database
45
+ * restart/race coverage remains a host responsibility; this factory never opens storage. */
46
+ export declare function createAssistantRunFinalizer(args: AssistantRunFinalizerArgs, options?: AssistantRunFinalizerOptions): AssistantRunFinalizer;
47
+ //# sourceMappingURL=entry.d.ts.map