@aexol/spectral 0.9.129 → 0.9.131
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/dist/extensions/code-order/analyzer.d.ts +47 -0
- package/dist/extensions/code-order/analyzer.d.ts.map +1 -0
- package/dist/extensions/code-order/analyzer.js +315 -0
- package/dist/extensions/code-order/heuristics.d.ts +37 -0
- package/dist/extensions/code-order/heuristics.d.ts.map +1 -0
- package/dist/extensions/code-order/heuristics.js +188 -0
- package/dist/extensions/code-order/index.d.ts +15 -0
- package/dist/extensions/code-order/index.d.ts.map +1 -0
- package/dist/extensions/code-order/index.js +76 -0
- package/dist/extensions/code-order/report.d.ts +14 -0
- package/dist/extensions/code-order/report.d.ts.map +1 -0
- package/dist/extensions/code-order/report.js +140 -0
- package/dist/extensions/code-order/types.d.ts +63 -0
- package/dist/extensions/code-order/types.d.ts.map +1 -0
- package/dist/extensions/code-order/types.js +7 -0
- package/dist/mcp/ui-stream-types.d.ts +2 -2
- package/dist/relay/dispatcher.d.ts +2 -2
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +84 -50
- package/dist/relay/history-chunker.d.ts +46 -0
- package/dist/relay/history-chunker.d.ts.map +1 -0
- package/dist/relay/history-chunker.js +60 -0
- package/dist/sdk/coding-agent/core/extensions/native-extensions.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/extensions/native-extensions.js +11 -0
- package/dist/sdk/coding-agent/core/system-prompt.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/system-prompt.js +2 -0
- package/dist/sdk/coding-agent/core/tools/bash-blocklist.d.ts +42 -0
- package/dist/sdk/coding-agent/core/tools/bash-blocklist.d.ts.map +1 -0
- package/dist/sdk/coding-agent/core/tools/bash-blocklist.js +141 -0
- package/dist/sdk/coding-agent/core/tools/bash.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/tools/bash.js +5 -0
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +6 -3
- package/dist/server/error-humanizer.d.ts +31 -0
- package/dist/server/error-humanizer.d.ts.map +1 -0
- package/dist/server/error-humanizer.js +77 -0
- package/dist/server/session-stream.d.ts.map +1 -1
- package/dist/server/session-stream.js +7 -6
- package/dist/server/wire.d.ts +40 -0
- package/dist/server/wire.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/** Maximum number of messages packed into a single `history_chunk`. */
|
|
2
|
+
export const MAX_MESSAGES_PER_CHUNK = 25;
|
|
3
|
+
/** Maximum serialized byte size of a single `history_chunk`'s messages. */
|
|
4
|
+
export const MAX_BYTES_PER_CHUNK = 512 * 1024; // 512 KB
|
|
5
|
+
/**
|
|
6
|
+
* Estimate the UTF-8 byte size of a serialized message. Uses `TextEncoder` so
|
|
7
|
+
* the helper stays environment-agnostic (Node, browser, Deno).
|
|
8
|
+
*/
|
|
9
|
+
function messageByteSize(message) {
|
|
10
|
+
return new TextEncoder().encode(JSON.stringify(message)).length;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Split `history` into atomic chunks bounded by `maxMessages` and `maxBytes`.
|
|
14
|
+
*
|
|
15
|
+
* - Empty history → `[]` (the caller still emits `session_ready_start` +
|
|
16
|
+
* `session_ready_end` with zero `history_chunk` frames in between).
|
|
17
|
+
* - `index` is 0-based; `total` is the final chunk count and is identical on
|
|
18
|
+
* every chunk in the returned array (computed after packing so it is always
|
|
19
|
+
* accurate, even when oversize messages force solo chunks).
|
|
20
|
+
* - Messages are atomic: a single message is never split across two chunks.
|
|
21
|
+
* - If a single message exceeds `maxBytes`, it is emitted alone in its own
|
|
22
|
+
* chunk and `console.warn` is called with the message id and index.
|
|
23
|
+
*
|
|
24
|
+
* Pure and synchronous — no I/O, no async, no external state.
|
|
25
|
+
*/
|
|
26
|
+
export function chunkHistory(history, opts = {}) {
|
|
27
|
+
const maxMessages = opts.maxMessages ?? MAX_MESSAGES_PER_CHUNK;
|
|
28
|
+
const maxBytes = opts.maxBytes ?? MAX_BYTES_PER_CHUNK;
|
|
29
|
+
if (history.length === 0) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
const groups = [];
|
|
33
|
+
for (let i = 0; i < history.length; i++) {
|
|
34
|
+
const message = history[i];
|
|
35
|
+
const size = messageByteSize(message);
|
|
36
|
+
const oversize = size > maxBytes;
|
|
37
|
+
if (oversize) {
|
|
38
|
+
// Anomaly: a single message exceeds the byte ceiling. Emit it alone and
|
|
39
|
+
// warn so the operator can investigate (e.g. a runaway tool result).
|
|
40
|
+
const id = typeof message.id === "string" && message.id.length > 0
|
|
41
|
+
? message.id
|
|
42
|
+
: `index:${i}`;
|
|
43
|
+
console.warn(`[history-chunker] message ${id} exceeds maxBytes (${size} > ${maxBytes}); emitting as a solo chunk`);
|
|
44
|
+
groups.push([message]);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const current = groups.length > 0 ? groups[groups.length - 1] : null;
|
|
48
|
+
const wouldExceedMessages = current !== null && current.length >= maxMessages;
|
|
49
|
+
const wouldExceedBytes = current !== null &&
|
|
50
|
+
current.reduce((sum, m) => sum + messageByteSize(m), 0) + size > maxBytes;
|
|
51
|
+
if (current === null || wouldExceedMessages || wouldExceedBytes) {
|
|
52
|
+
groups.push([message]);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
current.push(message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const total = groups.length;
|
|
59
|
+
return groups.map((messages, index) => ({ index, total, messages }));
|
|
60
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-extensions.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/extensions/native-extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;IAChD;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,cAAc,EAAE,OAAO,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"native-extensions.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/extensions/native-extensions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,uBAAuB;IACtC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,mDAAmD;IACnD,QAAQ,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,CAAC;IAChD;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,cAAc,EAAE,OAAO,CAAC;IACxB,mCAAmC;IACnC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,uBAAuB,EAsItD,CAAC;AAEF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS,CAElF;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAI1G;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;IAClG,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB,CAAC,CAUD"}
|
|
@@ -129,6 +129,17 @@ export const NATIVE_EXTENSIONS = [
|
|
|
129
129
|
defaultEnabled: true,
|
|
130
130
|
tags: ["screenshot", "desktop", "vision", "screen"],
|
|
131
131
|
},
|
|
132
|
+
{
|
|
133
|
+
id: "code-order",
|
|
134
|
+
label: "Code Order",
|
|
135
|
+
description: "Analyzes folder structure and file sizes, then generates a cleanup report " +
|
|
136
|
+
"(oversized files, deep nesting, empty folders, duplicates, single-child folders). " +
|
|
137
|
+
"Language-agnostic, read-only, zero config. Input for reorganizing code.",
|
|
138
|
+
category: "automation",
|
|
139
|
+
entryPath: "src/extensions/code-order/index.ts",
|
|
140
|
+
defaultEnabled: true,
|
|
141
|
+
tags: ["structure", "analysis", "cleanup", "tree", "audit"],
|
|
142
|
+
},
|
|
132
143
|
];
|
|
133
144
|
/**
|
|
134
145
|
* Look up a native extension by id. Returns undefined for unknown ids.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../../src/sdk/coding-agent/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../../src/sdk/coding-agent/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,yBAAyB;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CA4K3E"}
|
|
@@ -86,6 +86,8 @@ export function buildSystemPrompt(options) {
|
|
|
86
86
|
addGuideline(normalized);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
addGuideline("When creating new files, maintain a tree-like directory structure. Place files in semantically meaningful subdirectories (e.g. `handlers/auth/`, `utils/string/`) rather than dumping them at the project root or in shallow flat folders. Group related files into dedicated folders, prefer `feature/module/file.ts` over `feature-file.ts` at root. Avoid creating files directly in root unless they are truly project-wide (e.g. config, package.json). Keep folder depth reasonable (max 5–6 levels) but prefer nesting over flattening — tree-like structure improves LLM navigability and agentic coding efficiency.");
|
|
90
|
+
addGuideline("When editing code, first inspect nearby files and existing patterns; follow the codebase’s conventions and libraries");
|
|
89
91
|
addGuideline("When editing code, first inspect nearby files and existing patterns; follow the codebase’s conventions and libraries");
|
|
90
92
|
// Always include these
|
|
91
93
|
if (hasSubagent) {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash command blocklist for filesystem-wide scans.
|
|
3
|
+
*
|
|
4
|
+
* Blocks recursive scans originating from the filesystem root `/` or other
|
|
5
|
+
* system directories (e.g. `/etc`, `/home`, `/usr`, `/var`) because they can
|
|
6
|
+
* take a very long time and are almost never the intended action inside a
|
|
7
|
+
* workspace-scoped bash tool. Scoped scans (e.g. `find .`, `grep -r src/`,
|
|
8
|
+
* `ls -R src/`) remain allowed.
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally a regex-based heuristic, not a full shell parser. It
|
|
11
|
+
* targets the common scan shapes; exotic obfuscation is out of scope.
|
|
12
|
+
*/
|
|
13
|
+
/** Result of a blocklist check. */
|
|
14
|
+
export interface BashBlocklistResult {
|
|
15
|
+
/** Whether the command should be blocked. */
|
|
16
|
+
blocked: boolean;
|
|
17
|
+
/** Human-readable reason (empty when not blocked). */
|
|
18
|
+
reason: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Default, reusable explanation returned to the LLM when a command is blocked.
|
|
22
|
+
* Phrased to steer the model toward a scoped alternative.
|
|
23
|
+
*/
|
|
24
|
+
export declare const BASH_BLOCKLIST_REASON: string;
|
|
25
|
+
/**
|
|
26
|
+
* Check a bash command against the filesystem-scan blocklist.
|
|
27
|
+
*
|
|
28
|
+
* @param command The raw command string passed to the bash tool (after any
|
|
29
|
+
* command prefix has been applied).
|
|
30
|
+
* @returns `{ blocked: true, reason }` when the command matches a blocked
|
|
31
|
+
* pattern, otherwise `{ blocked: false, reason: "" }`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* checkBashBlocklist("find /") // { blocked: true, ... }
|
|
35
|
+
* checkBashBlocklist("find / -name foo") // { blocked: true, ... }
|
|
36
|
+
* checkBashBlocklist("find .") // { blocked: false, reason: "" }
|
|
37
|
+
* checkBashBlocklist("grep -r /") // { blocked: true, ... }
|
|
38
|
+
* checkBashBlocklist("grep -r src/") // { blocked: false, reason: "" }
|
|
39
|
+
* checkBashBlocklist("cat /etc/hosts") // { blocked: false, reason: "" }
|
|
40
|
+
*/
|
|
41
|
+
export declare function checkBashBlocklist(command: string): BashBlocklistResult;
|
|
42
|
+
//# sourceMappingURL=bash-blocklist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bash-blocklist.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/tools/bash-blocklist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,mCAAmC;AACnC,MAAM,WAAW,mBAAmB;IACnC,6CAA6C;IAC7C,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;CACf;AA0GD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAGgD,CAAC;AAEnF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,mBAAmB,CAevE"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bash command blocklist for filesystem-wide scans.
|
|
3
|
+
*
|
|
4
|
+
* Blocks recursive scans originating from the filesystem root `/` or other
|
|
5
|
+
* system directories (e.g. `/etc`, `/home`, `/usr`, `/var`) because they can
|
|
6
|
+
* take a very long time and are almost never the intended action inside a
|
|
7
|
+
* workspace-scoped bash tool. Scoped scans (e.g. `find .`, `grep -r src/`,
|
|
8
|
+
* `ls -R src/`) remain allowed.
|
|
9
|
+
*
|
|
10
|
+
* This is intentionally a regex-based heuristic, not a full shell parser. It
|
|
11
|
+
* targets the common scan shapes; exotic obfuscation is out of scope.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Absolute system paths that a workspace bash tool should never recursively
|
|
15
|
+
* scan. Each entry is matched as a literal path token (anchored or
|
|
16
|
+
* space/quote-delimited) and is also the prefix of a directory subtree.
|
|
17
|
+
*
|
|
18
|
+
* Notes:
|
|
19
|
+
* - `/` is the root.
|
|
20
|
+
* - We deliberately exclude `/tmp` and `/Users` style home roots here; they
|
|
21
|
+
* are handled by the recursive-root rules where relevant, but blocking every
|
|
22
|
+
* `/Users/...` access would also block legitimate `cat /Users/.../file`
|
|
23
|
+
* reads. We only block *recursive scans* against `/`, not arbitrary reads.
|
|
24
|
+
*/
|
|
25
|
+
const SYSTEM_SCAN_ROOTS = [
|
|
26
|
+
"/",
|
|
27
|
+
"/etc",
|
|
28
|
+
"/home",
|
|
29
|
+
"/usr",
|
|
30
|
+
"/var",
|
|
31
|
+
"/bin",
|
|
32
|
+
"/sbin",
|
|
33
|
+
"/lib",
|
|
34
|
+
"/lib64",
|
|
35
|
+
"/opt",
|
|
36
|
+
"/root",
|
|
37
|
+
"/sys",
|
|
38
|
+
"/proc",
|
|
39
|
+
"/dev",
|
|
40
|
+
"/boot",
|
|
41
|
+
"/srv",
|
|
42
|
+
"/mnt",
|
|
43
|
+
"/media",
|
|
44
|
+
];
|
|
45
|
+
/**
|
|
46
|
+
* Build an alternation of system roots, escaping regex metacharacters. `/` has
|
|
47
|
+
* no special regex meaning so it does not need escaping, but we escape it for
|
|
48
|
+
* safety/generality. Longest entries first so `/etc` matches before `/`.
|
|
49
|
+
*/
|
|
50
|
+
const ROOTS_ALT = SYSTEM_SCAN_ROOTS.slice()
|
|
51
|
+
.sort((a, b) => b.length - a.length)
|
|
52
|
+
.map((r) => r.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
53
|
+
.join("|");
|
|
54
|
+
/**
|
|
55
|
+
* Match a command token that starts with one of the system roots.
|
|
56
|
+
*
|
|
57
|
+
* The token is anchored by start-of-string, a preceding space, or an opening
|
|
58
|
+
* quote, and extends to the next whitespace or end-of-string. This prevents
|
|
59
|
+
* false positives like `cat /etc/hosts` being treated as a scan of `/etc`,
|
|
60
|
+
* because we only apply this pattern to recursive-scan commands (find/grep -r
|
|
61
|
+
* / ls -R) below.
|
|
62
|
+
*
|
|
63
|
+
* Captured group 1 is the matched root path token.
|
|
64
|
+
*/
|
|
65
|
+
const SYSTEM_ROOT_TOKEN = new RegExp(`(?:^|\\s|['"])(?<root>${ROOTS_ALT})[^\\s'"]*(?=\\s|$|['"])`);
|
|
66
|
+
/**
|
|
67
|
+
* `find <root>` — `find` invoked with a system root as one of its path
|
|
68
|
+
* arguments. We match `find` followed by optional flags/options and then a
|
|
69
|
+
* system-root token anywhere in the argument list.
|
|
70
|
+
*
|
|
71
|
+
* `find` is inherently recursive, so any `find /` (or `find /etc ...`) is a
|
|
72
|
+
* filesystem scan. Scoped forms (`find .`, `find src/`, `find ./packages`)
|
|
73
|
+
* are not matched because their path tokens are not system roots.
|
|
74
|
+
*/
|
|
75
|
+
const FIND_SYSTEM_ROOT = new RegExp(
|
|
76
|
+
// `find` as its own token, followed by anything, then a system-root token.
|
|
77
|
+
`(?:^|[\\s;&|]+)(?:sudo\\s+)?find\\b.*${SYSTEM_ROOT_TOKEN.source}`);
|
|
78
|
+
/**
|
|
79
|
+
* Recursive grep targeting a system root. Requires a recursive flag
|
|
80
|
+
* (`-r`, `-R`, `--recursive`, or a combined short flag containing `r`/`R`
|
|
81
|
+
* such as `-rn`, `-RI`, `-rnI`) and a system-root path token.
|
|
82
|
+
*
|
|
83
|
+
* Supports `grep`, `ggrep`, `egrep`, `fgrep`, `rg` (ripgrep), and `ack`.
|
|
84
|
+
*/
|
|
85
|
+
const GREP_SYSTEM_ROOT = new RegExp(`(?:^|[\\s;&|]+)(?:sudo\\s+)?(?:g?grep|egrep|fgrep)\\b` +
|
|
86
|
+
// require a recursive flag somewhere before/after — combined short flags
|
|
87
|
+
// like -rn, -RI are covered by [-][A-Za-z]*[rR][A-Za-z]*
|
|
88
|
+
`.*(?:-r\\b|-R\\b|--recursive\\b|-[A-Za-z]*[rR][A-Za-z]*)` +
|
|
89
|
+
`.*${SYSTEM_ROOT_TOKEN.source}`);
|
|
90
|
+
/**
|
|
91
|
+
* Recursive `ls` targeting a system root. `ls` is only a scan when `-R`
|
|
92
|
+
* (or a combined short flag containing `R`, e.g. `-laR`, `-AR`) is present
|
|
93
|
+
* AND the target is a system root.
|
|
94
|
+
*/
|
|
95
|
+
const LS_SYSTEM_ROOT = new RegExp(`(?:^|[\\s;&|]+)(?:sudo\\s+)?ls\\b` +
|
|
96
|
+
`.*(?:-R\\b|--recursive\\b|-[A-Za-z]*R[A-Za-z]*)` +
|
|
97
|
+
`.*${SYSTEM_ROOT_TOKEN.source}`);
|
|
98
|
+
const BLOCKED_PATTERNS = [
|
|
99
|
+
{ name: "find on system root", pattern: FIND_SYSTEM_ROOT },
|
|
100
|
+
{ name: "recursive grep on system root", pattern: GREP_SYSTEM_ROOT },
|
|
101
|
+
{ name: "recursive ls on system root", pattern: LS_SYSTEM_ROOT },
|
|
102
|
+
];
|
|
103
|
+
/**
|
|
104
|
+
* Default, reusable explanation returned to the LLM when a command is blocked.
|
|
105
|
+
* Phrased to steer the model toward a scoped alternative.
|
|
106
|
+
*/
|
|
107
|
+
export const BASH_BLOCKLIST_REASON = "Command blocked: a filesystem-wide scan starting from a system root ('/' or a system directory such as /etc, /usr, /home) was detected. " +
|
|
108
|
+
"Such scans can take a very long time. Use the find/grep/ls tools with a scoped path within the workspace " +
|
|
109
|
+
"(e.g. '.', 'src/', './packages') instead of scanning '/' or system directories.";
|
|
110
|
+
/**
|
|
111
|
+
* Check a bash command against the filesystem-scan blocklist.
|
|
112
|
+
*
|
|
113
|
+
* @param command The raw command string passed to the bash tool (after any
|
|
114
|
+
* command prefix has been applied).
|
|
115
|
+
* @returns `{ blocked: true, reason }` when the command matches a blocked
|
|
116
|
+
* pattern, otherwise `{ blocked: false, reason: "" }`.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* checkBashBlocklist("find /") // { blocked: true, ... }
|
|
120
|
+
* checkBashBlocklist("find / -name foo") // { blocked: true, ... }
|
|
121
|
+
* checkBashBlocklist("find .") // { blocked: false, reason: "" }
|
|
122
|
+
* checkBashBlocklist("grep -r /") // { blocked: true, ... }
|
|
123
|
+
* checkBashBlocklist("grep -r src/") // { blocked: false, reason: "" }
|
|
124
|
+
* checkBashBlocklist("cat /etc/hosts") // { blocked: false, reason: "" }
|
|
125
|
+
*/
|
|
126
|
+
export function checkBashBlocklist(command) {
|
|
127
|
+
if (typeof command !== "string" || command.length === 0) {
|
|
128
|
+
return { blocked: false, reason: "" };
|
|
129
|
+
}
|
|
130
|
+
// Strip quoted substrings before matching so that system-root tokens that
|
|
131
|
+
// appear only inside a quoted option value (e.g. `find . -name '/etc/hosts'`)
|
|
132
|
+
// do not false-positive. A real scan target like `find /` or `grep -r /etc`
|
|
133
|
+
// is an unquoted path token and survives this stripping.
|
|
134
|
+
const normalized = command.replace(/'[^']*'|"[^"]*"/g, "");
|
|
135
|
+
for (const { pattern } of BLOCKED_PATTERNS) {
|
|
136
|
+
if (pattern.test(normalized)) {
|
|
137
|
+
return { blocked: true, reason: BASH_BLOCKLIST_REASON };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return { blocked: false, reason: "" };
|
|
141
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/tools/bash.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAU5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../../src/sdk/coding-agent/core/tools/bash.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAU5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAK7D,OAAO,EAAoD,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAExG,QAAA,MAAM,UAAU;;;EAGd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B;;;;;;OAMG;IACH,IAAI,EAAE,CACL,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAC/B,MAAM,CAAC,EAAE,WAAW,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;KACxB,KACG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC;CAC1C;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAkF1F;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,gBAAgB,KAAK,gBAAgB,CAAC;AAO5E,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,mFAAmF;IACnF,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,aAAa,CAAC;CAC1B;AAyFD,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CA0IhE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG"}
|
|
@@ -4,6 +4,7 @@ import { Type } from "typebox";
|
|
|
4
4
|
import { waitForChildProcess } from "../../utils/child-process.js";
|
|
5
5
|
import { getShellConfig, getShellEnv, killProcessTree, trackDetachedChildPid, untrackDetachedChildPid, } from "../../utils/shell.js";
|
|
6
6
|
import { OutputAccumulator } from "./output-accumulator.js";
|
|
7
|
+
import { checkBashBlocklist } from "./bash-blocklist.js";
|
|
7
8
|
import { getTextOutput, str } from "./render-utils.js";
|
|
8
9
|
import { wrapToolDefinition } from "./tool-definition-wrapper.js";
|
|
9
10
|
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "./truncate.js";
|
|
@@ -196,6 +197,10 @@ export function createBashToolDefinition(cwd, options) {
|
|
|
196
197
|
async execute(_toolCallId, { command, timeout }, signal, onUpdate, _ctx) {
|
|
197
198
|
const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
|
|
198
199
|
const spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook);
|
|
200
|
+
const blocklistResult = checkBashBlocklist(spawnContext.command);
|
|
201
|
+
if (blocklistResult.blocked) {
|
|
202
|
+
throw new Error(blocklistResult.reason);
|
|
203
|
+
}
|
|
199
204
|
const output = new OutputAccumulator({ tempFilePrefix: "spectral-bash" });
|
|
200
205
|
let updateTimer;
|
|
201
206
|
let updateDirty = false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAaH,OAAO,EAQL,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EAEtB,MAAM,8BAA8B,CAAC;AAYtC,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"agent-bridge.d.ts","sourceRoot":"","sources":["../../src/server/agent-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -59,11 +59,13 @@ import { loadAgentSettings, } from "./handlers/agent-settings.js";
|
|
|
59
59
|
import kanbanBridgeExtension from "../extensions/kanban-bridge.js";
|
|
60
60
|
import spectralVisionExtension from "../extensions/spectral-vision-fallback.js";
|
|
61
61
|
import desktopScreenshotExtension from "../extensions/desktop-screenshot/index.js";
|
|
62
|
+
import codeOrderExtension from "../extensions/code-order/index.js";
|
|
62
63
|
import subagentExt from "../agent/index.js";
|
|
63
64
|
import designerExtension from "../designer/index.js";
|
|
64
65
|
import observationalMemory from "../memory/index.js";
|
|
65
66
|
import { OBSERVATIONAL_MEMORY_CONTEXT_CUSTOM_TYPE, OBSERVATIONAL_MEMORY_SNAPSHOT_CUSTOM_TYPE, } from "../memory/types.js";
|
|
66
67
|
import { fetchAllowedModels as defaultFetchAllowedModels, } from "../relay/models-fetch.js";
|
|
68
|
+
import { humanizeProviderError } from "./error-humanizer.js";
|
|
67
69
|
import { readStudioBinding, getBindingFilePath } from "../studio-binding.js";
|
|
68
70
|
/**
|
|
69
71
|
* Synthetic provider names registered with spectral's `ModelRegistry`. They route
|
|
@@ -657,6 +659,7 @@ export class AgentBridge {
|
|
|
657
659
|
});
|
|
658
660
|
});
|
|
659
661
|
extensionFactories.push(desktopScreenshotExtension);
|
|
662
|
+
extensionFactories.push(codeOrderExtension);
|
|
660
663
|
// Register the bundled MCP adapter. Static import is required so the
|
|
661
664
|
// adapter is included in compiled standalone binaries (Bun build), where
|
|
662
665
|
// filesystem-based discovery via jiti fails because the source files are
|
|
@@ -1287,7 +1290,7 @@ export class AgentBridge {
|
|
|
1287
1290
|
this.opts.onError?.(e);
|
|
1288
1291
|
this.opts.emit({
|
|
1289
1292
|
type: "error",
|
|
1290
|
-
message: `Failed to switch to modelId "${modelId}": ${e
|
|
1293
|
+
message: `Failed to switch to modelId "${modelId}": ${humanizeProviderError(e)}`,
|
|
1291
1294
|
});
|
|
1292
1295
|
return false;
|
|
1293
1296
|
}
|
|
@@ -1346,7 +1349,7 @@ export class AgentBridge {
|
|
|
1346
1349
|
this.opts.onError?.(e);
|
|
1347
1350
|
this.opts.emit({
|
|
1348
1351
|
type: "error",
|
|
1349
|
-
message: `Failed to set reasoning effort: ${e
|
|
1352
|
+
message: `Failed to set reasoning effort: ${humanizeProviderError(e)}`,
|
|
1350
1353
|
});
|
|
1351
1354
|
}
|
|
1352
1355
|
}
|
|
@@ -1406,7 +1409,7 @@ export class AgentBridge {
|
|
|
1406
1409
|
catch {
|
|
1407
1410
|
// best-effort: abort failure must not propagate out of error handler
|
|
1408
1411
|
}
|
|
1409
|
-
this.opts.emit({ type: "error", message:
|
|
1412
|
+
this.opts.emit({ type: "error", message: humanizeProviderError(err) });
|
|
1410
1413
|
this.opts.emit({ type: "agent_end" });
|
|
1411
1414
|
}
|
|
1412
1415
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error humanizer for the agent streaming path.
|
|
3
|
+
*
|
|
4
|
+
* Raw upstream provider errors (e.g. OpenRouter 429s) surface as JSON blobs
|
|
5
|
+
* containing internal identifiers (org_..., user_id, provider_name, model
|
|
6
|
+
* names). These must never reach end users via the `error` ServerEvent.
|
|
7
|
+
*
|
|
8
|
+
* This module converts any caught error into a short, safe, user-facing
|
|
9
|
+
* string. Raw errors are still logged server-side at the catch sites; this
|
|
10
|
+
* helper only controls the user-facing message.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Classification regex reused from agent-loop.ts (retry classification).
|
|
14
|
+
* Matches transient provider errors: rate limits, overload, timeouts, and
|
|
15
|
+
* network failures.
|
|
16
|
+
*/
|
|
17
|
+
export declare const PROVIDER_ERROR_PATTERNS: RegExp;
|
|
18
|
+
/**
|
|
19
|
+
* Convert a caught error into a clean, user-facing message.
|
|
20
|
+
*
|
|
21
|
+
* Classification (priority order):
|
|
22
|
+
* 1. Rate limit / 429 / overloaded / 529 / "too many requests" /
|
|
23
|
+
* "temporarily rate-limited" → "Rate limit reached. Please try again in a moment."
|
|
24
|
+
* 2. timeout / econnreset / "fetch failed" / network → "Network error. Please try again."
|
|
25
|
+
* 3. Any other Error or non-Error value → "Something went wrong. Please try again."
|
|
26
|
+
*
|
|
27
|
+
* Never leaks raw messages, JSON blobs, or internal identifiers (org_...,
|
|
28
|
+
* user_id, provider_name, is_byok, upstream model names).
|
|
29
|
+
*/
|
|
30
|
+
export declare function humanizeProviderError(err: unknown): string;
|
|
31
|
+
//# sourceMappingURL=error-humanizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-humanizer.d.ts","sourceRoot":"","sources":["../../src/server/error-humanizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,QACuC,CAAC;AAoC5E;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAa1D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error humanizer for the agent streaming path.
|
|
3
|
+
*
|
|
4
|
+
* Raw upstream provider errors (e.g. OpenRouter 429s) surface as JSON blobs
|
|
5
|
+
* containing internal identifiers (org_..., user_id, provider_name, model
|
|
6
|
+
* names). These must never reach end users via the `error` ServerEvent.
|
|
7
|
+
*
|
|
8
|
+
* This module converts any caught error into a short, safe, user-facing
|
|
9
|
+
* string. Raw errors are still logged server-side at the catch sites; this
|
|
10
|
+
* helper only controls the user-facing message.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Classification regex reused from agent-loop.ts (retry classification).
|
|
14
|
+
* Matches transient provider errors: rate limits, overload, timeouts, and
|
|
15
|
+
* network failures.
|
|
16
|
+
*/
|
|
17
|
+
export const PROVIDER_ERROR_PATTERNS = /rate.?limit|429|overloaded|529|timeout|network|econnreset|fetch failed/i;
|
|
18
|
+
const RATE_LIMIT_MESSAGE = "Rate limit reached. Please try again in a moment.";
|
|
19
|
+
const NETWORK_ERROR_MESSAGE = "Network error. Please try again.";
|
|
20
|
+
const GENERIC_MESSAGE = "Something went wrong. Please try again.";
|
|
21
|
+
/**
|
|
22
|
+
* Coerce any caught value into a single string suitable for regex matching,
|
|
23
|
+
* without ever returning it to the user. This is only used internally for
|
|
24
|
+
* classification; the returned user-facing string never contains this text.
|
|
25
|
+
*/
|
|
26
|
+
function toErrorString(err) {
|
|
27
|
+
if (err instanceof Error) {
|
|
28
|
+
// Include both message and any nested cause chain, since upstream SDKs
|
|
29
|
+
// sometimes stash the real classification in `cause`.
|
|
30
|
+
const parts = [err.message];
|
|
31
|
+
let cause = err.cause;
|
|
32
|
+
while (cause) {
|
|
33
|
+
if (cause instanceof Error) {
|
|
34
|
+
parts.push(cause.message);
|
|
35
|
+
cause = cause.cause;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
parts.push(String(cause));
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return parts.join("\n");
|
|
43
|
+
}
|
|
44
|
+
if (typeof err === "string")
|
|
45
|
+
return err;
|
|
46
|
+
try {
|
|
47
|
+
return JSON.stringify(err);
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return String(err);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Convert a caught error into a clean, user-facing message.
|
|
55
|
+
*
|
|
56
|
+
* Classification (priority order):
|
|
57
|
+
* 1. Rate limit / 429 / overloaded / 529 / "too many requests" /
|
|
58
|
+
* "temporarily rate-limited" → "Rate limit reached. Please try again in a moment."
|
|
59
|
+
* 2. timeout / econnreset / "fetch failed" / network → "Network error. Please try again."
|
|
60
|
+
* 3. Any other Error or non-Error value → "Something went wrong. Please try again."
|
|
61
|
+
*
|
|
62
|
+
* Never leaks raw messages, JSON blobs, or internal identifiers (org_...,
|
|
63
|
+
* user_id, provider_name, is_byok, upstream model names).
|
|
64
|
+
*/
|
|
65
|
+
export function humanizeProviderError(err) {
|
|
66
|
+
const text = toErrorString(err);
|
|
67
|
+
// "too many requests" and "temporarily rate-limited" are covered by the
|
|
68
|
+
// shared regex via the `rate.?limit` and `429` alternations; rate-limit
|
|
69
|
+
// and overload signals take priority over network signals.
|
|
70
|
+
if (/\b(429|529)\b|rate.?limit|overloaded|too many requests|temporarily.?rate.?limited/i.test(text)) {
|
|
71
|
+
return RATE_LIMIT_MESSAGE;
|
|
72
|
+
}
|
|
73
|
+
if (PROVIDER_ERROR_PATTERNS.test(text)) {
|
|
74
|
+
return NETWORK_ERROR_MESSAGE;
|
|
75
|
+
}
|
|
76
|
+
return GENERIC_MESSAGE;
|
|
77
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-stream.d.ts","sourceRoot":"","sources":["../../src/server/session-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAMH,OAAO,EAAe,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACtF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAoBjD,OAAO,KAAK,EACV,eAAe,EACf,sBAAsB,EAEtB,WAAW,EACX,iBAAiB,EACjB,WAAW,EACX,wBAAwB,EAGzB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"session-stream.d.ts","sourceRoot":"","sources":["../../src/server/session-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,6 +48,7 @@ import { loadConfig } from "../memory/config.js";
|
|
|
48
48
|
import { setProjectObsStore } from "../memory/project-observations-store.js";
|
|
49
49
|
import { estimateStringTokens } from "../memory/tokens.js";
|
|
50
50
|
import { reflectionContent, reflectionId } from "../memory/types.js";
|
|
51
|
+
import { humanizeProviderError } from "./error-humanizer.js";
|
|
51
52
|
/**
|
|
52
53
|
* Extract the `creditsUsed` value from a `token_usage` event embedded in an
|
|
53
54
|
* events JSONL string. Returns `null` if no `token_usage` event is present
|
|
@@ -902,7 +903,7 @@ export class SessionStreamManager {
|
|
|
902
903
|
stream.startError = e;
|
|
903
904
|
this.broadcast(stream, {
|
|
904
905
|
type: "error",
|
|
905
|
-
message: `Failed to start agent: ${e
|
|
906
|
+
message: `Failed to start agent: ${humanizeProviderError(e)}`,
|
|
906
907
|
});
|
|
907
908
|
throw e;
|
|
908
909
|
});
|
|
@@ -914,7 +915,7 @@ export class SessionStreamManager {
|
|
|
914
915
|
}
|
|
915
916
|
catch (err) {
|
|
916
917
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
917
|
-
this.broadcast(stream, { type: "error", message: `Agent not ready: ${e
|
|
918
|
+
this.broadcast(stream, { type: "error", message: `Agent not ready: ${humanizeProviderError(e)}` });
|
|
918
919
|
return;
|
|
919
920
|
}
|
|
920
921
|
// Sticky-model resolution & application. Phase 3 (Available Models
|
|
@@ -1025,7 +1026,7 @@ export class SessionStreamManager {
|
|
|
1025
1026
|
console.error(`[spectral] error: bridge.prompt failed: ${msg}`);
|
|
1026
1027
|
this.broadcast(stream, {
|
|
1027
1028
|
type: "error",
|
|
1028
|
-
message:
|
|
1029
|
+
message: humanizeProviderError(err),
|
|
1029
1030
|
});
|
|
1030
1031
|
});
|
|
1031
1032
|
}
|
|
@@ -1417,7 +1418,7 @@ export class SessionStreamManager {
|
|
|
1417
1418
|
console.error(`[spectral] fork-compact failed for ${stream.sessionId}: ${outcome.error.message}`);
|
|
1418
1419
|
this.broadcast(stream, {
|
|
1419
1420
|
type: "error",
|
|
1420
|
-
message: `Context compaction failed: ${outcome.error
|
|
1421
|
+
message: `Context compaction failed: ${humanizeProviderError(outcome.error)}`,
|
|
1421
1422
|
});
|
|
1422
1423
|
});
|
|
1423
1424
|
}
|
|
@@ -1642,7 +1643,7 @@ export class SessionStreamManager {
|
|
|
1642
1643
|
// dead connection. Late attachers see startError via attach->ready.
|
|
1643
1644
|
this.broadcast(stream, {
|
|
1644
1645
|
type: "error",
|
|
1645
|
-
message: `Failed to start agent: ${e
|
|
1646
|
+
message: `Failed to start agent: ${humanizeProviderError(e)}`,
|
|
1646
1647
|
});
|
|
1647
1648
|
throw e;
|
|
1648
1649
|
});
|
|
@@ -2100,7 +2101,7 @@ export class SessionStreamManager {
|
|
|
2100
2101
|
console.error(`[spectral] error: auto-dequeue failed: ${msg}`);
|
|
2101
2102
|
this.broadcast(stream, {
|
|
2102
2103
|
type: "error",
|
|
2103
|
-
message: `Failed to start auto-dequeued prompt: ${msg}`,
|
|
2104
|
+
message: `Failed to start auto-dequeued prompt: ${humanizeProviderError(msg)}`,
|
|
2104
2105
|
});
|
|
2105
2106
|
});
|
|
2106
2107
|
return true;
|