@jini-ai/chat 0.3.11 → 0.5.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.
Files changed (205) hide show
  1. package/CHANGELOG.md +126 -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
@@ -0,0 +1,49 @@
1
+ /**
2
+ * @module store/sqlite/schema
3
+ *
4
+ * Canonical unchanged DDL for ai_chats and ai_chat_messages. Hosts own their database,
5
+ * migration ledger and connection configuration. A host with migrations retains its frozen
6
+ * migration statements; a fresh fixture or host without a migrator may call the explicit helper.
7
+ * Store construction never invokes it, chooses a file, or sets connection-wide pragmas.
8
+ */
9
+ import type { SqliteClient } from '@jini-ai/db/sqlite';
10
+ /**
11
+ * The canonical chat-history schema.
12
+ *
13
+ * Notes on the parts that are easy to get wrong:
14
+ *
15
+ * - **`scope_id`** is the host's partition key (workspace/tenant/project). It is `NOT NULL` from
16
+ * the first migration on purpose: adding it later is trivial, but *backfilling* it is not —
17
+ * pre-existing rows carry no evidence of which partition they belonged to, so a late addition
18
+ * forces a choice between deleting history and guessing.
19
+ * - **`owner_kind` + the CHECK pair** make "a guest row with a `user_id`" unrepresentable rather
20
+ * than merely discouraged.
21
+ * - **`owner_id`** holds a user id for `user`, and a *hash* of the session key for `guest`. The
22
+ * raw token never reaches this table.
23
+ * - **`title_source`** exists so an agent-generated title cannot clobber a manual rename. That
24
+ * rule is enforced in the store, but it needs a column to be enforceable at all.
25
+ * - **`position`** orders messages, not `created_at`: two inserts inside the same millisecond
26
+ * are ordinary under concurrent writers, and a tie there corrupts replay order permanently.
27
+ * `UNIQUE (conversation_id, position)` turns a position-assignment bug into a loud constraint
28
+ * violation instead of a silently scrambled transcript.
29
+ * - **`expires_at NULL`** means "never expires". The retention sweep filters on
30
+ * `expires_at IS NOT NULL`, so authenticated history is out of its reach by construction, not
31
+ * by a predicate that could drift.
32
+ */
33
+ export declare const CHAT_HISTORY_DDL = "\nCREATE TABLE IF NOT EXISTS ai_chats (\n id TEXT PRIMARY KEY,\n scope_id TEXT NOT NULL,\n owner_kind TEXT NOT NULL CHECK (owner_kind IN ('user','guest')),\n owner_id TEXT NOT NULL,\n title TEXT,\n title_source TEXT NOT NULL DEFAULT 'fallback'\n CHECK (title_source IN ('fallback','generated','manual')),\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n expires_at INTEGER\n);\n\nCREATE INDEX IF NOT EXISTS idx_ai_chats_owner\n ON ai_chats(scope_id, owner_kind, owner_id, updated_at DESC);\n\nCREATE INDEX IF NOT EXISTS idx_ai_chats_expiry\n ON ai_chats(expires_at) WHERE expires_at IS NOT NULL;\n\nCREATE TABLE IF NOT EXISTS ai_chat_messages (\n id TEXT PRIMARY KEY,\n conversation_id TEXT NOT NULL REFERENCES ai_chats(id) ON DELETE CASCADE,\n role TEXT NOT NULL CHECK (role IN ('user','assistant')),\n content TEXT NOT NULL,\n agent_id TEXT,\n agent_name TEXT,\n events_json TEXT,\n attachments_json TEXT,\n run_id TEXT,\n run_status TEXT,\n position INTEGER NOT NULL,\n created_at INTEGER NOT NULL,\n started_at INTEGER,\n ended_at INTEGER,\n UNIQUE (conversation_id, position)\n);\n\nCREATE INDEX IF NOT EXISTS idx_ai_chat_messages_order\n ON ai_chat_messages(conversation_id, position);\n";
34
+ /**
35
+ * Creates the chat-history tables in the given database if they are absent.
36
+ *
37
+ * Idempotent, matching `ensureToolCatalogTables`'s convention. For a host whose database is
38
+ * managed by its own migration system, prefer copying {@link CHAT_HISTORY_DDL} into a numbered
39
+ * migration instead — see this module's header for why two migrators over one file is a hazard.
40
+ *
41
+ * The caller is responsible for `PRAGMA foreign_keys = ON`; without it the `ON DELETE CASCADE`
42
+ * above is silently inert and deleting a conversation orphans its messages. This function does
43
+ * not set it, because pragmas are connection-wide and a library has no business reconfiguring a
44
+ * handle it was merely lent.
45
+ */
46
+ export declare function ensureChatHistoryTables({ db }: {
47
+ db: Pick<SqliteClient, 'exec'>;
48
+ }): void;
49
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1,80 @@
1
+ /**
2
+ * The canonical chat-history schema.
3
+ *
4
+ * Notes on the parts that are easy to get wrong:
5
+ *
6
+ * - **`scope_id`** is the host's partition key (workspace/tenant/project). It is `NOT NULL` from
7
+ * the first migration on purpose: adding it later is trivial, but *backfilling* it is not —
8
+ * pre-existing rows carry no evidence of which partition they belonged to, so a late addition
9
+ * forces a choice between deleting history and guessing.
10
+ * - **`owner_kind` + the CHECK pair** make "a guest row with a `user_id`" unrepresentable rather
11
+ * than merely discouraged.
12
+ * - **`owner_id`** holds a user id for `user`, and a *hash* of the session key for `guest`. The
13
+ * raw token never reaches this table.
14
+ * - **`title_source`** exists so an agent-generated title cannot clobber a manual rename. That
15
+ * rule is enforced in the store, but it needs a column to be enforceable at all.
16
+ * - **`position`** orders messages, not `created_at`: two inserts inside the same millisecond
17
+ * are ordinary under concurrent writers, and a tie there corrupts replay order permanently.
18
+ * `UNIQUE (conversation_id, position)` turns a position-assignment bug into a loud constraint
19
+ * violation instead of a silently scrambled transcript.
20
+ * - **`expires_at NULL`** means "never expires". The retention sweep filters on
21
+ * `expires_at IS NOT NULL`, so authenticated history is out of its reach by construction, not
22
+ * by a predicate that could drift.
23
+ */
24
+ export const CHAT_HISTORY_DDL = `
25
+ CREATE TABLE IF NOT EXISTS ai_chats (
26
+ id TEXT PRIMARY KEY,
27
+ scope_id TEXT NOT NULL,
28
+ owner_kind TEXT NOT NULL CHECK (owner_kind IN ('user','guest')),
29
+ owner_id TEXT NOT NULL,
30
+ title TEXT,
31
+ title_source TEXT NOT NULL DEFAULT 'fallback'
32
+ CHECK (title_source IN ('fallback','generated','manual')),
33
+ created_at INTEGER NOT NULL,
34
+ updated_at INTEGER NOT NULL,
35
+ expires_at INTEGER
36
+ );
37
+
38
+ CREATE INDEX IF NOT EXISTS idx_ai_chats_owner
39
+ ON ai_chats(scope_id, owner_kind, owner_id, updated_at DESC);
40
+
41
+ CREATE INDEX IF NOT EXISTS idx_ai_chats_expiry
42
+ ON ai_chats(expires_at) WHERE expires_at IS NOT NULL;
43
+
44
+ CREATE TABLE IF NOT EXISTS ai_chat_messages (
45
+ id TEXT PRIMARY KEY,
46
+ conversation_id TEXT NOT NULL REFERENCES ai_chats(id) ON DELETE CASCADE,
47
+ role TEXT NOT NULL CHECK (role IN ('user','assistant')),
48
+ content TEXT NOT NULL,
49
+ agent_id TEXT,
50
+ agent_name TEXT,
51
+ events_json TEXT,
52
+ attachments_json TEXT,
53
+ run_id TEXT,
54
+ run_status TEXT,
55
+ position INTEGER NOT NULL,
56
+ created_at INTEGER NOT NULL,
57
+ started_at INTEGER,
58
+ ended_at INTEGER,
59
+ UNIQUE (conversation_id, position)
60
+ );
61
+
62
+ CREATE INDEX IF NOT EXISTS idx_ai_chat_messages_order
63
+ ON ai_chat_messages(conversation_id, position);
64
+ `;
65
+ /**
66
+ * Creates the chat-history tables in the given database if they are absent.
67
+ *
68
+ * Idempotent, matching `ensureToolCatalogTables`'s convention. For a host whose database is
69
+ * managed by its own migration system, prefer copying {@link CHAT_HISTORY_DDL} into a numbered
70
+ * migration instead — see this module's header for why two migrators over one file is a hazard.
71
+ *
72
+ * The caller is responsible for `PRAGMA foreign_keys = ON`; without it the `ON DELETE CASCADE`
73
+ * above is silently inert and deleting a conversation orphans its messages. This function does
74
+ * not set it, because pragmas are connection-wide and a library has no business reconfiguring a
75
+ * handle it was merely lent.
76
+ */
77
+ export function ensureChatHistoryTables({ db }) {
78
+ db.exec(CHAT_HISTORY_DDL);
79
+ }
80
+ //# sourceMappingURL=schema.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/chat",
3
- "version": "0.3.11",
3
+ "version": "0.5.0",
4
4
  "description": "Jini's chat/artifact frontend, consolidated into one package with two subpaths: framework-free chat vocabulary and pure parsers in `/core`, headless hooks + presentational components + slots in `/react`. Import only the layer you need.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -17,11 +17,29 @@
17
17
  "./core": "universal",
18
18
  "./react": "browser",
19
19
  "./react/chat-pane": "browser",
20
- "./react/styles/reference.css": "browser"
21
- }
20
+ "./react/styles/reference.css": "browser",
21
+ "./store": "universal",
22
+ "./store/sqlite": "node",
23
+ "./store/pglite": "node",
24
+ "./store/postgres": "node",
25
+ "./store/legacy": "universal",
26
+ "./store/legacy/sqlite": "node",
27
+ "./core/run-events": "universal",
28
+ "./core/ag-ui": "universal",
29
+ "./server/run-finalizer": "universal",
30
+ "./react/embed": "browser",
31
+ "./transports/fetch-sse": "universal",
32
+ "./browser/session-store": "browser",
33
+ "./browser/page-actions": "browser"
34
+ },
35
+ "neutralEntries": [
36
+ "src/store/contracts"
37
+ ]
22
38
  },
23
39
  "type": "module",
24
- "sideEffects": false,
40
+ "sideEffects": [
41
+ "./dist/**/*.css"
42
+ ],
25
43
  "main": "./dist/core/index.js",
26
44
  "types": "./dist/core/index.d.ts",
27
45
  "exports": {
@@ -45,15 +63,81 @@
45
63
  "import": "./dist/react/chat-pane.js",
46
64
  "default": "./dist/react/chat-pane.js"
47
65
  },
48
- "./react/styles/reference.css": "./dist/react/styles/reference.css"
66
+ "./react/styles/reference.css": "./dist/react/styles/reference.css",
67
+ "./store": {
68
+ "types": "./dist/store/index.d.ts",
69
+ "import": "./dist/store/index.js"
70
+ },
71
+ "./store/sqlite": {
72
+ "types": "./dist/store/sqlite/index.d.ts",
73
+ "import": "./dist/store/sqlite/index.js"
74
+ },
75
+ "./store/pglite": {
76
+ "types": "./dist/store/pglite/index.d.ts",
77
+ "import": "./dist/store/pglite/index.js"
78
+ },
79
+ "./store/postgres": {
80
+ "types": "./dist/store/postgres/index.d.ts",
81
+ "import": "./dist/store/postgres/index.js"
82
+ },
83
+ "./store/legacy": {
84
+ "types": "./dist/store/legacy/index.d.ts",
85
+ "import": "./dist/store/legacy/index.js",
86
+ "default": "./dist/store/legacy/index.js"
87
+ },
88
+ "./store/legacy/sqlite": {
89
+ "types": "./dist/store/legacy/sqlite/index.d.ts",
90
+ "import": "./dist/store/legacy/sqlite/index.js",
91
+ "default": "./dist/store/legacy/sqlite/index.js"
92
+ },
93
+ "./core/run-events": {
94
+ "types": "./dist/core/run-events/entry.d.ts",
95
+ "import": "./dist/core/run-events/entry.js",
96
+ "default": "./dist/core/run-events/entry.js"
97
+ },
98
+ "./core/ag-ui": {
99
+ "types": "./dist/core/ag-ui/entry.d.ts",
100
+ "import": "./dist/core/ag-ui/entry.js",
101
+ "default": "./dist/core/ag-ui/entry.js"
102
+ },
103
+ "./server/run-finalizer": {
104
+ "types": "./dist/server/run-finalizer/entry.d.ts",
105
+ "import": "./dist/server/run-finalizer/entry.js",
106
+ "default": "./dist/server/run-finalizer/entry.js"
107
+ },
108
+ "./react/embed": {
109
+ "types": "./dist/embed-widget/react/embed.d.ts",
110
+ "import": "./dist/embed-widget/react/embed.js",
111
+ "default": "./dist/embed-widget/react/embed.js"
112
+ },
113
+ "./transports/fetch-sse": {
114
+ "types": "./dist/embed-widget/transports/fetch-sse.d.ts",
115
+ "import": "./dist/embed-widget/transports/fetch-sse.js",
116
+ "default": "./dist/embed-widget/transports/fetch-sse.js"
117
+ },
118
+ "./browser/session-store": {
119
+ "types": "./dist/embed-widget/browser/session-store.d.ts",
120
+ "import": "./dist/embed-widget/browser/session-store.js",
121
+ "default": "./dist/embed-widget/browser/session-store.js"
122
+ },
123
+ "./browser/page-actions": {
124
+ "types": "./dist/embed-widget/browser/page-actions.d.ts",
125
+ "import": "./dist/embed-widget/browser/page-actions.js",
126
+ "default": "./dist/embed-widget/browser/page-actions.js"
127
+ }
49
128
  },
50
129
  "files": [
51
130
  "dist",
131
+ "README.md",
132
+ "CHANGELOG.md",
133
+ "LICENSE",
52
134
  "!dist/**/*.test.js",
53
135
  "!dist/**/*.test.d.ts",
54
136
  "!dist/**/*.test.js.map",
55
137
  "!dist/**/*.test.d.ts.map",
56
138
  "!dist/**/__tests__/**",
139
+ "!dist/react/poc-mcp-ui-official/**",
140
+ "!dist/react/features/model-picker/**",
57
141
  "!dist/**/*.map"
58
142
  ],
59
143
  "publishConfig": {
@@ -61,16 +145,27 @@
61
145
  "registry": "https://registry.npmjs.org"
62
146
  },
63
147
  "dependencies": {
64
- "@mcp-ui/client": "7.1.1",
65
- "@mcp-ui/server": "6.1.0",
66
- "@jini-ai/agentic": "0.3.7",
67
- "@jini-ai/platform": "0.3.0",
68
- "@jini-ai/protocol": "0.3.1",
69
- "@jini-ai/ui": "0.3.14"
148
+ "@jini-ai/protocol": "0.4.0",
149
+ "@jini-ai/agentic": "0.4.0",
150
+ "@jini-ai/ui": "0.4.0",
151
+ "@jini-ai/core": "0.4.0"
70
152
  },
71
153
  "peerDependencies": {
72
154
  "react": "^18.3.0 || ^19.0.0",
73
- "react-dom": "^18.3.0 || ^19.0.0"
155
+ "react-dom": "^18.3.0 || ^19.0.0",
156
+ "@jini-ai/db": "^0.2.0",
157
+ "kysely": "^0.29.6",
158
+ "better-sqlite3": "^13.0.0",
159
+ "@electric-sql/pglite": "0.5.8",
160
+ "pg": "^8.23.0",
161
+ "@ag-ui/core": "0.0.58",
162
+ "@mcp-ui/client": "7.1.1",
163
+ "@radix-ui/react-checkbox": "^1.3.11",
164
+ "@radix-ui/react-label": "^2.1.15",
165
+ "@radix-ui/react-radio-group": "^1.4.7",
166
+ "@radix-ui/react-select": "^2.3.7",
167
+ "@radix-ui/react-slot": "^1.3.3",
168
+ "recharts": "^3.10.1"
74
169
  },
75
170
  "peerDependenciesMeta": {
76
171
  "react": {
@@ -78,23 +173,125 @@
78
173
  },
79
174
  "react-dom": {
80
175
  "optional": true
176
+ },
177
+ "@jini-ai/db": {
178
+ "optional": true
179
+ },
180
+ "kysely": {
181
+ "optional": true
182
+ },
183
+ "better-sqlite3": {
184
+ "optional": true
185
+ },
186
+ "@electric-sql/pglite": {
187
+ "optional": true
188
+ },
189
+ "pg": {
190
+ "optional": true
191
+ },
192
+ "@ag-ui/core": {
193
+ "optional": true
194
+ },
195
+ "@mcp-ui/client": {
196
+ "optional": true
197
+ },
198
+ "@radix-ui/react-checkbox": {
199
+ "optional": true
200
+ },
201
+ "@radix-ui/react-label": {
202
+ "optional": true
203
+ },
204
+ "@radix-ui/react-radio-group": {
205
+ "optional": true
206
+ },
207
+ "@radix-ui/react-select": {
208
+ "optional": true
209
+ },
210
+ "@radix-ui/react-slot": {
211
+ "optional": true
212
+ },
213
+ "recharts": {
214
+ "optional": true
81
215
  }
82
216
  },
83
217
  "devDependencies": {
218
+ "@mcp-ui/client": "7.1.1",
219
+ "@radix-ui/react-checkbox": "^1.3.11",
220
+ "@radix-ui/react-label": "^2.1.15",
221
+ "@radix-ui/react-radio-group": "^1.4.7",
222
+ "@radix-ui/react-select": "^2.3.7",
223
+ "@radix-ui/react-slot": "^1.3.3",
84
224
  "@testing-library/jest-dom": "^6.6.3",
85
225
  "@testing-library/react": "^16.3.0",
86
226
  "@testing-library/user-event": "^14.5.0",
227
+ "@types/better-sqlite3": "7.6.13",
228
+ "@types/jsdom": "^21.1.7",
87
229
  "@types/react": "^19.2.0",
88
230
  "@types/react-dom": "^19.2.0",
89
231
  "@vitest/coverage-v8": "^2.1.9",
90
232
  "jsdom": "^25.0.1",
91
233
  "react": "^19.2.0",
92
- "react-dom": "^19.2.0"
234
+ "react-dom": "^19.2.0",
235
+ "recharts": "^3.10.1",
236
+ "kysely": "0.29.6",
237
+ "better-sqlite3": "13.0.3",
238
+ "@electric-sql/pglite": "0.5.8",
239
+ "pg": "8.23.0",
240
+ "@ag-ui/core": "0.0.58",
241
+ "@jini-ai/db": "0.2.0",
242
+ "@jini-ai/agent-runtime": "0.4.0"
243
+ },
244
+ "typesVersions": {
245
+ "*": {
246
+ "core": [
247
+ "./dist/core/index.d.ts"
248
+ ],
249
+ "react": [
250
+ "./dist/react/index.d.ts"
251
+ ],
252
+ "store": [
253
+ "./dist/store/index.d.ts"
254
+ ],
255
+ "store/sqlite": [
256
+ "./dist/store/sqlite/index.d.ts"
257
+ ],
258
+ "store/pglite": [
259
+ "./dist/store/pglite/index.d.ts"
260
+ ],
261
+ "store/postgres": [
262
+ "./dist/store/postgres/index.d.ts"
263
+ ],
264
+ "react/chat-pane": [
265
+ "./dist/react/chat-pane.d.ts"
266
+ ],
267
+ "core/run-events": [
268
+ "./dist/core/run-events/entry.d.ts"
269
+ ],
270
+ "core/ag-ui": [
271
+ "./dist/core/ag-ui/entry.d.ts"
272
+ ],
273
+ "server/run-finalizer": [
274
+ "./dist/server/run-finalizer/entry.d.ts"
275
+ ],
276
+ "react/embed": [
277
+ "./dist/embed-widget/react/embed.d.ts"
278
+ ],
279
+ "transports/fetch-sse": [
280
+ "./dist/embed-widget/transports/fetch-sse.d.ts"
281
+ ],
282
+ "browser/session-store": [
283
+ "./dist/embed-widget/browser/session-store.d.ts"
284
+ ],
285
+ "browser/page-actions": [
286
+ "./dist/embed-widget/browser/page-actions.d.ts"
287
+ ]
288
+ }
93
289
  },
94
290
  "scripts": {
95
291
  "build": "tsc -p tsconfig.json && mkdir -p dist/react/styles && cp src/react/styles/reference.css dist/react/styles/",
96
292
  "typecheck": "tsc -p tsconfig.json --noEmit",
97
293
  "test": "vitest run",
98
- "test:coverage": "vitest run --coverage"
294
+ "test:coverage": "vitest run --coverage",
295
+ "test:postgres": "vitest run --config vitest.postgres.config.ts src/store/__tests__/postgres.postgres.test.ts"
99
296
  }
100
297
  }
@@ -1,7 +0,0 @@
1
- import type { CredentialStatus } from '../types.js';
2
- export interface CredentialStatusBadgeProps {
3
- status: CredentialStatus;
4
- className?: string;
5
- }
6
- export declare function CredentialStatusBadge({ status, className }: CredentialStatusBadgeProps): import("react").JSX.Element;
7
- //# sourceMappingURL=CredentialStatusBadge.d.ts.map
@@ -1,20 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- /**
3
- * @module CredentialStatusBadge
4
- *
5
- * A provider's credential status as a small pill — ported from
6
- * `NewProjectPanel.tsx`'s inline `newproj-provider-badge` span
7
- * ("Configured"/"Integrated"/"Unsupported"), de-branded and relabeled to
8
- * this feature's generic `CredentialStatus` union.
9
- */
10
- import { useT } from '../../../hooks/context.js';
11
- const STATUS_LABEL = {
12
- configured: 'Configured',
13
- available: 'Available',
14
- unconfigured: 'Not configured',
15
- };
16
- export function CredentialStatusBadge({ status, className }) {
17
- const t = useT();
18
- return (_jsx("span", { className: `model-picker-status-badge model-picker-status-badge--${status}${className ? ` ${className}` : ''}`, "data-status": status, children: t(STATUS_LABEL[status]) }));
19
- }
20
- //# sourceMappingURL=CredentialStatusBadge.js.map
@@ -1,9 +0,0 @@
1
- import type { UseModelPickerOptions } from '../hooks/useModelPicker.hooks.js';
2
- export interface ModelPickerProps extends UseModelPickerOptions {
3
- label: string;
4
- searchPlaceholder?: string;
5
- className?: string;
6
- 'data-testid'?: string;
7
- }
8
- export declare function ModelPicker({ label, searchPlaceholder, className, 'data-testid': testId, ...pickerOptions }: ModelPickerProps): import("react").JSX.Element;
9
- //# sourceMappingURL=ModelPicker.d.ts.map
@@ -1,34 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- /**
3
- * @module ModelPicker
4
- *
5
- * A generic, provider-grouped, credential-status-badged, searchable model
6
- * picker: trigger button + inline popover. Consolidates two independently
7
- * re-implemented OD shapes that R6 confirmed share this exact pattern —
8
- * `NewProjectPanel.tsx`'s `MediaModelCards` (provider grouping + status
9
- * badges + search) and `modelOptions.tsx`'s `SearchableModelSelect`
10
- * (searchable trigger/popover with outside-click/Escape dismissal, folded
11
- * into `useModelPicker`). Unlike `SearchableModelSelect`, the popover
12
- * renders inline rather than via a `document.body` portal — this package
13
- * has no fixed-positioning collision-avoidance primitive of its own, and an
14
- * inline popover keeps the component trivially testable; a host embedding
15
- * this inside a clipping/overflow container can override positioning with
16
- * its own CSS. See `source-map.md`.
17
- */
18
- import { useT } from '../../../hooks/context.js';
19
- import { Icon } from '../../../components/Icon.js';
20
- import { modelSubtitle } from '../rules.js';
21
- import { useModelPicker } from '../hooks/useModelPicker.hooks.js';
22
- import { CredentialStatusBadge } from './CredentialStatusBadge.js';
23
- export function ModelPicker({ label, searchPlaceholder, className, 'data-testid': testId, ...pickerOptions }) {
24
- const t = useT();
25
- const { open, query, filteredGroups, selection, shouldShowSearch, containerRef, setQuery, toggle, select } = useModelPicker(pickerOptions);
26
- const triggerTitle = selection?.model.label ?? t('No model selected');
27
- const triggerSubtitle = selection ? modelSubtitle(selection) : t('Choose a model');
28
- const totalMatches = filteredGroups.reduce((count, group) => count + group.models.length, 0);
29
- return (_jsxs("div", { className: `model-picker${className ? ` ${className}` : ''}`, ref: containerRef, "data-testid": testId, children: [_jsx("span", { className: "model-picker-label", children: t(label) }), _jsxs("button", { type: "button", className: `model-picker-trigger${open ? ' is-open' : ''}${selection ? '' : ' is-empty'}`, onClick: toggle, "aria-haspopup": "listbox", "aria-expanded": open, "data-testid": testId ? `${testId}-trigger` : undefined, children: [_jsxs("span", { className: "model-picker-trigger-meta", children: [_jsx("span", { className: "model-picker-trigger-title", children: triggerTitle }), _jsx("span", { className: "model-picker-trigger-subtitle", children: triggerSubtitle })] }), _jsx(Icon, { name: "chevron-down", size: 14, className: "model-picker-trigger-chevron" })] }), open ? (_jsxs("div", { className: "model-picker-popover", role: "listbox", "data-testid": testId ? `${testId}-popover` : undefined, children: [shouldShowSearch ? (_jsx("div", { className: "model-picker-search-row", children: _jsx("input", { type: "search", className: "model-picker-search", value: query, placeholder: t(searchPlaceholder ?? 'Search models'), "aria-label": t(searchPlaceholder ?? 'Search models'), "data-testid": testId ? `${testId}-search` : undefined, onChange: (event) => setQuery(event.target.value) }) })) : null, _jsx("div", { className: "model-picker-list", children: totalMatches === 0 ? (_jsx("div", { className: "model-picker-empty", children: t('No matching models') })) : (filteredGroups.map((group) => (_jsxs("div", { className: "model-picker-group", children: [_jsxs("div", { className: "model-picker-group-head", children: [_jsx("span", { children: t(group.provider.label) }), _jsx(CredentialStatusBadge, { status: group.status })] }), group.models.map((model) => {
30
- const active = selection?.model.id === model.id;
31
- return (_jsxs("button", { type: "button", role: "option", "aria-selected": active, className: `model-picker-option${active ? ' is-active' : ''}`, "data-testid": testId ? `${testId}-option-${model.id}` : undefined, onClick: () => select(model.id), children: [_jsxs("span", { className: "model-picker-option-title", children: [model.label, model.default ? _jsx("span", { className: "model-picker-option-badge", children: t('Recommended') }) : null] }), model.hint ? _jsx("span", { className: "model-picker-option-hint", children: model.hint }) : null] }, model.id));
32
- })] }, group.provider.id)))) })] })) : null] }));
33
- }
34
- //# sourceMappingURL=ModelPicker.js.map
@@ -1,6 +0,0 @@
1
- import type { CredentialStatus } from './types.js';
2
- /** Below this many total options, the picker skips the search input (matches OD's `SearchableModelSelect`). */
3
- export declare const DEFAULT_MIN_SEARCHABLE_OPTIONS = 8;
4
- /** Lower sorts first: configured providers surface above merely-available, above unconfigured. */
5
- export declare const CREDENTIAL_STATUS_SORT_PRIORITY: Record<CredentialStatus, number>;
6
- //# sourceMappingURL=constants.d.ts.map
@@ -1,9 +0,0 @@
1
- /** Below this many total options, the picker skips the search input (matches OD's `SearchableModelSelect`). */
2
- export const DEFAULT_MIN_SEARCHABLE_OPTIONS = 8;
3
- /** Lower sorts first: configured providers surface above merely-available, above unconfigured. */
4
- export const CREDENTIAL_STATUS_SORT_PRIORITY = {
5
- configured: 0,
6
- available: 1,
7
- unconfigured: 2,
8
- };
9
- //# sourceMappingURL=constants.js.map
@@ -1,11 +0,0 @@
1
- import type { ModelPickerPort } from './ports.js';
2
- /**
3
- * Default port: no live provider-model fetch — the picker works from
4
- * whatever `models`/`providers` a host passes in directly. A host that wants
5
- * a live catalogue supplies its own `ModelPickerPort` (a real fetch
6
- * implementation) to `useModelPicker`/`<ModelPicker>` instead; this package
7
- * ships only the no-op default, never a concrete transport call, matching
8
- * the `features/connectors/` canary's `dependencies.ts` precedent.
9
- */
10
- export declare const defaultModelPickerPort: ModelPickerPort;
11
- //# sourceMappingURL=dependencies.d.ts.map
@@ -1,10 +0,0 @@
1
- /**
2
- * Default port: no live provider-model fetch — the picker works from
3
- * whatever `models`/`providers` a host passes in directly. A host that wants
4
- * a live catalogue supplies its own `ModelPickerPort` (a real fetch
5
- * implementation) to `useModelPicker`/`<ModelPicker>` instead; this package
6
- * ships only the no-op default, never a concrete transport call, matching
7
- * the `features/connectors/` canary's `dependencies.ts` precedent.
8
- */
9
- export const defaultModelPickerPort = {};
10
- //# sourceMappingURL=dependencies.js.map
@@ -1,27 +0,0 @@
1
- import type { RefObject } from 'react';
2
- import type { CredentialStatus, ModelOption, ModelPickerGroup, ModelPickerSelection, ModelProvider } from '../types.js';
3
- export interface UseModelPickerOptions {
4
- models: readonly ModelOption[];
5
- providers: readonly ModelProvider[];
6
- statusByProviderId: Readonly<Record<string, CredentialStatus>>;
7
- value: string;
8
- onChange: (modelId: string) => void;
9
- /** When true, auto-selects the first available model whenever `value` doesn't match any model. Defaults to false. */
10
- autoSelectFirst?: boolean;
11
- minSearchableOptions?: number;
12
- }
13
- export interface ModelPickerController {
14
- open: boolean;
15
- query: string;
16
- groups: ModelPickerGroup[];
17
- filteredGroups: ModelPickerGroup[];
18
- selection: ModelPickerSelection | null;
19
- shouldShowSearch: boolean;
20
- containerRef: RefObject<HTMLDivElement | null>;
21
- setQuery: (query: string) => void;
22
- toggle: () => void;
23
- close: () => void;
24
- select: (modelId: string) => void;
25
- }
26
- export declare function useModelPicker({ models, providers, statusByProviderId, value, onChange, autoSelectFirst, minSearchableOptions, }: UseModelPickerOptions): ModelPickerController;
27
- //# sourceMappingURL=useModelPicker.hooks.d.ts.map
@@ -1,62 +0,0 @@
1
- /**
2
- * @module useModelPicker
3
- *
4
- * Headless controller for the model-picker feature: open/query state,
5
- * derived provider groups + current selection, and the outside-click/
6
- * Escape dismissal that `InlineModelSwitcher.tsx`'s popover and
7
- * `modelOptions.tsx`'s `SearchableModelSelect` both hand-roll. All grouping/
8
- * filtering/selection logic is delegated to the pure `rules.ts` — this hook
9
- * only owns React state and the DOM-subscription effect.
10
- */
11
- import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
12
- import { DEFAULT_MIN_SEARCHABLE_OPTIONS } from '../constants.js';
13
- import { filterModelGroups, findSelectedModel, firstAvailableModelId, groupModelsByProvider } from '../rules.js';
14
- export function useModelPicker({ models, providers, statusByProviderId, value, onChange, autoSelectFirst = false, minSearchableOptions = DEFAULT_MIN_SEARCHABLE_OPTIONS, }) {
15
- const [open, setOpen] = useState(false);
16
- const [query, setQuery] = useState('');
17
- const containerRef = useRef(null);
18
- const groups = useMemo(() => groupModelsByProvider(models, providers, statusByProviderId), [models, providers, statusByProviderId]);
19
- const filteredGroups = useMemo(() => filterModelGroups(groups, query), [groups, query]);
20
- const selection = useMemo(() => findSelectedModel(groups, value), [groups, value]);
21
- const totalOptionCount = useMemo(() => groups.reduce((count, group) => count + group.models.length, 0), [groups]);
22
- const shouldShowSearch = totalOptionCount >= minSearchableOptions;
23
- useEffect(() => {
24
- if (!autoSelectFirst || selection)
25
- return;
26
- const fallbackId = firstAvailableModelId(groups);
27
- if (fallbackId)
28
- onChange(fallbackId);
29
- }, [autoSelectFirst, groups, onChange, selection]);
30
- const close = useCallback(() => {
31
- setOpen(false);
32
- setQuery('');
33
- }, []);
34
- const toggle = useCallback(() => {
35
- setOpen((prev) => !prev);
36
- }, []);
37
- const select = useCallback((modelId) => {
38
- onChange(modelId);
39
- close();
40
- }, [close, onChange]);
41
- useEffect(() => {
42
- if (!open)
43
- return;
44
- const onPointerDown = (event) => {
45
- if (containerRef.current?.contains(event.target))
46
- return;
47
- close();
48
- };
49
- const onKeyDown = (event) => {
50
- if (event.key === 'Escape')
51
- close();
52
- };
53
- document.addEventListener('mousedown', onPointerDown);
54
- document.addEventListener('keydown', onKeyDown);
55
- return () => {
56
- document.removeEventListener('mousedown', onPointerDown);
57
- document.removeEventListener('keydown', onKeyDown);
58
- };
59
- }, [open, close]);
60
- return { open, query, groups, filteredGroups, selection, shouldShowSearch, containerRef, setQuery, toggle, close, select };
61
- }
62
- //# sourceMappingURL=useModelPicker.hooks.js.map