mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
feat: add configurable sandbox mode setting
Add a global setting to enable/disable sandbox mode for Claude Agent SDK. This allows users to control sandbox behavior based on their authentication setup and system compatibility. Changes: - Add enableSandboxMode to GlobalSettings (default: true) - Add sandbox mode checkbox in Claude settings UI - Wire up setting through app store and settings service - Update createChatOptions and createAutoModeOptions to use setting - Add getEnableSandboxModeSetting helper function - Remove hardcoded sandbox configuration from ClaudeProvider - Add detailed logging throughout agent execution flow The sandbox mode requires API key or OAuth token authentication. Users experiencing issues with CLI-only auth can disable it in settings. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,11 @@ import { ProviderFactory } from '../providers/provider-factory.js';
|
||||
import { createChatOptions, validateWorkingDirectory } from '../lib/sdk-options.js';
|
||||
import { PathNotAllowedError } from '@automaker/platform';
|
||||
import type { SettingsService } from './settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting, filterClaudeMdFromContext } from '../lib/settings-helpers.js';
|
||||
import {
|
||||
getAutoLoadClaudeMdSetting,
|
||||
getEnableSandboxModeSetting,
|
||||
filterClaudeMdFromContext,
|
||||
} from '../lib/settings-helpers.js';
|
||||
|
||||
interface Message {
|
||||
id: string;
|
||||
@@ -140,12 +144,29 @@ export class AgentService {
|
||||
imagePaths?: string[];
|
||||
model?: string;
|
||||
}) {
|
||||
console.log('[AgentService] sendMessage() called:', {
|
||||
sessionId,
|
||||
messageLength: message?.length,
|
||||
workingDirectory,
|
||||
imageCount: imagePaths?.length || 0,
|
||||
model,
|
||||
});
|
||||
|
||||
const session = this.sessions.get(sessionId);
|
||||
if (!session) {
|
||||
console.error('[AgentService] ERROR: Session not found:', sessionId);
|
||||
throw new Error(`Session ${sessionId} not found`);
|
||||
}
|
||||
|
||||
console.log('[AgentService] Session found:', {
|
||||
sessionId,
|
||||
messageCount: session.messages.length,
|
||||
isRunning: session.isRunning,
|
||||
workingDirectory: session.workingDirectory,
|
||||
});
|
||||
|
||||
if (session.isRunning) {
|
||||
console.error('[AgentService] ERROR: Agent already running for session:', sessionId);
|
||||
throw new Error('Agent is already processing a message');
|
||||
}
|
||||
|
||||
@@ -192,16 +213,19 @@ export class AgentService {
|
||||
session.abortController = new AbortController();
|
||||
|
||||
// Emit started event so UI can show thinking indicator
|
||||
console.log('[AgentService] Emitting "started" event for session:', sessionId);
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'started',
|
||||
});
|
||||
|
||||
// Emit user message event
|
||||
console.log('[AgentService] Emitting "message" event for session:', sessionId);
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'message',
|
||||
message: userMessage,
|
||||
});
|
||||
|
||||
console.log('[AgentService] Saving session messages');
|
||||
await this.saveSession(sessionId, session.messages);
|
||||
|
||||
try {
|
||||
@@ -215,6 +239,12 @@ export class AgentService {
|
||||
'[AgentService]'
|
||||
);
|
||||
|
||||
// Load enableSandboxMode setting (global setting only)
|
||||
const enableSandboxMode = await getEnableSandboxModeSetting(
|
||||
this.settingsService,
|
||||
'[AgentService]'
|
||||
);
|
||||
|
||||
// Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.)
|
||||
const contextResult = await loadContextFiles({
|
||||
projectPath: effectiveWorkDir,
|
||||
@@ -239,6 +269,7 @@ export class AgentService {
|
||||
systemPrompt: combinedSystemPrompt,
|
||||
abortController: session.abortController!,
|
||||
autoLoadClaudeMd,
|
||||
enableSandboxMode,
|
||||
});
|
||||
|
||||
// Extract model, maxTurns, and allowedTools from SDK options
|
||||
@@ -247,6 +278,7 @@ export class AgentService {
|
||||
const allowedTools = sdkOptions.allowedTools as string[] | undefined;
|
||||
|
||||
// Get provider for this model
|
||||
console.log('[AgentService] Getting provider for model:', effectiveModel);
|
||||
const provider = ProviderFactory.getProviderForModel(effectiveModel);
|
||||
|
||||
console.log(
|
||||
@@ -267,6 +299,7 @@ export class AgentService {
|
||||
sdkSessionId: session.sdkSessionId, // Pass SDK session ID for resuming
|
||||
};
|
||||
|
||||
console.log('[AgentService] Building prompt with images...');
|
||||
// Build prompt content with images
|
||||
const { content: promptContent } = await buildPromptWithImages(
|
||||
message,
|
||||
@@ -278,14 +311,32 @@ export class AgentService {
|
||||
// Set the prompt in options
|
||||
options.prompt = promptContent;
|
||||
|
||||
console.log('[AgentService] Executing query via provider:', {
|
||||
model: effectiveModel,
|
||||
promptLength: typeof promptContent === 'string' ? promptContent.length : 'array',
|
||||
hasConversationHistory: !!conversationHistory.length,
|
||||
sdkSessionId: session.sdkSessionId,
|
||||
});
|
||||
|
||||
// Execute via provider
|
||||
const stream = provider.executeQuery(options);
|
||||
console.log('[AgentService] Stream created, starting to iterate...');
|
||||
|
||||
let currentAssistantMessage: Message | null = null;
|
||||
let responseText = '';
|
||||
const toolUses: Array<{ name: string; input: unknown }> = [];
|
||||
let messageCount = 0;
|
||||
|
||||
console.log('[AgentService] Entering stream loop...');
|
||||
for await (const msg of stream) {
|
||||
messageCount++;
|
||||
console.log(`[AgentService] Stream message #${messageCount}:`, {
|
||||
type: msg.type,
|
||||
subtype: (msg as any).subtype,
|
||||
hasContent: !!(msg as any).message?.content,
|
||||
session_id: msg.session_id,
|
||||
});
|
||||
|
||||
// Capture SDK session ID from any message and persist it
|
||||
if (msg.session_id && !session.sdkSessionId) {
|
||||
session.sdkSessionId = msg.session_id;
|
||||
@@ -295,6 +346,7 @@ export class AgentService {
|
||||
}
|
||||
|
||||
if (msg.type === 'assistant') {
|
||||
console.log('[AgentService] Processing assistant message...');
|
||||
if (msg.message?.content) {
|
||||
for (const block of msg.message.content) {
|
||||
if (block.type === 'text') {
|
||||
@@ -312,6 +364,10 @@ export class AgentService {
|
||||
currentAssistantMessage.content = responseText;
|
||||
}
|
||||
|
||||
console.log(
|
||||
'[AgentService] Emitting "stream" event, text length:',
|
||||
responseText.length
|
||||
);
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'stream',
|
||||
messageId: currentAssistantMessage.id,
|
||||
@@ -325,6 +381,7 @@ export class AgentService {
|
||||
};
|
||||
toolUses.push(toolUse);
|
||||
|
||||
console.log('[AgentService] Tool use detected:', toolUse.name);
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'tool_use',
|
||||
tool: toolUse,
|
||||
@@ -333,6 +390,7 @@ export class AgentService {
|
||||
}
|
||||
}
|
||||
} else if (msg.type === 'result') {
|
||||
console.log('[AgentService] Result message received, subtype:', (msg as any).subtype);
|
||||
if (msg.subtype === 'success' && msg.result) {
|
||||
if (currentAssistantMessage) {
|
||||
currentAssistantMessage.content = msg.result;
|
||||
@@ -340,6 +398,7 @@ export class AgentService {
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[AgentService] Emitting "complete" event');
|
||||
this.emitAgentEvent(sessionId, {
|
||||
type: 'complete',
|
||||
messageId: currentAssistantMessage?.id,
|
||||
@@ -349,6 +408,8 @@ export class AgentService {
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[AgentService] Stream loop completed, total messages:', messageCount);
|
||||
|
||||
await this.saveSession(sessionId, session.messages);
|
||||
|
||||
session.isRunning = false;
|
||||
@@ -757,7 +818,13 @@ export class AgentService {
|
||||
}
|
||||
|
||||
private emitAgentEvent(sessionId: string, data: Record<string, unknown>): void {
|
||||
console.log('[AgentService] emitAgentEvent() called:', {
|
||||
sessionId,
|
||||
eventType: data.type,
|
||||
dataKeys: Object.keys(data),
|
||||
});
|
||||
this.events.emit('agent:stream', { sessionId, ...data });
|
||||
console.log('[AgentService] Event emitted to EventEmitter');
|
||||
}
|
||||
|
||||
private getSystemPrompt(): string {
|
||||
|
||||
@@ -32,7 +32,11 @@ import {
|
||||
} from '../lib/sdk-options.js';
|
||||
import { FeatureLoader } from './feature-loader.js';
|
||||
import type { SettingsService } from './settings-service.js';
|
||||
import { getAutoLoadClaudeMdSetting, filterClaudeMdFromContext } from '../lib/settings-helpers.js';
|
||||
import {
|
||||
getAutoLoadClaudeMdSetting,
|
||||
getEnableSandboxModeSetting,
|
||||
filterClaudeMdFromContext,
|
||||
} from '../lib/settings-helpers.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
@@ -1833,12 +1837,16 @@ This mock response was generated because AUTOMAKER_MOCK_AGENT=true was set.
|
||||
? options.autoLoadClaudeMd
|
||||
: await getAutoLoadClaudeMdSetting(finalProjectPath, this.settingsService, '[AutoMode]');
|
||||
|
||||
// Load enableSandboxMode setting (global setting only)
|
||||
const enableSandboxMode = await getEnableSandboxModeSetting(this.settingsService, '[AutoMode]');
|
||||
|
||||
// Build SDK options using centralized configuration for feature implementation
|
||||
const sdkOptions = createAutoModeOptions({
|
||||
cwd: workDir,
|
||||
model: model,
|
||||
abortController,
|
||||
autoLoadClaudeMd,
|
||||
enableSandboxMode,
|
||||
});
|
||||
|
||||
// Extract model, maxTurns, and allowedTools from SDK options
|
||||
|
||||
Reference in New Issue
Block a user