@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
|
@@ -5,18 +5,20 @@
|
|
|
5
5
|
* the flattened text a host sends to an agent as prior-turn context.
|
|
6
6
|
*
|
|
7
7
|
* Adapted from OD's `providers/daemon.ts` transcript section (see
|
|
8
|
-
*
|
|
8
|
+
* archived provenance ledger). The OD original also owned SSE/fetch transport
|
|
9
9
|
* (`streamViaDaemon`, `DaemonStreamHandlers`) — none of that is ported here;
|
|
10
10
|
* only the pure string-assembly helpers. It also hard-coded OD's BYOK/
|
|
11
11
|
* OpenCode agent-family policy and an `agent-browser`-tool-specific
|
|
12
12
|
* context-warning heuristic; both are OD product policy, not generic
|
|
13
13
|
* transcript assembly, so they are generalized into caller-supplied hooks
|
|
14
|
-
* (or dropped) below — see
|
|
14
|
+
* (or dropped) below — see archived provenance ledger for the full accounting.
|
|
15
15
|
*/
|
|
16
16
|
import type { ChatMessage } from './messages.js';
|
|
17
17
|
import type { PersistedArtifactFileRef } from './util/strip.js';
|
|
18
18
|
/** The most recent `user`-authored message's content, or `''` if there isn't one. */
|
|
19
|
-
export declare function latestUserPromptFromHistory(history
|
|
19
|
+
export declare function latestUserPromptFromHistory({ history }: {
|
|
20
|
+
history: ChatMessage[];
|
|
21
|
+
}): string;
|
|
20
22
|
/**
|
|
21
23
|
* Strip transcript-echo hazards from a prior assistant turn before it goes
|
|
22
24
|
* back to the agent as history: an already-answered `<question-form>` /
|
|
@@ -36,7 +38,11 @@ export declare function latestUserPromptFromHistory(history: ChatMessage[]): str
|
|
|
36
38
|
* @complexity O(n) in `content.length` (a small fixed number of regex
|
|
37
39
|
* passes) plus {@link summarizeArtifactsForTranscript}'s cost.
|
|
38
40
|
*/
|
|
39
|
-
export declare function sanitizePriorAssistantTurn(content
|
|
41
|
+
export declare function sanitizePriorAssistantTurn({ content }: {
|
|
42
|
+
content: string;
|
|
43
|
+
}, { persistedArtifactFiles }?: {
|
|
44
|
+
persistedArtifactFiles?: (ReadonlyArray<PersistedArtifactFileRef>) | undefined;
|
|
45
|
+
}): string;
|
|
40
46
|
export interface BuildTranscriptOptions {
|
|
41
47
|
/**
|
|
42
48
|
* Scope the transcript to messages from this agent's family onward,
|
|
@@ -77,5 +83,7 @@ export interface BuildTranscriptOptions {
|
|
|
77
83
|
* scope, one to sanitize/truncate/join each message, one to scan events
|
|
78
84
|
* for the warning.
|
|
79
85
|
*/
|
|
80
|
-
export declare function buildTranscript(history
|
|
86
|
+
export declare function buildTranscript({ history }: {
|
|
87
|
+
history: ChatMessage[];
|
|
88
|
+
}, options?: BuildTranscriptOptions): string;
|
|
81
89
|
//# sourceMappingURL=transcript.d.ts.map
|
package/dist/core/transcript.js
CHANGED
|
@@ -3,7 +3,7 @@ const DEFAULT_MAX_TRANSCRIPT_MESSAGE_CHARS = 12_000;
|
|
|
3
3
|
const DEFAULT_LARGE_TOOL_RESULT_CHARS = 8_000;
|
|
4
4
|
const DEFAULT_HIGH_INPUT_TOKEN_WARNING_THRESHOLD = 200_000;
|
|
5
5
|
/** The most recent `user`-authored message's content, or `''` if there isn't one. */
|
|
6
|
-
export function latestUserPromptFromHistory(history) {
|
|
6
|
+
export function latestUserPromptFromHistory({ history }) {
|
|
7
7
|
for (let i = history.length - 1; i >= 0; i -= 1) {
|
|
8
8
|
const message = history[i];
|
|
9
9
|
if (message?.role === 'user')
|
|
@@ -82,7 +82,7 @@ function scopeHistoryToAgent(history, targetAgentId, isSameAgentFamily) {
|
|
|
82
82
|
* @complexity O(n) in `content.length` (a small fixed number of regex
|
|
83
83
|
* passes) plus {@link summarizeArtifactsForTranscript}'s cost.
|
|
84
84
|
*/
|
|
85
|
-
export function sanitizePriorAssistantTurn(content, persistedArtifactFiles = []) {
|
|
85
|
+
export function sanitizePriorAssistantTurn({ content }, { persistedArtifactFiles = [] } = {}) {
|
|
86
86
|
let sanitized = content.replace(
|
|
87
87
|
// `\1` backreference keeps the open/close tag names matched so this never
|
|
88
88
|
// splices across a `<question-form>…</ask-question>` mismatch.
|
|
@@ -99,7 +99,7 @@ export function sanitizePriorAssistantTurn(content, persistedArtifactFiles = [])
|
|
|
99
99
|
// Replace prior-turn `<artifact>` HTML with a one-line summary for
|
|
100
100
|
// artifacts CONFIRMED persisted (see summarizeArtifactsForTranscript's own
|
|
101
101
|
// doc for why an unconfirmed save is left verbatim).
|
|
102
|
-
sanitized = summarizeArtifactsForTranscript(sanitized, persistedArtifactFiles);
|
|
102
|
+
sanitized = summarizeArtifactsForTranscript({ content: sanitized, persistedFiles: persistedArtifactFiles });
|
|
103
103
|
return sanitized;
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
@@ -113,7 +113,7 @@ export function sanitizePriorAssistantTurn(content, persistedArtifactFiles = [])
|
|
|
113
113
|
* scope, one to sanitize/truncate/join each message, one to scan events
|
|
114
114
|
* for the warning.
|
|
115
115
|
*/
|
|
116
|
-
export function buildTranscript(history, options = {}) {
|
|
116
|
+
export function buildTranscript({ history }, options = {}) {
|
|
117
117
|
const maxMessageChars = options.maxMessageChars ?? DEFAULT_MAX_TRANSCRIPT_MESSAGE_CHARS;
|
|
118
118
|
const largeToolResultChars = options.largeToolResultChars ?? DEFAULT_LARGE_TOOL_RESULT_CHARS;
|
|
119
119
|
const highInputTokenWarningThreshold = options.highInputTokenWarningThreshold ?? DEFAULT_HIGH_INPUT_TOKEN_WARNING_THRESHOLD;
|
|
@@ -123,7 +123,7 @@ export function buildTranscript(history, options = {}) {
|
|
|
123
123
|
const transcript = scopedHistory
|
|
124
124
|
.map((m) => {
|
|
125
125
|
const trimmed = m.content.trim();
|
|
126
|
-
const sanitized = m.role === 'assistant' ? sanitizePriorAssistantTurn(trimmed, resolvePersistedArtifactFiles(m)) : trimmed;
|
|
126
|
+
const sanitized = m.role === 'assistant' ? sanitizePriorAssistantTurn({ content: trimmed }, { persistedArtifactFiles: resolvePersistedArtifactFiles(m) }) : trimmed;
|
|
127
127
|
return `## ${m.role}\n${escapeTranscriptRoleDelimiters(truncateForTranscript(sanitized, maxMessageChars))}`;
|
|
128
128
|
})
|
|
129
129
|
.join('\n\n');
|
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type { ArtifactManifest } from './types.js';
|
|
8
8
|
/** The manifest sidecar file name convention for a given artifact entry file name. */
|
|
9
|
-
export declare function artifactManifestNameFor(entry
|
|
9
|
+
export declare function artifactManifestNameFor({ entry }: {
|
|
10
|
+
entry: string;
|
|
11
|
+
}): string;
|
|
10
12
|
/** Build a fresh, complete manifest for a newly-persisted HTML artifact. */
|
|
11
13
|
export declare function createHtmlArtifactManifest(input: {
|
|
12
14
|
entry: string;
|
|
@@ -15,7 +17,9 @@ export declare function createHtmlArtifactManifest(input: {
|
|
|
15
17
|
sourceSkillId?: string;
|
|
16
18
|
designSystemId?: string | null;
|
|
17
19
|
}): ArtifactManifest;
|
|
18
|
-
export declare function serializeArtifactManifest(manifest
|
|
20
|
+
export declare function serializeArtifactManifest({ manifest }: {
|
|
21
|
+
manifest: ArtifactManifest;
|
|
22
|
+
}): string;
|
|
19
23
|
/**
|
|
20
24
|
* Parse and validate a manifest JSON string, rejecting anything that isn't a
|
|
21
25
|
* well-formed, currently-supported manifest (wrong version, missing
|
|
@@ -25,7 +29,9 @@ export declare function serializeArtifactManifest(manifest: ArtifactManifest): s
|
|
|
25
29
|
* @returns The validated manifest, or `null` on any parse/shape failure.
|
|
26
30
|
* @complexity O(k) in the manifest's own field/array count — no I/O.
|
|
27
31
|
*/
|
|
28
|
-
export declare function parseArtifactManifest(raw
|
|
32
|
+
export declare function parseArtifactManifest({ raw }: {
|
|
33
|
+
raw: string;
|
|
34
|
+
}): ArtifactManifest | null;
|
|
29
35
|
/**
|
|
30
36
|
* Infer a manifest for a legacy artifact file that predates manifest
|
|
31
37
|
* sidecars, from its entry file name alone (extension → kind → renderer).
|
|
@@ -55,7 +55,7 @@ function exportsForKind(kind) {
|
|
|
55
55
|
return ['html', 'pdf', 'zip'];
|
|
56
56
|
}
|
|
57
57
|
/** The manifest sidecar file name convention for a given artifact entry file name. */
|
|
58
|
-
export function artifactManifestNameFor(entry) {
|
|
58
|
+
export function artifactManifestNameFor({ entry }) {
|
|
59
59
|
return `${entry}.artifact.json`;
|
|
60
60
|
}
|
|
61
61
|
/** Build a fresh, complete manifest for a newly-persisted HTML artifact. */
|
|
@@ -77,7 +77,7 @@ export function createHtmlArtifactManifest(input) {
|
|
|
77
77
|
metadata: input.metadata,
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
|
-
export function serializeArtifactManifest(manifest) {
|
|
80
|
+
export function serializeArtifactManifest({ manifest }) {
|
|
81
81
|
return JSON.stringify(manifest, null, 2);
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
@@ -89,7 +89,7 @@ export function serializeArtifactManifest(manifest) {
|
|
|
89
89
|
* @returns The validated manifest, or `null` on any parse/shape failure.
|
|
90
90
|
* @complexity O(k) in the manifest's own field/array count — no I/O.
|
|
91
91
|
*/
|
|
92
|
-
export function parseArtifactManifest(raw) {
|
|
92
|
+
export function parseArtifactManifest({ raw }) {
|
|
93
93
|
try {
|
|
94
94
|
const parsed = JSON.parse(raw);
|
|
95
95
|
if (parsed?.version !== MANIFEST_VERSION)
|
|
@@ -22,7 +22,10 @@ export declare const INLINE_CODE_RE: RegExp;
|
|
|
22
22
|
* continuation (e.g. `<artifactual`) is a prefix-shared literal that must
|
|
23
23
|
* not be treated as a tag.
|
|
24
24
|
*/
|
|
25
|
-
export declare function isRealArtifactOpenAt(content
|
|
25
|
+
export declare function isRealArtifactOpenAt({ content, idx }: {
|
|
26
|
+
content: string;
|
|
27
|
+
idx: number;
|
|
28
|
+
}): boolean;
|
|
26
29
|
export type Range = readonly [number, number];
|
|
27
30
|
/**
|
|
28
31
|
* Compute the half-open `[start, end)` ranges of `buffer` that a Markdown
|
|
@@ -38,10 +41,15 @@ export type Range = readonly [number, number];
|
|
|
38
41
|
* @complexity O(n) in `buffer.length` — one line-by-line scan plus one
|
|
39
42
|
* backtick scan per accumulated paragraph block.
|
|
40
43
|
*/
|
|
41
|
-
export declare function computeSkipRanges(buffer
|
|
44
|
+
export declare function computeSkipRanges({ buffer }: {
|
|
45
|
+
buffer: string;
|
|
46
|
+
}): {
|
|
42
47
|
ranges: Range[];
|
|
43
48
|
unclosedFenceStart: number | null;
|
|
44
49
|
};
|
|
45
50
|
/** `true` when position `p` falls inside one of `ranges` (half-open intervals). */
|
|
46
|
-
export declare function rangeContains(ranges
|
|
51
|
+
export declare function rangeContains({ ranges, p }: {
|
|
52
|
+
ranges: ReadonlyArray<Range>;
|
|
53
|
+
p: number;
|
|
54
|
+
}): boolean;
|
|
47
55
|
//# sourceMappingURL=markdown-context.d.ts.map
|
|
@@ -34,7 +34,7 @@ const OL_ITEM_RE = /^\s*\d+\.\s+/;
|
|
|
34
34
|
* continuation (e.g. `<artifactual`) is a prefix-shared literal that must
|
|
35
35
|
* not be treated as a tag.
|
|
36
36
|
*/
|
|
37
|
-
export function isRealArtifactOpenAt(content, idx) {
|
|
37
|
+
export function isRealArtifactOpenAt({ content, idx }) {
|
|
38
38
|
const next = content.charAt(idx + '<artifact'.length);
|
|
39
39
|
return next !== '' && /\s/.test(next);
|
|
40
40
|
}
|
|
@@ -52,7 +52,7 @@ export function isRealArtifactOpenAt(content, idx) {
|
|
|
52
52
|
* @complexity O(n) in `buffer.length` — one line-by-line scan plus one
|
|
53
53
|
* backtick scan per accumulated paragraph block.
|
|
54
54
|
*/
|
|
55
|
-
export function computeSkipRanges(buffer) {
|
|
55
|
+
export function computeSkipRanges({ buffer }) {
|
|
56
56
|
const ranges = [];
|
|
57
57
|
// Paragraph-block regions are contiguous spans of paragraph lines outside
|
|
58
58
|
// any fenced code block; inline-code scanning is restricted to one block at
|
|
@@ -115,7 +115,7 @@ export function computeSkipRanges(buffer) {
|
|
|
115
115
|
return { ranges, unclosedFenceStart: inFence ? fenceStart : null };
|
|
116
116
|
}
|
|
117
117
|
/** `true` when position `p` falls inside one of `ranges` (half-open intervals). */
|
|
118
|
-
export function rangeContains(ranges, p) {
|
|
118
|
+
export function rangeContains({ ranges, p }) {
|
|
119
119
|
for (const [s, e] of ranges) {
|
|
120
120
|
if (p >= s && p < e)
|
|
121
121
|
return true;
|
|
@@ -16,5 +16,7 @@
|
|
|
16
16
|
* Parse `name="value"` / `name='value'` pairs out of a tag's raw attribute
|
|
17
17
|
* string (the content between the tag name and the closing `>`).
|
|
18
18
|
*/
|
|
19
|
-
export declare function parseQuotedAttrs(raw
|
|
19
|
+
export declare function parseQuotedAttrs({ raw }: {
|
|
20
|
+
raw: string;
|
|
21
|
+
}): Record<string, string>;
|
|
20
22
|
//# sourceMappingURL=markup-attributes.d.ts.map
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* Parse `name="value"` / `name='value'` pairs out of a tag's raw attribute
|
|
17
17
|
* string (the content between the tag name and the closing `>`).
|
|
18
18
|
*/
|
|
19
|
-
export function parseQuotedAttrs(raw) {
|
|
19
|
+
export function parseQuotedAttrs({ raw }) {
|
|
20
20
|
const re = /(\w+)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
21
21
|
const out = {};
|
|
22
22
|
let m = re.exec(raw);
|
|
@@ -16,7 +16,7 @@ export type ArtifactEvent = {
|
|
|
16
16
|
fullContent: string;
|
|
17
17
|
};
|
|
18
18
|
/**
|
|
19
|
-
* Create a fresh streaming artifact parser. Call `feed(delta)` for each
|
|
19
|
+
* Create a fresh streaming artifact parser. Call `feed({ delta })` for each
|
|
20
20
|
* chunk as it arrives (iterate its generator to drain queued events), and
|
|
21
21
|
* `flush()` once at end-of-stream to emit whatever is still buffered.
|
|
22
22
|
*
|
|
@@ -25,9 +25,11 @@ export type ArtifactEvent = {
|
|
|
25
25
|
* the generator), which is the standard tradeoff for streaming tag
|
|
26
26
|
* detection over an ever-growing buffer.
|
|
27
27
|
*/
|
|
28
|
-
export declare function createArtifactParser(): {
|
|
29
|
-
feed: (
|
|
30
|
-
|
|
28
|
+
export declare function createArtifactParser(_requiredArgs: Record<string, never>): {
|
|
29
|
+
feed: (args: {
|
|
30
|
+
delta: string;
|
|
31
|
+
}) => Generator<ArtifactEvent>;
|
|
32
|
+
flush: (args: Record<string, never>) => Generator<ArtifactEvent>;
|
|
31
33
|
};
|
|
32
34
|
/**
|
|
33
35
|
* Convenience wrapper over {@link createArtifactParser} for the common
|
|
@@ -38,5 +40,7 @@ export declare function createArtifactParser(): {
|
|
|
38
40
|
* @param content - A complete (already fully-arrived) message body.
|
|
39
41
|
* @complexity O(n) in `content.length` (one `feed` + one `flush` over the whole string).
|
|
40
42
|
*/
|
|
41
|
-
export declare function parseArtifacts(content
|
|
43
|
+
export declare function parseArtifacts({ content }: {
|
|
44
|
+
content: string;
|
|
45
|
+
}): ArtifactEvent[];
|
|
42
46
|
//# sourceMappingURL=parser.d.ts.map
|
package/dist/core/util/parser.js
CHANGED
|
@@ -24,7 +24,7 @@ const CLOSE_TAG = '</artifact>';
|
|
|
24
24
|
// future chunk may turn it into an inline code span.
|
|
25
25
|
function findOpenTag(buffer) {
|
|
26
26
|
const len = buffer.length;
|
|
27
|
-
const { ranges, unclosedFenceStart } = computeSkipRanges(buffer);
|
|
27
|
+
const { ranges, unclosedFenceStart } = computeSkipRanges({ buffer: buffer });
|
|
28
28
|
// Pass 1: scan for the earliest *complete* real `<artifact …>` open outside
|
|
29
29
|
// any skip range, before any hold-back decision — otherwise a stray
|
|
30
30
|
// backtick or fence-opener prefix on a tail line would suppress an
|
|
@@ -35,7 +35,7 @@ function findOpenTag(buffer) {
|
|
|
35
35
|
const idx = buffer.indexOf(OPEN_PREFIX, from);
|
|
36
36
|
if (idx === -1)
|
|
37
37
|
break;
|
|
38
|
-
if (rangeContains(ranges, idx)) {
|
|
38
|
+
if (rangeContains({ ranges: ranges, p: idx })) {
|
|
39
39
|
from = idx + OPEN_PREFIX.length;
|
|
40
40
|
continue;
|
|
41
41
|
}
|
|
@@ -53,7 +53,7 @@ function findOpenTag(buffer) {
|
|
|
53
53
|
earliestPartialOpen = idx;
|
|
54
54
|
break;
|
|
55
55
|
}
|
|
56
|
-
if (!isRealArtifactOpenAt(buffer, idx)) {
|
|
56
|
+
if (!isRealArtifactOpenAt({ content: buffer, idx: idx })) {
|
|
57
57
|
from = after; // e.g. "<artifactual" — not a real open, keep scanning
|
|
58
58
|
continue;
|
|
59
59
|
}
|
|
@@ -101,7 +101,7 @@ function findOpenTag(buffer) {
|
|
|
101
101
|
for (let k = lastNl + 1; k < len; k++) {
|
|
102
102
|
if (buffer.charAt(k) !== '`')
|
|
103
103
|
continue;
|
|
104
|
-
if (rangeContains(ranges, k))
|
|
104
|
+
if (rangeContains({ ranges: ranges, p: k }))
|
|
105
105
|
continue;
|
|
106
106
|
if (parity === 0) {
|
|
107
107
|
firstUnmatched = k;
|
|
@@ -115,7 +115,7 @@ function findOpenTag(buffer) {
|
|
|
115
115
|
note(firstUnmatched);
|
|
116
116
|
// Strict prefix at the tail (e.g. "<art") — hold back.
|
|
117
117
|
const tailLt = buffer.lastIndexOf('<');
|
|
118
|
-
if (tailLt !== -1 && !rangeContains(ranges, tailLt)) {
|
|
118
|
+
if (tailLt !== -1 && !rangeContains({ ranges: ranges, p: tailLt })) {
|
|
119
119
|
const slice = buffer.slice(tailLt);
|
|
120
120
|
if (OPEN_PREFIX.startsWith(slice) && slice.length < OPEN_PREFIX.length) {
|
|
121
121
|
note(tailLt);
|
|
@@ -126,7 +126,7 @@ function findOpenTag(buffer) {
|
|
|
126
126
|
return { kind: 'none' };
|
|
127
127
|
}
|
|
128
128
|
/**
|
|
129
|
-
* Create a fresh streaming artifact parser. Call `feed(delta)` for each
|
|
129
|
+
* Create a fresh streaming artifact parser. Call `feed({ delta })` for each
|
|
130
130
|
* chunk as it arrives (iterate its generator to drain queued events), and
|
|
131
131
|
* `flush()` once at end-of-stream to emit whatever is still buffered.
|
|
132
132
|
*
|
|
@@ -135,7 +135,7 @@ function findOpenTag(buffer) {
|
|
|
135
135
|
* the generator), which is the standard tradeoff for streaming tag
|
|
136
136
|
* detection over an ever-growing buffer.
|
|
137
137
|
*/
|
|
138
|
-
export function createArtifactParser() {
|
|
138
|
+
export function createArtifactParser(_requiredArgs) {
|
|
139
139
|
const state = {
|
|
140
140
|
inside: false,
|
|
141
141
|
buffer: '',
|
|
@@ -144,7 +144,7 @@ export function createArtifactParser() {
|
|
|
144
144
|
title: '',
|
|
145
145
|
content: '',
|
|
146
146
|
};
|
|
147
|
-
function* feed(delta) {
|
|
147
|
+
function* feed({ delta }) {
|
|
148
148
|
state.buffer += delta;
|
|
149
149
|
while (state.buffer.length > 0) {
|
|
150
150
|
if (!state.inside) {
|
|
@@ -164,7 +164,7 @@ export function createArtifactParser() {
|
|
|
164
164
|
if (open.start > 0) {
|
|
165
165
|
yield { type: 'text', delta: state.buffer.slice(0, open.start) };
|
|
166
166
|
}
|
|
167
|
-
const attrs = parseQuotedAttrs(open.attrs);
|
|
167
|
+
const attrs = parseQuotedAttrs({ raw: open.attrs });
|
|
168
168
|
state.inside = true;
|
|
169
169
|
state.identifier = attrs['identifier'] ?? '';
|
|
170
170
|
state.artifactType = attrs['type'] ?? '';
|
|
@@ -205,7 +205,7 @@ export function createArtifactParser() {
|
|
|
205
205
|
state.content = '';
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
|
-
function* flush() {
|
|
208
|
+
function* flush(_requiredArgs) {
|
|
209
209
|
if (state.inside) {
|
|
210
210
|
if (state.buffer.length > 0) {
|
|
211
211
|
state.content += state.buffer;
|
|
@@ -231,8 +231,8 @@ export function createArtifactParser() {
|
|
|
231
231
|
* @param content - A complete (already fully-arrived) message body.
|
|
232
232
|
* @complexity O(n) in `content.length` (one `feed` + one `flush` over the whole string).
|
|
233
233
|
*/
|
|
234
|
-
export function parseArtifacts(content) {
|
|
235
|
-
const parser = createArtifactParser();
|
|
236
|
-
return [...parser.feed(content), ...parser.flush()];
|
|
234
|
+
export function parseArtifacts({ content }) {
|
|
235
|
+
const parser = createArtifactParser({});
|
|
236
|
+
return [...parser.feed({ delta: content }), ...parser.flush({})];
|
|
237
237
|
}
|
|
238
238
|
//# sourceMappingURL=parser.js.map
|
|
@@ -27,7 +27,9 @@ export declare function recoverHtmlArtifactFromPrecedingDocument({ artifactHtml,
|
|
|
27
27
|
*/
|
|
28
28
|
export declare function resolvePersistedArtifactHtml(input: RecoverHtmlArtifactInput): string;
|
|
29
29
|
/** Recover a complete `<html>…</html>` document that IS the entire (trimmed) `sourceText`, or `null` otherwise. */
|
|
30
|
-
export declare function recoverStandaloneHtmlDocument(sourceText
|
|
30
|
+
export declare function recoverStandaloneHtmlDocument({ sourceText }: {
|
|
31
|
+
sourceText: string | null | undefined;
|
|
32
|
+
}): string | null;
|
|
31
33
|
/**
|
|
32
34
|
* Recover a complete HTML document from a *single* ```html fenced block in
|
|
33
35
|
* `sourceText`. Returns `null` when there is no such fence, more than one
|
|
@@ -35,6 +37,8 @@ export declare function recoverStandaloneHtmlDocument(sourceText: string | null
|
|
|
35
37
|
* candidates are ambiguous about which one is "the" artifact, so none is
|
|
36
38
|
* chosen automatically.
|
|
37
39
|
*/
|
|
38
|
-
export declare function recoverHtmlDocumentFromMarkdownFence(sourceText
|
|
40
|
+
export declare function recoverHtmlDocumentFromMarkdownFence({ sourceText }: {
|
|
41
|
+
sourceText: string | null | undefined;
|
|
42
|
+
}): string | null;
|
|
39
43
|
export {};
|
|
40
44
|
//# sourceMappingURL=recover.d.ts.map
|
|
@@ -44,7 +44,7 @@ function lastIndexOfRegex(re, text) {
|
|
|
44
44
|
export function recoverHtmlArtifactFromPrecedingDocument({ artifactHtml, identifier, sourceText }) {
|
|
45
45
|
if (!sourceText)
|
|
46
46
|
return null;
|
|
47
|
-
if (validateHtmlArtifact(artifactHtml).ok)
|
|
47
|
+
if (validateHtmlArtifact({ content: artifactHtml }).ok)
|
|
48
48
|
return null;
|
|
49
49
|
const artifactOpen = findLastArtifactOpen(sourceText, identifier);
|
|
50
50
|
if (artifactOpen === -1)
|
|
@@ -67,7 +67,7 @@ export function recoverHtmlArtifactFromPrecedingDocument({ artifactHtml, identif
|
|
|
67
67
|
const adjacentDoctype = beforeHtmlOpen.match(ADJACENT_DOCTYPE_RE);
|
|
68
68
|
const htmlStart = adjacentDoctype ? htmlOpenStart - adjacentDoctype[0].length : htmlOpenStart;
|
|
69
69
|
const candidate = beforeArtifact.slice(htmlStart, htmlClose + closeMatch[0].length).trim();
|
|
70
|
-
return validateHtmlArtifact(candidate).ok ? candidate : null;
|
|
70
|
+
return validateHtmlArtifact({ content: candidate }).ok ? candidate : null;
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
73
|
* Resolve the HTML that should actually be persisted for an artifact. When
|
|
@@ -84,11 +84,11 @@ export function resolvePersistedArtifactHtml(input) {
|
|
|
84
84
|
return recoverHtmlArtifactFromPrecedingDocument(input) ?? input.artifactHtml;
|
|
85
85
|
}
|
|
86
86
|
/** Recover a complete `<html>…</html>` document that IS the entire (trimmed) `sourceText`, or `null` otherwise. */
|
|
87
|
-
export function recoverStandaloneHtmlDocument(sourceText) {
|
|
87
|
+
export function recoverStandaloneHtmlDocument({ sourceText }) {
|
|
88
88
|
const candidate = String(sourceText || '').replace(/^/, '').trim();
|
|
89
89
|
if (!/<\/html\s*>$/i.test(candidate))
|
|
90
90
|
return null;
|
|
91
|
-
return validateHtmlArtifact(candidate).ok ? candidate : null;
|
|
91
|
+
return validateHtmlArtifact({ content: candidate }).ok ? candidate : null;
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
94
|
* Recover a complete HTML document from a *single* ```html fenced block in
|
|
@@ -97,7 +97,7 @@ export function recoverStandaloneHtmlDocument(sourceText) {
|
|
|
97
97
|
* candidates are ambiguous about which one is "the" artifact, so none is
|
|
98
98
|
* chosen automatically.
|
|
99
99
|
*/
|
|
100
|
-
export function recoverHtmlDocumentFromMarkdownFence(sourceText) {
|
|
100
|
+
export function recoverHtmlDocumentFromMarkdownFence({ sourceText }) {
|
|
101
101
|
const text = String(sourceText || '');
|
|
102
102
|
HTML_FENCE_RE.lastIndex = 0;
|
|
103
103
|
let recovered = null;
|
|
@@ -107,7 +107,7 @@ export function recoverHtmlDocumentFromMarkdownFence(sourceText) {
|
|
|
107
107
|
const candidate = (match[1] || '').replace(/^/, '').trim();
|
|
108
108
|
if (!/<\/html\s*>$/i.test(candidate))
|
|
109
109
|
continue;
|
|
110
|
-
if (!validateHtmlArtifact(candidate).ok)
|
|
110
|
+
if (!validateHtmlArtifact({ content: candidate }).ok)
|
|
111
111
|
continue;
|
|
112
112
|
recovered = candidate;
|
|
113
113
|
count += 1;
|
|
@@ -14,7 +14,9 @@
|
|
|
14
14
|
* @complexity O(n) in `content.length` — one skip-range computation plus a
|
|
15
15
|
* pair of linear scans for the open/close tags.
|
|
16
16
|
*/
|
|
17
|
-
export declare function stripArtifact(content
|
|
17
|
+
export declare function stripArtifact({ content }: {
|
|
18
|
+
content: string;
|
|
19
|
+
}): string;
|
|
18
20
|
/**
|
|
19
21
|
* Display-only cleanup for a fallback shape some models emit: a complete
|
|
20
22
|
* HTML document as a standalone reply, or as a single ```html fenced block,
|
|
@@ -29,7 +31,11 @@ export declare function stripArtifact(content: string): string;
|
|
|
29
31
|
*
|
|
30
32
|
* @complexity O(n) in `content.length` (plus one bounded regex scan over `sourceText` for the fence-recovery path).
|
|
31
33
|
*/
|
|
32
|
-
export declare function stripRecoveredHtmlFallbackForDisplay(content
|
|
34
|
+
export declare function stripRecoveredHtmlFallbackForDisplay({ content }: {
|
|
35
|
+
content: string;
|
|
36
|
+
}, { sourceText }?: {
|
|
37
|
+
sourceText?: (string) | undefined;
|
|
38
|
+
}): string;
|
|
33
39
|
/**
|
|
34
40
|
* A persisted file a host confirms an artifact save wrote to storage.
|
|
35
41
|
* `identifier` is the artifact manifest's `metadata.identifier` when present
|
|
@@ -48,7 +54,10 @@ export interface PersistedArtifactFileRef {
|
|
|
48
54
|
*
|
|
49
55
|
* @complexity O(m) in `persistedFiles.length` (linear `find`s).
|
|
50
56
|
*/
|
|
51
|
-
export declare function matchPersistedArtifactFile(attrs
|
|
57
|
+
export declare function matchPersistedArtifactFile({ attrs, persistedFiles }: {
|
|
58
|
+
attrs: Record<string, string>;
|
|
59
|
+
persistedFiles: ReadonlyArray<PersistedArtifactFileRef>;
|
|
60
|
+
}): PersistedArtifactFileRef | null;
|
|
52
61
|
/**
|
|
53
62
|
* Replace every real `<artifact …>…</artifact>` block whose body is
|
|
54
63
|
* CONFIRMED persisted to a file with a one-line summary, for use in a
|
|
@@ -77,7 +86,10 @@ export declare function matchPersistedArtifactFile(attrs: Record<string, string>
|
|
|
77
86
|
* consumes at least one full artifact block or the remaining tail), times
|
|
78
87
|
* O(m) for the `persistedFiles` lookup per block.
|
|
79
88
|
*/
|
|
80
|
-
export declare function summarizeArtifactsForTranscript(content
|
|
89
|
+
export declare function summarizeArtifactsForTranscript({ content, persistedFiles }: {
|
|
90
|
+
content: string;
|
|
91
|
+
persistedFiles: ReadonlyArray<PersistedArtifactFileRef>;
|
|
92
|
+
}): string;
|
|
81
93
|
export interface StreamingArtifact {
|
|
82
94
|
artifactType: string;
|
|
83
95
|
title: string;
|
|
@@ -105,7 +117,9 @@ export interface StreamingArtifact {
|
|
|
105
117
|
*
|
|
106
118
|
* @complexity O(n) in `content.length`.
|
|
107
119
|
*/
|
|
108
|
-
export declare function splitStreamingArtifact(content
|
|
120
|
+
export declare function splitStreamingArtifact({ content }: {
|
|
121
|
+
content: string;
|
|
122
|
+
}): {
|
|
109
123
|
head: string;
|
|
110
124
|
live: StreamingArtifact | null;
|
|
111
125
|
};
|
package/dist/core/util/strip.js
CHANGED
|
@@ -20,7 +20,7 @@ function findUnskipped(content, needle, fromIndex, ranges) {
|
|
|
20
20
|
const idx = content.indexOf(needle, from);
|
|
21
21
|
if (idx === -1)
|
|
22
22
|
return -1;
|
|
23
|
-
if (!rangeContains(ranges, idx))
|
|
23
|
+
if (!rangeContains({ ranges: ranges, p: idx }))
|
|
24
24
|
return idx;
|
|
25
25
|
from = idx + needle.length;
|
|
26
26
|
}
|
|
@@ -38,7 +38,7 @@ function findRealOpen(content, fromIndex, ranges) {
|
|
|
38
38
|
const idx = content.indexOf(OPEN, from);
|
|
39
39
|
if (idx === -1)
|
|
40
40
|
return -1;
|
|
41
|
-
if (rangeContains(ranges, idx) || !isRealArtifactOpenAt(content, idx)) {
|
|
41
|
+
if (rangeContains({ ranges: ranges, p: idx }) || !isRealArtifactOpenAt({ content: content, idx: idx })) {
|
|
42
42
|
from = idx + OPEN.length;
|
|
43
43
|
continue;
|
|
44
44
|
}
|
|
@@ -61,8 +61,8 @@ function findRealOpen(content, fromIndex, ranges) {
|
|
|
61
61
|
* @complexity O(n) in `content.length` — one skip-range computation plus a
|
|
62
62
|
* pair of linear scans for the open/close tags.
|
|
63
63
|
*/
|
|
64
|
-
export function stripArtifact(content) {
|
|
65
|
-
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges(content);
|
|
64
|
+
export function stripArtifact({ content }) {
|
|
65
|
+
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges({ buffer: content });
|
|
66
66
|
// For complete (non-streaming) content, an unclosed fence renders as a code
|
|
67
67
|
// block extending to end of input — the stripper mirrors that, otherwise a
|
|
68
68
|
// literal `<artifact …>` tucked into a trailing code example (no trailing
|
|
@@ -86,7 +86,7 @@ function findSingleRecoverableHtmlFence(content) {
|
|
|
86
86
|
let match = HTML_FENCE_RE.exec(content);
|
|
87
87
|
while (match !== null) {
|
|
88
88
|
const html = (match[1] || '').replace(/^/, '').trim();
|
|
89
|
-
if (recoverHtmlDocumentFromMarkdownFence(match[0]) === html) {
|
|
89
|
+
if (recoverHtmlDocumentFromMarkdownFence({ sourceText: match[0] }) === html) {
|
|
90
90
|
recovered = { start: match.index, end: match.index + match[0].length, html };
|
|
91
91
|
count += 1;
|
|
92
92
|
}
|
|
@@ -95,7 +95,7 @@ function findSingleRecoverableHtmlFence(content) {
|
|
|
95
95
|
return count === 1 ? recovered : null;
|
|
96
96
|
}
|
|
97
97
|
function findRecoverablePrecedingHtmlArtifact(sourceText) {
|
|
98
|
-
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges(sourceText);
|
|
98
|
+
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges({ buffer: sourceText });
|
|
99
99
|
const ranges = unclosedFenceStart !== null ? [...baseRanges, [unclosedFenceStart, sourceText.length]] : baseRanges;
|
|
100
100
|
let from = 0;
|
|
101
101
|
// `findRealOpen` already returns -1 once `from` runs past `sourceText.length`
|
|
@@ -111,7 +111,7 @@ function findRecoverablePrecedingHtmlArtifact(sourceText) {
|
|
|
111
111
|
const end = findUnskipped(sourceText, CLOSE, closeTag, ranges);
|
|
112
112
|
if (end === -1)
|
|
113
113
|
return null;
|
|
114
|
-
const attrs = parseQuotedAttrs(sourceText.slice(open, closeTag));
|
|
114
|
+
const attrs = parseQuotedAttrs({ raw: sourceText.slice(open, closeTag) });
|
|
115
115
|
const recovered = recoverHtmlArtifactFromPrecedingDocument({
|
|
116
116
|
artifactHtml: sourceText.slice(closeTag + 1, end),
|
|
117
117
|
identifier: attrs['identifier'],
|
|
@@ -145,11 +145,11 @@ function stripRecoverablePrecedingHtml(content, sourceText) {
|
|
|
145
145
|
*
|
|
146
146
|
* @complexity O(n) in `content.length` (plus one bounded regex scan over `sourceText` for the fence-recovery path).
|
|
147
147
|
*/
|
|
148
|
-
export function stripRecoveredHtmlFallbackForDisplay(content, sourceText = content) {
|
|
148
|
+
export function stripRecoveredHtmlFallbackForDisplay({ content }, { sourceText = content } = {}) {
|
|
149
149
|
const withoutPrecedingDocument = stripRecoverablePrecedingHtml(content, sourceText);
|
|
150
150
|
if (withoutPrecedingDocument !== null)
|
|
151
151
|
return withoutPrecedingDocument;
|
|
152
|
-
if (recoverStandaloneHtmlDocument(content))
|
|
152
|
+
if (recoverStandaloneHtmlDocument({ sourceText: content }))
|
|
153
153
|
return '';
|
|
154
154
|
const fence = findSingleRecoverableHtmlFence(content);
|
|
155
155
|
if (!fence)
|
|
@@ -188,7 +188,7 @@ function artifactBaseNameForAttrs(attrs) {
|
|
|
188
188
|
*
|
|
189
189
|
* @complexity O(m) in `persistedFiles.length` (linear `find`s).
|
|
190
190
|
*/
|
|
191
|
-
export function matchPersistedArtifactFile(attrs, persistedFiles) {
|
|
191
|
+
export function matchPersistedArtifactFile({ attrs, persistedFiles }) {
|
|
192
192
|
const identifier = attrs['identifier'] ?? '';
|
|
193
193
|
if (identifier) {
|
|
194
194
|
const byManifest = persistedFiles.find((f) => f.identifier === identifier);
|
|
@@ -228,7 +228,7 @@ export function matchPersistedArtifactFile(attrs, persistedFiles) {
|
|
|
228
228
|
* consumes at least one full artifact block or the remaining tail), times
|
|
229
229
|
* O(m) for the `persistedFiles` lookup per block.
|
|
230
230
|
*/
|
|
231
|
-
export function summarizeArtifactsForTranscript(content, persistedFiles) {
|
|
231
|
+
export function summarizeArtifactsForTranscript({ content, persistedFiles }) {
|
|
232
232
|
if (persistedFiles.length === 0)
|
|
233
233
|
return content;
|
|
234
234
|
let result = '';
|
|
@@ -237,7 +237,7 @@ export function summarizeArtifactsForTranscript(content, persistedFiles) {
|
|
|
237
237
|
// stay valid as we consume the string left to right.
|
|
238
238
|
while (cursor <= content.length) {
|
|
239
239
|
const tail = content.slice(cursor);
|
|
240
|
-
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges(tail);
|
|
240
|
+
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges({ buffer: tail });
|
|
241
241
|
const ranges = unclosedFenceStart !== null ? [...baseRanges, [unclosedFenceStart, tail.length]] : baseRanges;
|
|
242
242
|
const open = findRealOpen(tail, 0, ranges);
|
|
243
243
|
if (open === -1) {
|
|
@@ -256,8 +256,8 @@ export function summarizeArtifactsForTranscript(content, persistedFiles) {
|
|
|
256
256
|
result += tail;
|
|
257
257
|
break;
|
|
258
258
|
}
|
|
259
|
-
const attrs = parseQuotedAttrs(tail.slice(open, gt));
|
|
260
|
-
const persisted = matchPersistedArtifactFile(attrs, persistedFiles);
|
|
259
|
+
const attrs = parseQuotedAttrs({ raw: tail.slice(open, gt) });
|
|
260
|
+
const persisted = matchPersistedArtifactFile({ attrs: attrs, persistedFiles: persistedFiles });
|
|
261
261
|
result += persisted
|
|
262
262
|
? tail.slice(0, open) + artifactTranscriptSummary(attrs, persisted)
|
|
263
263
|
: // Unconfirmed save — the transcript copy may be the only surviving
|
|
@@ -294,8 +294,8 @@ function artifactTranscriptSummary(attrs, persisted) {
|
|
|
294
294
|
*
|
|
295
295
|
* @complexity O(n) in `content.length`.
|
|
296
296
|
*/
|
|
297
|
-
export function splitStreamingArtifact(content) {
|
|
298
|
-
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges(content);
|
|
297
|
+
export function splitStreamingArtifact({ content }) {
|
|
298
|
+
const { ranges: baseRanges, unclosedFenceStart } = computeSkipRanges({ buffer: content });
|
|
299
299
|
const ranges = unclosedFenceStart !== null ? [...baseRanges, [unclosedFenceStart, content.length]] : baseRanges;
|
|
300
300
|
const open = findRealOpen(content, 0, ranges);
|
|
301
301
|
if (open === -1)
|
|
@@ -313,7 +313,7 @@ export function splitStreamingArtifact(content) {
|
|
|
313
313
|
// A matching close means the block is complete; defer to stripArtifact.
|
|
314
314
|
if (findUnskipped(content, CLOSE, gt, ranges) !== -1)
|
|
315
315
|
return { head: content, live: null };
|
|
316
|
-
const attrs = parseQuotedAttrs(content.slice(open, gt));
|
|
316
|
+
const attrs = parseQuotedAttrs({ raw: content.slice(open, gt) });
|
|
317
317
|
const artifactType = attrs['type'] ?? '';
|
|
318
318
|
// Only HTML/text artifacts read as code. An unknown type (attrs not fully
|
|
319
319
|
// parsed, or omitted) is treated as code-eligible since the dominant case
|
|
@@ -46,5 +46,7 @@ export type HtmlArtifactValidationResult = {
|
|
|
46
46
|
*
|
|
47
47
|
* @complexity O(n) in `content.length` — a handful of linear regex scans.
|
|
48
48
|
*/
|
|
49
|
-
export declare function validateHtmlArtifact(content
|
|
49
|
+
export declare function validateHtmlArtifact({ content }: {
|
|
50
|
+
content: string;
|
|
51
|
+
}): HtmlArtifactValidationResult;
|
|
50
52
|
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -51,7 +51,7 @@ const CSS_IMPORT_RE = /@import\s+(?:url\(\s*(?:"([^"]*)"|'([^']*)'|([^)]*?))\s*\
|
|
|
51
51
|
*
|
|
52
52
|
* @complexity O(n) in `content.length` — a handful of linear regex scans.
|
|
53
53
|
*/
|
|
54
|
-
export function validateHtmlArtifact(content) {
|
|
54
|
+
export function validateHtmlArtifact({ content }) {
|
|
55
55
|
const trimmed = content.replace(/^/, '').trim();
|
|
56
56
|
if (trimmed.length === 0) {
|
|
57
57
|
return { ok: false, reason: 'empty content' };
|