wave-agent-sdk 1.0.7 → 1.0.9
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/builtin/skills/artifact/SKILL.md +14 -0
- package/builtin/skills/settings/ENV.md +2 -1
- package/builtin/skills/settings/MODELS.md +3 -0
- package/builtin/skills/settings/SKILL.md +7 -0
- package/builtin/skills/settings/SUBAGENTS.md +1 -1
- package/builtin/subagents/vision.md +18 -0
- package/dist/constants/tools.d.ts +1 -0
- package/dist/constants/tools.js +1 -0
- package/dist/managers/aiManager.js +46 -4
- package/dist/managers/backgroundTaskManager.js +52 -4
- package/dist/managers/messageManager.js +8 -2
- package/dist/managers/permissionManager.d.ts +5 -0
- package/dist/managers/permissionManager.js +18 -2
- package/dist/managers/pluginManager.d.ts +9 -0
- package/dist/managers/pluginManager.js +20 -0
- package/dist/managers/skillManager.d.ts +13 -0
- package/dist/managers/skillManager.js +30 -0
- package/dist/managers/subagentManager.d.ts +12 -0
- package/dist/managers/subagentManager.js +32 -2
- package/dist/managers/toolManager.d.ts +8 -0
- package/dist/managers/toolManager.js +18 -0
- package/dist/services/aiService.d.ts +1 -1
- package/dist/services/aiService.js +3 -2
- package/dist/services/artifactAvailability.d.ts +9 -0
- package/dist/services/artifactAvailability.js +34 -0
- package/dist/services/artifactSession.d.ts +27 -0
- package/dist/services/artifactSession.js +52 -0
- package/dist/services/configurationService.d.ts +2 -1
- package/dist/services/configurationService.js +16 -1
- package/dist/services/initializationService.js +5 -0
- package/dist/services/remoteSettingsService.js +2 -0
- package/dist/tools/agentTool.js +2 -1
- package/dist/tools/artifactTool.d.ts +2 -0
- package/dist/tools/artifactTool.js +357 -0
- package/dist/tools/bashTool.js +24 -13
- package/dist/tools/editTool.js +7 -2
- package/dist/tools/types.d.ts +3 -1
- package/dist/tools/webFetchTool.js +141 -0
- package/dist/types/agent.d.ts +2 -0
- package/dist/types/config.d.ts +2 -0
- package/dist/types/configuration.d.ts +2 -0
- package/dist/types/messaging.d.ts +3 -1
- package/dist/types/permissions.d.ts +3 -1
- package/dist/types/permissions.js +2 -1
- package/dist/utils/bashParser.d.ts +14 -0
- package/dist/utils/bashParser.js +45 -1
- package/dist/utils/containerSetup.js +8 -0
- package/dist/utils/convertMessagesForAPI.js +51 -4
- package/dist/utils/encoding.d.ts +28 -0
- package/dist/utils/encoding.js +99 -0
- package/dist/utils/messageOperations.d.ts +4 -2
- package/dist/utils/messageOperations.js +23 -7
- package/dist/utils/subagentParser.d.ts +5 -2
- package/dist/utils/subagentParser.js +14 -4
- package/package.json +2 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming byte-to-text decoder for bash tool output on Windows.
|
|
3
|
+
*
|
|
4
|
+
* Git Bash (MSYS) tools emit UTF-8, but native Windows programs (taskkill,
|
|
5
|
+
* powershell, ping, ...) write the system OEM code page — GBK (cp936) on
|
|
6
|
+
* zh-CN systems. Node's default `data.toString()` decodes every stream as
|
|
7
|
+
* UTF-8, so GBK bytes turn into U+FFFD mojibake (issue #1753).
|
|
8
|
+
*
|
|
9
|
+
* Strategy (per-chunk buffering, decide-once):
|
|
10
|
+
* - Accumulate raw bytes; try strict UTF-8 (`fatal: true`) over everything
|
|
11
|
+
* buffered so far. If it decodes cleanly, emit the text.
|
|
12
|
+
* - If strict UTF-8 fails, hold back up to 3 trailing bytes (a UTF-8
|
|
13
|
+
* character split across chunk boundaries) and retry on the next chunk.
|
|
14
|
+
* - Once even the head is not valid UTF-8, the stream is GBK: re-decode all
|
|
15
|
+
* buffered bytes with GBK and switch to GBK for every subsequent chunk.
|
|
16
|
+
* - `flush()` decodes any leftover buffered bytes (leniently) at stream end.
|
|
17
|
+
*/
|
|
18
|
+
export class WindowsStreamDecoder {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.pending = Buffer.alloc(0);
|
|
21
|
+
this.gbkDecoder = null;
|
|
22
|
+
}
|
|
23
|
+
push(data) {
|
|
24
|
+
// Already determined GBK: decode each chunk as it arrives.
|
|
25
|
+
if (this.gbkDecoder) {
|
|
26
|
+
return this.gbkDecoder.decode(data);
|
|
27
|
+
}
|
|
28
|
+
this.pending = Buffer.concat([this.pending, data]);
|
|
29
|
+
try {
|
|
30
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(this.pending);
|
|
31
|
+
this.pending = Buffer.alloc(0);
|
|
32
|
+
return text;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Strict UTF-8 failed. The trailing bytes may be a UTF-8 sequence split
|
|
36
|
+
// across chunks: hold only the trailing run of non-ASCII bytes (max 3,
|
|
37
|
+
// the longest incomplete UTF-8 tail). Everything before it is already
|
|
38
|
+
// decodable and is emitted immediately.
|
|
39
|
+
const n = this.pending.length;
|
|
40
|
+
let keep = 0;
|
|
41
|
+
while (keep < WindowsStreamDecoder.MAX_UTF8_TRAIL_BYTES &&
|
|
42
|
+
keep < n &&
|
|
43
|
+
this.pending[n - 1 - keep] >= 0x80) {
|
|
44
|
+
keep++;
|
|
45
|
+
}
|
|
46
|
+
const head = this.pending.subarray(0, n - keep);
|
|
47
|
+
if (head.length > 0) {
|
|
48
|
+
try {
|
|
49
|
+
const text = new TextDecoder("utf-8", { fatal: true }).decode(head);
|
|
50
|
+
this.pending = Buffer.from(this.pending.subarray(n - keep));
|
|
51
|
+
return text;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Head is not valid UTF-8 → the whole stream is GBK. Re-decode
|
|
55
|
+
// everything accumulated so far and commit to GBK.
|
|
56
|
+
this.gbkDecoder = new TextDecoder("gbk");
|
|
57
|
+
const text = this.gbkDecoder.decode(this.pending);
|
|
58
|
+
this.pending = Buffer.alloc(0);
|
|
59
|
+
return text;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Only the trailing bytes are suspect: hold them for the next chunk.
|
|
63
|
+
return "";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** Decode any bytes still held at stream end (lenient UTF-8, else GBK). */
|
|
67
|
+
flush() {
|
|
68
|
+
if (this.pending.length === 0)
|
|
69
|
+
return "";
|
|
70
|
+
const rest = this.pending;
|
|
71
|
+
this.pending = Buffer.alloc(0);
|
|
72
|
+
if (this.gbkDecoder) {
|
|
73
|
+
return this.gbkDecoder.decode(rest);
|
|
74
|
+
}
|
|
75
|
+
const utf8 = rest.toString("utf-8");
|
|
76
|
+
if (!utf8.includes("\uFFFD"))
|
|
77
|
+
return utf8;
|
|
78
|
+
try {
|
|
79
|
+
return new TextDecoder("gbk").decode(rest);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return utf8;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Longest possible incomplete UTF-8 tail at a chunk boundary is 3 bytes. */
|
|
87
|
+
WindowsStreamDecoder.MAX_UTF8_TRAIL_BYTES = 3;
|
|
88
|
+
/** Decode a single complete byte sequence (used for non-streaming reads). */
|
|
89
|
+
export function decodeBytes(buf) {
|
|
90
|
+
const utf8 = buf.toString("utf-8");
|
|
91
|
+
if (!utf8.includes("\uFFFD"))
|
|
92
|
+
return utf8;
|
|
93
|
+
try {
|
|
94
|
+
return new TextDecoder("gbk").decode(buf);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return utf8;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -40,7 +40,9 @@ export interface UpdateToolBlockParams {
|
|
|
40
40
|
}>;
|
|
41
41
|
compactParams?: string;
|
|
42
42
|
parametersChunk?: string;
|
|
43
|
-
|
|
43
|
+
backgroundTaskId?: string;
|
|
44
|
+
backgroundedByUser?: boolean;
|
|
45
|
+
assistantAutoBackgrounded?: boolean;
|
|
44
46
|
timestamp?: number;
|
|
45
47
|
}
|
|
46
48
|
export type AgentToolBlockUpdateParams = Omit<UpdateToolBlockParams, "messages">;
|
|
@@ -86,7 +88,7 @@ export declare const addToolBlockToMessageInMessages: (messages: Message[], mess
|
|
|
86
88
|
messages: Message[];
|
|
87
89
|
toolBlockId: string;
|
|
88
90
|
};
|
|
89
|
-
export declare const updateToolBlockInMessage: ({ messages, id, messageId, parameters, result, success, error, stage, name, shortResult, startLineNumber, images, compactParams, parametersChunk,
|
|
91
|
+
export declare const updateToolBlockInMessage: ({ messages, id, messageId, parameters, result, success, error, stage, name, shortResult, startLineNumber, images, compactParams, parametersChunk, backgroundTaskId, backgroundedByUser, assistantAutoBackgrounded, }: UpdateToolBlockParams) => {
|
|
90
92
|
messages: Message[];
|
|
91
93
|
messageId?: string;
|
|
92
94
|
};
|
|
@@ -158,7 +158,7 @@ export const addToolBlockToMessageInMessages = (messages, messageId, params) =>
|
|
|
158
158
|
return { messages: newMessages, toolBlockId };
|
|
159
159
|
};
|
|
160
160
|
// Update Tool Block of the last assistant or user message
|
|
161
|
-
export const updateToolBlockInMessage = ({ messages, id, messageId, parameters, result, success, error, stage, name, shortResult, startLineNumber, images, compactParams, parametersChunk,
|
|
161
|
+
export const updateToolBlockInMessage = ({ messages, id, messageId, parameters, result, success, error, stage, name, shortResult, startLineNumber, images, compactParams, parametersChunk, backgroundTaskId, backgroundedByUser, assistantAutoBackgrounded, }) => {
|
|
162
162
|
const newMessages = [...messages];
|
|
163
163
|
// If messageId is provided, target that specific message
|
|
164
164
|
if (messageId) {
|
|
@@ -170,6 +170,9 @@ export const updateToolBlockInMessage = ({ messages, id, messageId, parameters,
|
|
|
170
170
|
if (toolBlock.type === "tool") {
|
|
171
171
|
if (parameters !== undefined)
|
|
172
172
|
toolBlock.parameters = parameters;
|
|
173
|
+
else if (parametersChunk !== undefined)
|
|
174
|
+
toolBlock.parameters =
|
|
175
|
+
(toolBlock.parameters || "") + parametersChunk;
|
|
173
176
|
if (result !== undefined)
|
|
174
177
|
toolBlock.result = result;
|
|
175
178
|
if (shortResult !== undefined)
|
|
@@ -188,8 +191,12 @@ export const updateToolBlockInMessage = ({ messages, id, messageId, parameters,
|
|
|
188
191
|
toolBlock.compactParams = compactParams;
|
|
189
192
|
if (parametersChunk !== undefined)
|
|
190
193
|
toolBlock.parametersChunk = parametersChunk;
|
|
191
|
-
if (
|
|
192
|
-
toolBlock.
|
|
194
|
+
if (backgroundTaskId !== undefined)
|
|
195
|
+
toolBlock.backgroundTaskId = backgroundTaskId;
|
|
196
|
+
if (backgroundedByUser !== undefined)
|
|
197
|
+
toolBlock.backgroundedByUser = backgroundedByUser;
|
|
198
|
+
if (assistantAutoBackgrounded !== undefined)
|
|
199
|
+
toolBlock.assistantAutoBackgrounded = assistantAutoBackgrounded;
|
|
193
200
|
}
|
|
194
201
|
}
|
|
195
202
|
}
|
|
@@ -204,6 +211,9 @@ export const updateToolBlockInMessage = ({ messages, id, messageId, parameters,
|
|
|
204
211
|
if (toolBlock.type === "tool") {
|
|
205
212
|
if (parameters !== undefined)
|
|
206
213
|
toolBlock.parameters = parameters;
|
|
214
|
+
else if (parametersChunk !== undefined)
|
|
215
|
+
toolBlock.parameters =
|
|
216
|
+
(toolBlock.parameters || "") + parametersChunk;
|
|
207
217
|
if (result !== undefined)
|
|
208
218
|
toolBlock.result = result;
|
|
209
219
|
if (shortResult !== undefined)
|
|
@@ -222,8 +232,12 @@ export const updateToolBlockInMessage = ({ messages, id, messageId, parameters,
|
|
|
222
232
|
toolBlock.compactParams = compactParams;
|
|
223
233
|
if (parametersChunk !== undefined)
|
|
224
234
|
toolBlock.parametersChunk = parametersChunk;
|
|
225
|
-
if (
|
|
226
|
-
toolBlock.
|
|
235
|
+
if (backgroundTaskId !== undefined)
|
|
236
|
+
toolBlock.backgroundTaskId = backgroundTaskId;
|
|
237
|
+
if (backgroundedByUser !== undefined)
|
|
238
|
+
toolBlock.backgroundedByUser = backgroundedByUser;
|
|
239
|
+
if (assistantAutoBackgrounded !== undefined)
|
|
240
|
+
toolBlock.assistantAutoBackgrounded = assistantAutoBackgrounded;
|
|
227
241
|
}
|
|
228
242
|
const foundMessageId = newMessages[i].id;
|
|
229
243
|
return { messages: newMessages, messageId: foundMessageId };
|
|
@@ -233,7 +247,7 @@ export const updateToolBlockInMessage = ({ messages, id, messageId, parameters,
|
|
|
233
247
|
// This handles cases where we're streaming tool parameters before execution
|
|
234
248
|
newMessages[i].blocks.push({
|
|
235
249
|
type: "tool",
|
|
236
|
-
parameters: parameters,
|
|
250
|
+
parameters: parameters !== undefined ? parameters : (parametersChunk ?? ""),
|
|
237
251
|
result: result || "",
|
|
238
252
|
shortResult: shortResult,
|
|
239
253
|
startLineNumber: startLineNumber,
|
|
@@ -245,7 +259,9 @@ export const updateToolBlockInMessage = ({ messages, id, messageId, parameters,
|
|
|
245
259
|
stage: stage ?? "start",
|
|
246
260
|
compactParams: compactParams,
|
|
247
261
|
parametersChunk: parametersChunk,
|
|
248
|
-
|
|
262
|
+
backgroundTaskId: backgroundTaskId,
|
|
263
|
+
backgroundedByUser: backgroundedByUser,
|
|
264
|
+
assistantAutoBackgrounded: assistantAutoBackgrounded,
|
|
249
265
|
});
|
|
250
266
|
const foundMessageId = newMessages[i].id;
|
|
251
267
|
return { messages: newMessages, messageId: foundMessageId };
|
|
@@ -17,9 +17,12 @@ export interface SubagentConfiguration {
|
|
|
17
17
|
export declare function parseAgentFile(filePath: string, scope: "plugin", pluginRoot: string): SubagentConfiguration;
|
|
18
18
|
/**
|
|
19
19
|
* Load all subagent configurations from project and user directories, plus built-in subagents
|
|
20
|
+
* @param workdir - Working directory to scan for project-level subagents
|
|
21
|
+
* @param env - Merged environment (settings.json env over OS env). Defaults to process.env.
|
|
22
|
+
* Used for conditional registration of builtin subagents (e.g. WAVE_VISION_MODEL).
|
|
20
23
|
*/
|
|
21
|
-
export declare function loadSubagentConfigurations(workdir: string): Promise<SubagentConfiguration[]>;
|
|
24
|
+
export declare function loadSubagentConfigurations(workdir: string, env?: Record<string, string>): Promise<SubagentConfiguration[]>;
|
|
22
25
|
/**
|
|
23
26
|
* Find subagent by exact name match
|
|
24
27
|
*/
|
|
25
|
-
export declare function findSubagentByName(name: string, workdir: string): Promise<SubagentConfiguration | null>;
|
|
28
|
+
export declare function findSubagentByName(name: string, workdir: string, env?: Record<string, string>): Promise<SubagentConfiguration | null>;
|
|
@@ -158,15 +158,25 @@ function scanSubagentDirectory(dirPath, scope) {
|
|
|
158
158
|
}
|
|
159
159
|
/**
|
|
160
160
|
* Load all subagent configurations from project and user directories, plus built-in subagents
|
|
161
|
+
* @param workdir - Working directory to scan for project-level subagents
|
|
162
|
+
* @param env - Merged environment (settings.json env over OS env). Defaults to process.env.
|
|
163
|
+
* Used for conditional registration of builtin subagents (e.g. WAVE_VISION_MODEL).
|
|
161
164
|
*/
|
|
162
|
-
export async function loadSubagentConfigurations(workdir) {
|
|
165
|
+
export async function loadSubagentConfigurations(workdir, env = process.env) {
|
|
163
166
|
const projectWaveDir = join(workdir, ".wave", "agents");
|
|
164
167
|
const projectClaudeDir = join(workdir, ".claude", "agents");
|
|
165
168
|
const userWaveDir = join(process.env.HOME || "~", ".wave", "agents");
|
|
166
169
|
const userClaudeDir = join(process.env.HOME || "~", ".claude", "agents");
|
|
167
170
|
const builtinDir = getBuiltinSubagentsDir();
|
|
168
171
|
// Load configurations from all sources
|
|
169
|
-
|
|
172
|
+
let builtinConfigs = scanSubagentDirectory(builtinDir, "builtin");
|
|
173
|
+
// Conditional registration: builtin subagents whose frontmatter requires the
|
|
174
|
+
// WAVE_VISION_MODEL env var (`model: visionModel`) are only loaded when it is
|
|
175
|
+
// set — otherwise the main model would delegate image recognition to a
|
|
176
|
+
// subagent that resolves to a non-vision model.
|
|
177
|
+
if (!env.WAVE_VISION_MODEL) {
|
|
178
|
+
builtinConfigs = builtinConfigs.filter((config) => config.model !== "visionModel");
|
|
179
|
+
}
|
|
170
180
|
const userClaudeConfigs = scanSubagentDirectory(userClaudeDir, "user");
|
|
171
181
|
const userWaveConfigs = scanSubagentDirectory(userWaveDir, "user");
|
|
172
182
|
const projectClaudeConfigs = scanSubagentDirectory(projectClaudeDir, "project");
|
|
@@ -193,7 +203,7 @@ export async function loadSubagentConfigurations(workdir) {
|
|
|
193
203
|
/**
|
|
194
204
|
* Find subagent by exact name match
|
|
195
205
|
*/
|
|
196
|
-
export async function findSubagentByName(name, workdir) {
|
|
197
|
-
const configurations = await loadSubagentConfigurations(workdir);
|
|
206
|
+
export async function findSubagentByName(name, workdir, env) {
|
|
207
|
+
const configurations = await loadSubagentConfigurations(workdir, env);
|
|
198
208
|
return configurations.find((config) => config.name === name) || null;
|
|
199
209
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-agent-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
4
4
|
"description": "SDK for building AI-powered development tools and agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"fuzzysort": "^3.1.0",
|
|
56
56
|
"glob": "^13.0.0",
|
|
57
57
|
"lru-cache": "^11.3.5",
|
|
58
|
+
"marked": "^17.0.2",
|
|
58
59
|
"minimatch": "^10.0.3",
|
|
59
60
|
"openai": "^5.12.2",
|
|
60
61
|
"turndown": "^7.2.2"
|