feat: プロバイダー非依存の permission_mode 値を導入し sandboxMode を設定可能にする (#87)
- permission_mode を readonly/edit/full に統一(プロバイダー非依存) - Claude SDK: readonly→default, edit→acceptEdits, full→bypassPermissions とマッピング - Codex SDK: readonly→read-only, edit→workspace-write, full→danger-full-access とマッピング - Legacy値(default/acceptEdits/bypassPermissions)のサポートを削除 - 全ビルトインワークフローを新しい permission_mode 値に更新 - AgentRunner の ProviderCallOptions 生成ロジックをリファクタリング(DRY化)
This commit is contained in:
parent
18894e2587
commit
7377c5f9d9
@ -99,7 +99,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: Implementation complete
|
- condition: Implementation complete
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -220,7 +220,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: AI issues fixed
|
- condition: AI issues fixed
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -389,7 +389,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: Fix complete
|
- condition: Fix complete
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -502,7 +502,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: Fix complete
|
- condition: Fix complete
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -515,7 +515,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: Fix complete
|
- condition: Fix complete
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -95,7 +95,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: Implementation complete
|
- condition: Implementation complete
|
||||||
next: ai_review
|
next: ai_review
|
||||||
|
|||||||
@ -90,7 +90,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: 実装完了
|
- condition: 実装完了
|
||||||
next: ai_review
|
next: ai_review
|
||||||
@ -215,7 +215,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
pass_previous_response: true
|
pass_previous_response: true
|
||||||
rules:
|
rules:
|
||||||
- condition: AI問題の修正完了
|
- condition: AI問題の修正完了
|
||||||
@ -395,7 +395,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: 修正完了
|
- condition: 修正完了
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -510,7 +510,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: 修正が完了した
|
- condition: 修正が完了した
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -501,7 +501,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
rules:
|
rules:
|
||||||
- condition: 修正が完了した
|
- condition: 修正が完了した
|
||||||
next: reviewers
|
next: reviewers
|
||||||
|
|||||||
@ -94,7 +94,7 @@ steps:
|
|||||||
- Bash
|
- Bash
|
||||||
- WebSearch
|
- WebSearch
|
||||||
- WebFetch
|
- WebFetch
|
||||||
permission_mode: acceptEdits
|
permission_mode: edit
|
||||||
instruction_template: |
|
instruction_template: |
|
||||||
planステップで立てた計画に従って実装してください。
|
planステップで立てた計画に従って実装してください。
|
||||||
計画レポート({report:00-plan.md})を参照し、実装を進めてください。
|
計画レポート({report:00-plan.md})を参照し、実装を進めてください。
|
||||||
|
|||||||
@ -43,14 +43,17 @@ describe('StatusSchema', () => {
|
|||||||
|
|
||||||
describe('PermissionModeSchema', () => {
|
describe('PermissionModeSchema', () => {
|
||||||
it('should accept valid permission modes', () => {
|
it('should accept valid permission modes', () => {
|
||||||
expect(PermissionModeSchema.parse('default')).toBe('default');
|
expect(PermissionModeSchema.parse('readonly')).toBe('readonly');
|
||||||
expect(PermissionModeSchema.parse('acceptEdits')).toBe('acceptEdits');
|
expect(PermissionModeSchema.parse('edit')).toBe('edit');
|
||||||
expect(PermissionModeSchema.parse('bypassPermissions')).toBe('bypassPermissions');
|
expect(PermissionModeSchema.parse('full')).toBe('full');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should reject invalid permission modes', () => {
|
it('should reject invalid permission modes', () => {
|
||||||
expect(() => PermissionModeSchema.parse('readOnly')).toThrow();
|
expect(() => PermissionModeSchema.parse('readOnly')).toThrow();
|
||||||
expect(() => PermissionModeSchema.parse('admin')).toThrow();
|
expect(() => PermissionModeSchema.parse('admin')).toThrow();
|
||||||
|
expect(() => PermissionModeSchema.parse('default')).toThrow();
|
||||||
|
expect(() => PermissionModeSchema.parse('acceptEdits')).toThrow();
|
||||||
|
expect(() => PermissionModeSchema.parse('bypassPermissions')).toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -87,7 +90,7 @@ describe('WorkflowConfigRawSchema', () => {
|
|||||||
name: 'implement',
|
name: 'implement',
|
||||||
agent: 'coder',
|
agent: 'coder',
|
||||||
allowed_tools: ['Read', 'Edit', 'Write', 'Bash'],
|
allowed_tools: ['Read', 'Edit', 'Write', 'Bash'],
|
||||||
permission_mode: 'acceptEdits',
|
permission_mode: 'edit',
|
||||||
instruction: '{task}',
|
instruction: '{task}',
|
||||||
rules: [
|
rules: [
|
||||||
{ condition: 'Done', next: 'COMPLETE' },
|
{ condition: 'Done', next: 'COMPLETE' },
|
||||||
@ -97,7 +100,7 @@ describe('WorkflowConfigRawSchema', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const result = WorkflowConfigRawSchema.parse(config);
|
const result = WorkflowConfigRawSchema.parse(config);
|
||||||
expect(result.steps[0]?.permission_mode).toBe('acceptEdits');
|
expect(result.steps[0]?.permission_mode).toBe('edit');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow omitting permission_mode', () => {
|
it('should allow omitting permission_mode', () => {
|
||||||
|
|||||||
54
src/__tests__/permission-mode.test.ts
Normal file
54
src/__tests__/permission-mode.test.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Tests for permission mode mapping functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, it, expect } from 'vitest';
|
||||||
|
import { SdkOptionsBuilder } from '../infra/claude/options-builder.js';
|
||||||
|
import { mapToCodexSandboxMode } from '../infra/codex/types.js';
|
||||||
|
import type { PermissionMode } from '../core/models/index.js';
|
||||||
|
|
||||||
|
describe('SdkOptionsBuilder.mapToSdkPermissionMode', () => {
|
||||||
|
it('should map readonly to SDK default', () => {
|
||||||
|
expect(SdkOptionsBuilder.mapToSdkPermissionMode('readonly')).toBe('default');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map edit to SDK acceptEdits', () => {
|
||||||
|
expect(SdkOptionsBuilder.mapToSdkPermissionMode('edit')).toBe('acceptEdits');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map full to SDK bypassPermissions', () => {
|
||||||
|
expect(SdkOptionsBuilder.mapToSdkPermissionMode('full')).toBe('bypassPermissions');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map all PermissionMode values exhaustively', () => {
|
||||||
|
const modes: PermissionMode[] = ['readonly', 'edit', 'full'];
|
||||||
|
for (const mode of modes) {
|
||||||
|
const result = SdkOptionsBuilder.mapToSdkPermissionMode(mode);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(typeof result).toBe('string');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('mapToCodexSandboxMode', () => {
|
||||||
|
it('should map readonly to read-only', () => {
|
||||||
|
expect(mapToCodexSandboxMode('readonly')).toBe('read-only');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map edit to workspace-write', () => {
|
||||||
|
expect(mapToCodexSandboxMode('edit')).toBe('workspace-write');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map full to danger-full-access', () => {
|
||||||
|
expect(mapToCodexSandboxMode('full')).toBe('danger-full-access');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should map all PermissionMode values exhaustively', () => {
|
||||||
|
const modes: PermissionMode[] = ['readonly', 'edit', 'full'];
|
||||||
|
for (const mode of modes) {
|
||||||
|
const result = mapToCodexSandboxMode(mode);
|
||||||
|
expect(result).toBeDefined();
|
||||||
|
expect(typeof result).toBe('string');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -154,6 +154,26 @@ export class AgentRunner {
|
|||||||
return provider.callCustom(agentConfig.name, task, systemPrompt, callOptions);
|
return provider.callCustom(agentConfig.name, task, systemPrompt, callOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Build ProviderCallOptions from RunAgentOptions with optional systemPrompt override */
|
||||||
|
private static buildProviderCallOptions(
|
||||||
|
options: RunAgentOptions,
|
||||||
|
systemPrompt?: string,
|
||||||
|
): ProviderCallOptions {
|
||||||
|
return {
|
||||||
|
cwd: options.cwd,
|
||||||
|
sessionId: options.sessionId,
|
||||||
|
allowedTools: options.allowedTools,
|
||||||
|
maxTurns: options.maxTurns,
|
||||||
|
model: AgentRunner.resolveModel(options.cwd, options),
|
||||||
|
systemPrompt,
|
||||||
|
permissionMode: options.permissionMode,
|
||||||
|
onStream: options.onStream,
|
||||||
|
onPermissionRequest: options.onPermissionRequest,
|
||||||
|
onAskUserQuestion: options.onAskUserQuestion,
|
||||||
|
bypassPermissions: options.bypassPermissions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/** Run an agent by name, path, inline prompt string, or no agent at all */
|
/** Run an agent by name, path, inline prompt string, or no agent at all */
|
||||||
async run(
|
async run(
|
||||||
agentSpec: string | undefined,
|
agentSpec: string | undefined,
|
||||||
@ -174,25 +194,9 @@ export class AgentRunner {
|
|||||||
// 1. If agentPath is provided (resolved file exists), load prompt from file
|
// 1. If agentPath is provided (resolved file exists), load prompt from file
|
||||||
if (options.agentPath) {
|
if (options.agentPath) {
|
||||||
const systemPrompt = AgentRunner.loadAgentPromptFromPath(options.agentPath);
|
const systemPrompt = AgentRunner.loadAgentPromptFromPath(options.agentPath);
|
||||||
|
|
||||||
const providerType = AgentRunner.resolveProvider(options.cwd, options);
|
const providerType = AgentRunner.resolveProvider(options.cwd, options);
|
||||||
const provider = getProvider(providerType);
|
const provider = getProvider(providerType);
|
||||||
|
return provider.call(agentName, task, AgentRunner.buildProviderCallOptions(options, systemPrompt));
|
||||||
const callOptions: ProviderCallOptions = {
|
|
||||||
cwd: options.cwd,
|
|
||||||
sessionId: options.sessionId,
|
|
||||||
allowedTools: options.allowedTools,
|
|
||||||
maxTurns: options.maxTurns,
|
|
||||||
model: AgentRunner.resolveModel(options.cwd, options),
|
|
||||||
systemPrompt,
|
|
||||||
permissionMode: options.permissionMode,
|
|
||||||
onStream: options.onStream,
|
|
||||||
onPermissionRequest: options.onPermissionRequest,
|
|
||||||
onAskUserQuestion: options.onAskUserQuestion,
|
|
||||||
bypassPermissions: options.bypassPermissions,
|
|
||||||
};
|
|
||||||
|
|
||||||
return provider.call(agentName, task, callOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. If agentSpec is provided but no agentPath (file not found), try custom agent first,
|
// 2. If agentSpec is provided but no agentPath (file not found), try custom agent first,
|
||||||
@ -207,42 +211,13 @@ export class AgentRunner {
|
|||||||
// Use agentSpec string as inline system prompt
|
// Use agentSpec string as inline system prompt
|
||||||
const providerType = AgentRunner.resolveProvider(options.cwd, options);
|
const providerType = AgentRunner.resolveProvider(options.cwd, options);
|
||||||
const provider = getProvider(providerType);
|
const provider = getProvider(providerType);
|
||||||
|
return provider.call(agentName, task, AgentRunner.buildProviderCallOptions(options, agentSpec));
|
||||||
const callOptions: ProviderCallOptions = {
|
|
||||||
cwd: options.cwd,
|
|
||||||
sessionId: options.sessionId,
|
|
||||||
allowedTools: options.allowedTools,
|
|
||||||
maxTurns: options.maxTurns,
|
|
||||||
model: AgentRunner.resolveModel(options.cwd, options),
|
|
||||||
systemPrompt: agentSpec,
|
|
||||||
permissionMode: options.permissionMode,
|
|
||||||
onStream: options.onStream,
|
|
||||||
onPermissionRequest: options.onPermissionRequest,
|
|
||||||
onAskUserQuestion: options.onAskUserQuestion,
|
|
||||||
bypassPermissions: options.bypassPermissions,
|
|
||||||
};
|
|
||||||
|
|
||||||
return provider.call(agentName, task, callOptions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. No agent specified — run with instruction_template only (no system prompt)
|
// 3. No agent specified — run with instruction_template only (no system prompt)
|
||||||
const providerType = AgentRunner.resolveProvider(options.cwd, options);
|
const providerType = AgentRunner.resolveProvider(options.cwd, options);
|
||||||
const provider = getProvider(providerType);
|
const provider = getProvider(providerType);
|
||||||
|
return provider.call(agentName, task, AgentRunner.buildProviderCallOptions(options));
|
||||||
const callOptions: ProviderCallOptions = {
|
|
||||||
cwd: options.cwd,
|
|
||||||
sessionId: options.sessionId,
|
|
||||||
allowedTools: options.allowedTools,
|
|
||||||
maxTurns: options.maxTurns,
|
|
||||||
model: AgentRunner.resolveModel(options.cwd, options),
|
|
||||||
permissionMode: options.permissionMode,
|
|
||||||
onStream: options.onStream,
|
|
||||||
onPermissionRequest: options.onPermissionRequest,
|
|
||||||
onAskUserQuestion: options.onAskUserQuestion,
|
|
||||||
bypassPermissions: options.bypassPermissions,
|
|
||||||
};
|
|
||||||
|
|
||||||
return provider.call(agentName, task, callOptions);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@ export const StatusSchema = z.enum([
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
/** Permission mode schema for tool execution */
|
/** Permission mode schema for tool execution */
|
||||||
export const PermissionModeSchema = z.enum(['default', 'acceptEdits', 'bypassPermissions']);
|
export const PermissionModeSchema = z.enum(['readonly', 'edit', 'full']);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report object schema (new structured format).
|
* Report object schema (new structured format).
|
||||||
|
|||||||
@ -25,5 +25,5 @@ export type RuleMatchMethod =
|
|||||||
| 'ai_judge'
|
| 'ai_judge'
|
||||||
| 'ai_judge_fallback';
|
| 'ai_judge_fallback';
|
||||||
|
|
||||||
/** Permission mode for tool execution */
|
/** Permission mode for tool execution (provider-agnostic) */
|
||||||
export type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions';
|
export type PermissionMode = 'readonly' | 'edit' | 'full';
|
||||||
|
|||||||
@ -14,8 +14,9 @@ import type {
|
|||||||
HookInput,
|
HookInput,
|
||||||
HookJSONOutput,
|
HookJSONOutput,
|
||||||
PreToolUseHookInput,
|
PreToolUseHookInput,
|
||||||
PermissionMode,
|
PermissionMode as SdkPermissionMode,
|
||||||
} from '@anthropic-ai/claude-agent-sdk';
|
} from '@anthropic-ai/claude-agent-sdk';
|
||||||
|
import type { PermissionMode } from '../../core/models/index.js';
|
||||||
import { createLogger } from '../../shared/utils/index.js';
|
import { createLogger } from '../../shared/utils/index.js';
|
||||||
import type {
|
import type {
|
||||||
PermissionHandler,
|
PermissionHandler,
|
||||||
@ -86,13 +87,23 @@ export class SdkOptionsBuilder {
|
|||||||
return sdkOptions;
|
return sdkOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Map TAKT PermissionMode to Claude SDK PermissionMode */
|
||||||
|
static mapToSdkPermissionMode(mode: PermissionMode): SdkPermissionMode {
|
||||||
|
const mapping: Record<PermissionMode, SdkPermissionMode> = {
|
||||||
|
readonly: 'default',
|
||||||
|
edit: 'acceptEdits',
|
||||||
|
full: 'bypassPermissions',
|
||||||
|
};
|
||||||
|
return mapping[mode];
|
||||||
|
}
|
||||||
|
|
||||||
/** Resolve permission mode with priority: bypassPermissions > explicit > callback-based > default */
|
/** Resolve permission mode with priority: bypassPermissions > explicit > callback-based > default */
|
||||||
private resolvePermissionMode(): PermissionMode {
|
private resolvePermissionMode(): SdkPermissionMode {
|
||||||
if (this.options.bypassPermissions) {
|
if (this.options.bypassPermissions) {
|
||||||
return 'bypassPermissions';
|
return 'bypassPermissions';
|
||||||
}
|
}
|
||||||
if (this.options.permissionMode) {
|
if (this.options.permissionMode) {
|
||||||
return this.options.permissionMode;
|
return SdkOptionsBuilder.mapToSdkPermissionMode(this.options.permissionMode);
|
||||||
}
|
}
|
||||||
if (this.options.onPermissionRequest) {
|
if (this.options.onPermissionRequest) {
|
||||||
return 'default';
|
return 'default';
|
||||||
|
|||||||
@ -152,8 +152,8 @@ export interface ClaudeSpawnOptions {
|
|||||||
onStream?: StreamCallback;
|
onStream?: StreamCallback;
|
||||||
/** Custom agents to register */
|
/** Custom agents to register */
|
||||||
agents?: Record<string, AgentDefinition>;
|
agents?: Record<string, AgentDefinition>;
|
||||||
/** Permission mode for tool execution (default: 'default' for interactive) */
|
/** Permission mode for tool execution (TAKT abstract value, mapped to SDK value in SdkOptionsBuilder) */
|
||||||
permissionMode?: SdkPermissionMode;
|
permissionMode?: PermissionMode;
|
||||||
/** Custom permission handler for interactive permission prompts */
|
/** Custom permission handler for interactive permission prompts */
|
||||||
onPermissionRequest?: PermissionHandler;
|
onPermissionRequest?: PermissionHandler;
|
||||||
/** Custom handler for AskUserQuestion tool */
|
/** Custom handler for AskUserQuestion tool */
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
import { Codex } from '@openai/codex-sdk';
|
import { Codex } from '@openai/codex-sdk';
|
||||||
import type { AgentResponse } from '../../core/models/index.js';
|
import type { AgentResponse } from '../../core/models/index.js';
|
||||||
import { createLogger, getErrorMessage } from '../../shared/utils/index.js';
|
import { createLogger, getErrorMessage } from '../../shared/utils/index.js';
|
||||||
import type { CodexCallOptions } from './types.js';
|
import { mapToCodexSandboxMode, type CodexCallOptions } from './types.js';
|
||||||
import {
|
import {
|
||||||
type CodexEvent,
|
type CodexEvent,
|
||||||
type CodexItem,
|
type CodexItem,
|
||||||
@ -39,9 +39,13 @@ export class CodexClient {
|
|||||||
options: CodexCallOptions,
|
options: CodexCallOptions,
|
||||||
): Promise<AgentResponse> {
|
): Promise<AgentResponse> {
|
||||||
const codex = new Codex(options.openaiApiKey ? { apiKey: options.openaiApiKey } : undefined);
|
const codex = new Codex(options.openaiApiKey ? { apiKey: options.openaiApiKey } : undefined);
|
||||||
|
const sandboxMode = options.permissionMode
|
||||||
|
? mapToCodexSandboxMode(options.permissionMode)
|
||||||
|
: 'workspace-write';
|
||||||
const threadOptions = {
|
const threadOptions = {
|
||||||
model: options.model,
|
model: options.model,
|
||||||
workingDirectory: options.cwd,
|
workingDirectory: options.cwd,
|
||||||
|
sandboxMode,
|
||||||
};
|
};
|
||||||
const thread = options.sessionId
|
const thread = options.sessionId
|
||||||
? await codex.resumeThread(options.sessionId, threadOptions)
|
? await codex.resumeThread(options.sessionId, threadOptions)
|
||||||
|
|||||||
@ -3,4 +3,5 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export { CodexClient, callCodex, callCodexCustom } from './client.js';
|
export { CodexClient, callCodex, callCodexCustom } from './client.js';
|
||||||
export type { CodexCallOptions } from './types.js';
|
export { mapToCodexSandboxMode } from './types.js';
|
||||||
|
export type { CodexCallOptions, CodexSandboxMode } from './types.js';
|
||||||
|
|||||||
@ -3,6 +3,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { StreamCallback } from '../claude/index.js';
|
import type { StreamCallback } from '../claude/index.js';
|
||||||
|
import type { PermissionMode } from '../../core/models/index.js';
|
||||||
|
|
||||||
|
/** Codex sandbox mode values */
|
||||||
|
export type CodexSandboxMode = 'read-only' | 'workspace-write' | 'danger-full-access';
|
||||||
|
|
||||||
|
/** Map TAKT PermissionMode to Codex sandbox mode */
|
||||||
|
export function mapToCodexSandboxMode(mode: PermissionMode): CodexSandboxMode {
|
||||||
|
const mapping: Record<PermissionMode, CodexSandboxMode> = {
|
||||||
|
readonly: 'read-only',
|
||||||
|
edit: 'workspace-write',
|
||||||
|
full: 'danger-full-access',
|
||||||
|
};
|
||||||
|
return mapping[mode];
|
||||||
|
}
|
||||||
|
|
||||||
/** Options for calling Codex */
|
/** Options for calling Codex */
|
||||||
export interface CodexCallOptions {
|
export interface CodexCallOptions {
|
||||||
@ -10,6 +24,8 @@ export interface CodexCallOptions {
|
|||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
model?: string;
|
model?: string;
|
||||||
systemPrompt?: string;
|
systemPrompt?: string;
|
||||||
|
/** Permission mode for sandbox configuration */
|
||||||
|
permissionMode?: PermissionMode;
|
||||||
/** Enable streaming mode with callback (best-effort) */
|
/** Enable streaming mode with callback (best-effort) */
|
||||||
onStream?: StreamCallback;
|
onStream?: StreamCallback;
|
||||||
/** OpenAI API key (bypasses CLI auth) */
|
/** OpenAI API key (bypasses CLI auth) */
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export class CodexProvider implements Provider {
|
|||||||
sessionId: options.sessionId,
|
sessionId: options.sessionId,
|
||||||
model: options.model,
|
model: options.model,
|
||||||
systemPrompt: options.systemPrompt,
|
systemPrompt: options.systemPrompt,
|
||||||
|
permissionMode: options.permissionMode,
|
||||||
onStream: options.onStream,
|
onStream: options.onStream,
|
||||||
openaiApiKey: options.openaiApiKey ?? resolveOpenaiApiKey(),
|
openaiApiKey: options.openaiApiKey ?? resolveOpenaiApiKey(),
|
||||||
};
|
};
|
||||||
@ -27,6 +28,7 @@ export class CodexProvider implements Provider {
|
|||||||
cwd: options.cwd,
|
cwd: options.cwd,
|
||||||
sessionId: options.sessionId,
|
sessionId: options.sessionId,
|
||||||
model: options.model,
|
model: options.model,
|
||||||
|
permissionMode: options.permissionMode,
|
||||||
onStream: options.onStream,
|
onStream: options.onStream,
|
||||||
openaiApiKey: options.openaiApiKey ?? resolveOpenaiApiKey(),
|
openaiApiKey: options.openaiApiKey ?? resolveOpenaiApiKey(),
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user