mirror of
https://github.com/Gitlawb/openclaude.git
synced 2026-08-24 02:34:15 -05:00
fix(agents): surface worktree fallback when sync agents background
Share async_launched payload construction so the sync-to-background path includes worktreeIsolationFallback when worktree isolation soft-falls back.
This commit is contained in:
@@ -5,6 +5,7 @@ import { join } from 'path'
|
||||
import {
|
||||
AgentTool,
|
||||
assertAgentToolCwdAllowed,
|
||||
buildAsyncLaunchedToolData,
|
||||
buildWorktreeIsolationFallbackNotice,
|
||||
formatWorktreeIsolationFallbackResultText,
|
||||
fullInputSchema,
|
||||
@@ -205,6 +206,36 @@ describe('AgentTool input schema isolation contract', () => {
|
||||
)
|
||||
})
|
||||
|
||||
test('buildAsyncLaunchedToolData carries worktree isolation fallback for backgrounded sync agents', () => {
|
||||
const data = buildAsyncLaunchedToolData({
|
||||
agentId: 'agent-bg-1',
|
||||
description: baseInput.description,
|
||||
prompt: baseInput.prompt,
|
||||
canReadOutputFile: true,
|
||||
worktreeIsolationFallback: true,
|
||||
})
|
||||
|
||||
expect(data.worktreeIsolationFallback).toBe(true)
|
||||
expect(outputSchema().safeParse(data).success).toBe(true)
|
||||
|
||||
const block = AgentTool.mapToolResultToToolResultBlockParam(data, 'toolu_bg')
|
||||
const text = block.content[0]?.type === 'text' ? block.content[0].text : ''
|
||||
expect(text).toContain('worktreeIsolationFallback: true')
|
||||
expect(text).toContain('ran without an isolated worktree')
|
||||
})
|
||||
|
||||
test('buildAsyncLaunchedToolData omits fallback when isolation succeeded', () => {
|
||||
const data = buildAsyncLaunchedToolData({
|
||||
agentId: 'agent-bg-2',
|
||||
description: baseInput.description,
|
||||
prompt: baseInput.prompt,
|
||||
canReadOutputFile: false,
|
||||
worktreeIsolationFallback: false,
|
||||
})
|
||||
|
||||
expect(data.worktreeIsolationFallback).toBeUndefined()
|
||||
})
|
||||
|
||||
test('prefers worktree cwd over explicit cwd when both are present defensively', () => {
|
||||
const worktreePath = join(tmpdir(), 'openclaude-worktree')
|
||||
expect(
|
||||
|
||||
@@ -216,6 +216,26 @@ export function formatWorktreeIsolationFallbackResultText(): string {
|
||||
return 'worktreeIsolationFallback: true\nnote: Worktree isolation was unavailable; this agent ran without an isolated worktree (edits are not sandboxed in a worktree).';
|
||||
}
|
||||
|
||||
/** Shared async_launched payload for direct-async and sync-to-background paths. */
|
||||
export function buildAsyncLaunchedToolData(args: {
|
||||
agentId: string;
|
||||
description: string;
|
||||
prompt: string;
|
||||
canReadOutputFile: boolean;
|
||||
worktreeIsolationFallback?: boolean;
|
||||
}) {
|
||||
return {
|
||||
isAsync: true as const,
|
||||
status: 'async_launched' as const,
|
||||
agentId: args.agentId,
|
||||
description: args.description,
|
||||
prompt: args.prompt,
|
||||
outputFile: getTaskOutputPath(args.agentId),
|
||||
canReadOutputFile: args.canReadOutputFile,
|
||||
...(args.worktreeIsolationFallback && { worktreeIsolationFallback: true as const }),
|
||||
};
|
||||
}
|
||||
|
||||
// Output schema - multi-agent spawned schema added dynamically at runtime when enabled
|
||||
export const outputSchema = lazySchema(() => {
|
||||
const syncOutputSchema = agentToolResultSchema().extend({
|
||||
@@ -910,16 +930,13 @@ export const AgentTool = buildTool({
|
||||
})));
|
||||
const canReadOutputFile = toolUseContext.options.tools.some(t => toolMatchesName(t, FILE_READ_TOOL_NAME) || toolMatchesName(t, BASH_TOOL_NAME));
|
||||
return {
|
||||
data: {
|
||||
isAsync: true as const,
|
||||
status: 'async_launched' as const,
|
||||
data: buildAsyncLaunchedToolData({
|
||||
agentId: agentBackgroundTask.agentId,
|
||||
description: description,
|
||||
prompt: prompt,
|
||||
outputFile: getTaskOutputPath(agentBackgroundTask.agentId),
|
||||
description,
|
||||
prompt,
|
||||
canReadOutputFile,
|
||||
...(worktreeIsolationFallback && { worktreeIsolationFallback: true as const }),
|
||||
}
|
||||
worktreeIsolationFallback,
|
||||
}),
|
||||
};
|
||||
} else {
|
||||
// Create an explicit agentId for sync agents
|
||||
@@ -1202,15 +1219,13 @@ export const AgentTool = buildTool({
|
||||
// Return async_launched result immediately
|
||||
const canReadOutputFile = toolUseContext.options.tools.some(t => toolMatchesName(t, FILE_READ_TOOL_NAME) || toolMatchesName(t, BASH_TOOL_NAME));
|
||||
return {
|
||||
data: {
|
||||
isAsync: true as const,
|
||||
status: 'async_launched' as const,
|
||||
data: buildAsyncLaunchedToolData({
|
||||
agentId: backgroundedTaskId,
|
||||
description: description,
|
||||
prompt: prompt,
|
||||
outputFile: getTaskOutputPath(backgroundedTaskId),
|
||||
canReadOutputFile
|
||||
}
|
||||
description,
|
||||
prompt,
|
||||
canReadOutputFile,
|
||||
worktreeIsolationFallback,
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user