feat: assemble resource prompts and skills

This commit is contained in:
Codex
2026-06-02 20:40:14 +08:00
parent a53f5b8a0d
commit 3018b8a937
11 changed files with 394 additions and 15 deletions
+27 -5
View File
@@ -1,7 +1,7 @@
import { RunnerManagerApi, failureKindFromError, terminalStatusForFailure, errorMessage } from "./manager-api.js";
import { createBackendSession, runBackendTurn, type BackendActiveTurnControl, type BackendAdapterOptions, type BackendSession } from "../backend/adapter.js";
import { materializeResourceBundle } from "./resource-bundle.js";
import type { BackendEvent, BackendProfile, CommandRecord, FailureKind, JsonRecord, RunRecord, RunnerRecord, TerminalStatus } from "../common/types.js";
import type { BackendEvent, BackendProfile, CommandRecord, FailureKind, InitialPromptAssembly, JsonRecord, RunRecord, RunnerRecord, TerminalStatus } from "../common/types.js";
import { AgentRunError } from "../common/errors.js";
export interface RunnerOnceOptions extends BackendAdapterOptions {
@@ -66,6 +66,7 @@ export async function runOnce(options: RunnerOnceOptions): Promise<JsonRecord> {
const commandResults: CommandExecutionResult[] = [];
let workspacePath: string | undefined;
let resourceEnv: NodeJS.ProcessEnv | undefined;
let initialPrompt: InitialPromptAssembly | undefined;
let materializationAttempted = false;
let materializationFailure: { failureKind: FailureKind; terminalStatus: TerminalStatus; message: string } | null = null;
let backendSession: BackendSession | null = null;
@@ -95,7 +96,8 @@ export async function runOnce(options: RunnerOnceOptions): Promise<JsonRecord> {
const materialized = await materializeResourceBundle(claimed.resourceBundleRef ?? null, options.env ?? process.env);
if (materialized) {
workspacePath = materialized.workspacePath;
resourceEnv = materialized.binPath ? prependPath(options.env ?? process.env, materialized.binPath) : undefined;
resourceEnv = resourceEnvForMaterialized(options.env ?? process.env, materialized);
initialPrompt = materialized.initialPrompt;
await api.appendEvent(options.runId, { type: "backend_status", payload: { ...materialized.event, commandId: command.id, attemptId, runnerId: runner.id } });
}
} catch (error) {
@@ -106,7 +108,7 @@ export async function runOnce(options: RunnerOnceOptions): Promise<JsonRecord> {
const result = materializationFailure
? await reportCommandFailure(api, options.runId, command.id, runner, attemptId, materializationFailure, "runner:resource-bundle")
: await executeCommand(api, withResourceEnv(options, resourceEnv), command, runner, attemptId, workspacePath, backendSession ?? (backendSession = createBackendSession(currentRun, withResourceEnv(options, resourceEnv))));
: await executeCommand(api, withResourceAssembly(options, resourceEnv, initialPrompt), command, runner, attemptId, workspacePath, backendSession ?? (backendSession = createBackendSession(currentRun, withResourceAssembly(options, resourceEnv, initialPrompt))));
commandResults.push(result);
if (options.oneShot === true) {
const run = await api.reportStatus(options.runId, { terminalStatus: result.terminalStatus, failureKind: result.failureKind, failureMessage: null });
@@ -133,8 +135,28 @@ export async function runOnce(options: RunnerOnceOptions): Promise<JsonRecord> {
}
}
function withResourceEnv(options: RunnerOnceOptions, resourceEnv: NodeJS.ProcessEnv | undefined): RunnerOnceOptions {
return resourceEnv ? { ...options, env: resourceEnv } : options;
function withResourceAssembly(options: RunnerOnceOptions, resourceEnv: NodeJS.ProcessEnv | undefined, initialPrompt: InitialPromptAssembly | undefined): RunnerOnceOptions {
return {
...options,
...(resourceEnv ? { env: resourceEnv } : {}),
...(initialPrompt ? { initialPrompt } : {}),
};
}
function resourceEnvForMaterialized(env: NodeJS.ProcessEnv, materialized: Awaited<ReturnType<typeof materializeResourceBundle>>): NodeJS.ProcessEnv | undefined {
if (!materialized) return undefined;
let next: NodeJS.ProcessEnv | undefined;
if (materialized.binPath) next = prependPath(env, materialized.binPath);
if (materialized.skillsDir) {
const base = next ?? { ...env };
const previous = base.AGENTRUN_SKILLS_DIRS;
next = {
...base,
AGENTRUN_SKILLS_DIRS: previous && previous.trim().length > 0 ? `${materialized.skillsDir}${pathDelimiter()}${previous}` : materialized.skillsDir,
HWLAB_CODE_AGENT_SKILLS_DIRS: materialized.skillsDir,
};
}
return next;
}
function prependPath(env: NodeJS.ProcessEnv, binPath: string): NodeJS.ProcessEnv {