@jini-ai/chat 0.5.3 → 0.5.5
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 +11 -0
- package/dist/core/ag-ui/entry.d.ts +33 -0
- package/dist/core/ag-ui/entry.js +80 -0
- package/dist/core/agentic/chat-capabilities.d.ts +2 -4
- package/dist/core/agentic/index.d.ts +4 -17
- package/dist/core/agentic/index.js +4 -17
- package/dist/core/assistant-client/a2ui-action-poster.d.ts +46 -0
- package/dist/core/assistant-client/a2ui-action-poster.js +113 -0
- package/dist/core/assistant-client/ag-ui-transport.d.ts +68 -0
- package/dist/core/assistant-client/ag-ui-transport.js +147 -0
- package/dist/core/assistant-client/attachment-liveness.d.ts +37 -0
- package/dist/core/assistant-client/attachment-liveness.js +93 -0
- package/dist/core/assistant-client/durable-run-subscription.d.ts +39 -0
- package/dist/core/assistant-client/durable-run-subscription.js +96 -0
- package/dist/core/assistant-client/entry.d.ts +13 -0
- package/dist/core/assistant-client/entry.js +7 -0
- package/dist/core/assistant-client/messages.d.ts +73 -0
- package/dist/core/assistant-client/messages.js +68 -0
- package/dist/core/assistant-client/transport.d.ts +164 -0
- package/dist/core/assistant-client/transport.js +734 -0
- package/dist/core/browser/page-actions.d.ts +121 -0
- package/dist/core/browser/page-actions.js +113 -0
- package/dist/core/composer-history.d.ts +54 -0
- package/dist/core/composer-history.js +57 -0
- package/dist/core/durable-projection.d.ts +28 -0
- package/dist/core/durable-projection.js +71 -0
- package/dist/core/durable-runs/continuation.d.ts +18 -0
- package/dist/core/durable-runs/continuation.js +61 -0
- package/dist/core/durable-runs/ledger-contracts.d.ts +53 -0
- package/dist/core/durable-runs/ledger-contracts.js +2 -0
- package/dist/core/durable-runs/policies.d.ts +6 -0
- package/dist/core/durable-runs/policies.js +6 -0
- package/dist/core/durable-runs/ports.d.ts +123 -0
- package/dist/core/durable-runs/ports.js +2 -0
- package/dist/core/durable-runs/run-contracts.d.ts +17 -0
- package/dist/core/durable-runs/run-contracts.js +2 -0
- package/dist/core/durable-runs/run-lock.d.ts +4 -0
- package/dist/core/durable-runs/run-lock.js +4 -0
- package/dist/core/index.d.ts +9 -19
- package/dist/core/index.js +8 -19
- package/dist/core/messages.d.ts +2 -0
- package/dist/core/question-form/format.d.ts +0 -9
- package/dist/core/question-form/format.js +16 -2
- package/dist/core/question-form/normalize.js +1 -0
- package/dist/core/question-form/secret-answers.d.ts +38 -0
- package/dist/core/question-form/secret-answers.js +45 -0
- package/dist/core/question-form/types.d.ts +2 -0
- package/dist/core/question-form.d.ts +1 -0
- package/dist/core/question-form.js +1 -0
- package/dist/core/run-events/entry.d.ts +208 -16
- package/dist/core/run-events/entry.js +273 -39
- package/dist/core/transcript.d.ts +3 -2
- package/dist/core/transcript.js +19 -3
- package/dist/core/transport.d.ts +4 -0
- package/dist/core/user-text-redaction.d.ts +56 -0
- package/dist/core/user-text-redaction.js +89 -0
- package/dist/embed-widget/browser/page-actions.d.ts +1 -120
- package/dist/embed-widget/browser/page-actions.js +2 -112
- package/dist/embed-widget/react/embed.d.ts +1 -1
- package/dist/embed-widget/react/embed.js +1 -1
- package/dist/react/artifact-types.d.ts +9 -15
- package/dist/react/components/Composer.js +6 -0
- package/dist/react/components/MessageRow.js +24 -11
- package/dist/react/components/QuestionForm.d.ts +2 -1
- package/dist/react/components/QuestionForm.js +18 -12
- package/dist/react/components/QuestionsPanel.d.ts +3 -2
- package/dist/react/components/QuestionsPanel.js +2 -2
- package/dist/react/features/chat-pane/agent-tools.d.ts +1 -1
- package/dist/react/features/chat-pane/agent-tools.js +0 -1
- package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +5 -2
- package/dist/react/features/chat-pane/components/ChatPane.d.ts +1 -1
- package/dist/react/features/chat-pane/components/ChatPane.js +9 -4
- package/dist/react/features/chat-pane/create-typed-answer-poster.d.ts +2 -1
- package/dist/react/features/chat-pane/create-typed-answer-poster.js +33 -1
- package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +3 -2
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.d.ts +7 -1
- package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +38 -23
- package/dist/react/features/chat-pane/model-options.d.ts +10 -0
- package/dist/react/features/chat-pane/model-options.js +51 -0
- package/dist/react/features/chat-pane/rules.d.ts +3 -2
- package/dist/react/features/chat-pane/rules.js +12 -4
- package/dist/react/features/chat-pane/types.d.ts +30 -1
- package/dist/react/hooks/assistant-chats-contracts.d.ts +164 -0
- package/dist/react/hooks/assistant-chats-contracts.js +2 -0
- package/dist/react/hooks/assistant-chats.d.ts +7 -0
- package/dist/react/hooks/assistant-chats.js +960 -0
- package/dist/react/hooks/attachment-preview-cache.d.ts +1 -1
- package/dist/react/hooks/attachment-preview-cache.js +1 -1
- package/dist/react/hooks/composer-draft-cache.d.ts +2 -2
- package/dist/react/hooks/composer-draft-cache.js +2 -2
- package/dist/react/hooks/composer-history-storage.d.ts +8 -0
- package/dist/react/hooks/composer-history-storage.js +40 -0
- package/dist/react/hooks/fab-position.d.ts +90 -0
- package/dist/react/hooks/fab-position.js +271 -0
- package/dist/react/hooks/useComposer.d.ts +10 -1
- package/dist/react/hooks/useComposer.js +14 -2
- package/dist/react/hooks/useComposerHistory.hooks.d.ts +15 -0
- package/dist/react/hooks/useComposerHistory.hooks.js +90 -0
- package/dist/react/hooks/useComposerHistoryKeys.hooks.d.ts +9 -0
- package/dist/react/hooks/useComposerHistoryKeys.hooks.js +90 -0
- package/dist/react/hooks/useConversation.d.ts +4 -1
- package/dist/react/hooks/useConversation.js +20 -14
- package/dist/react/hooks/useRunStream.js +12 -2
- package/dist/react/hooks/useUserTextGuard.d.ts +11 -0
- package/dist/react/hooks/useUserTextGuard.js +19 -0
- package/dist/react/index.d.ts +14 -21
- package/dist/react/index.js +8 -0
- package/dist/server/durable-runs/accept.d.ts +25 -0
- package/dist/server/durable-runs/accept.js +21 -0
- package/dist/server/durable-runs/entry.d.ts +5 -0
- package/dist/server/durable-runs/entry.js +4 -0
- package/dist/server/durable-runs/recover.d.ts +5 -0
- package/dist/server/durable-runs/recover.js +147 -0
- package/dist/server/run-finalizer/ports.d.ts +2 -16
- package/dist/store/legacy/sqlite/messages.d.ts +24 -18
- package/dist/store/legacy/sqlite/messages.js +12 -2
- package/dist/store/pglite/index.d.ts +2 -1
- package/dist/store/postgres/index.d.ts +2 -1
- package/dist/store/runtime/chat-expiry-sweep.d.ts +40 -0
- package/dist/store/runtime/chat-expiry-sweep.js +70 -0
- package/dist/store/runtime/chat-history-store.d.ts +20 -0
- package/dist/store/runtime/chat-history-store.js +50 -0
- package/dist/store/runtime/durable-run-store.d.ts +21 -0
- package/dist/store/runtime/durable-run-store.js +342 -0
- package/dist/store/runtime/entry.d.ts +7 -0
- package/dist/store/runtime/entry.js +6 -0
- package/dist/store/runtime/kernel.d.ts +29 -0
- package/dist/store/runtime/kernel.js +2 -0
- package/dist/store/runtime/run-guarded-chat-store.d.ts +10 -0
- package/dist/store/runtime/run-guarded-chat-store.js +42 -0
- package/dist/store/runtime/run-ledger.d.ts +15 -0
- package/dist/store/runtime/run-ledger.js +206 -0
- package/dist/store/sql/boundary.d.ts +6 -0
- package/dist/store/sql/boundary.js +7 -1
- package/dist/store/sql/store.d.ts +3 -2
- package/dist/store/sql/store.js +9 -2
- package/dist/store/sqlite/index.d.ts +3 -2
- package/package.json +75 -10
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import type { AgentEvent, ChatMessage } from "../index.js";
|
|
2
|
+
import type { RunRef, RunSettlement } from "./ledger-contracts.js";
|
|
3
|
+
export interface AcceptedRunRequest {
|
|
4
|
+
readonly agentId?: string;
|
|
5
|
+
readonly contextRef: string;
|
|
6
|
+
}
|
|
7
|
+
export interface DurableRun extends RunRef {
|
|
8
|
+
readonly workspaceId: string;
|
|
9
|
+
readonly principalId: string | null;
|
|
10
|
+
readonly engine: string;
|
|
11
|
+
readonly message: ChatMessage;
|
|
12
|
+
readonly request: AcceptedRunRequest;
|
|
13
|
+
readonly transcript: readonly ChatMessage[];
|
|
14
|
+
readonly recoveryCount: number;
|
|
15
|
+
readonly recoveryDeadline: number | null;
|
|
16
|
+
readonly attemptStartedAt: number;
|
|
17
|
+
readonly lastProgressAt: number;
|
|
18
|
+
readonly cancelReason: string | null;
|
|
19
|
+
readonly sessionId: string | null;
|
|
20
|
+
readonly sessionConfirmed: boolean;
|
|
21
|
+
readonly child: {
|
|
22
|
+
pid: number;
|
|
23
|
+
startedAt: string;
|
|
24
|
+
} | null;
|
|
25
|
+
readonly attemptBase: readonly AgentEvent[];
|
|
26
|
+
}
|
|
27
|
+
export interface DurableRunStore {
|
|
28
|
+
load(required: {
|
|
29
|
+
messageId: string;
|
|
30
|
+
}, optional: {}): Promise<DurableRun | null>;
|
|
31
|
+
find(required: {
|
|
32
|
+
runId: string;
|
|
33
|
+
principalId?: string;
|
|
34
|
+
}, optional: {}): Promise<DurableRun | null>;
|
|
35
|
+
accept(required: RunRef & {
|
|
36
|
+
principalId: string;
|
|
37
|
+
workspaceId: string;
|
|
38
|
+
request: AcceptedRunRequest;
|
|
39
|
+
now: number;
|
|
40
|
+
}, optional: {}): Promise<DurableRun | null>;
|
|
41
|
+
advance(required: {
|
|
42
|
+
run: DurableRun;
|
|
43
|
+
nextRunId: string;
|
|
44
|
+
now: number;
|
|
45
|
+
events: readonly AgentEvent[];
|
|
46
|
+
}, optional: {}): Promise<boolean>;
|
|
47
|
+
cancel(required: {
|
|
48
|
+
runId: string;
|
|
49
|
+
reason: string;
|
|
50
|
+
}, optional: {}): Promise<void>;
|
|
51
|
+
cancelPending(required: RunRef & {
|
|
52
|
+
principalId: string;
|
|
53
|
+
workspaceId: string;
|
|
54
|
+
now: number;
|
|
55
|
+
}, optional: {}): Promise<DurableRun | null>;
|
|
56
|
+
captureSession(required: {
|
|
57
|
+
runId: string;
|
|
58
|
+
sessionId: string;
|
|
59
|
+
confirmed?: boolean;
|
|
60
|
+
child?: {
|
|
61
|
+
pid: number;
|
|
62
|
+
startedAt: string;
|
|
63
|
+
};
|
|
64
|
+
}, optional: {}): Promise<boolean>;
|
|
65
|
+
clearSession(required: {
|
|
66
|
+
runId: string;
|
|
67
|
+
sessionId: string;
|
|
68
|
+
}, optional: {}): Promise<void>;
|
|
69
|
+
recoveryClock(required: {
|
|
70
|
+
runId: string;
|
|
71
|
+
now: number;
|
|
72
|
+
active: boolean;
|
|
73
|
+
}, optional: {}): Promise<void>;
|
|
74
|
+
guardTool(required: {
|
|
75
|
+
runId: string;
|
|
76
|
+
toolId: string;
|
|
77
|
+
input: unknown;
|
|
78
|
+
toolUseId?: string;
|
|
79
|
+
}, optional: {}): Promise<"allowed" | "unknown" | "stale">;
|
|
80
|
+
completeTool(required: {
|
|
81
|
+
runId: string;
|
|
82
|
+
toolUseId: string;
|
|
83
|
+
content: string;
|
|
84
|
+
}, optional: {}): Promise<void>;
|
|
85
|
+
}
|
|
86
|
+
export type RunProbe = "live" | "dead" | "uncertain";
|
|
87
|
+
export interface RecoveryPorts {
|
|
88
|
+
readonly store: DurableRunStore;
|
|
89
|
+
readonly now: () => number;
|
|
90
|
+
readonly mintRunId: () => string;
|
|
91
|
+
readonly probe: (required: DurableRun, optional: {}) => Promise<RunProbe>;
|
|
92
|
+
readonly attach: (required: DurableRun, optional: {}) => void;
|
|
93
|
+
readonly launch: (required: {
|
|
94
|
+
run: DurableRun;
|
|
95
|
+
request: AcceptedRunRequest;
|
|
96
|
+
}, optional: {}) => Promise<void>;
|
|
97
|
+
readonly cancelAttempt: (required: DurableRun, optional: {}) => Promise<void>;
|
|
98
|
+
readonly verifyChildDead: (required: {
|
|
99
|
+
pid: number;
|
|
100
|
+
startedAt: string;
|
|
101
|
+
}, optional: {}) => Promise<boolean>;
|
|
102
|
+
readonly supportsNativeResume: (required: {
|
|
103
|
+
agentId: string;
|
|
104
|
+
}, optional: {}) => boolean;
|
|
105
|
+
readonly settle: (required: RunSettlement, optional: {}) => Promise<boolean>;
|
|
106
|
+
}
|
|
107
|
+
export type RecoveryTrigger = "boot" | "browser" | "stream" | "timeout" | "attempt-failed";
|
|
108
|
+
export type RecoveryResult = "gone" | "terminal" | "reattached" | "waiting" | "continued" | "superseded" | "finalized";
|
|
109
|
+
export interface DurableRecovery {
|
|
110
|
+
recover(required: {
|
|
111
|
+
messageId: string;
|
|
112
|
+
trigger: RecoveryTrigger;
|
|
113
|
+
expectedRunId?: string;
|
|
114
|
+
}, optional: {
|
|
115
|
+
/** Fresh HTTP 200 from the owning watch's bounded probe, scoped to exactly that attempt. */
|
|
116
|
+
liveRunId?: string;
|
|
117
|
+
}): Promise<RecoveryResult>;
|
|
118
|
+
}
|
|
119
|
+
/** Host run-ID classification; never infer transport identity from an engine default. */
|
|
120
|
+
export type RunIdPolicy = (required: {
|
|
121
|
+
runId: string;
|
|
122
|
+
}, optional?: {}) => boolean;
|
|
123
|
+
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AgentEvent } from "../events.js";
|
|
2
|
+
import type { ChatRunStatus } from "../messages.js";
|
|
3
|
+
/** Exactly which run owns the row; the host binds authorization and storage scope. */
|
|
4
|
+
export interface RunRef {
|
|
5
|
+
readonly conversationId: string;
|
|
6
|
+
readonly messageId: string;
|
|
7
|
+
readonly runId: string;
|
|
8
|
+
}
|
|
9
|
+
export interface RunProgress extends RunRef {
|
|
10
|
+
readonly content: string;
|
|
11
|
+
readonly events: readonly AgentEvent[];
|
|
12
|
+
}
|
|
13
|
+
export interface RunSettlement extends RunProgress {
|
|
14
|
+
readonly status: Extract<ChatRunStatus, 'succeeded' | 'failed' | 'canceled'>;
|
|
15
|
+
readonly endedAt: number;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=run-contracts.d.ts.map
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* from any product package's scope. See ADS-memory/reports/jini-port/extraction-plan.md
|
|
6
|
-
* §12 C2/C3 and ADS-memory/reports/jini-port/recon/r4b-webui-design.md §1 for the design
|
|
7
|
-
* this package targets, and archived provenance ledger for exact provenance.
|
|
8
|
-
*
|
|
9
|
-
* Was `@jini-ai/chat-core` (its own top-level package, one entry point) through npm 0.1.2 —
|
|
10
|
-
* consolidated 2026-08-03 into `@jini-ai/chat`'s `./core` subpath alongside `./react` (formerly
|
|
11
|
-
* `@jini-ai/ui`'s `./chat` export), following `@jini-ai/admin`'s umbrella-with-subpaths precedent.
|
|
12
|
-
* `@jini-ai/chat-core` is retired, not deprecated-and-kept — its published npm versions
|
|
13
|
-
* (0.1.0–0.1.2) go end-of-life as-is; `@jini-ai/chat` supersedes it.
|
|
2
|
+
* @jini-ai/chat/core — framework-free chat vocabulary and pure parsers.
|
|
3
|
+
* No React, DOM/browser globals, Node built-ins or product-package imports (extraction-plan §12
|
|
4
|
+
* C2/C3). Hosts can implement the transport port without importing a browser component graph.
|
|
14
5
|
*/
|
|
15
6
|
export * from './events.js';
|
|
16
7
|
export * from './messages.js';
|
|
@@ -27,13 +18,8 @@ export * from './run-activity.js';
|
|
|
27
18
|
export * from './surface-expiry.js';
|
|
28
19
|
export * from './assistant-content.js';
|
|
29
20
|
export * from './compact-events.js';
|
|
30
|
-
/**
|
|
31
|
-
*
|
|
32
|
-
* vocabulary this used to sit alongside — `CapabilityDef`, `PAGE_CAPABILITIES`, the
|
|
33
|
-
* `data-agent-*` convention, the policy gate, the protocol projections — moved to `@jini-ai/agentic`
|
|
34
|
-
* on 2026-07-26; import it directly rather than through this package. See
|
|
35
|
-
* `packages/agentic/archived provenance ledger` and this package's own archived provenance ledger for the extraction.
|
|
36
|
-
*/
|
|
21
|
+
/** Chat-pane capability manifest. Generic agent-control vocabulary, markup and projections are
|
|
22
|
+
* owned by @jini-ai/agentic; import them there so non-chat callers stay independent of chat. */
|
|
37
23
|
export * from './agentic/index.js';
|
|
38
24
|
/**
|
|
39
25
|
* Durable chat history — the storage-neutral `ChatHistoryStore` port and the local title
|
|
@@ -42,4 +28,8 @@ export * from './agentic/index.js';
|
|
|
42
28
|
* module, and a host binds it to its own authentication.
|
|
43
29
|
*/
|
|
44
30
|
export * from './persistence/index.js';
|
|
31
|
+
export { recoveredRunEvents } from './durable-projection.js';
|
|
32
|
+
export { composerHistoryKeyAction, createComposerHistoryState, mergeComposerHistory, normalizeComposerHistory, transitionComposerHistory, } from './composer-history.js';
|
|
33
|
+
export type { ComposerHistoryKeyInput, ComposerHistoryState, ComposerHistoryStoragePort } from './composer-history.js';
|
|
34
|
+
export * from './user-text-redaction.js';
|
|
45
35
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/core/index.js
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* from any product package's scope. See ADS-memory/reports/jini-port/extraction-plan.md
|
|
6
|
-
* §12 C2/C3 and ADS-memory/reports/jini-port/recon/r4b-webui-design.md §1 for the design
|
|
7
|
-
* this package targets, and archived provenance ledger for exact provenance.
|
|
8
|
-
*
|
|
9
|
-
* Was `@jini-ai/chat-core` (its own top-level package, one entry point) through npm 0.1.2 —
|
|
10
|
-
* consolidated 2026-08-03 into `@jini-ai/chat`'s `./core` subpath alongside `./react` (formerly
|
|
11
|
-
* `@jini-ai/ui`'s `./chat` export), following `@jini-ai/admin`'s umbrella-with-subpaths precedent.
|
|
12
|
-
* `@jini-ai/chat-core` is retired, not deprecated-and-kept — its published npm versions
|
|
13
|
-
* (0.1.0–0.1.2) go end-of-life as-is; `@jini-ai/chat` supersedes it.
|
|
2
|
+
* @jini-ai/chat/core — framework-free chat vocabulary and pure parsers.
|
|
3
|
+
* No React, DOM/browser globals, Node built-ins or product-package imports (extraction-plan §12
|
|
4
|
+
* C2/C3). Hosts can implement the transport port without importing a browser component graph.
|
|
14
5
|
*/
|
|
15
6
|
export * from './events.js';
|
|
16
7
|
export * from './messages.js';
|
|
@@ -27,13 +18,8 @@ export * from './run-activity.js';
|
|
|
27
18
|
export * from './surface-expiry.js';
|
|
28
19
|
export * from './assistant-content.js';
|
|
29
20
|
export * from './compact-events.js';
|
|
30
|
-
/**
|
|
31
|
-
*
|
|
32
|
-
* vocabulary this used to sit alongside — `CapabilityDef`, `PAGE_CAPABILITIES`, the
|
|
33
|
-
* `data-agent-*` convention, the policy gate, the protocol projections — moved to `@jini-ai/agentic`
|
|
34
|
-
* on 2026-07-26; import it directly rather than through this package. See
|
|
35
|
-
* `packages/agentic/archived provenance ledger` and this package's own archived provenance ledger for the extraction.
|
|
36
|
-
*/
|
|
21
|
+
/** Chat-pane capability manifest. Generic agent-control vocabulary, markup and projections are
|
|
22
|
+
* owned by @jini-ai/agentic; import them there so non-chat callers stay independent of chat. */
|
|
37
23
|
export * from './agentic/index.js';
|
|
38
24
|
/**
|
|
39
25
|
* Durable chat history — the storage-neutral `ChatHistoryStore` port and the local title
|
|
@@ -42,4 +28,7 @@ export * from './agentic/index.js';
|
|
|
42
28
|
* module, and a host binds it to its own authentication.
|
|
43
29
|
*/
|
|
44
30
|
export * from './persistence/index.js';
|
|
31
|
+
export { recoveredRunEvents } from './durable-projection.js';
|
|
32
|
+
export { composerHistoryKeyAction, createComposerHistoryState, mergeComposerHistory, normalizeComposerHistory, transitionComposerHistory, } from './composer-history.js';
|
|
33
|
+
export * from './user-text-redaction.js';
|
|
45
34
|
//# sourceMappingURL=index.js.map
|
package/dist/core/messages.d.ts
CHANGED
|
@@ -33,6 +33,8 @@ export interface ChatAttachment {
|
|
|
33
33
|
* host layers those on top via its own message extension, not this type.
|
|
34
34
|
*/
|
|
35
35
|
export interface ChatMessage {
|
|
36
|
+
/** Transient safe receipt; storage requires no new column. */
|
|
37
|
+
secretRedaction?: import('./user-text-redaction.js').SecretRedactionSignal;
|
|
36
38
|
id: string;
|
|
37
39
|
role: ChatRole;
|
|
38
40
|
content: string;
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module question-form/format
|
|
3
|
-
*
|
|
4
|
-
* Answer presentation: turning a submitted answer set into the prose the
|
|
5
|
-
* agent reads on its next turn, plus the label/value lookups also used by
|
|
6
|
-
* `normalize.ts`'s default-value resolution. Split out of the original
|
|
7
|
-
* single-file `question-form.ts`; see `../question-form.ts` for the public
|
|
8
|
-
* facade.
|
|
9
|
-
*/
|
|
10
1
|
import type { FormOption, QuestionForm } from './types.js';
|
|
11
2
|
/**
|
|
12
3
|
* Format a finished set of answers into a prose user message the agent can
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module question-form/format
|
|
3
|
+
*
|
|
4
|
+
* Answer presentation: turning a submitted answer set into the prose the
|
|
5
|
+
* agent reads on its next turn, plus the label/value lookups also used by
|
|
6
|
+
* `normalize.ts`'s default-value resolution. Split out of the original
|
|
7
|
+
* single-file `question-form.ts`; see `../question-form.ts` for the public
|
|
8
|
+
* facade.
|
|
9
|
+
*/
|
|
10
|
+
import { redactQuestionAnswers, isSecretQuestion } from './secret-answers.js';
|
|
11
|
+
import { CREDENTIAL_CARD_GUIDANCE, redactUserText } from '../user-text-redaction.js';
|
|
1
12
|
/**
|
|
2
13
|
* Format a finished set of answers into a prose user message the agent can
|
|
3
14
|
* read on its next turn. The shape is stable enough that the agent can
|
|
@@ -6,10 +17,11 @@
|
|
|
6
17
|
* @complexity O(q) in the number of questions on the form.
|
|
7
18
|
*/
|
|
8
19
|
export function formatFormAnswers({ form, answers }) {
|
|
20
|
+
const safe = redactQuestionAnswers({ form, answers });
|
|
9
21
|
const lines = [];
|
|
10
22
|
lines.push(`[form answers — ${form.id}]`);
|
|
11
23
|
for (const q of form.questions) {
|
|
12
|
-
const v = answers[q.id];
|
|
24
|
+
const v = safe.answers[q.id];
|
|
13
25
|
let display;
|
|
14
26
|
if (Array.isArray(v)) {
|
|
15
27
|
display = v.length > 0 ? v.map((value) => formOptionDisplayForValue(q, value)).join(', ') : '(skipped)';
|
|
@@ -22,7 +34,9 @@ export function formatFormAnswers({ form, answers }) {
|
|
|
22
34
|
}
|
|
23
35
|
lines.push(`- ${q.label}: ${display}`);
|
|
24
36
|
}
|
|
25
|
-
|
|
37
|
+
if (safe.secretRedacted || form.questions.some(question => isSecretQuestion({ question })))
|
|
38
|
+
lines.push(CREDENTIAL_CARD_GUIDANCE);
|
|
39
|
+
return redactUserText({ text: lines.join('\n') }).text;
|
|
26
40
|
}
|
|
27
41
|
function formOptionDisplayForValue(question, value) {
|
|
28
42
|
const match = question.options?.find((option) => option.value === value || option.label === value);
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** Chat question forms are model-visible text, never secure credential storage. */
|
|
2
|
+
import { type UserTextRedactionOptions } from '../user-text-redaction.js';
|
|
3
|
+
import type { FormQuestion, QuestionForm } from './types.js';
|
|
4
|
+
export declare function isSecretQuestion({ question }: {
|
|
5
|
+
readonly question: Pick<FormQuestion, 'id' | 'label' | 'type' | 'name'>;
|
|
6
|
+
}): boolean;
|
|
7
|
+
/** The map as well as its formatted transcript must be safe: hosts often persist both. */
|
|
8
|
+
export declare function redactQuestionAnswers({ form, answers }: {
|
|
9
|
+
readonly form: QuestionForm;
|
|
10
|
+
readonly answers: Readonly<Record<string, string | string[]>>;
|
|
11
|
+
}, options?: UserTextRedactionOptions): {
|
|
12
|
+
readonly answers: Record<string, string | string[]>;
|
|
13
|
+
readonly secretRedacted: boolean;
|
|
14
|
+
readonly count: number;
|
|
15
|
+
};
|
|
16
|
+
/** Never populate a credential text question from model-supplied defaults. */
|
|
17
|
+
export declare function withoutSecretQuestionDefaults({ form }: {
|
|
18
|
+
readonly form: QuestionForm;
|
|
19
|
+
}): QuestionForm;
|
|
20
|
+
/** Attributes are presentation policy, shared by any host renderer. */
|
|
21
|
+
export declare function questionTextInputProps({ question }: {
|
|
22
|
+
readonly question: FormQuestion;
|
|
23
|
+
}): {
|
|
24
|
+
type: 'password' | 'text';
|
|
25
|
+
autoComplete?: string;
|
|
26
|
+
spellCheck?: boolean;
|
|
27
|
+
};
|
|
28
|
+
export declare function questionTextareaProps({ question }: {
|
|
29
|
+
readonly question: FormQuestion;
|
|
30
|
+
}): {
|
|
31
|
+
autoComplete?: string;
|
|
32
|
+
spellCheck?: boolean;
|
|
33
|
+
style?: {
|
|
34
|
+
WebkitTextSecurity: string;
|
|
35
|
+
whiteSpace: 'pre-wrap';
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=secret-answers.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** Chat question forms are model-visible text, never secure credential storage. */
|
|
2
|
+
import { redactUserText } from '../user-text-redaction.js';
|
|
3
|
+
export function isSecretQuestion({ question }) {
|
|
4
|
+
if (question.type !== 'text' && question.type !== 'textarea')
|
|
5
|
+
return false;
|
|
6
|
+
const names = [question.id, question.label, question.name ?? ''].join(' ').replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
7
|
+
return /(?:^|[^a-z0-9])(?:key|token|password|passwd|secret)(?:$|[^a-z0-9])/i.test(names);
|
|
8
|
+
}
|
|
9
|
+
/** The map as well as its formatted transcript must be safe: hosts often persist both. */
|
|
10
|
+
export function redactQuestionAnswers({ form, answers }, options = {}) {
|
|
11
|
+
let count = 0;
|
|
12
|
+
const cleaned = {};
|
|
13
|
+
const redact = options.redactUserText ?? redactUserText;
|
|
14
|
+
for (const question of form.questions) {
|
|
15
|
+
const value = answers[question.id];
|
|
16
|
+
if (value === undefined)
|
|
17
|
+
continue;
|
|
18
|
+
const guard = (text) => {
|
|
19
|
+
const result = redact({ text }, { secretField: isSecretQuestion({ question }) });
|
|
20
|
+
count += result.count;
|
|
21
|
+
return result.text;
|
|
22
|
+
};
|
|
23
|
+
cleaned[question.id] = Array.isArray(value) ? value.map(guard) : guard(value);
|
|
24
|
+
}
|
|
25
|
+
if (count > 0)
|
|
26
|
+
options.onSecretRedacted?.({ secretRedacted: true, count });
|
|
27
|
+
return { answers: cleaned, secretRedacted: count > 0, count };
|
|
28
|
+
}
|
|
29
|
+
/** Never populate a credential text question from model-supplied defaults. */
|
|
30
|
+
export function withoutSecretQuestionDefaults({ form }) {
|
|
31
|
+
return { ...form, questions: form.questions.map(question => {
|
|
32
|
+
if (!isSecretQuestion({ question }))
|
|
33
|
+
return question;
|
|
34
|
+
const { defaultValue: _defaultValue, ...safe } = question;
|
|
35
|
+
return safe;
|
|
36
|
+
}) };
|
|
37
|
+
}
|
|
38
|
+
/** Attributes are presentation policy, shared by any host renderer. */
|
|
39
|
+
export function questionTextInputProps({ question }) {
|
|
40
|
+
return isSecretQuestion({ question }) ? { type: 'password', autoComplete: 'new-password', spellCheck: false } : { type: 'text' };
|
|
41
|
+
}
|
|
42
|
+
export function questionTextareaProps({ question }) {
|
|
43
|
+
return isSecretQuestion({ question }) ? { autoComplete: 'off', spellCheck: false, style: { WebkitTextSecurity: 'disc', whiteSpace: 'pre-wrap' } } : {};
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=secret-answers.js.map
|
|
@@ -36,4 +36,5 @@ export type { QuestionType, DirectionCard, FormOption, FormQuestion, QuestionFor
|
|
|
36
36
|
export { splitOnQuestionForms, findFirstQuestionForm, parseQuestionForm, stripTrailingOpenQuestionForm, hasUnterminatedQuestionForm, parsePartialQuestionForm, } from './question-form/scan.js';
|
|
37
37
|
export { isRenderableColor } from './question-form/normalize.js';
|
|
38
38
|
export { formatFormAnswers, formOptionLabelForValue, formOptionValueForLabel } from './question-form/format.js';
|
|
39
|
+
export { isSecretQuestion, redactQuestionAnswers, withoutSecretQuestionDefaults, questionTextInputProps, questionTextareaProps } from './question-form/secret-answers.js';
|
|
39
40
|
//# sourceMappingURL=question-form.d.ts.map
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { splitOnQuestionForms, findFirstQuestionForm, parseQuestionForm, stripTrailingOpenQuestionForm, hasUnterminatedQuestionForm, parsePartialQuestionForm, } from './question-form/scan.js';
|
|
2
2
|
export { isRenderableColor } from './question-form/normalize.js';
|
|
3
3
|
export { formatFormAnswers, formOptionLabelForValue, formOptionValueForLabel } from './question-form/format.js';
|
|
4
|
+
export { isSecretQuestion, redactQuestionAnswers, withoutSecretQuestionDefaults, questionTextInputProps, questionTextareaProps } from './question-form/secret-answers.js';
|
|
4
5
|
//# sourceMappingURL=question-form.js.map
|