wave-agent-sdk 1.0.1 → 1.0.3
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/agent.js +12 -0
- package/dist/managers/aiManager.js +4 -0
- package/dist/managers/permissionManager.js +13 -11
- package/dist/prompts/index.d.ts +0 -1
- package/dist/prompts/index.js +71 -43
- package/package.json +1 -1
- package/src/agent.ts +14 -0
- package/src/managers/aiManager.ts +4 -0
- package/src/managers/permissionManager.ts +15 -13
- package/src/prompts/index.ts +75 -52
package/dist/agent.js
CHANGED
|
@@ -503,6 +503,13 @@ export class Agent {
|
|
|
503
503
|
await this.messageManager.saveSession();
|
|
504
504
|
}
|
|
505
505
|
async clearMessages() {
|
|
506
|
+
// Aligned with webview (ChatApp handleClearChat): /clear is ignored
|
|
507
|
+
// while the agent is running, instead of aborting the AI mid-turn
|
|
508
|
+
// (which used to inject a late "Request was aborted" error into the
|
|
509
|
+
// newly cleared session).
|
|
510
|
+
if (this.aiManager.isLoading) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
506
513
|
this.aiManager.abortAIMessage();
|
|
507
514
|
// Capture old session info before clearing
|
|
508
515
|
const oldSessionId = this.messageManager.getSessionId();
|
|
@@ -546,6 +553,11 @@ export class Agent {
|
|
|
546
553
|
* @param customInstructions - Optional custom instructions for compaction
|
|
547
554
|
*/
|
|
548
555
|
async compact(customInstructions) {
|
|
556
|
+
// Aligned with webview: /compact is ignored while the agent is running,
|
|
557
|
+
// instead of aborting the AI mid-turn before compacting.
|
|
558
|
+
if (this.aiManager.isLoading) {
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
549
561
|
this.aiManager.abortAIMessage();
|
|
550
562
|
await this.aiManager.compactConversation({
|
|
551
563
|
customInstructions,
|
|
@@ -1606,6 +1606,8 @@ ${question}`;
|
|
|
1606
1606
|
id: toolId,
|
|
1607
1607
|
shortResult,
|
|
1608
1608
|
stage: "running",
|
|
1609
|
+
compactParams,
|
|
1610
|
+
name: toolName,
|
|
1609
1611
|
});
|
|
1610
1612
|
},
|
|
1611
1613
|
onResultUpdate: (result) => {
|
|
@@ -1613,6 +1615,8 @@ ${question}`;
|
|
|
1613
1615
|
id: toolId,
|
|
1614
1616
|
result,
|
|
1615
1617
|
stage: "running",
|
|
1618
|
+
compactParams,
|
|
1619
|
+
name: toolName,
|
|
1616
1620
|
});
|
|
1617
1621
|
},
|
|
1618
1622
|
onCwdChange: async (newCwd) => {
|
|
@@ -310,16 +310,8 @@ export class PermissionManager {
|
|
|
310
310
|
};
|
|
311
311
|
}
|
|
312
312
|
}
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
// must still prompt the user, matching Claude Code's requiresUserInteraction behavior.
|
|
316
|
-
if (context.permissionMode === "bypassPermissions") {
|
|
317
|
-
const requiresUserInteraction = context.toolName === ASK_USER_QUESTION_TOOL_NAME;
|
|
318
|
-
if (!requiresUserInteraction) {
|
|
319
|
-
return { behavior: "allow" };
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// 1.0 Check worktree safety for Write and Edit tools
|
|
313
|
+
// Check worktree safety for Write and Edit tools — unconditional safety
|
|
314
|
+
// check, applied regardless of permission mode (same as read-before-edit).
|
|
323
315
|
// Support both CLI -w sessions (container-registered) and EnterWorktree mid-session
|
|
324
316
|
// (per-agent WorktreeSession stored in this session's container)
|
|
325
317
|
const worktreeSession = this.container.get("WorktreeSession");
|
|
@@ -371,7 +363,17 @@ export class PermissionManager {
|
|
|
371
363
|
}
|
|
372
364
|
}
|
|
373
365
|
}
|
|
374
|
-
//
|
|
366
|
+
// If bypassPermissions mode, always allow
|
|
367
|
+
// Exception: tools that require user interaction (e.g. AskUserQuestion)
|
|
368
|
+
// must still prompt the user, matching Claude Code's requiresUserInteraction behavior.
|
|
369
|
+
// Worktree safety check above runs unconditionally, so bypass never skips it.
|
|
370
|
+
if (context.permissionMode === "bypassPermissions") {
|
|
371
|
+
const requiresUserInteraction = context.toolName === ASK_USER_QUESTION_TOOL_NAME;
|
|
372
|
+
if (!requiresUserInteraction) {
|
|
373
|
+
return { behavior: "allow" };
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// If acceptEdits mode, allow Edit, Write, and mkdir in safe zone
|
|
375
377
|
if (context.permissionMode === "acceptEdits") {
|
|
376
378
|
const autoAcceptedTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
|
|
377
379
|
if (autoAcceptedTools.includes(context.toolName)) {
|
package/dist/prompts/index.d.ts
CHANGED
|
@@ -45,4 +45,3 @@ export declare function buildSystemPrompt(basePrompt: string | undefined, tools:
|
|
|
45
45
|
content: string;
|
|
46
46
|
};
|
|
47
47
|
}): SystemPromptBlock[];
|
|
48
|
-
export declare function enhanceSystemPromptWithEnvDetails(existingSystemPrompt: string, workdir: string, originalWorkdir?: string, worktreeSession?: WorktreeSession | null): string;
|
package/dist/prompts/index.js
CHANGED
|
@@ -285,6 +285,43 @@ export function formatCompactSummary(summary) {
|
|
|
285
285
|
return formattedSummary.trim();
|
|
286
286
|
}
|
|
287
287
|
export const WEB_CONTENT_SYSTEM_PROMPT = `You are a helpful assistant that extracts information from web content. The content is provided in Markdown format.`;
|
|
288
|
+
/**
|
|
289
|
+
* Notes block prepended to the subagent env section, aligned with Claude
|
|
290
|
+
* Code's enhanceSystemPromptWithEnvDetails().
|
|
291
|
+
*/
|
|
292
|
+
const SUBAGENT_ENV_NOTES = `Notes:
|
|
293
|
+
- Agent threads always have their cwd reset between bash calls, as a result please only use absolute file paths.
|
|
294
|
+
- In your final response, share file paths (always absolute, never relative) that are relevant to the task. Include code snippets only when the exact text is load-bearing (e.g., a bug you found, a function signature the caller asked for) — do not recap code you merely read.
|
|
295
|
+
- For clear communication with the user the assistant MUST avoid using emojis.
|
|
296
|
+
- Do not use a colon before tool calls. Text like "Let me read the file:" followed by a read tool call should just be "Let me read the file." with a period.`;
|
|
297
|
+
/**
|
|
298
|
+
* Shell info line, aligned with Claude Code's getShellInfoLine(). On win32 an
|
|
299
|
+
* extra Unix-syntax hint is appended.
|
|
300
|
+
*/
|
|
301
|
+
function getShellInfoLine() {
|
|
302
|
+
const shell = process.env.SHELL || "unknown";
|
|
303
|
+
const shellName = shell.includes("zsh")
|
|
304
|
+
? "zsh"
|
|
305
|
+
: shell.includes("bash")
|
|
306
|
+
? "bash"
|
|
307
|
+
: shell;
|
|
308
|
+
if (os.platform() === "win32") {
|
|
309
|
+
return `Shell: ${shellName} (use Unix shell syntax, not Windows — e.g., /dev/null not NUL, forward slashes in paths)`;
|
|
310
|
+
}
|
|
311
|
+
return `Shell: ${shellName}`;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* OS Version value, aligned with Claude Code's getUnameSR(). os.type() and
|
|
315
|
+
* os.release() wrap uname(3) on POSIX, producing output byte-identical to
|
|
316
|
+
* `uname -sr`. Windows has no uname(3); os.type() returns "Windows_NT" there,
|
|
317
|
+
* but os.version() gives the friendlier "Windows 11 Pro", so use that instead.
|
|
318
|
+
*/
|
|
319
|
+
function getUnameSR() {
|
|
320
|
+
if (os.platform() === "win32") {
|
|
321
|
+
return `${os.version()} ${os.release()}`;
|
|
322
|
+
}
|
|
323
|
+
return `${os.type()} ${os.release()}`;
|
|
324
|
+
}
|
|
288
325
|
export function buildSystemPrompt(basePrompt, tools, options = {}) {
|
|
289
326
|
// --- Static block (cacheable) ---
|
|
290
327
|
let staticText = basePrompt || DEFAULT_SYSTEM_PROMPT;
|
|
@@ -305,27 +342,49 @@ export function buildSystemPrompt(basePrompt, tools, options = {}) {
|
|
|
305
342
|
if (options.workdir) {
|
|
306
343
|
const isGitRepo = isGitRepository(options.workdir);
|
|
307
344
|
const platform = os.platform();
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
const
|
|
311
|
-
const shellName = shell.includes("zsh")
|
|
312
|
-
? "zsh"
|
|
313
|
-
: shell.includes("bash")
|
|
314
|
-
? "bash"
|
|
315
|
-
: shell;
|
|
345
|
+
const shellInfo = getShellInfoLine();
|
|
346
|
+
const osVersion = getUnameSR();
|
|
347
|
+
const primaryWorkdir = options.originalWorkdir ?? options.workdir;
|
|
316
348
|
const worktreeSession = options.worktreeSession;
|
|
317
|
-
|
|
349
|
+
if (options.isSubagent) {
|
|
350
|
+
// Subagent env section, aligned with Claude Code's computeEnvInfo() +
|
|
351
|
+
// enhanceSystemPromptWithEnvDetails() (without the model description and
|
|
352
|
+
// knowledge cutoff lines, which Wave does not use).
|
|
353
|
+
dynamicText += `
|
|
354
|
+
|
|
355
|
+
${SUBAGENT_ENV_NOTES}
|
|
318
356
|
|
|
319
357
|
Here is useful information about the environment you are running in:
|
|
320
358
|
<env>
|
|
321
|
-
|
|
359
|
+
Working directory: ${primaryWorkdir}
|
|
322
360
|
Is directory a git repo: ${isGitRepo}
|
|
323
361
|
Platform: ${platform}
|
|
324
|
-
|
|
362
|
+
${shellInfo}
|
|
325
363
|
OS Version: ${osVersion}
|
|
326
|
-
Today's date: ${today}
|
|
327
364
|
</env>
|
|
328
365
|
`;
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
// Main agent env section, aligned with Claude Code's
|
|
369
|
+
// computeSimpleEnvInfo() (without the model description, knowledge
|
|
370
|
+
// cutoff, and marketing lines, which Wave does not use).
|
|
371
|
+
const envItems = [
|
|
372
|
+
`Primary working directory: ${primaryWorkdir}`,
|
|
373
|
+
worktreeSession
|
|
374
|
+
? `This is a git worktree — an isolated copy of the repository. Run all commands from this directory. Do NOT \`cd\` to the original repository root.`
|
|
375
|
+
: null,
|
|
376
|
+
`Is a git repository: ${isGitRepo}`,
|
|
377
|
+
`Platform: ${platform}`,
|
|
378
|
+
shellInfo,
|
|
379
|
+
`OS Version: ${osVersion}`,
|
|
380
|
+
].filter((item) => item !== null);
|
|
381
|
+
const envBlock = [
|
|
382
|
+
`# Environment`,
|
|
383
|
+
`You have been invoked in the following environment: `,
|
|
384
|
+
...envItems.map((item) => ` - ${item}`),
|
|
385
|
+
].join("\n");
|
|
386
|
+
dynamicText += `\n\n${envBlock}`;
|
|
387
|
+
}
|
|
329
388
|
}
|
|
330
389
|
if (options.autoMemory) {
|
|
331
390
|
dynamicText += `\n\n${buildAutoMemoryPrompt(options.autoMemory.directory)}`;
|
|
@@ -338,34 +397,3 @@ Today's date: ${today}
|
|
|
338
397
|
}
|
|
339
398
|
return blocks;
|
|
340
399
|
}
|
|
341
|
-
export function enhanceSystemPromptWithEnvDetails(existingSystemPrompt, workdir, originalWorkdir, worktreeSession) {
|
|
342
|
-
const isGitRepo = isGitRepository(workdir);
|
|
343
|
-
const platform = os.platform();
|
|
344
|
-
const osVersion = `${os.type()} ${os.release()}`;
|
|
345
|
-
const today = new Date().toISOString().split("T")[0];
|
|
346
|
-
const shell = process.env.SHELL || "unknown";
|
|
347
|
-
const shellName = shell.includes("zsh")
|
|
348
|
-
? "zsh"
|
|
349
|
-
: shell.includes("bash")
|
|
350
|
-
? "bash"
|
|
351
|
-
: shell;
|
|
352
|
-
const notes = `Notes:
|
|
353
|
-
- Agent threads always have their cwd reset between bash calls, as a result please only use absolute file paths.${worktreeSession ? `\n- You are in a git worktree at ${worktreeSession.worktreePath} (branch: ${worktreeSession.worktreeBranch}). Absolute paths from prior context may refer to the original repo at ${worktreeSession.originalCwd}; translate them to your worktree. Do NOT edit files outside this worktree.` : ""}
|
|
354
|
-
- In your final response, share file paths (always absolute, never relative) that are relevant to the task. Include code snippets only when the exact text is load-bearing (e.g., a bug you found, a function signature the caller asked for) — do not recap code you merely read.
|
|
355
|
-
- For clear communication with the user the assistant MUST avoid using emojis.
|
|
356
|
-
- Do not use a colon before tool calls. Text like "Let me read the file:" followed by a read tool call should just be "Let me read the file." with a period.`;
|
|
357
|
-
return `${existingSystemPrompt}
|
|
358
|
-
|
|
359
|
-
${notes}
|
|
360
|
-
|
|
361
|
-
Here is useful information about the environment you are running in:
|
|
362
|
-
<env>
|
|
363
|
-
Primary working directory: ${originalWorkdir ?? workdir}${worktreeSession ? `\nThis is a git worktree — an isolated copy of the repository. Run all commands from this directory. Do NOT \`cd\` to the original repository root at ${worktreeSession.originalCwd}.` : ""}
|
|
364
|
-
Is directory a git repo: ${isGitRepo}
|
|
365
|
-
Platform: ${platform}
|
|
366
|
-
Shell: ${shellName}
|
|
367
|
-
OS Version: ${osVersion}
|
|
368
|
-
Today's date: ${today}
|
|
369
|
-
</env>
|
|
370
|
-
`;
|
|
371
|
-
}
|
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -681,6 +681,14 @@ export class Agent {
|
|
|
681
681
|
}
|
|
682
682
|
|
|
683
683
|
public async clearMessages(): Promise<void> {
|
|
684
|
+
// Aligned with webview (ChatApp handleClearChat): /clear is ignored
|
|
685
|
+
// while the agent is running, instead of aborting the AI mid-turn
|
|
686
|
+
// (which used to inject a late "Request was aborted" error into the
|
|
687
|
+
// newly cleared session).
|
|
688
|
+
if (this.aiManager.isLoading) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
|
|
684
692
|
this.aiManager.abortAIMessage();
|
|
685
693
|
|
|
686
694
|
// Capture old session info before clearing
|
|
@@ -743,6 +751,12 @@ export class Agent {
|
|
|
743
751
|
* @param customInstructions - Optional custom instructions for compaction
|
|
744
752
|
*/
|
|
745
753
|
public async compact(customInstructions?: string): Promise<void> {
|
|
754
|
+
// Aligned with webview: /compact is ignored while the agent is running,
|
|
755
|
+
// instead of aborting the AI mid-turn before compacting.
|
|
756
|
+
if (this.aiManager.isLoading) {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
|
|
746
760
|
this.aiManager.abortAIMessage();
|
|
747
761
|
|
|
748
762
|
await this.aiManager.compactConversation({
|
|
@@ -2195,6 +2195,8 @@ ${question}`;
|
|
|
2195
2195
|
id: toolId,
|
|
2196
2196
|
shortResult,
|
|
2197
2197
|
stage: "running",
|
|
2198
|
+
compactParams,
|
|
2199
|
+
name: toolName,
|
|
2198
2200
|
});
|
|
2199
2201
|
},
|
|
2200
2202
|
onResultUpdate: (result: string) => {
|
|
@@ -2202,6 +2204,8 @@ ${question}`;
|
|
|
2202
2204
|
id: toolId,
|
|
2203
2205
|
result,
|
|
2204
2206
|
stage: "running",
|
|
2207
|
+
compactParams,
|
|
2208
|
+
name: toolName,
|
|
2205
2209
|
});
|
|
2206
2210
|
},
|
|
2207
2211
|
onCwdChange: async (newCwd: string) => {
|
|
@@ -427,18 +427,8 @@ export class PermissionManager {
|
|
|
427
427
|
}
|
|
428
428
|
}
|
|
429
429
|
|
|
430
|
-
//
|
|
431
|
-
//
|
|
432
|
-
// must still prompt the user, matching Claude Code's requiresUserInteraction behavior.
|
|
433
|
-
if (context.permissionMode === "bypassPermissions") {
|
|
434
|
-
const requiresUserInteraction =
|
|
435
|
-
context.toolName === ASK_USER_QUESTION_TOOL_NAME;
|
|
436
|
-
if (!requiresUserInteraction) {
|
|
437
|
-
return { behavior: "allow" };
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// 1.0 Check worktree safety for Write and Edit tools
|
|
430
|
+
// Check worktree safety for Write and Edit tools — unconditional safety
|
|
431
|
+
// check, applied regardless of permission mode (same as read-before-edit).
|
|
442
432
|
// Support both CLI -w sessions (container-registered) and EnterWorktree mid-session
|
|
443
433
|
// (per-agent WorktreeSession stored in this session's container)
|
|
444
434
|
const worktreeSession = this.container.get<WorktreeSession | null>(
|
|
@@ -503,7 +493,19 @@ export class PermissionManager {
|
|
|
503
493
|
}
|
|
504
494
|
}
|
|
505
495
|
|
|
506
|
-
//
|
|
496
|
+
// If bypassPermissions mode, always allow
|
|
497
|
+
// Exception: tools that require user interaction (e.g. AskUserQuestion)
|
|
498
|
+
// must still prompt the user, matching Claude Code's requiresUserInteraction behavior.
|
|
499
|
+
// Worktree safety check above runs unconditionally, so bypass never skips it.
|
|
500
|
+
if (context.permissionMode === "bypassPermissions") {
|
|
501
|
+
const requiresUserInteraction =
|
|
502
|
+
context.toolName === ASK_USER_QUESTION_TOOL_NAME;
|
|
503
|
+
if (!requiresUserInteraction) {
|
|
504
|
+
return { behavior: "allow" };
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// If acceptEdits mode, allow Edit, Write, and mkdir in safe zone
|
|
507
509
|
if (context.permissionMode === "acceptEdits") {
|
|
508
510
|
const autoAcceptedTools = [EDIT_TOOL_NAME, WRITE_TOOL_NAME];
|
|
509
511
|
if (autoAcceptedTools.includes(context.toolName)) {
|
package/src/prompts/index.ts
CHANGED
|
@@ -347,6 +347,46 @@ export function formatCompactSummary(summary: string): string {
|
|
|
347
347
|
|
|
348
348
|
export const WEB_CONTENT_SYSTEM_PROMPT = `You are a helpful assistant that extracts information from web content. The content is provided in Markdown format.`;
|
|
349
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Notes block prepended to the subagent env section, aligned with Claude
|
|
352
|
+
* Code's enhanceSystemPromptWithEnvDetails().
|
|
353
|
+
*/
|
|
354
|
+
const SUBAGENT_ENV_NOTES = `Notes:
|
|
355
|
+
- Agent threads always have their cwd reset between bash calls, as a result please only use absolute file paths.
|
|
356
|
+
- In your final response, share file paths (always absolute, never relative) that are relevant to the task. Include code snippets only when the exact text is load-bearing (e.g., a bug you found, a function signature the caller asked for) — do not recap code you merely read.
|
|
357
|
+
- For clear communication with the user the assistant MUST avoid using emojis.
|
|
358
|
+
- Do not use a colon before tool calls. Text like "Let me read the file:" followed by a read tool call should just be "Let me read the file." with a period.`;
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Shell info line, aligned with Claude Code's getShellInfoLine(). On win32 an
|
|
362
|
+
* extra Unix-syntax hint is appended.
|
|
363
|
+
*/
|
|
364
|
+
function getShellInfoLine(): string {
|
|
365
|
+
const shell = process.env.SHELL || "unknown";
|
|
366
|
+
const shellName = shell.includes("zsh")
|
|
367
|
+
? "zsh"
|
|
368
|
+
: shell.includes("bash")
|
|
369
|
+
? "bash"
|
|
370
|
+
: shell;
|
|
371
|
+
if (os.platform() === "win32") {
|
|
372
|
+
return `Shell: ${shellName} (use Unix shell syntax, not Windows — e.g., /dev/null not NUL, forward slashes in paths)`;
|
|
373
|
+
}
|
|
374
|
+
return `Shell: ${shellName}`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* OS Version value, aligned with Claude Code's getUnameSR(). os.type() and
|
|
379
|
+
* os.release() wrap uname(3) on POSIX, producing output byte-identical to
|
|
380
|
+
* `uname -sr`. Windows has no uname(3); os.type() returns "Windows_NT" there,
|
|
381
|
+
* but os.version() gives the friendlier "Windows 11 Pro", so use that instead.
|
|
382
|
+
*/
|
|
383
|
+
function getUnameSR(): string {
|
|
384
|
+
if (os.platform() === "win32") {
|
|
385
|
+
return `${os.version()} ${os.release()}`;
|
|
386
|
+
}
|
|
387
|
+
return `${os.type()} ${os.release()}`;
|
|
388
|
+
}
|
|
389
|
+
|
|
350
390
|
export function buildSystemPrompt(
|
|
351
391
|
basePrompt: string | undefined,
|
|
352
392
|
tools: ToolPlugin[],
|
|
@@ -387,29 +427,51 @@ export function buildSystemPrompt(
|
|
|
387
427
|
if (options.workdir) {
|
|
388
428
|
const isGitRepo = isGitRepository(options.workdir);
|
|
389
429
|
const platform = os.platform();
|
|
390
|
-
const
|
|
391
|
-
const
|
|
392
|
-
const
|
|
393
|
-
const shellName = shell.includes("zsh")
|
|
394
|
-
? "zsh"
|
|
395
|
-
: shell.includes("bash")
|
|
396
|
-
? "bash"
|
|
397
|
-
: shell;
|
|
398
|
-
|
|
430
|
+
const shellInfo = getShellInfoLine();
|
|
431
|
+
const osVersion = getUnameSR();
|
|
432
|
+
const primaryWorkdir = options.originalWorkdir ?? options.workdir;
|
|
399
433
|
const worktreeSession = options.worktreeSession;
|
|
400
434
|
|
|
401
|
-
|
|
435
|
+
if (options.isSubagent) {
|
|
436
|
+
// Subagent env section, aligned with Claude Code's computeEnvInfo() +
|
|
437
|
+
// enhanceSystemPromptWithEnvDetails() (without the model description and
|
|
438
|
+
// knowledge cutoff lines, which Wave does not use).
|
|
439
|
+
dynamicText += `
|
|
440
|
+
|
|
441
|
+
${SUBAGENT_ENV_NOTES}
|
|
402
442
|
|
|
403
443
|
Here is useful information about the environment you are running in:
|
|
404
444
|
<env>
|
|
405
|
-
|
|
445
|
+
Working directory: ${primaryWorkdir}
|
|
406
446
|
Is directory a git repo: ${isGitRepo}
|
|
407
447
|
Platform: ${platform}
|
|
408
|
-
|
|
448
|
+
${shellInfo}
|
|
409
449
|
OS Version: ${osVersion}
|
|
410
|
-
Today's date: ${today}
|
|
411
450
|
</env>
|
|
412
451
|
`;
|
|
452
|
+
} else {
|
|
453
|
+
// Main agent env section, aligned with Claude Code's
|
|
454
|
+
// computeSimpleEnvInfo() (without the model description, knowledge
|
|
455
|
+
// cutoff, and marketing lines, which Wave does not use).
|
|
456
|
+
const envItems = [
|
|
457
|
+
`Primary working directory: ${primaryWorkdir}`,
|
|
458
|
+
worktreeSession
|
|
459
|
+
? `This is a git worktree — an isolated copy of the repository. Run all commands from this directory. Do NOT \`cd\` to the original repository root.`
|
|
460
|
+
: null,
|
|
461
|
+
`Is a git repository: ${isGitRepo}`,
|
|
462
|
+
`Platform: ${platform}`,
|
|
463
|
+
shellInfo,
|
|
464
|
+
`OS Version: ${osVersion}`,
|
|
465
|
+
].filter((item): item is string => item !== null);
|
|
466
|
+
|
|
467
|
+
const envBlock = [
|
|
468
|
+
`# Environment`,
|
|
469
|
+
`You have been invoked in the following environment: `,
|
|
470
|
+
...envItems.map((item) => ` - ${item}`),
|
|
471
|
+
].join("\n");
|
|
472
|
+
|
|
473
|
+
dynamicText += `\n\n${envBlock}`;
|
|
474
|
+
}
|
|
413
475
|
}
|
|
414
476
|
|
|
415
477
|
if (options.autoMemory) {
|
|
@@ -425,42 +487,3 @@ Today's date: ${today}
|
|
|
425
487
|
|
|
426
488
|
return blocks;
|
|
427
489
|
}
|
|
428
|
-
|
|
429
|
-
export function enhanceSystemPromptWithEnvDetails(
|
|
430
|
-
existingSystemPrompt: string,
|
|
431
|
-
workdir: string,
|
|
432
|
-
originalWorkdir?: string,
|
|
433
|
-
worktreeSession?: WorktreeSession | null,
|
|
434
|
-
): string {
|
|
435
|
-
const isGitRepo = isGitRepository(workdir);
|
|
436
|
-
const platform = os.platform();
|
|
437
|
-
const osVersion = `${os.type()} ${os.release()}`;
|
|
438
|
-
const today = new Date().toISOString().split("T")[0];
|
|
439
|
-
const shell = process.env.SHELL || "unknown";
|
|
440
|
-
const shellName = shell.includes("zsh")
|
|
441
|
-
? "zsh"
|
|
442
|
-
: shell.includes("bash")
|
|
443
|
-
? "bash"
|
|
444
|
-
: shell;
|
|
445
|
-
|
|
446
|
-
const notes = `Notes:
|
|
447
|
-
- Agent threads always have their cwd reset between bash calls, as a result please only use absolute file paths.${worktreeSession ? `\n- You are in a git worktree at ${worktreeSession.worktreePath} (branch: ${worktreeSession.worktreeBranch}). Absolute paths from prior context may refer to the original repo at ${worktreeSession.originalCwd}; translate them to your worktree. Do NOT edit files outside this worktree.` : ""}
|
|
448
|
-
- In your final response, share file paths (always absolute, never relative) that are relevant to the task. Include code snippets only when the exact text is load-bearing (e.g., a bug you found, a function signature the caller asked for) — do not recap code you merely read.
|
|
449
|
-
- For clear communication with the user the assistant MUST avoid using emojis.
|
|
450
|
-
- Do not use a colon before tool calls. Text like "Let me read the file:" followed by a read tool call should just be "Let me read the file." with a period.`;
|
|
451
|
-
|
|
452
|
-
return `${existingSystemPrompt}
|
|
453
|
-
|
|
454
|
-
${notes}
|
|
455
|
-
|
|
456
|
-
Here is useful information about the environment you are running in:
|
|
457
|
-
<env>
|
|
458
|
-
Primary working directory: ${originalWorkdir ?? workdir}${worktreeSession ? `\nThis is a git worktree — an isolated copy of the repository. Run all commands from this directory. Do NOT \`cd\` to the original repository root at ${worktreeSession.originalCwd}.` : ""}
|
|
459
|
-
Is directory a git repo: ${isGitRepo}
|
|
460
|
-
Platform: ${platform}
|
|
461
|
-
Shell: ${shellName}
|
|
462
|
-
OS Version: ${osVersion}
|
|
463
|
-
Today's date: ${today}
|
|
464
|
-
</env>
|
|
465
|
-
`;
|
|
466
|
-
}
|