a
This commit is contained in:
@@ -9,7 +9,6 @@ import {
|
||||
import { isDomainEventType, type DomainEventEmission } from "../agents/domain-events.js";
|
||||
import type { ActorExecutionInput, ActorExecutionResult, ActorExecutor } from "../agents/pipeline.js";
|
||||
import { isRecord, type JsonObject, type JsonValue } from "../agents/types.js";
|
||||
import { createSessionContext, type SessionContext } from "../examples/session-context.js";
|
||||
import { ClaudeObservabilityLogger } from "./claude-observability.js";
|
||||
|
||||
export type RunProvider = "codex" | "claude";
|
||||
@@ -17,7 +16,7 @@ export type RunProvider = "codex" | "claude";
|
||||
export type ProviderRunRuntime = {
|
||||
provider: RunProvider;
|
||||
config: Readonly<AppConfig>;
|
||||
sessionContext: SessionContext;
|
||||
sharedEnv: Record<string, string>;
|
||||
claudeObservability: ClaudeObservabilityLogger;
|
||||
close: () => Promise<void>;
|
||||
};
|
||||
@@ -30,6 +29,16 @@ type ProviderUsage = {
|
||||
costUsd?: number;
|
||||
};
|
||||
|
||||
function sanitizeEnv(input: Record<string, string | undefined>): Record<string, string> {
|
||||
const output: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(input)) {
|
||||
if (typeof value === "string") {
|
||||
output[key] = value;
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
const ACTOR_RESPONSE_SCHEMA = {
|
||||
type: "object",
|
||||
additionalProperties: true,
|
||||
@@ -74,8 +83,6 @@ const CLAUDE_OUTPUT_FORMAT = {
|
||||
schema: ACTOR_RESPONSE_SCHEMA,
|
||||
} as const;
|
||||
|
||||
const CLAUDE_PROVIDER_MAX_TURNS = 2;
|
||||
|
||||
function toErrorMessage(error: unknown): string {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
@@ -83,6 +90,23 @@ function toErrorMessage(error: unknown): string {
|
||||
return String(error);
|
||||
}
|
||||
|
||||
export function resolveProviderWorkingDirectory(actorInput: ActorExecutionInput): string {
|
||||
return actorInput.executionContext.security.worktreePath;
|
||||
}
|
||||
|
||||
export function buildProviderRuntimeEnv(input: {
|
||||
runtime: ProviderRunRuntime;
|
||||
actorInput: ActorExecutionInput;
|
||||
includeClaudeAuth?: boolean;
|
||||
}): Record<string, string> {
|
||||
const workingDirectory = resolveProviderWorkingDirectory(input.actorInput);
|
||||
return sanitizeEnv({
|
||||
...input.runtime.sharedEnv,
|
||||
...(input.includeClaudeAuth ? buildClaudeAuthEnv(input.runtime.config.provider) : {}),
|
||||
AGENT_WORKTREE_PATH: workingDirectory,
|
||||
});
|
||||
}
|
||||
|
||||
function toJsonValue(value: unknown): JsonValue {
|
||||
return JSON.parse(JSON.stringify(value)) as JsonValue;
|
||||
}
|
||||
@@ -367,6 +391,7 @@ async function runCodexActor(input: {
|
||||
const prompt = buildActorPrompt(actorInput);
|
||||
const startedAt = Date.now();
|
||||
const apiKey = resolveOpenAiApiKey(runtime.config.provider);
|
||||
const workingDirectory = resolveProviderWorkingDirectory(actorInput);
|
||||
|
||||
const codex = new Codex({
|
||||
...(apiKey ? { apiKey } : {}),
|
||||
@@ -376,20 +401,21 @@ async function runCodexActor(input: {
|
||||
...(actorInput.mcp.resolvedConfig.codexConfig
|
||||
? { config: actorInput.mcp.resolvedConfig.codexConfig }
|
||||
: {}),
|
||||
env: runtime.sessionContext.runtimeInjection.env,
|
||||
env: buildProviderRuntimeEnv({
|
||||
runtime,
|
||||
actorInput,
|
||||
}),
|
||||
});
|
||||
|
||||
const thread = codex.startThread({
|
||||
workingDirectory: runtime.sessionContext.runtimeInjection.workingDirectory,
|
||||
workingDirectory,
|
||||
skipGitRepoCheck: runtime.config.provider.codexSkipGitCheck,
|
||||
});
|
||||
|
||||
const turn = await runtime.sessionContext.runInSession(() =>
|
||||
thread.run(prompt, {
|
||||
signal: actorInput.signal,
|
||||
outputSchema: ACTOR_RESPONSE_SCHEMA,
|
||||
}),
|
||||
);
|
||||
const turn = await thread.run(prompt, {
|
||||
signal: actorInput.signal,
|
||||
outputSchema: ACTOR_RESPONSE_SCHEMA,
|
||||
});
|
||||
|
||||
const usage: ProviderUsage = {
|
||||
...(turn.usage
|
||||
@@ -457,6 +483,7 @@ function buildClaudeOptions(input: {
|
||||
actorInput: ActorExecutionInput;
|
||||
}): Options {
|
||||
const { runtime, actorInput } = input;
|
||||
const workingDirectory = resolveProviderWorkingDirectory(actorInput);
|
||||
|
||||
const authOptionOverrides = runtime.config.provider.anthropicOauthToken
|
||||
? { authToken: runtime.config.provider.anthropicOauthToken }
|
||||
@@ -465,14 +492,15 @@ function buildClaudeOptions(input: {
|
||||
return token ? { apiKey: token } : {};
|
||||
})();
|
||||
|
||||
const runtimeEnv = {
|
||||
...runtime.sessionContext.runtimeInjection.env,
|
||||
...buildClaudeAuthEnv(runtime.config.provider),
|
||||
};
|
||||
const runtimeEnv = buildProviderRuntimeEnv({
|
||||
runtime,
|
||||
actorInput,
|
||||
includeClaudeAuth: true,
|
||||
});
|
||||
const traceContext = toClaudeTraceContext(actorInput);
|
||||
|
||||
return {
|
||||
maxTurns: CLAUDE_PROVIDER_MAX_TURNS,
|
||||
maxTurns: runtime.config.provider.claudeMaxTurns,
|
||||
...(runtime.config.provider.claudeModel
|
||||
? { model: runtime.config.provider.claudeModel }
|
||||
: {}),
|
||||
@@ -484,7 +512,7 @@ function buildClaudeOptions(input: {
|
||||
? { mcpServers: actorInput.mcp.resolvedConfig.claudeMcpServers as Options["mcpServers"] }
|
||||
: {}),
|
||||
canUseTool: actorInput.mcp.createClaudeCanUseTool(),
|
||||
cwd: runtime.sessionContext.runtimeInjection.workingDirectory,
|
||||
cwd: workingDirectory,
|
||||
env: runtimeEnv,
|
||||
...runtime.claudeObservability.toOptionOverrides({
|
||||
context: traceContext,
|
||||
@@ -507,8 +535,8 @@ async function runClaudeTurn(input: {
|
||||
context: traceContext,
|
||||
data: {
|
||||
...(options.model ? { model: options.model } : {}),
|
||||
maxTurns: options.maxTurns ?? CLAUDE_PROVIDER_MAX_TURNS,
|
||||
cwd: input.runtime.sessionContext.runtimeInjection.workingDirectory,
|
||||
maxTurns: options.maxTurns ?? input.runtime.config.provider.claudeMaxTurns,
|
||||
...(typeof options.cwd === "string" ? { cwd: options.cwd } : {}),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -605,13 +633,11 @@ async function runClaudeActor(input: {
|
||||
actorInput: ActorExecutionInput;
|
||||
}): Promise<ActorExecutionResult> {
|
||||
const prompt = buildActorPrompt(input.actorInput);
|
||||
const turn = await input.runtime.sessionContext.runInSession(() =>
|
||||
runClaudeTurn({
|
||||
runtime: input.runtime,
|
||||
actorInput: input.actorInput,
|
||||
prompt,
|
||||
}),
|
||||
);
|
||||
const turn = await runClaudeTurn({
|
||||
runtime: input.runtime,
|
||||
actorInput: input.actorInput,
|
||||
prompt,
|
||||
});
|
||||
|
||||
const parsed = parseActorExecutionResultFromModelOutput({
|
||||
rawText: turn.text,
|
||||
@@ -626,33 +652,21 @@ async function runClaudeActor(input: {
|
||||
|
||||
export async function createProviderRunRuntime(input: {
|
||||
provider: RunProvider;
|
||||
initialPrompt: string;
|
||||
config: Readonly<AppConfig>;
|
||||
projectPath: string;
|
||||
observabilityRootPath?: string;
|
||||
baseEnv?: Record<string, string | undefined>;
|
||||
}): Promise<ProviderRunRuntime> {
|
||||
const sessionContext = await createSessionContext(input.provider, {
|
||||
prompt: input.initialPrompt,
|
||||
config: input.config,
|
||||
workspaceRoot: input.projectPath,
|
||||
});
|
||||
const claudeObservability = new ClaudeObservabilityLogger({
|
||||
workspaceRoot: input.observabilityRootPath ?? input.projectPath,
|
||||
workspaceRoot: input.observabilityRootPath ?? process.cwd(),
|
||||
config: input.config.provider.claudeObservability,
|
||||
});
|
||||
|
||||
return {
|
||||
provider: input.provider,
|
||||
config: input.config,
|
||||
sessionContext,
|
||||
sharedEnv: sanitizeEnv(input.baseEnv ?? process.env),
|
||||
claudeObservability,
|
||||
close: async () => {
|
||||
try {
|
||||
await sessionContext.close();
|
||||
} finally {
|
||||
await claudeObservability.close();
|
||||
}
|
||||
},
|
||||
close: async () => claudeObservability.close(),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user