@jini-ai/chat 0.3.10 → 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.
- package/CHANGELOG.md +126 -0
- package/README.md +152 -6
- package/dist/core/ag-ui/entry.d.ts +53 -0
- package/dist/core/ag-ui/entry.js +135 -0
- package/dist/core/agentic/chat-capabilities.d.ts +1 -1
- package/dist/core/agentic/index.d.ts +1 -1
- package/dist/core/agentic/index.js +1 -1
- package/dist/core/assistant-content.d.ts +6 -2
- package/dist/core/assistant-content.js +2 -2
- package/dist/core/compact-events.d.ts +3 -1
- package/dist/core/compact-events.js +1 -1
- package/dist/core/events.d.ts +1 -1
- package/dist/core/events.js +1 -1
- package/dist/core/index.d.ts +3 -3
- package/dist/core/index.js +3 -3
- package/dist/core/messages.d.ts +4 -2
- package/dist/core/messages.js +2 -2
- package/dist/core/partial-json.d.ts +6 -2
- package/dist/core/partial-json.js +3 -3
- package/dist/core/persistence/index.d.ts +1 -1
- package/dist/core/persistence/index.js +1 -1
- package/dist/core/persistence/ports.d.ts +2 -123
- package/dist/core/persistence/title.d.ts +3 -1
- package/dist/core/persistence/title.js +1 -1
- package/dist/core/question-form/format.d.ts +16 -7
- package/dist/core/question-form/format.js +3 -3
- package/dist/core/question-form/normalize.d.ts +7 -2
- package/dist/core/question-form/normalize.js +5 -5
- package/dist/core/question-form/scan.d.ts +18 -6
- package/dist/core/question-form/scan.js +14 -14
- package/dist/core/run-activity.d.ts +16 -4
- package/dist/core/run-activity.js +11 -11
- package/dist/core/run-events/entry.d.ts +121 -0
- package/dist/core/run-events/entry.js +290 -0
- package/dist/core/todos.d.ts +20 -8
- package/dist/core/todos.js +11 -11
- package/dist/core/tool-events.d.ts +3 -1
- package/dist/core/tool-events.js +1 -1
- package/dist/core/tool-output.d.ts +3 -1
- package/dist/core/tool-output.js +1 -1
- package/dist/core/tools.d.ts +14 -3
- package/dist/core/tools.js +3 -3
- package/dist/core/transcript.d.ts +13 -5
- package/dist/core/transcript.js +5 -5
- package/dist/core/util/manifest.d.ts +9 -3
- package/dist/core/util/manifest.js +3 -3
- package/dist/core/util/markdown-context.d.ts +11 -3
- package/dist/core/util/markdown-context.js +3 -3
- package/dist/core/util/markup-attributes.d.ts +3 -1
- package/dist/core/util/markup-attributes.js +1 -1
- package/dist/core/util/parser.d.ts +9 -5
- package/dist/core/util/parser.js +13 -13
- package/dist/core/util/recover.d.ts +6 -2
- package/dist/core/util/recover.js +6 -6
- package/dist/core/util/strip.d.ts +19 -5
- package/dist/core/util/strip.js +17 -17
- package/dist/core/util/validate.d.ts +3 -1
- package/dist/core/util/validate.js +1 -1
- package/dist/embed-widget/browser/page-actions.d.ts +121 -0
- package/dist/embed-widget/browser/page-actions.js +113 -0
- package/dist/embed-widget/browser/session-store.d.ts +44 -0
- package/dist/embed-widget/browser/session-store.js +103 -0
- package/dist/embed-widget/react/embed.d.ts +45 -0
- package/dist/embed-widget/react/embed.js +87 -0
- package/dist/embed-widget/react/header.d.ts +21 -0
- package/dist/embed-widget/react/header.js +18 -0
- package/dist/embed-widget/transports/fetch-sse.d.ts +75 -0
- package/dist/embed-widget/transports/fetch-sse.js +175 -0
- package/dist/react/agent-bridge/frontend-session-bridge.d.ts +15 -3
- package/dist/react/agent-bridge/frontend-session-bridge.js +13 -6
- package/dist/react/artifact-types.d.ts +3 -3
- package/dist/react/artifact-types.js +3 -3
- package/dist/react/components/A2uiSurfaceCard.js +34 -13
- package/dist/react/components/AttachmentPreviewModal.hooks.d.ts +7 -2
- package/dist/react/components/AttachmentPreviewModal.hooks.js +5 -5
- package/dist/react/components/AttachmentPreviewModal.js +2 -2
- package/dist/react/components/AttachmentTray.d.ts +3 -1
- package/dist/react/components/AttachmentTray.js +2 -2
- package/dist/react/components/ChatFab.js +1 -1
- package/dist/react/components/Composer.js +9 -9
- package/dist/react/components/ConversationList.js +1 -1
- package/dist/react/components/McpUiSurfaceCard.d.ts +4 -2
- package/dist/react/components/McpUiSurfaceCard.js +5 -5
- package/dist/react/components/MessageList.js +1 -1
- package/dist/react/components/MessageRow.js +9 -9
- package/dist/react/components/QuestionForm.js +5 -5
- package/dist/react/components/ToolCard.js +9 -9
- package/dist/react/components/composer-discovery.d.ts +29 -8
- package/dist/react/components/composer-discovery.js +10 -10
- package/dist/react/ext-event-renderer-registry.d.ts +15 -5
- package/dist/react/ext-event-renderer-registry.js +4 -4
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.d.ts +3 -1
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +3 -3
- package/dist/react/features/chat-pane/components/ChatPane.js +43 -43
- package/dist/react/features/chat-pane/create-daemon-attachment-uploader.d.ts +4 -1
- package/dist/react/features/chat-pane/create-daemon-attachment-uploader.js +5 -35
- package/dist/react/features/chat-pane/create-mcp-ui-tool-caller.d.ts +5 -2
- package/dist/react/features/chat-pane/create-mcp-ui-tool-caller.js +1 -1
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.d.ts +38 -10
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +15 -15
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +31 -31
- package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.d.ts +3 -1
- package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.js +3 -3
- package/dist/react/features/chat-pane/hooks/useChatPaneComposerPlaceholder.hooks.d.ts +4 -1
- package/dist/react/features/chat-pane/hooks/useChatPaneComposerPlaceholder.hooks.js +1 -1
- package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.d.ts +3 -0
- package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.js +80 -38
- package/dist/react/features/chat-pane/hooks/useChatPaneWorkingDirectory.hooks.js +57 -57
- package/dist/react/features/chat-pane/rules.d.ts +13 -4
- package/dist/react/features/chat-pane/rules.js +5 -5
- package/dist/react/features/chat-pane/types.d.ts +1 -1
- package/dist/react/hooks/attachment-preview-cache.d.ts +7 -2
- package/dist/react/hooks/attachment-preview-cache.js +2 -2
- package/dist/react/hooks/composer-draft-cache.d.ts +17 -5
- package/dist/react/hooks/composer-draft-cache.js +6 -6
- package/dist/react/hooks/useArtifactStream.d.ts +5 -1
- package/dist/react/hooks/useArtifactStream.js +3 -3
- package/dist/react/hooks/useChatFabDrag.d.ts +9 -4
- package/dist/react/hooks/useChatFabDrag.js +4 -4
- package/dist/react/hooks/useComposer.js +8 -8
- package/dist/react/hooks/useConversation.js +56 -4
- package/dist/react/hooks/useExtEventGroups.d.ts +5 -1
- package/dist/react/hooks/useExtEventGroups.js +1 -1
- package/dist/react/hooks/useLatestOperation.d.ts +8 -3
- package/dist/react/hooks/useLatestOperation.js +4 -4
- package/dist/react/hooks/usePinnedTodos.d.ts +3 -1
- package/dist/react/hooks/usePinnedTodos.js +3 -3
- package/dist/react/hooks/useQuestionForms.d.ts +7 -2
- package/dist/react/hooks/useQuestionForms.js +7 -7
- package/dist/react/hooks/useRunActivity.d.ts +6 -1
- package/dist/react/hooks/useRunActivity.js +3 -3
- package/dist/react/hooks/useRunStream.d.ts +3 -1
- package/dist/react/hooks/useRunStream.js +1 -1
- package/dist/react/hooks/useToolTimeline.d.ts +3 -1
- package/dist/react/hooks/useToolTimeline.js +3 -3
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +6 -6
- package/dist/react/message-blocks.d.ts +10 -4
- package/dist/react/message-blocks.js +2 -2
- package/dist/react/styles/reference.css +3 -3
- package/dist/react/tool-renderer-registry.d.ts +8 -3
- package/dist/react/tool-renderer-registry.js +3 -3
- package/dist/react/util/defined-props.d.ts +3 -1
- package/dist/react/util/defined-props.js +1 -1
- package/dist/server/run-finalizer/entry.d.ts +47 -0
- package/dist/server/run-finalizer/entry.js +156 -0
- package/dist/server/run-finalizer/ports.d.ts +52 -0
- package/dist/store/contracts/index.d.ts +5 -0
- package/dist/store/contracts/index.js +5 -0
- package/dist/store/errors.d.ts +12 -0
- package/dist/store/errors.js +18 -0
- package/dist/store/index.d.ts +4 -0
- package/dist/store/index.js +2 -0
- package/dist/store/legacy/index.d.ts +3 -0
- package/dist/store/legacy/index.js +2 -0
- package/dist/store/legacy/sqlite/conversations.d.ts +129 -0
- package/dist/store/legacy/sqlite/conversations.js +274 -0
- package/dist/store/legacy/sqlite/index.d.ts +6 -0
- package/dist/store/legacy/sqlite/index.js +5 -0
- package/dist/store/legacy/sqlite/messages.d.ts +156 -0
- package/dist/store/legacy/sqlite/messages.js +246 -0
- package/dist/store/legacy/sqlite/schema.d.ts +3 -0
- package/dist/store/legacy/sqlite/schema.js +40 -0
- package/dist/store/pglite/index.d.ts +21 -0
- package/dist/store/pglite/index.js +17 -0
- package/dist/store/ports.d.ts +121 -0
- package/dist/store/ports.js +2 -0
- package/dist/store/postgres/index.d.ts +21 -0
- package/dist/store/postgres/index.js +17 -0
- package/dist/store/sql/boundary.d.ts +28 -0
- package/dist/store/sql/boundary.js +32 -0
- package/dist/store/sql/cursor.d.ts +24 -0
- package/dist/store/sql/cursor.js +49 -0
- package/dist/store/sql/maintenance.d.ts +9 -0
- package/dist/store/sql/maintenance.js +16 -0
- package/dist/store/sql/store.d.ts +22 -0
- package/dist/store/sql/store.js +340 -0
- package/dist/store/sql/tables.d.ts +34 -0
- package/dist/store/sql/tables.js +2 -0
- package/dist/store/sqlite/index.d.ts +36 -0
- package/dist/store/sqlite/index.js +29 -0
- package/dist/store/sqlite/schema.d.ts +49 -0
- package/dist/store/sqlite/schema.js +80 -0
- package/package.json +211 -14
- package/dist/react/features/model-picker/components/CredentialStatusBadge.d.ts +0 -7
- package/dist/react/features/model-picker/components/CredentialStatusBadge.js +0 -20
- package/dist/react/features/model-picker/components/ModelPicker.d.ts +0 -9
- package/dist/react/features/model-picker/components/ModelPicker.js +0 -34
- package/dist/react/features/model-picker/constants.d.ts +0 -6
- package/dist/react/features/model-picker/constants.js +0 -9
- package/dist/react/features/model-picker/dependencies.d.ts +0 -11
- package/dist/react/features/model-picker/dependencies.js +0 -10
- package/dist/react/features/model-picker/hooks/useModelPicker.hooks.d.ts +0 -27
- package/dist/react/features/model-picker/hooks/useModelPicker.hooks.js +0 -62
- package/dist/react/features/model-picker/index.d.ts +0 -32
- package/dist/react/features/model-picker/index.js +0 -29
- package/dist/react/features/model-picker/ports.d.ts +0 -11
- package/dist/react/features/model-picker/rules.d.ts +0 -26
- package/dist/react/features/model-picker/rules.js +0 -84
- package/dist/react/features/model-picker/types.d.ts +0 -38
- package/dist/react/features/model-picker/types.js +0 -2
- package/dist/react/poc-mcp-ui-official/PocMcpUiCard.d.ts +0 -9
- package/dist/react/poc-mcp-ui-official/PocMcpUiCard.js +0 -29
- package/dist/react/poc-mcp-ui-official/create-poc-resource.d.ts +0 -30
- package/dist/react/poc-mcp-ui-official/create-poc-resource.js +0 -44
- /package/dist/{react/features/model-picker → server/run-finalizer}/ports.js +0 -0
package/dist/core/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Zero React, zero DOM/browser globals, zero Node built-ins, zero imports
|
|
5
5
|
* from any product package's scope. See ADS-memory/reports/jini-port/extraction-plan.md
|
|
6
6
|
* §12 C2/C3 and ADS-memory/reports/jini-port/recon/r4b-webui-design.md §1 for the design
|
|
7
|
-
* this package targets, and
|
|
7
|
+
* this package targets, and archived provenance ledger for exact provenance.
|
|
8
8
|
*
|
|
9
9
|
* Was `@jini-ai/chat-core` (its own top-level package, one entry point) through npm 0.1.2 —
|
|
10
10
|
* consolidated 2026-08-03 into `@jini-ai/chat`'s `./core` subpath alongside `./react` (formerly
|
|
@@ -31,13 +31,13 @@ export * from './compact-events.js';
|
|
|
31
31
|
* vocabulary this used to sit alongside — `CapabilityDef`, `PAGE_CAPABILITIES`, the
|
|
32
32
|
* `data-agent-*` convention, the policy gate, the protocol projections — moved to `@jini-ai/agentic`
|
|
33
33
|
* on 2026-07-26; import it directly rather than through this package. See
|
|
34
|
-
* `packages/agentic/
|
|
34
|
+
* `packages/agentic/archived provenance ledger` and this package's own archived provenance ledger for the extraction.
|
|
35
35
|
*/
|
|
36
36
|
export * from './agentic/index.js';
|
|
37
37
|
/**
|
|
38
38
|
* Durable chat history — the storage-neutral `ChatHistoryStore` port and the local title
|
|
39
39
|
* heuristic. Types and pure functions only, so this package stays framework-free and
|
|
40
|
-
* `runtime: universal`; the SQLite implementation lives in `@jini-ai/sqlite`'s `chat-history`
|
|
40
|
+
* `runtime: universal`; the SQLite implementation lives in `@jini-ai/sqlite-chat`'s `chat-history`
|
|
41
41
|
* module, and a host binds it to its own authentication.
|
|
42
42
|
*/
|
|
43
43
|
export * from './persistence/index.js';
|
package/dist/core/messages.d.ts
CHANGED
|
@@ -8,12 +8,14 @@ export type ChatRole = 'user' | 'assistant';
|
|
|
8
8
|
* `RunStatus` for a different shape at a different layer — a richer `{ id, state, ... }` record.
|
|
9
9
|
* This is the flat string union a chat message stamps on itself. While both were called
|
|
10
10
|
* `RunStatus`, every consumer importing both packages had to alias one on import, and nothing
|
|
11
|
-
* stopped the two from being confused at a glance. See
|
|
11
|
+
* stopped the two from being confused at a glance. See archived provenance ledger.
|
|
12
12
|
*/
|
|
13
13
|
export declare const CHAT_RUN_STATUSES: readonly ["queued", "running", "succeeded", "failed", "canceled"];
|
|
14
14
|
export type ChatRunStatus = (typeof CHAT_RUN_STATUSES)[number];
|
|
15
15
|
/** `true` once a run has reached a terminal status (no further events will arrive). */
|
|
16
|
-
export declare function isTerminalRunStatus(status
|
|
16
|
+
export declare function isTerminalRunStatus({ status }: {
|
|
17
|
+
status: ChatRunStatus | undefined;
|
|
18
|
+
}): boolean;
|
|
17
19
|
/** A file or image a user turn carries alongside its text. */
|
|
18
20
|
export interface ChatAttachment {
|
|
19
21
|
path: string;
|
package/dist/core/messages.js
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
* `RunStatus` for a different shape at a different layer — a richer `{ id, state, ... }` record.
|
|
6
6
|
* This is the flat string union a chat message stamps on itself. While both were called
|
|
7
7
|
* `RunStatus`, every consumer importing both packages had to alias one on import, and nothing
|
|
8
|
-
* stopped the two from being confused at a glance. See
|
|
8
|
+
* stopped the two from being confused at a glance. See archived provenance ledger.
|
|
9
9
|
*/
|
|
10
10
|
export const CHAT_RUN_STATUSES = ['queued', 'running', 'succeeded', 'failed', 'canceled'];
|
|
11
11
|
const TERMINAL_RUN_STATUSES = new Set(['succeeded', 'failed', 'canceled']);
|
|
12
12
|
/** `true` once a run has reached a terminal status (no further events will arrive). */
|
|
13
|
-
export function isTerminalRunStatus(status) {
|
|
13
|
+
export function isTerminalRunStatus({ status }) {
|
|
14
14
|
return status !== undefined && TERMINAL_RUN_STATUSES.has(status);
|
|
15
15
|
}
|
|
16
16
|
//# sourceMappingURL=messages.js.map
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
* depth `d` — one linear scan plus a bounded fixed-point cleanup loop over
|
|
24
24
|
* the (already shrinking) tail.
|
|
25
25
|
*/
|
|
26
|
-
export declare function repairJsonPrefix(buf
|
|
26
|
+
export declare function repairJsonPrefix({ buf }: {
|
|
27
|
+
buf: string;
|
|
28
|
+
}): string;
|
|
27
29
|
/**
|
|
28
30
|
* Best-effort parse of a (possibly truncated) JSON prefix.
|
|
29
31
|
*
|
|
@@ -32,5 +34,7 @@ export declare function repairJsonPrefix(buf: string): string;
|
|
|
32
34
|
* parse failure — callers should fall back to their last good value.
|
|
33
35
|
* @complexity O(n) — dominated by {@link repairJsonPrefix}.
|
|
34
36
|
*/
|
|
35
|
-
export declare function parsePartialJson(buf
|
|
37
|
+
export declare function parsePartialJson({ buf }: {
|
|
38
|
+
buf: string;
|
|
39
|
+
}): unknown;
|
|
36
40
|
//# sourceMappingURL=partial-json.d.ts.map
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* depth `d` — one linear scan plus a bounded fixed-point cleanup loop over
|
|
24
24
|
* the (already shrinking) tail.
|
|
25
25
|
*/
|
|
26
|
-
export function repairJsonPrefix(buf) {
|
|
26
|
+
export function repairJsonPrefix({ buf }) {
|
|
27
27
|
const stack = []; // closers owed, e.g. ['}', ']']
|
|
28
28
|
let inStr = false;
|
|
29
29
|
let esc = false;
|
|
@@ -105,12 +105,12 @@ export function repairJsonPrefix(buf) {
|
|
|
105
105
|
* parse failure — callers should fall back to their last good value.
|
|
106
106
|
* @complexity O(n) — dominated by {@link repairJsonPrefix}.
|
|
107
107
|
*/
|
|
108
|
-
export function parsePartialJson(buf) {
|
|
108
|
+
export function parsePartialJson({ buf }) {
|
|
109
109
|
const trimmed = buf.trim();
|
|
110
110
|
if (!trimmed)
|
|
111
111
|
return null;
|
|
112
112
|
try {
|
|
113
|
-
return JSON.parse(repairJsonPrefix(trimmed));
|
|
113
|
+
return JSON.parse(repairJsonPrefix({ buf: trimmed }));
|
|
114
114
|
}
|
|
115
115
|
catch {
|
|
116
116
|
return null;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @module persistence
|
|
3
3
|
*
|
|
4
4
|
* Durable chat history: the storage-neutral port plus the local title heuristic. No driver, no
|
|
5
|
-
* DDL, no I/O — a SQLite implementation lives in `@jini-ai/sqlite`'s `chat-history` module, and
|
|
5
|
+
* DDL, no I/O — a SQLite implementation lives in `@jini-ai/sqlite-chat`'s `chat-history` module, and
|
|
6
6
|
* a host binds it to its own auth. See `./ports.ts` for why the owner scope is bound into the
|
|
7
7
|
* store rather than passed per call.
|
|
8
8
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @module persistence
|
|
3
3
|
*
|
|
4
4
|
* Durable chat history: the storage-neutral port plus the local title heuristic. No driver, no
|
|
5
|
-
* DDL, no I/O — a SQLite implementation lives in `@jini-ai/sqlite`'s `chat-history` module, and
|
|
5
|
+
* DDL, no I/O — a SQLite implementation lives in `@jini-ai/sqlite-chat`'s `chat-history` module, and
|
|
6
6
|
* a host binds it to its own auth. See `./ports.ts` for why the owner scope is bound into the
|
|
7
7
|
* store rather than passed per call.
|
|
8
8
|
*/
|
|
@@ -1,124 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @
|
|
3
|
-
*
|
|
4
|
-
* The storage-neutral contract for durable chat history: conversations and their messages,
|
|
5
|
-
* scoped to an owner. Types and signatures only — this module imports no driver, opens no
|
|
6
|
-
* file, and issues no DDL, so it stays inside `chat-core`'s `runtime: universal` promise.
|
|
7
|
-
*
|
|
8
|
-
* Why here and not in `@jini-ai/agentic`: `chat-core` already depends on `agentic`, so a port
|
|
9
|
-
* living in `agentic` could not import {@link ChatMessage} — the type it exists to persist —
|
|
10
|
-
* without inverting that edge. It would have to redefine the message shape (two sources of
|
|
11
|
-
* truth) or be generic over an opaque type (a persistence abstraction naming nothing).
|
|
12
|
-
*
|
|
13
|
-
* Why the owner scope is baked into the port rather than passed per call: every read must be
|
|
14
|
-
* `WHERE scope = ? AND owner = ? AND id = ?`, never `WHERE id = ?`. A port whose methods take
|
|
15
|
-
* a bare id invites exactly one bug — a handler that forgets the predicate — and that bug is
|
|
16
|
-
* an omission, so review does not reliably catch it. {@link ChatHistoryStore} is obtained
|
|
17
|
-
* already-bound to a {@link ChatOwnerScope}; there is no method on it that can read across
|
|
18
|
-
* owners. Hosts bind the scope from their own auth, which is the one part of this that cannot
|
|
19
|
-
* be reused.
|
|
20
|
-
*/
|
|
21
|
-
import type { ChatMessage } from '../messages.js';
|
|
22
|
-
/**
|
|
23
|
-
* Which kind of principal owns a conversation.
|
|
24
|
-
*
|
|
25
|
-
* `user` is an authenticated account; `guest` is an anonymous visitor identified only by an
|
|
26
|
-
* opaque bearer token. They are separated rather than collapsed into one `ownerId` because the
|
|
27
|
-
* retention and disclosure rules differ: guest history expires, user history does not, and a
|
|
28
|
-
* guest's identifier is a credential that must be stored hashed.
|
|
29
|
-
*/
|
|
30
|
-
export type ChatOwnerKind = 'user' | 'guest';
|
|
31
|
-
/**
|
|
32
|
-
* The isolation predicate, resolved by the host from its own authentication, and bound into a
|
|
33
|
-
* store before any query runs.
|
|
34
|
-
*
|
|
35
|
-
* `scopeId` is the host's partition key — a workspace, a tenant, a project, whatever that host
|
|
36
|
-
* partitions by. This package does not interpret it; it only guarantees every statement filters
|
|
37
|
-
* on it.
|
|
38
|
-
*
|
|
39
|
-
* `ownerId` for a `guest` MUST already be hashed by the host. This package never sees, stores,
|
|
40
|
-
* or logs a raw bearer token, and cannot verify that a caller honored this — it is stated here
|
|
41
|
-
* because the constraint is real and the type system cannot express it.
|
|
42
|
-
*/
|
|
43
|
-
export interface ChatOwnerScope {
|
|
44
|
-
readonly scopeId: string;
|
|
45
|
-
readonly ownerKind: ChatOwnerKind;
|
|
46
|
-
readonly ownerId: string;
|
|
47
|
-
}
|
|
48
|
-
/** Where a conversation's current title came from — see {@link ChatHistoryStore.rename}. */
|
|
49
|
-
export type ChatTitleSource = 'fallback' | 'generated' | 'manual';
|
|
50
|
-
/**
|
|
51
|
-
* A conversation as the list UI needs it: enough to render a row without loading any messages.
|
|
52
|
-
*
|
|
53
|
-
* `messageCount` is computed by the adapter in the same round-trip as the list itself, so a
|
|
54
|
-
* list of N conversations costs one query rather than N+1.
|
|
55
|
-
*/
|
|
56
|
-
export interface ChatConversation {
|
|
57
|
-
readonly id: string;
|
|
58
|
-
readonly title: string | null;
|
|
59
|
-
readonly titleSource: ChatTitleSource;
|
|
60
|
-
readonly messageCount: number;
|
|
61
|
-
readonly createdAt: number;
|
|
62
|
-
readonly updatedAt: number;
|
|
63
|
-
/** Absent means no expiry — the row is retained until explicitly deleted. */
|
|
64
|
-
readonly expiresAt?: number;
|
|
65
|
-
}
|
|
66
|
-
/** Everything a host may specify when starting a conversation. */
|
|
67
|
-
export interface CreateChatConversationInput {
|
|
68
|
-
readonly id: string;
|
|
69
|
-
readonly title?: string | null;
|
|
70
|
-
readonly titleSource?: ChatTitleSource;
|
|
71
|
-
/** Epoch ms. Omit for history that never expires. */
|
|
72
|
-
readonly expiresAt?: number;
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Durable chat history for exactly one {@link ChatOwnerScope}.
|
|
76
|
-
*
|
|
77
|
-
* Every method is already scoped. `get(id)` for an id belonging to another owner resolves to
|
|
78
|
-
* `null` rather than throwing — a caller must not be able to distinguish "does not exist" from
|
|
79
|
-
* "exists but is not yours", since that distinction is itself an enumeration oracle.
|
|
80
|
-
*/
|
|
81
|
-
export interface ChatHistoryStore {
|
|
82
|
-
/** Most-recently-updated first. */
|
|
83
|
-
list(): Promise<ChatConversation[]>;
|
|
84
|
-
/** `null` when the id does not exist *or* is not owned by this scope. */
|
|
85
|
-
get(id: string): Promise<ChatConversation | null>;
|
|
86
|
-
create(input: CreateChatConversationInput): Promise<ChatConversation>;
|
|
87
|
-
/**
|
|
88
|
-
* Sets the title and stamps `titleSource`. A `manual` title is never overwritten by a
|
|
89
|
-
* `generated` one — that rule lives in the adapter so no host can forget it, and it is the
|
|
90
|
-
* reason `titleSource` is a column rather than a UI concern.
|
|
91
|
-
*/
|
|
92
|
-
rename(id: string, title: string, source?: ChatTitleSource): Promise<ChatConversation | null>;
|
|
93
|
-
/** Bumps `updatedAt`, optionally extending expiry for a still-active guest session. */
|
|
94
|
-
touch(id: string, options?: {
|
|
95
|
-
readonly expiresAt?: number;
|
|
96
|
-
}): Promise<void>;
|
|
97
|
-
/** Cascades to the conversation's messages. No-op when the id is not owned by this scope. */
|
|
98
|
-
delete(id: string): Promise<void>;
|
|
99
|
-
/** Ordered by position. Empty when the id is not owned by this scope. */
|
|
100
|
-
messages(conversationId: string): Promise<ChatMessage[]>;
|
|
101
|
-
/**
|
|
102
|
-
* Inserts or updates one message, assigning the next position on insert.
|
|
103
|
-
*
|
|
104
|
-
* `null` when the conversation is not owned by this scope — so a mis-scoped write is a
|
|
105
|
-
* no-op rather than a cross-owner insert.
|
|
106
|
-
*/
|
|
107
|
-
appendMessage(conversationId: string, message: ChatMessage): Promise<ChatMessage | null>;
|
|
108
|
-
}
|
|
109
|
-
/**
|
|
110
|
-
* Retention. Deliberately NOT on {@link ChatHistoryStore}: a sweep runs across every owner, so
|
|
111
|
-
* putting it on a per-owner store would require an unscoped store to exist, which is the exact
|
|
112
|
-
* escape hatch this design removes.
|
|
113
|
-
*/
|
|
114
|
-
export interface ChatHistoryMaintenance {
|
|
115
|
-
/**
|
|
116
|
-
* Hard-deletes conversations whose `expiresAt` is at or before `now`, cascading to messages.
|
|
117
|
-
*
|
|
118
|
-
* `limit` bounds one call so a large backlog is drained in chunks rather than held in a
|
|
119
|
-
* single long write transaction — an unbounded `DELETE` is what starves concurrent inserts.
|
|
120
|
-
* Returns the number of conversations deleted, so a caller can loop until it reports 0.
|
|
121
|
-
*/
|
|
122
|
-
sweepExpired(now: number, limit?: number): Promise<number>;
|
|
123
|
-
}
|
|
1
|
+
/** Compatibility types; the neutral store entry is the single source of truth. */
|
|
2
|
+
export type * from '@jini-ai/chat/store';
|
|
124
3
|
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -31,5 +31,7 @@
|
|
|
31
31
|
*
|
|
32
32
|
* @complexity O(n) in prompt length; no allocation beyond the intermediate strings.
|
|
33
33
|
*/
|
|
34
|
-
export declare function deriveConversationTitle(prompt
|
|
34
|
+
export declare function deriveConversationTitle({ prompt }: {
|
|
35
|
+
prompt: string;
|
|
36
|
+
}): string;
|
|
35
37
|
//# sourceMappingURL=title.d.ts.map
|
|
@@ -122,7 +122,7 @@ function trimCjkTitle(input) {
|
|
|
122
122
|
*
|
|
123
123
|
* @complexity O(n) in prompt length; no allocation beyond the intermediate strings.
|
|
124
124
|
*/
|
|
125
|
-
export function deriveConversationTitle(prompt) {
|
|
125
|
+
export function deriveConversationTitle({ prompt }) {
|
|
126
126
|
const cleaned = cleanPrompt(prompt);
|
|
127
127
|
if (!cleaned)
|
|
128
128
|
return '';
|
|
@@ -15,13 +15,22 @@ import type { FormOption, QuestionForm } from './types.js';
|
|
|
15
15
|
*
|
|
16
16
|
* @complexity O(q) in the number of questions on the form.
|
|
17
17
|
*/
|
|
18
|
-
export declare function formatFormAnswers(form
|
|
18
|
+
export declare function formatFormAnswers({ form, answers }: {
|
|
19
|
+
form: QuestionForm;
|
|
20
|
+
answers: Record<string, string | string[]>;
|
|
21
|
+
}): string;
|
|
19
22
|
/** Resolve a submitted answer value back to its display label, or the value itself when unmatched. */
|
|
20
|
-
export declare function formOptionLabelForValue(question: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
export declare function formOptionLabelForValue({ question, value }: {
|
|
24
|
+
question: {
|
|
25
|
+
options?: FormOption[] | undefined;
|
|
26
|
+
};
|
|
27
|
+
value: string;
|
|
28
|
+
}): string;
|
|
23
29
|
/** Resolve a label or value to the canonical option `value`, or the input itself when unmatched. */
|
|
24
|
-
export declare function formOptionValueForLabel(question: {
|
|
25
|
-
|
|
26
|
-
|
|
30
|
+
export declare function formOptionValueForLabel({ question, labelOrValue }: {
|
|
31
|
+
question: {
|
|
32
|
+
options?: FormOption[] | undefined;
|
|
33
|
+
};
|
|
34
|
+
labelOrValue: string;
|
|
35
|
+
}): string;
|
|
27
36
|
//# sourceMappingURL=format.d.ts.map
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @complexity O(q) in the number of questions on the form.
|
|
7
7
|
*/
|
|
8
|
-
export function formatFormAnswers(form, answers) {
|
|
8
|
+
export function formatFormAnswers({ form, answers }) {
|
|
9
9
|
const lines = [];
|
|
10
10
|
lines.push(`[form answers — ${form.id}]`);
|
|
11
11
|
for (const q of form.questions) {
|
|
@@ -33,12 +33,12 @@ function formOptionDisplayForValue(question, value) {
|
|
|
33
33
|
return `${match.label} [value: ${match.value}]`;
|
|
34
34
|
}
|
|
35
35
|
/** Resolve a submitted answer value back to its display label, or the value itself when unmatched. */
|
|
36
|
-
export function formOptionLabelForValue(question, value) {
|
|
36
|
+
export function formOptionLabelForValue({ question, value }) {
|
|
37
37
|
const match = question.options?.find((option) => option.value === value || option.label === value);
|
|
38
38
|
return match?.label ?? value;
|
|
39
39
|
}
|
|
40
40
|
/** Resolve a label or value to the canonical option `value`, or the input itself when unmatched. */
|
|
41
|
-
export function formOptionValueForLabel(question, labelOrValue) {
|
|
41
|
+
export function formOptionValueForLabel({ question, labelOrValue }) {
|
|
42
42
|
const match = question.options?.find((option) => option.value === labelOrValue || option.label === labelOrValue);
|
|
43
43
|
return match?.value ?? labelOrValue;
|
|
44
44
|
}
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
* question objects.
|
|
11
11
|
*/
|
|
12
12
|
import type { FormQuestion } from './types.js';
|
|
13
|
-
export declare function mapRawQuestion(q
|
|
13
|
+
export declare function mapRawQuestion({ q, index }: {
|
|
14
|
+
q: unknown;
|
|
15
|
+
index: number;
|
|
16
|
+
}): FormQuestion | null;
|
|
14
17
|
/**
|
|
15
18
|
* Whether a model-supplied palette entry may be written into a CSS value.
|
|
16
19
|
*
|
|
@@ -26,5 +29,7 @@ export declare function mapRawQuestion(q: unknown, index: number): FormQuestion
|
|
|
26
29
|
* rather than substituted: a silently recoloured swatch would misrepresent the agent's proposal,
|
|
27
30
|
* and a card with fewer swatches is honest about what survived validation.
|
|
28
31
|
*/
|
|
29
|
-
export declare function isRenderableColor(value
|
|
32
|
+
export declare function isRenderableColor({ value }: {
|
|
33
|
+
value: string;
|
|
34
|
+
}): boolean;
|
|
30
35
|
//# sourceMappingURL=normalize.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formOptionValueForLabel } from './format.js';
|
|
2
|
-
export function mapRawQuestion(q, index) {
|
|
2
|
+
export function mapRawQuestion({ q, index }) {
|
|
3
3
|
if (!q || typeof q !== 'object')
|
|
4
4
|
return null;
|
|
5
5
|
const qo = q;
|
|
@@ -128,9 +128,9 @@ function parseDefaultValue(question, options) {
|
|
|
128
128
|
? String(question.default)
|
|
129
129
|
: undefined;
|
|
130
130
|
if (typeof raw === 'string')
|
|
131
|
-
return formOptionValueForLabel({ options }, raw);
|
|
131
|
+
return formOptionValueForLabel({ question: { options }, labelOrValue: raw });
|
|
132
132
|
if (Array.isArray(raw)) {
|
|
133
|
-
return raw.filter((value) => typeof value === 'string').map((value) => formOptionValueForLabel({ options }, value));
|
|
133
|
+
return raw.filter((value) => typeof value === 'string').map((value) => formOptionValueForLabel({ question: { options }, labelOrValue: value }));
|
|
134
134
|
}
|
|
135
135
|
return undefined;
|
|
136
136
|
}
|
|
@@ -158,7 +158,7 @@ const COLOR_FUNCTION = /^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color)\(\s
|
|
|
158
158
|
* rather than substituted: a silently recoloured swatch would misrepresent the agent's proposal,
|
|
159
159
|
* and a card with fewer swatches is honest about what survived validation.
|
|
160
160
|
*/
|
|
161
|
-
export function isRenderableColor(value) {
|
|
161
|
+
export function isRenderableColor({ value }) {
|
|
162
162
|
const candidate = value.trim();
|
|
163
163
|
// Bounded before any regex runs: these come from model output, and the function pattern's `\s*`
|
|
164
164
|
// plus a character class is the shape that makes a pathological input worth not accepting at all.
|
|
@@ -181,7 +181,7 @@ function parseDirectionCards(raw) {
|
|
|
181
181
|
const mood = typeof e.mood === 'string' ? e.mood : '';
|
|
182
182
|
const references = Array.isArray(e.references) ? e.references.filter((r) => typeof r === 'string').slice(0, 6) : [];
|
|
183
183
|
const palette = Array.isArray(e.palette)
|
|
184
|
-
? e.palette.filter((p) => typeof p === 'string' && isRenderableColor(p)).slice(0, 8)
|
|
184
|
+
? e.palette.filter((p) => typeof p === 'string' && isRenderableColor({ value: p })).slice(0, 8)
|
|
185
185
|
: [];
|
|
186
186
|
const displayFont = typeof e.displayFont === 'string' ? e.displayFont : 'Georgia, serif';
|
|
187
187
|
const bodyFont = typeof e.bodyFont === 'string' ? e.bodyFont : '-apple-system, system-ui, sans-serif';
|
|
@@ -8,9 +8,13 @@ import type { FormSegment, QuestionForm } from './types.js';
|
|
|
8
8
|
* @complexity O(n) amortized in `input.length` — each iteration advances the
|
|
9
9
|
* cursor past the segment it just emitted.
|
|
10
10
|
*/
|
|
11
|
-
export declare function splitOnQuestionForms(input
|
|
11
|
+
export declare function splitOnQuestionForms({ input }: {
|
|
12
|
+
input: string;
|
|
13
|
+
}): FormSegment[];
|
|
12
14
|
/** The first complete, parseable `<question-form>` in `input`, or `null`. */
|
|
13
|
-
export declare function findFirstQuestionForm(input
|
|
15
|
+
export declare function findFirstQuestionForm({ input }: {
|
|
16
|
+
input: string;
|
|
17
|
+
}): {
|
|
14
18
|
form: QuestionForm;
|
|
15
19
|
raw: string;
|
|
16
20
|
} | null;
|
|
@@ -21,19 +25,25 @@ export declare function findFirstQuestionForm(input: string): {
|
|
|
21
25
|
* question-form block. For a still-streaming block use
|
|
22
26
|
* {@link parsePartialQuestionForm} instead.
|
|
23
27
|
*/
|
|
24
|
-
export declare function parseQuestionForm(input
|
|
28
|
+
export declare function parseQuestionForm({ input }: {
|
|
29
|
+
input: string;
|
|
30
|
+
}): QuestionForm | null;
|
|
25
31
|
/**
|
|
26
32
|
* Drop a trailing, not-yet-closed question-form block from streaming text so
|
|
27
33
|
* a chat surface doesn't flash raw `<question-form>{…` markup before the
|
|
28
34
|
* JSON finishes. Returns the visible text plus whether such an open block
|
|
29
35
|
* existed (meaning a form is mid-generation).
|
|
30
36
|
*/
|
|
31
|
-
export declare function stripTrailingOpenQuestionForm(input
|
|
37
|
+
export declare function stripTrailingOpenQuestionForm({ input }: {
|
|
38
|
+
input: string;
|
|
39
|
+
}): {
|
|
32
40
|
text: string;
|
|
33
41
|
hadOpenForm: boolean;
|
|
34
42
|
};
|
|
35
43
|
/** `true` when a question-form open tag is present but its close tag hasn't streamed in yet. */
|
|
36
|
-
export declare function hasUnterminatedQuestionForm(input
|
|
44
|
+
export declare function hasUnterminatedQuestionForm({ input }: {
|
|
45
|
+
input: string;
|
|
46
|
+
}): boolean;
|
|
37
47
|
/**
|
|
38
48
|
* Tolerant parser for a still-streaming `<question-form>` block. Unlike
|
|
39
49
|
* {@link tryParseForm} it does not require valid, complete JSON: it reads the
|
|
@@ -46,5 +56,7 @@ export declare function hasUnterminatedQuestionForm(input: string): boolean;
|
|
|
46
56
|
* @complexity O(n) in `input.length` (one regex scan plus a linear
|
|
47
57
|
* string-aware brace walk via {@link parsePartialJson}).
|
|
48
58
|
*/
|
|
49
|
-
export declare function parsePartialQuestionForm(input
|
|
59
|
+
export declare function parsePartialQuestionForm({ input }: {
|
|
60
|
+
input: string;
|
|
61
|
+
}): QuestionForm | null;
|
|
50
62
|
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -33,7 +33,7 @@ function matchedTagAndAttrs(m) {
|
|
|
33
33
|
* @complexity O(n) amortized in `input.length` — each iteration advances the
|
|
34
34
|
* cursor past the segment it just emitted.
|
|
35
35
|
*/
|
|
36
|
-
export function splitOnQuestionForms(input) {
|
|
36
|
+
export function splitOnQuestionForms({ input }) {
|
|
37
37
|
const out = [];
|
|
38
38
|
let cursor = 0;
|
|
39
39
|
while (cursor < input.length) {
|
|
@@ -57,7 +57,7 @@ export function splitOnQuestionForms(input) {
|
|
|
57
57
|
out.push({ kind: 'text', text: input.slice(cursor, openStart) });
|
|
58
58
|
}
|
|
59
59
|
const body = input.slice(openEnd, closeIdx);
|
|
60
|
-
const attrs = parseQuotedAttrs(rawAttrs);
|
|
60
|
+
const attrs = parseQuotedAttrs({ raw: rawAttrs });
|
|
61
61
|
const form = tryParseForm(body, attrs);
|
|
62
62
|
const blockEnd = closeIdx + closeTag.length;
|
|
63
63
|
if (form) {
|
|
@@ -72,8 +72,8 @@ export function splitOnQuestionForms(input) {
|
|
|
72
72
|
return out;
|
|
73
73
|
}
|
|
74
74
|
/** The first complete, parseable `<question-form>` in `input`, or `null`. */
|
|
75
|
-
export function findFirstQuestionForm(input) {
|
|
76
|
-
for (const seg of splitOnQuestionForms(input)) {
|
|
75
|
+
export function findFirstQuestionForm({ input }) {
|
|
76
|
+
for (const seg of splitOnQuestionForms({ input: input })) {
|
|
77
77
|
if (seg.kind === 'form')
|
|
78
78
|
return { form: seg.form, raw: seg.raw };
|
|
79
79
|
}
|
|
@@ -86,8 +86,8 @@ export function findFirstQuestionForm(input) {
|
|
|
86
86
|
* question-form block. For a still-streaming block use
|
|
87
87
|
* {@link parsePartialQuestionForm} instead.
|
|
88
88
|
*/
|
|
89
|
-
export function parseQuestionForm(input) {
|
|
90
|
-
return findFirstQuestionForm(input)?.form ?? null;
|
|
89
|
+
export function parseQuestionForm({ input }) {
|
|
90
|
+
return findFirstQuestionForm({ input: input })?.form ?? null;
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
93
|
* Drop a trailing, not-yet-closed question-form block from streaming text so
|
|
@@ -95,7 +95,7 @@ export function parseQuestionForm(input) {
|
|
|
95
95
|
* JSON finishes. Returns the visible text plus whether such an open block
|
|
96
96
|
* existed (meaning a form is mid-generation).
|
|
97
97
|
*/
|
|
98
|
-
export function stripTrailingOpenQuestionForm(input) {
|
|
98
|
+
export function stripTrailingOpenQuestionForm({ input }) {
|
|
99
99
|
let cursor = 0;
|
|
100
100
|
while (cursor < input.length) {
|
|
101
101
|
const slice = input.slice(cursor);
|
|
@@ -115,8 +115,8 @@ export function stripTrailingOpenQuestionForm(input) {
|
|
|
115
115
|
return { text: input, hadOpenForm: false };
|
|
116
116
|
}
|
|
117
117
|
/** `true` when a question-form open tag is present but its close tag hasn't streamed in yet. */
|
|
118
|
-
export function hasUnterminatedQuestionForm(input) {
|
|
119
|
-
return stripTrailingOpenQuestionForm(input).hadOpenForm;
|
|
118
|
+
export function hasUnterminatedQuestionForm({ input }) {
|
|
119
|
+
return stripTrailingOpenQuestionForm({ input: input }).hadOpenForm;
|
|
120
120
|
}
|
|
121
121
|
function findCloseTag(input, from, closeTag) {
|
|
122
122
|
const closeLower = closeTag.toLowerCase();
|
|
@@ -154,7 +154,7 @@ function tryParseForm(body, attrs) {
|
|
|
154
154
|
return null;
|
|
155
155
|
const questions = [];
|
|
156
156
|
rawQuestions.forEach((q, i) => {
|
|
157
|
-
const mapped = mapRawQuestion(q, i);
|
|
157
|
+
const mapped = mapRawQuestion({ q: q, index: i });
|
|
158
158
|
if (mapped)
|
|
159
159
|
questions.push(mapped);
|
|
160
160
|
});
|
|
@@ -184,14 +184,14 @@ function tryParseForm(body, attrs) {
|
|
|
184
184
|
* @complexity O(n) in `input.length` (one regex scan plus a linear
|
|
185
185
|
* string-aware brace walk via {@link parsePartialJson}).
|
|
186
186
|
*/
|
|
187
|
-
export function parsePartialQuestionForm(input) {
|
|
187
|
+
export function parsePartialQuestionForm({ input }) {
|
|
188
188
|
const m = OPEN_RE.exec(input);
|
|
189
189
|
if (!m)
|
|
190
190
|
return null;
|
|
191
191
|
const { tagName, rawAttrs } = matchedTagAndAttrs(m);
|
|
192
192
|
const closeTag = `</${tagName}>`;
|
|
193
193
|
const openEnd = m.index + m[0].length;
|
|
194
|
-
const attrs = parseQuotedAttrs(rawAttrs);
|
|
194
|
+
const attrs = parseQuotedAttrs({ raw: rawAttrs });
|
|
195
195
|
const closeIdx = findCloseTag(input, openEnd, closeTag);
|
|
196
196
|
const rawBody = closeIdx === -1 ? input.slice(openEnd) : input.slice(openEnd, closeIdx);
|
|
197
197
|
// Strip the fenced ```json wrapper some models emit. The opening fence is
|
|
@@ -203,7 +203,7 @@ export function parsePartialQuestionForm(input) {
|
|
|
203
203
|
// Derive form-level metadata from the *parsed top-level object*, not a
|
|
204
204
|
// whole-body regex scan: a nested question/option `id`/`title`/`description`
|
|
205
205
|
// must not masquerade as the form's own.
|
|
206
|
-
const parsed = parsePartialJson(body);
|
|
206
|
+
const parsed = parsePartialJson({ buf: body });
|
|
207
207
|
const top = parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
208
208
|
const topTitle = typeof top.title === 'string' && top.title.trim().length > 0 ? top.title : undefined;
|
|
209
209
|
// `id` keys a still-editable panel, so it must be stable for the whole
|
|
@@ -343,7 +343,7 @@ function shapeStreamingQuestions(rawQuestions, closedCount) {
|
|
|
343
343
|
const hasId = typeof q.id === 'string' && q.id.trim().length > 0;
|
|
344
344
|
if (!isClosed && !hasId)
|
|
345
345
|
return;
|
|
346
|
-
const mapped = mapRawQuestion(raw, index);
|
|
346
|
+
const mapped = mapRawQuestion({ q: raw, index: index });
|
|
347
347
|
if (mapped)
|
|
348
348
|
out.push(mapped);
|
|
349
349
|
});
|
|
@@ -48,7 +48,11 @@ export interface RunActivityState {
|
|
|
48
48
|
/** After this long with nothing new on screen, a thinking/writing line says "Still working…". */
|
|
49
49
|
export declare const RUN_ACTIVITY_IDLE_MS = 20000;
|
|
50
50
|
/** `"page.fill"` → `"Page Fill"`, `"mcp__supabase__list_projects"` → `"List Projects"`. Display only. */
|
|
51
|
-
export declare function humanizeToolName(name
|
|
51
|
+
export declare function humanizeToolName({ name }: {
|
|
52
|
+
name: string;
|
|
53
|
+
}, { input }?: {
|
|
54
|
+
input?: (unknown) | undefined;
|
|
55
|
+
}): string;
|
|
52
56
|
/**
|
|
53
57
|
* The latest signal in a running turn's events.
|
|
54
58
|
*
|
|
@@ -58,9 +62,13 @@ export declare function humanizeToolName(name: string, input?: unknown): string;
|
|
|
58
62
|
*
|
|
59
63
|
* @complexity O(n) in events, O(open tool calls) extra space.
|
|
60
64
|
*/
|
|
61
|
-
export declare function deriveRunActivity(events
|
|
65
|
+
export declare function deriveRunActivity({ events }: {
|
|
66
|
+
events: readonly AgentEvent[] | undefined;
|
|
67
|
+
}): RunActivityState;
|
|
62
68
|
/** `4` → `"4 s"`, `80` → `"1 m 20 s"`, `120` → `"2 m 0 s"`. */
|
|
63
|
-
export declare function formatActivityClock(totalSeconds
|
|
69
|
+
export declare function formatActivityClock({ totalSeconds }: {
|
|
70
|
+
totalSeconds: number;
|
|
71
|
+
}): string;
|
|
64
72
|
/** A translator: the chat package's `t(key, vars)`. */
|
|
65
73
|
export type RunActivityTranslate = (key: string, vars?: Record<string, string | number>) => string;
|
|
66
74
|
/** The clock values a label may use. */
|
|
@@ -84,5 +92,9 @@ export declare const RUN_ACTIVITY_LABELS: {
|
|
|
84
92
|
*
|
|
85
93
|
* @complexity O(1).
|
|
86
94
|
*/
|
|
87
|
-
export declare function describeRunActivity(activity
|
|
95
|
+
export declare function describeRunActivity({ activity, clock, t }: {
|
|
96
|
+
activity: RunActivity;
|
|
97
|
+
clock: RunActivityClock;
|
|
98
|
+
t: RunActivityTranslate;
|
|
99
|
+
}): string;
|
|
88
100
|
//# sourceMappingURL=run-activity.d.ts.map
|
|
@@ -24,7 +24,7 @@ function stringField(data, key) {
|
|
|
24
24
|
return typeof value === 'string' && value ? value : undefined;
|
|
25
25
|
}
|
|
26
26
|
/** `"page.fill"` → `"Page Fill"`, `"mcp__supabase__list_projects"` → `"List Projects"`. Display only. */
|
|
27
|
-
export function humanizeToolName(name, input) {
|
|
27
|
+
export function humanizeToolName({ name }, { input } = {}) {
|
|
28
28
|
const real = WRAPPER_TOOL_NAMES.has(name) ? (stringField(input, 'toolId') ?? name) : name;
|
|
29
29
|
const bare = real.startsWith('mcp__') ? real.split('__').slice(2).join('__') || real : real;
|
|
30
30
|
return bare
|
|
@@ -69,7 +69,7 @@ function scanEvent(scan, event, index) {
|
|
|
69
69
|
*
|
|
70
70
|
* @complexity O(n) in events, O(open tool calls) extra space.
|
|
71
71
|
*/
|
|
72
|
-
export function deriveRunActivity(events) {
|
|
72
|
+
export function deriveRunActivity({ events }) {
|
|
73
73
|
const scan = { open: [], lastVisible: null, lastCardIndex: -1, retry: null, progress: null, visibleCount: 0 };
|
|
74
74
|
(events ?? []).forEach((event, index) => scanEvent(scan, event, index));
|
|
75
75
|
const visibleCount = scan.visibleCount;
|
|
@@ -102,7 +102,7 @@ export function deriveRunActivity(events) {
|
|
|
102
102
|
return {
|
|
103
103
|
activity: {
|
|
104
104
|
kind: 'running-tool',
|
|
105
|
-
tool: humanizeToolName(newestOpen.name, newestOpen.input),
|
|
105
|
+
tool: humanizeToolName({ name: newestOpen.name }, { input: newestOpen.input }),
|
|
106
106
|
...(reported !== undefined ? { reportedSeconds: reported } : {}),
|
|
107
107
|
},
|
|
108
108
|
key: `tool:${newestOpen.id}`,
|
|
@@ -115,7 +115,7 @@ export function deriveRunActivity(events) {
|
|
|
115
115
|
return { activity: { kind: 'thinking' }, key: `thinking:${lastVisibleIndex}`, visibleCount };
|
|
116
116
|
}
|
|
117
117
|
/** `4` → `"4 s"`, `80` → `"1 m 20 s"`, `120` → `"2 m 0 s"`. */
|
|
118
|
-
export function formatActivityClock(totalSeconds) {
|
|
118
|
+
export function formatActivityClock({ totalSeconds }) {
|
|
119
119
|
const seconds = Math.max(0, Math.floor(totalSeconds));
|
|
120
120
|
const minutes = Math.floor(seconds / 60);
|
|
121
121
|
return minutes > 0 ? `${minutes} m ${seconds % 60} s` : `${seconds} s`;
|
|
@@ -126,14 +126,14 @@ export function formatActivityClock(totalSeconds) {
|
|
|
126
126
|
*/
|
|
127
127
|
export const RUN_ACTIVITY_LABELS = {
|
|
128
128
|
thinking: (_a, clock, t) => clock.idleMs >= RUN_ACTIVITY_IDLE_MS
|
|
129
|
-
? t('Still working… {time}', { time: formatActivityClock(clock.seconds) })
|
|
130
|
-
: t('Thinking… {time}', { time: formatActivityClock(clock.seconds) }),
|
|
129
|
+
? t('Still working… {time}', { time: formatActivityClock({ totalSeconds: clock.seconds }) })
|
|
130
|
+
: t('Thinking… {time}', { time: formatActivityClock({ totalSeconds: clock.seconds }) }),
|
|
131
131
|
writing: (_a, clock, t) => clock.idleMs >= RUN_ACTIVITY_IDLE_MS
|
|
132
|
-
? t('Still working… {time}', { time: formatActivityClock(clock.seconds) })
|
|
132
|
+
? t('Still working… {time}', { time: formatActivityClock({ totalSeconds: clock.seconds }) })
|
|
133
133
|
: t('Writing…'),
|
|
134
|
-
'finding-tool': (_a, clock, t) => t('Finding the right tool… {time}', { time: formatActivityClock(clock.seconds) }),
|
|
135
|
-
'running-tool': (a, clock, t) => t('Running {tool}… {time}', { tool: a.tool, time: formatActivityClock(clock.seconds) }),
|
|
136
|
-
'awaiting-answer': (_a, clock, t) => t('Waiting for your answer above · {time}', { time: formatActivityClock(clock.seconds) }),
|
|
134
|
+
'finding-tool': (_a, clock, t) => t('Finding the right tool… {time}', { time: formatActivityClock({ totalSeconds: clock.seconds }) }),
|
|
135
|
+
'running-tool': (a, clock, t) => t('Running {tool}… {time}', { tool: a.tool, time: formatActivityClock({ totalSeconds: clock.seconds }) }),
|
|
136
|
+
'awaiting-answer': (_a, clock, t) => t('Waiting for your answer above · {time}', { time: formatActivityClock({ totalSeconds: clock.seconds }) }),
|
|
137
137
|
retrying: (a, _clock, t) => {
|
|
138
138
|
const who = a.service ? t("{service}'s servers are busy", { service: a.service }) : t('The AI service is busy');
|
|
139
139
|
return a.attempt !== undefined && a.maxAttempts !== undefined
|
|
@@ -146,7 +146,7 @@ export const RUN_ACTIVITY_LABELS = {
|
|
|
146
146
|
*
|
|
147
147
|
* @complexity O(1).
|
|
148
148
|
*/
|
|
149
|
-
export function describeRunActivity(activity, clock, t) {
|
|
149
|
+
export function describeRunActivity({ activity, clock, t }) {
|
|
150
150
|
const label = RUN_ACTIVITY_LABELS[activity.kind];
|
|
151
151
|
return label(activity, clock, t);
|
|
152
152
|
}
|