@jini-ai/daemon 0.3.2 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/agent-executor.d.ts +133 -3
  2. package/dist/agent-executor.d.ts.map +1 -1
  3. package/dist/agent-executor.js +265 -11
  4. package/dist/agent-executor.js.map +1 -1
  5. package/dist/artifacts/index.d.ts +14 -0
  6. package/dist/artifacts/index.d.ts.map +1 -0
  7. package/dist/artifacts/index.js +14 -0
  8. package/dist/artifacts/index.js.map +1 -0
  9. package/dist/artifacts/manifest.d.ts +90 -0
  10. package/dist/artifacts/manifest.d.ts.map +1 -0
  11. package/dist/artifacts/manifest.js +229 -0
  12. package/dist/artifacts/manifest.js.map +1 -0
  13. package/dist/artifacts/publication-guard.d.ts +28 -0
  14. package/dist/artifacts/publication-guard.d.ts.map +1 -0
  15. package/dist/artifacts/publication-guard.js +77 -0
  16. package/dist/artifacts/publication-guard.js.map +1 -0
  17. package/dist/artifacts/runtime-compat.d.ts +37 -0
  18. package/dist/artifacts/runtime-compat.d.ts.map +1 -0
  19. package/dist/artifacts/runtime-compat.js +33 -0
  20. package/dist/artifacts/runtime-compat.js.map +1 -0
  21. package/dist/artifacts/store.d.ts +85 -0
  22. package/dist/artifacts/store.d.ts.map +1 -0
  23. package/dist/artifacts/store.js +92 -0
  24. package/dist/artifacts/store.js.map +1 -0
  25. package/dist/artifacts/stub-guard.d.ts +73 -0
  26. package/dist/artifacts/stub-guard.d.ts.map +1 -0
  27. package/dist/artifacts/stub-guard.js +198 -0
  28. package/dist/artifacts/stub-guard.js.map +1 -0
  29. package/dist/artifacts/text-suppression.d.ts +68 -0
  30. package/dist/artifacts/text-suppression.d.ts.map +1 -0
  31. package/dist/artifacts/text-suppression.js +184 -0
  32. package/dist/artifacts/text-suppression.js.map +1 -0
  33. package/dist/run-lifecycle.d.ts +20 -0
  34. package/dist/run-lifecycle.d.ts.map +1 -1
  35. package/dist/run-lifecycle.js +20 -0
  36. package/dist/run-lifecycle.js.map +1 -1
  37. package/dist/tool-result-surfaces.d.ts +1 -1
  38. package/dist/tool-result-surfaces.js +1 -1
  39. package/package.json +5 -5
@@ -0,0 +1,73 @@
1
+ export type ArtifactStubGuardMode = 'reject' | 'warn' | 'off';
2
+ export interface ArtifactStubGuardConfig {
3
+ readonly mode: ArtifactStubGuardMode;
4
+ readonly minRetainedRatio: number;
5
+ readonly minPriorBytes: number;
6
+ /** File-name extensions (including the leading dot) this guard scans for prior siblings, e.g. `['.html', '.htm']`. */
7
+ readonly siblingExtensions: readonly string[];
8
+ }
9
+ export interface PriorArtifactSibling {
10
+ readonly name: string;
11
+ readonly size: number;
12
+ }
13
+ export interface ArtifactStubGuardWarning {
14
+ readonly code: 'ARTIFACT_REGRESSION';
15
+ readonly message: string;
16
+ readonly identifier: string;
17
+ readonly newSize: number;
18
+ readonly priorSize: number;
19
+ readonly priorName: string;
20
+ }
21
+ export interface EvaluateArtifactStubGuardInput {
22
+ readonly scanDir: string;
23
+ readonly identifier: string;
24
+ readonly newSize: number;
25
+ readonly config: ArtifactStubGuardConfig;
26
+ }
27
+ export interface EvaluateArtifactStubGuardResult {
28
+ readonly outcome: 'pass' | 'warn' | 'reject';
29
+ readonly warning?: ArtifactStubGuardWarning;
30
+ }
31
+ export declare class ArtifactRegressionError extends Error {
32
+ readonly code = "ARTIFACT_REGRESSION";
33
+ readonly identifier: string;
34
+ readonly newSize: number;
35
+ readonly priorSize: number;
36
+ readonly priorName: string;
37
+ constructor(message: string, details: {
38
+ identifier: string;
39
+ newSize: number;
40
+ priorSize: number;
41
+ priorName: string;
42
+ });
43
+ }
44
+ export declare const DEFAULT_ARTIFACT_STUB_GUARD_CONFIG: ArtifactStubGuardConfig;
45
+ /** Slugifies a free-form identifier into a filename-safe basename (lowercase, `[a-z0-9_-]`, max 60 chars). */
46
+ export declare function slugifyArtifactIdentifier(value: string): string;
47
+ /** Fallback basename used when a slugified identifier is empty (e.g. an all-non-ASCII identifier strips to nothing). */
48
+ export declare const EMPTY_SLUG_FALLBACK_NAME = "artifact";
49
+ /**
50
+ * Two identifiers refer to the same artifact lineage when they're literally
51
+ * equal, or one is the canonical slug form of the other (and that slug is
52
+ * non-empty). Slug equality alone is not enough: a slugifier that truncates
53
+ * at a fixed length would otherwise falsely bridge two distinct identifiers
54
+ * that only diverge past that length — requiring one side to *be* the slug
55
+ * form of the other avoids that while still bridging e.g. "Landing Page" and
56
+ * "landing-page".
57
+ */
58
+ export declare function artifactIdentifiersMatch(a: string, b: string): boolean;
59
+ /**
60
+ * Finds prior siblings on disk that share an identifier with a newly-written
61
+ * artifact, matching `<identifier>(-N)?.<ext>` for any of `config.siblingExtensions`.
62
+ * The scan deliberately includes any file at the same path as the new write
63
+ * — when a write overwrites an existing file with the same name, the file
64
+ * currently on disk is the prior content (the overwrite happens after this
65
+ * scan runs).
66
+ */
67
+ export declare function findPriorArtifactSiblings(scanDir: string, identifier: string, config: Pick<ArtifactStubGuardConfig, 'siblingExtensions'>): Promise<PriorArtifactSibling[]>;
68
+ /** Reads guard config from `ARTIFACT_STUB_GUARD` / `ARTIFACT_STUB_GUARD_MIN_RATIO` / `ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES`, falling back to `defaults` for any unset/invalid value. */
69
+ export declare function readArtifactStubGuardConfigFromEnv(env?: NodeJS.ProcessEnv, defaults?: ArtifactStubGuardConfig): ArtifactStubGuardConfig;
70
+ /** Pure decision function: given the prior siblings on disk, decides whether the new body is a stub regression. Split from the disk scan so unit tests stay fast and can pre-fetch siblings. */
71
+ export declare function classifyArtifactStubGuard(priors: readonly PriorArtifactSibling[], identifier: string, newSize: number, config: ArtifactStubGuardConfig): EvaluateArtifactStubGuardResult;
72
+ export declare function evaluateArtifactStubGuard(input: EvaluateArtifactStubGuardInput): Promise<EvaluateArtifactStubGuardResult>;
73
+ //# sourceMappingURL=stub-guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub-guard.d.ts","sourceRoot":"","sources":["../../src/artifacts/stub-guard.ts"],"names":[],"mappings":"AAwBA,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,CAAC;AAE9D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,sHAAsH;IACtH,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;CAC1C;AAED,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;CAC7C;AAED,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,yBAAyB;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;gBAGzB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;CASzF;AAED,eAAO,MAAM,kCAAkC,EAAE,uBAKhD,CAAC;AAMF,8GAA8G;AAC9G,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/D;AAED,wHAAwH;AACxH,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAOtE;AA0BD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,IAAI,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,GACzD,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA2CjC;AAED,uLAAuL;AACvL,wBAAgB,kCAAkC,CAChD,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,QAAQ,GAAE,uBAA4D,GACrE,uBAAuB,CAezB;AAiBD,gMAAgM;AAChM,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,SAAS,oBAAoB,EAAE,EACvC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,uBAAuB,GAC9B,+BAA+B,CAqBjC;AAED,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CAK1C"}
@@ -0,0 +1,198 @@
1
+ import { readFile, readdir, stat } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export class ArtifactRegressionError extends Error {
4
+ code = 'ARTIFACT_REGRESSION';
5
+ identifier;
6
+ newSize;
7
+ priorSize;
8
+ priorName;
9
+ constructor(message, details) {
10
+ super(message);
11
+ this.name = 'ArtifactRegressionError';
12
+ this.identifier = details.identifier;
13
+ this.newSize = details.newSize;
14
+ this.priorSize = details.priorSize;
15
+ this.priorName = details.priorName;
16
+ }
17
+ }
18
+ export const DEFAULT_ARTIFACT_STUB_GUARD_CONFIG = {
19
+ mode: 'warn',
20
+ minRetainedRatio: 0.2,
21
+ minPriorBytes: 4096,
22
+ siblingExtensions: ['.html', '.htm'],
23
+ };
24
+ function escapeRegExp(value) {
25
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
26
+ }
27
+ /** Slugifies a free-form identifier into a filename-safe basename (lowercase, `[a-z0-9_-]`, max 60 chars). */
28
+ export function slugifyArtifactIdentifier(value) {
29
+ return value
30
+ .toLowerCase()
31
+ .replace(/[^a-z0-9_-]+/g, '-')
32
+ .replace(/^-+|-+$/g, '')
33
+ .slice(0, 60);
34
+ }
35
+ /** Fallback basename used when a slugified identifier is empty (e.g. an all-non-ASCII identifier strips to nothing). */
36
+ export const EMPTY_SLUG_FALLBACK_NAME = 'artifact';
37
+ /**
38
+ * Two identifiers refer to the same artifact lineage when they're literally
39
+ * equal, or one is the canonical slug form of the other (and that slug is
40
+ * non-empty). Slug equality alone is not enough: a slugifier that truncates
41
+ * at a fixed length would otherwise falsely bridge two distinct identifiers
42
+ * that only diverge past that length — requiring one side to *be* the slug
43
+ * form of the other avoids that while still bridging e.g. "Landing Page" and
44
+ * "landing-page".
45
+ */
46
+ export function artifactIdentifiersMatch(a, b) {
47
+ if (a === b)
48
+ return true;
49
+ const slugA = slugifyArtifactIdentifier(a);
50
+ if (slugA.length === 0)
51
+ return false;
52
+ const slugB = slugifyArtifactIdentifier(b);
53
+ if (slugA !== slugB)
54
+ return false;
55
+ return a === slugA || b === slugB;
56
+ }
57
+ async function readSidecarIdentifier(scanDir, entryName) {
58
+ try {
59
+ const raw = await readFile(path.join(scanDir, `${entryName}.artifact.json`), 'utf8');
60
+ const parsed = JSON.parse(raw);
61
+ const id = parsed?.metadata?.identifier;
62
+ return typeof id === 'string' && id.length > 0 ? id : null;
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ function extensionAlternation(extensions) {
69
+ return extensions.map((ext) => escapeRegExp(ext)).join('|');
70
+ }
71
+ function legacyCandidateIdentifiers(filename, extensionPattern, suffixPattern) {
72
+ const fullBasename = filename.replace(extensionPattern, '');
73
+ const stripped = filename.replace(suffixPattern, '');
74
+ const candidates = [];
75
+ if (fullBasename.length > 0)
76
+ candidates.push(fullBasename);
77
+ if (stripped.length > 0 && stripped !== fullBasename)
78
+ candidates.push(stripped);
79
+ return candidates;
80
+ }
81
+ /**
82
+ * Finds prior siblings on disk that share an identifier with a newly-written
83
+ * artifact, matching `<identifier>(-N)?.<ext>` for any of `config.siblingExtensions`.
84
+ * The scan deliberately includes any file at the same path as the new write
85
+ * — when a write overwrites an existing file with the same name, the file
86
+ * currently on disk is the prior content (the overwrite happens after this
87
+ * scan runs).
88
+ */
89
+ export async function findPriorArtifactSiblings(scanDir, identifier, config) {
90
+ if (identifier.length === 0)
91
+ return [];
92
+ const extAlternation = extensionAlternation(config.siblingExtensions);
93
+ if (!extAlternation)
94
+ return [];
95
+ const extensionPattern = new RegExp(`(?:${extAlternation})$`, 'i');
96
+ const suffixPattern = new RegExp(`(?:-\\d+)?(?:${extAlternation})$`, 'i');
97
+ const tokens = new Set();
98
+ tokens.add(identifier);
99
+ const slug = slugifyArtifactIdentifier(identifier);
100
+ if (slug.length > 0)
101
+ tokens.add(slug);
102
+ else
103
+ tokens.add(EMPTY_SLUG_FALLBACK_NAME);
104
+ const alternation = Array.from(tokens, escapeRegExp).join('|');
105
+ const pattern = new RegExp(`^(?:${alternation})(?:-\\d+)?(?:${extAlternation})$`, 'i');
106
+ let entries;
107
+ try {
108
+ entries = await readdir(scanDir, { withFileTypes: true });
109
+ }
110
+ catch {
111
+ return [];
112
+ }
113
+ const results = [];
114
+ for (const entry of entries) {
115
+ if (!entry.isFile())
116
+ continue;
117
+ if (!pattern.test(entry.name))
118
+ continue;
119
+ const sidecarIdentifier = await readSidecarIdentifier(scanDir, entry.name);
120
+ // `legacyCandidateIdentifiers` always returns at least one non-empty
121
+ // candidate here: `entry.name` already matched `pattern` above, which
122
+ // requires its basename to start with one of `tokens` (all non-empty),
123
+ // so an explicit `candidateIdentifiers.length === 0` guard would be
124
+ // dead code — an empty array's `.some()` below already `continue`s.
125
+ const candidateIdentifiers = sidecarIdentifier !== null
126
+ ? [sidecarIdentifier]
127
+ : legacyCandidateIdentifiers(entry.name, extensionPattern, suffixPattern);
128
+ if (!candidateIdentifiers.some((c) => artifactIdentifiersMatch(identifier, c)))
129
+ continue;
130
+ try {
131
+ const st = await stat(path.join(scanDir, entry.name));
132
+ results.push({ name: entry.name, size: st.size });
133
+ }
134
+ catch {
135
+ // Ignore unreadable entries — they don't influence the guard decision.
136
+ }
137
+ }
138
+ return results;
139
+ }
140
+ /** Reads guard config from `ARTIFACT_STUB_GUARD` / `ARTIFACT_STUB_GUARD_MIN_RATIO` / `ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES`, falling back to `defaults` for any unset/invalid value. */
141
+ export function readArtifactStubGuardConfigFromEnv(env = process.env, defaults = DEFAULT_ARTIFACT_STUB_GUARD_CONFIG) {
142
+ const rawMode = (env.ARTIFACT_STUB_GUARD ?? '').toLowerCase();
143
+ const mode = rawMode === 'reject' || rawMode === 'warn' || rawMode === 'off' ? rawMode : defaults.mode;
144
+ const ratioRaw = Number(env.ARTIFACT_STUB_GUARD_MIN_RATIO);
145
+ // Accept (0, 1] so a caller can set 1 to reject any shrinkage. Values <=0 or >1 fall back to default.
146
+ const minRetainedRatio = Number.isFinite(ratioRaw) && ratioRaw > 0 && ratioRaw <= 1 ? ratioRaw : defaults.minRetainedRatio;
147
+ const minPriorBytesRaw = Number(env.ARTIFACT_STUB_GUARD_MIN_PRIOR_BYTES);
148
+ const minPriorBytes = Number.isInteger(minPriorBytesRaw) && minPriorBytesRaw > 0 ? minPriorBytesRaw : defaults.minPriorBytes;
149
+ return { mode, minRetainedRatio, minPriorBytes, siblingExtensions: defaults.siblingExtensions };
150
+ }
151
+ function buildWarning(identifier, newSize, prior) {
152
+ return {
153
+ code: 'ARTIFACT_REGRESSION',
154
+ message: `New artifact body for identifier "${identifier}" is ${newSize} bytes, ` +
155
+ `but the largest prior sibling "${prior.name}" is ${prior.size} bytes. ` +
156
+ 'This pattern usually means the write emitted a placeholder instead of the full document. ' +
157
+ 'Set the guard mode to "warn" to record the warning without rejecting, or "off" to disable the guard entirely.',
158
+ identifier,
159
+ newSize,
160
+ priorSize: prior.size,
161
+ priorName: prior.name,
162
+ };
163
+ }
164
+ /** Pure decision function: given the prior siblings on disk, decides whether the new body is a stub regression. Split from the disk scan so unit tests stay fast and can pre-fetch siblings. */
165
+ export function classifyArtifactStubGuard(priors, identifier, newSize, config) {
166
+ if (config.mode === 'off')
167
+ return { outcome: 'pass' };
168
+ if (identifier.length === 0)
169
+ return { outcome: 'pass' };
170
+ if (priors.length === 0)
171
+ return { outcome: 'pass' };
172
+ let largestSoFar = null;
173
+ for (const prior of priors) {
174
+ if (largestSoFar === null || prior.size > largestSoFar.size)
175
+ largestSoFar = prior;
176
+ }
177
+ // Non-null assertion, not a runtime guard: `priors.length === 0` already
178
+ // returned above, so this loop always runs at least once, and its first
179
+ // iteration always satisfies `largestSoFar === null` — it's always
180
+ // assigned by the time the loop finishes.
181
+ const largest = largestSoFar;
182
+ if (largest.size < config.minPriorBytes)
183
+ return { outcome: 'pass' };
184
+ const threshold = largest.size * config.minRetainedRatio;
185
+ if (newSize >= threshold)
186
+ return { outcome: 'pass' };
187
+ const warning = buildWarning(identifier, newSize, largest);
188
+ return { outcome: config.mode === 'reject' ? 'reject' : 'warn', warning };
189
+ }
190
+ export async function evaluateArtifactStubGuard(input) {
191
+ if (input.config.mode === 'off')
192
+ return { outcome: 'pass' };
193
+ if (input.identifier.length === 0)
194
+ return { outcome: 'pass' };
195
+ const priors = await findPriorArtifactSiblings(input.scanDir, input.identifier, input.config);
196
+ return classifyArtifactStubGuard(priors, input.identifier, input.newSize, input.config);
197
+ }
198
+ //# sourceMappingURL=stub-guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stub-guard.js","sourceRoot":"","sources":["../../src/artifacts/stub-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * @module artifacts/text-suppression
3
+ *
4
+ * A streaming-text state machine that suppresses a tagged block (matched by
5
+ * caller-supplied open/close patterns) from user-visible output while it's
6
+ * still arriving — used to hide an artifact's raw markup from chat prose
7
+ * while it streams in, without buffering the whole response first. Ported
8
+ * from OD's `apps/daemon/src/artifacts/text-suppression.ts`.
9
+ *
10
+ * The core (`createTaggedTextSuppressor`) was already fully generic in the
11
+ * origin — it takes its open/close regexes and open/close prefix-match
12
+ * predicates as parameters, no product coupling. What needed de-branding
13
+ * were the origin's two pre-built instances: `createDsmlArtifactTextSuppressor`
14
+ * hardcoded OD's own "DSML" markup-language tag name family
15
+ * (`<|DSML artifact>`/`<artifact>`) as its open/close patterns.
16
+ * `createXmlTagTextSuppressor` below replaces it — a generic factory taking
17
+ * the caller's own tag-name list instead of a hardcoded vocabulary. The
18
+ * `tool_call`/`edit` pairing the origin's other instance
19
+ * (`createToolCallTextSuppressor`) suppressed is a generic agent-protocol
20
+ * convention, not OD-branded, and is kept as a named default instance.
21
+ */
22
+ export type StreamTextEvent = {
23
+ readonly type: 'text_delta';
24
+ readonly delta: string;
25
+ };
26
+ export type StreamEventSink = (event: StreamTextEvent) => void;
27
+ export interface ArtifactTextSuppressor {
28
+ strip(text: string): string;
29
+ flush(): string;
30
+ isSuppressing(): boolean;
31
+ hasPendingCandidate(): boolean;
32
+ stats(): ArtifactTextSuppressorStats;
33
+ }
34
+ export interface ArtifactTextSuppressorStats {
35
+ readonly suppressedChars: number;
36
+ readonly suppressedChunks: number;
37
+ readonly openedBlocks: number;
38
+ readonly closedBlocks: number;
39
+ readonly pendingCandidateChars: number;
40
+ readonly suppressing: boolean;
41
+ }
42
+ /**
43
+ * Builds a suppressor for a tagged block delimited by `openRe`/`closeRe`.
44
+ * `isPossibleOpen`/`isPossibleClose` decide whether a trailing `<...`
45
+ * fragment (with no closing `>` yet) *could* still become a match once more
46
+ * text arrives — this is what lets the suppressor hold back a
47
+ * not-yet-decidable tail across streaming chunk boundaries instead of
48
+ * either emitting a tag fragment early or hanging indefinitely on a `<` that
49
+ * turns out to be unrelated text.
50
+ */
51
+ export declare function createTaggedTextSuppressor(args: {
52
+ openRe: RegExp;
53
+ closeRe: RegExp;
54
+ isPossibleOpen: (text: string) => boolean;
55
+ isPossibleClose: (text: string) => boolean;
56
+ }): ArtifactTextSuppressor;
57
+ /** Feeds `text` through `suppressor` and emits a `text_delta` on `onEvent` only when something survives. Returns whether an event was emitted. */
58
+ export declare function emitWithTextSuppressor(suppressor: ArtifactTextSuppressor, onEvent: StreamEventSink, text: string): boolean;
59
+ /**
60
+ * Builds a suppressor for an XML-like `<tagName ...>...</tagName>` block (or
61
+ * a bracket-pipe variant `<|tagName ...>...<|/tagName|>`), matched
62
+ * case-insensitively against any of `tagNames`. Replaces the origin's
63
+ * hardcoded "DSML" tag-name family with a caller-supplied vocabulary.
64
+ */
65
+ export declare function createXmlTagTextSuppressor(tagNames: readonly string[]): ArtifactTextSuppressor;
66
+ /** Suppresses a `<tool_call>...</tool_call>` or `<edit>...</edit>` block — a generic agent-protocol convention, not product-branded. */
67
+ export declare function createToolCallTextSuppressor(): ArtifactTextSuppressor;
68
+ //# sourceMappingURL=text-suppression.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-suppression.d.ts","sourceRoot":"","sources":["../../src/artifacts/text-suppression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACtF,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AAE/D,MAAM,WAAW,sBAAsB;IACrC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,KAAK,IAAI,MAAM,CAAC;IAChB,aAAa,IAAI,OAAO,CAAC;IACzB,mBAAmB,IAAI,OAAO,CAAC;IAC/B,KAAK,IAAI,2BAA2B,CAAC;CACtC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAID;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE;IAC/C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;CAC5C,GAAG,sBAAsB,CAgFzB;AAED,kJAAkJ;AAClJ,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,sBAAsB,EAClC,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,MAAM,GACX,OAAO,CAKT;AAqBD;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,sBAAsB,CAmB9F;AAoBD,wIAAwI;AACxI,wBAAgB,4BAA4B,IAAI,sBAAsB,CAOrE"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @module artifacts/text-suppression
3
+ *
4
+ * A streaming-text state machine that suppresses a tagged block (matched by
5
+ * caller-supplied open/close patterns) from user-visible output while it's
6
+ * still arriving — used to hide an artifact's raw markup from chat prose
7
+ * while it streams in, without buffering the whole response first. Ported
8
+ * from OD's `apps/daemon/src/artifacts/text-suppression.ts`.
9
+ *
10
+ * The core (`createTaggedTextSuppressor`) was already fully generic in the
11
+ * origin — it takes its open/close regexes and open/close prefix-match
12
+ * predicates as parameters, no product coupling. What needed de-branding
13
+ * were the origin's two pre-built instances: `createDsmlArtifactTextSuppressor`
14
+ * hardcoded OD's own "DSML" markup-language tag name family
15
+ * (`<|DSML artifact>`/`<artifact>`) as its open/close patterns.
16
+ * `createXmlTagTextSuppressor` below replaces it — a generic factory taking
17
+ * the caller's own tag-name list instead of a hardcoded vocabulary. The
18
+ * `tool_call`/`edit` pairing the origin's other instance
19
+ * (`createToolCallTextSuppressor`) suppressed is a generic agent-protocol
20
+ * convention, not OD-branded, and is kept as a named default instance.
21
+ */
22
+ const MAX_CANDIDATE_LENGTH = 512;
23
+ /**
24
+ * Builds a suppressor for a tagged block delimited by `openRe`/`closeRe`.
25
+ * `isPossibleOpen`/`isPossibleClose` decide whether a trailing `<...`
26
+ * fragment (with no closing `>` yet) *could* still become a match once more
27
+ * text arrives — this is what lets the suppressor hold back a
28
+ * not-yet-decidable tail across streaming chunk boundaries instead of
29
+ * either emitting a tag fragment early or hanging indefinitely on a `<` that
30
+ * turns out to be unrelated text.
31
+ */
32
+ export function createTaggedTextSuppressor(args) {
33
+ let suppressing = false;
34
+ let candidate = '';
35
+ let suppressedChars = 0;
36
+ let suppressedChunks = 0;
37
+ let openedBlocks = 0;
38
+ let closedBlocks = 0;
39
+ function noteSuppressed(text) {
40
+ if (text.length <= 0)
41
+ return;
42
+ suppressedChars += text.length;
43
+ suppressedChunks += 1;
44
+ }
45
+ function strip(text) {
46
+ const current = `${candidate}${text}`;
47
+ candidate = '';
48
+ if (suppressing) {
49
+ const close = args.closeRe.exec(current);
50
+ if (!close || close.index === undefined) {
51
+ const closeCandidateStart = possibleTagStart(current, args.isPossibleClose);
52
+ if (closeCandidateStart !== -1) {
53
+ candidate = current.slice(closeCandidateStart);
54
+ noteSuppressed(current.slice(0, closeCandidateStart));
55
+ }
56
+ else {
57
+ noteSuppressed(current);
58
+ }
59
+ return '';
60
+ }
61
+ suppressing = false;
62
+ const end = close.index + close[0].length;
63
+ closedBlocks += 1;
64
+ noteSuppressed(current.slice(0, end));
65
+ return strip(current.slice(end));
66
+ }
67
+ const open = args.openRe.exec(current);
68
+ if (open && open.index !== undefined) {
69
+ suppressing = true;
70
+ openedBlocks += 1;
71
+ const prefix = current.slice(0, open.index);
72
+ const tail = current.slice(open.index + open[0].length);
73
+ noteSuppressed(open[0]);
74
+ return `${prefix}${strip(tail)}`;
75
+ }
76
+ const candidateStart = possibleTagStart(current, args.isPossibleOpen);
77
+ if (candidateStart === -1)
78
+ return current;
79
+ candidate = current.slice(candidateStart);
80
+ return current.slice(0, candidateStart);
81
+ }
82
+ function flush() {
83
+ const text = candidate;
84
+ candidate = '';
85
+ return suppressing ? '' : text;
86
+ }
87
+ function isSuppressing() {
88
+ return suppressing;
89
+ }
90
+ function hasPendingCandidate() {
91
+ return candidate.length > 0;
92
+ }
93
+ function stats() {
94
+ return {
95
+ suppressedChars,
96
+ suppressedChunks,
97
+ openedBlocks,
98
+ closedBlocks,
99
+ pendingCandidateChars: candidate.length,
100
+ suppressing,
101
+ };
102
+ }
103
+ return { strip, flush, isSuppressing, hasPendingCandidate, stats };
104
+ }
105
+ /** Feeds `text` through `suppressor` and emits a `text_delta` on `onEvent` only when something survives. Returns whether an event was emitted. */
106
+ export function emitWithTextSuppressor(suppressor, onEvent, text) {
107
+ const delta = suppressor.strip(text);
108
+ if (!delta)
109
+ return false;
110
+ onEvent({ type: 'text_delta', delta });
111
+ return true;
112
+ }
113
+ function possibleTagStart(text, predicate) {
114
+ const min = Math.max(0, text.length - MAX_CANDIDATE_LENGTH);
115
+ let index = text.lastIndexOf('<');
116
+ while (index >= min) {
117
+ const tail = text.slice(index);
118
+ if (predicate(tail))
119
+ return index;
120
+ if (index === 0)
121
+ break;
122
+ index = text.lastIndexOf('<', index - 1);
123
+ }
124
+ return -1;
125
+ }
126
+ // `text` is always a `possibleTagStart` tail slice starting at a `<`
127
+ // position (its only caller) — no `!text.startsWith('<')` re-check needed.
128
+ function compactTagCandidate(text, stripChars) {
129
+ if (text.includes('>'))
130
+ return null;
131
+ return text.toLowerCase().replace(stripChars, '');
132
+ }
133
+ /**
134
+ * Builds a suppressor for an XML-like `<tagName ...>...</tagName>` block (or
135
+ * a bracket-pipe variant `<|tagName ...>...<|/tagName|>`), matched
136
+ * case-insensitively against any of `tagNames`. Replaces the origin's
137
+ * hardcoded "DSML" tag-name family with a caller-supplied vocabulary.
138
+ */
139
+ export function createXmlTagTextSuppressor(tagNames) {
140
+ const canonicals = tagNames.map((t) => t.toLowerCase());
141
+ const namesPattern = canonicals.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
142
+ const openRe = new RegExp(`(?:<\\s*\\|?\\s*(?:${namesPattern})\\b[^>]*>)`, 'i');
143
+ const closeRe = new RegExp(`(?:<\\/(?:${namesPattern})>|<\\s*\\|?\\s*\\/\\s*(?:${namesPattern})\\s*\\|?\\s*>)`, 'i');
144
+ function isPossibleOpen(text) {
145
+ const compact = compactTagCandidate(text, /[<|,\s]/g);
146
+ if (compact === null)
147
+ return false;
148
+ return compact.length === 0 || canonicals.some((c) => c.startsWith(compact) || compact.startsWith(c));
149
+ }
150
+ function isPossibleClose(text) {
151
+ const compact = compactTagCandidate(text, /[<|/\s]/g);
152
+ if (compact === null)
153
+ return false;
154
+ return compact.length === 0 || canonicals.some((c) => c.startsWith(compact) || compact.startsWith(c));
155
+ }
156
+ return createTaggedTextSuppressor({ openRe, closeRe, isPossibleOpen, isPossibleClose });
157
+ }
158
+ const TOOL_CALL_OPEN_RE = /(?:<\s*tool_call\b[^>]*>|<\s*edit\s*>)/i;
159
+ const TOOL_CALL_CLOSE_RE = /(?:<\/\s*tool_call\s*>|<\/\s*edit\s*>)/i;
160
+ const TOOL_CALL_CANONICALS = ['toolcall', 'edit'];
161
+ // Same reasoning as compactTagCandidate above: `text` always starts with
162
+ // `<` here (a `possibleTagStart` tail slice) — no re-check needed.
163
+ function isPossibleToolCallOpen(text) {
164
+ if (text.includes('>'))
165
+ return false;
166
+ const compact = text.toLowerCase().replace(/[<|,\s_-]/g, '');
167
+ return compact.length === 0 || TOOL_CALL_CANONICALS.some((c) => c.startsWith(compact) || compact.startsWith(c));
168
+ }
169
+ function isPossibleToolCallClose(text) {
170
+ if (text.includes('>'))
171
+ return false;
172
+ const compact = text.toLowerCase().replace(/[<|/\s_-]/g, '');
173
+ return compact.length === 0 || TOOL_CALL_CANONICALS.some((c) => c.startsWith(compact) || compact.startsWith(c));
174
+ }
175
+ /** Suppresses a `<tool_call>...</tool_call>` or `<edit>...</edit>` block — a generic agent-protocol convention, not product-branded. */
176
+ export function createToolCallTextSuppressor() {
177
+ return createTaggedTextSuppressor({
178
+ openRe: TOOL_CALL_OPEN_RE,
179
+ closeRe: TOOL_CALL_CLOSE_RE,
180
+ isPossibleOpen: isPossibleToolCallOpen,
181
+ isPossibleClose: isPossibleToolCallClose,
182
+ });
183
+ }
184
+ //# sourceMappingURL=text-suppression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-suppression.js","sourceRoot":"","sources":["../../src/artifacts/text-suppression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAsBH,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAK1C;IACC,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,gBAAgB,GAAG,CAAC,CAAC;IACzB,IAAI,YAAY,GAAG,CAAC,CAAC;IACrB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,SAAS,cAAc,CAAC,IAAY;QAClC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO;QAC7B,eAAe,IAAI,IAAI,CAAC,MAAM,CAAC;QAC/B,gBAAgB,IAAI,CAAC,CAAC;IACxB,CAAC;IAED,SAAS,KAAK,CAAC,IAAY;QACzB,MAAM,OAAO,GAAG,GAAG,SAAS,GAAG,IAAI,EAAE,CAAC;QACtC,SAAS,GAAG,EAAE,CAAC;QAEf,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxC,MAAM,mBAAmB,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC,CAAC;gBAC5E,IAAI,mBAAmB,KAAK,CAAC,CAAC,EAAE,CAAC;oBAC/B,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAC;oBAC/C,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,mBAAmB,CAAC,CAAC,CAAC;gBACxD,CAAC;qBAAM,CAAC;oBACN,cAAc,CAAC,OAAO,CAAC,CAAC;gBAC1B,CAAC;gBACD,OAAO,EAAE,CAAC;YACZ,CAAC;YACD,WAAW,GAAG,KAAK,CAAC;YACpB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YAC1C,YAAY,IAAI,CAAC,CAAC;YAClB,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACtC,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;QACnC,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YACrC,WAAW,GAAG,IAAI,CAAC;YACnB,YAAY,IAAI,CAAC,CAAC;YAClB,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACxD,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACxB,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,CAAC;QAED,MAAM,cAAc,GAAG,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACtE,IAAI,cAAc,KAAK,CAAC,CAAC;YAAE,OAAO,OAAO,CAAC;QAE1C,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QAC1C,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC;IAC1C,CAAC;IAED,SAAS,KAAK;QACZ,MAAM,IAAI,GAAG,SAAS,CAAC;QACvB,SAAS,GAAG,EAAE,CAAC;QACf,OAAO,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IACjC,CAAC;IAED,SAAS,aAAa;QACpB,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,SAAS,mBAAmB;QAC1B,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9B,CAAC;IAED,SAAS,KAAK;QACZ,OAAO;YACL,eAAe;YACf,gBAAgB;YAChB,YAAY;YACZ,YAAY;YACZ,qBAAqB,EAAE,SAAS,CAAC,MAAM;YACvC,WAAW;SACZ,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;AACrE,CAAC;AAED,kJAAkJ;AAClJ,MAAM,UAAU,sBAAsB,CACpC,UAAkC,EAClC,OAAwB,EACxB,IAAY;IAEZ,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,SAAoC;IAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,oBAAoB,CAAC,CAAC;IAC5D,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,KAAK,IAAI,GAAG,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,SAAS,CAAC,IAAI,CAAC;YAAE,OAAO,KAAK,CAAC;QAClC,IAAI,KAAK,KAAK,CAAC;YAAE,MAAM;QACvB,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED,qEAAqE;AACrE,2EAA2E;AAC3E,SAAS,mBAAmB,CAAC,IAAY,EAAE,UAAkB;IAC3D,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAA2B;IACpE,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACxD,MAAM,YAAY,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC/F,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,sBAAsB,YAAY,aAAa,EAAE,GAAG,CAAC,CAAC;IAChF,MAAM,OAAO,GAAG,IAAI,MAAM,CAAC,aAAa,YAAY,6BAA6B,YAAY,iBAAiB,EAAE,GAAG,CAAC,CAAC;IAErH,SAAS,cAAc,CAAC,IAAY;QAClC,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACtD,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACnC,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACxG,CAAC;IAED,SAAS,eAAe,CAAC,IAAY;QACnC,MAAM,OAAO,GAAG,mBAAmB,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACtD,IAAI,OAAO,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACnC,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACxG,CAAC;IAED,OAAO,0BAA0B,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,iBAAiB,GAAG,yCAAyC,CAAC;AACpE,MAAM,kBAAkB,GAAG,yCAAyC,CAAC;AACrE,MAAM,oBAAoB,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAElD,yEAAyE;AACzE,mEAAmE;AACnE,SAAS,sBAAsB,CAAC,IAAY;IAC1C,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC7D,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAClH,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAY;IAC3C,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IAC7D,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AAClH,CAAC;AAED,wIAAwI;AACxI,MAAM,UAAU,4BAA4B;IAC1C,OAAO,0BAA0B,CAAC;QAChC,MAAM,EAAE,iBAAiB;QACzB,OAAO,EAAE,kBAAkB;QAC3B,cAAc,EAAE,sBAAsB;QACtC,eAAe,EAAE,uBAAuB;KACzC,CAAC,CAAC;AACL,CAAC"}
@@ -83,6 +83,26 @@ export interface RunLifecycle {
83
83
  /** Idempotent terminal transition; a second call while already terminal is a no-op that returns the existing status unchanged. */
84
84
  finish(input: FinishRunInput): Promise<RunStatus>;
85
85
  resume(runId: string): Promise<ResumeRunResult>;
86
+ /**
87
+ * Suspends the slow-run watchdog for `runId` while a daemon-managed operation of legitimately
88
+ * unbounded duration is in flight (e.g. an auto-resolved tool call the daemon itself awaits) — pair
89
+ * with {@link RunLifecycle.resumeSlowRunNotice} once that operation concludes. `emit()` is the
90
+ * *only* other reset signal the watchdog has, and it fires nothing while such an operation is
91
+ * running (there is no output to stream), so without this call a tool that legitimately runs past
92
+ * the threshold (an install, a build, a repo-wide scan) is indistinguishable from the exact
93
+ * CPU-starved-and-silent condition the watchdog exists to catch, and fires a "still working" notice
94
+ * on a run that never actually stalled. A driver that knows exactly why a run is quiet must say so
95
+ * rather than leaving the watchdog to guess from silence alone. No-op if `runId` is unknown,
96
+ * already terminal, or the slow-run notice is disabled kernel-wide (`slowRunThresholdMs: null`).
97
+ */
98
+ suspendSlowRunNotice(runId: string): void;
99
+ /**
100
+ * Re-arms the slow-run watchdog for `runId` with a fresh timeout window, undoing
101
+ * {@link RunLifecycle.suspendSlowRunNotice} once the known operation concludes — so a genuinely
102
+ * stalled stretch starting *after* that point is still caught. No-op under the same conditions as
103
+ * `suspendSlowRunNotice`.
104
+ */
105
+ resumeSlowRunNotice(runId: string): void;
86
106
  /** Resolves once `runId` reaches a terminal state; resolves immediately if it already has. */
87
107
  waitForTerminal(runId: string): Promise<RunStatus>;
88
108
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"run-lifecycle.d.ts","sourceRoot":"","sources":["../src/run-lifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run-lifecycle.d.ts","sourceRoot":"","sources":["../src/run-lifecycle.ts"],"names":[],"mappings":"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"}
@@ -735,12 +735,32 @@ export function createRunLifecycle(input) {
735
735
  record.cancelRequested = false;
736
736
  record.lastCancelRequest = undefined;
737
737
  record.terminalEndEntry = undefined;
738
+ // Mirrors `start()`'s own arm call: a resumed run gets exactly the same fresh slow-run window a
739
+ // freshly-started one does. Without this, `finish()`'s `record.slowRunWatchdog?.cancel()` (which
740
+ // never fires again on its own — the underlying timer is one-shot) left the notice permanently
741
+ // dark for the rest of a resumed run's life, silently disabling a feature the run is otherwise
742
+ // still eligible for.
743
+ armSlowRunWatchdogIfConfigured(record, slowRunThresholdMs, () => {
744
+ void handleSlowRunNotice(runId);
745
+ });
738
746
  // No protocol event is emitted here: none of RunProtocolEvent's six
739
747
  // kinds represents "resumed" (extraction-plan scope decision — see
740
748
  // source-map.md). The event log's cursor sequence continues
741
749
  // unbroken; only RunStatus.state changes.
742
750
  return { run: toPublicStatus(record), resumed: true };
743
751
  },
752
+ suspendSlowRunNotice(runId) {
753
+ const record = runs.get(runId);
754
+ if (!record || isTerminalRunState(record.status.state))
755
+ return;
756
+ record.slowRunWatchdog?.cancel();
757
+ },
758
+ resumeSlowRunNotice(runId) {
759
+ const record = runs.get(runId);
760
+ if (!record || isTerminalRunState(record.status.state))
761
+ return;
762
+ record.slowRunWatchdog?.noteActivity();
763
+ },
744
764
  async waitForTerminal(runId) {
745
765
  const record = requireRun(runId);
746
766
  // Awaited (and *propagated*, unlike in `get`/`list`) before any waiter is registered. A run