code-agent: inherit child profile via env
This commit is contained in:
@@ -297,7 +297,7 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
|
||||
});
|
||||
let runnerJob = null;
|
||||
try {
|
||||
const runnerJobInput = buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities });
|
||||
const runnerJobInput = buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities, backendProfile });
|
||||
runnerJob = await agentRunJson(fetchImpl, managerUrl, `/api/v1/runs/${encodeURIComponent(reusable.mapping.runId)}/runner-jobs`, {
|
||||
method: "POST",
|
||||
body: runnerJobInput,
|
||||
@@ -395,7 +395,7 @@ export async function submitAgentRunChatTurn({ params = {}, options = {}, traceI
|
||||
message: "AgentRun command " + commandId + " created; hwlab-cloud-api will start a runner Job explicitly without relying on scheduler automation.",
|
||||
runId, commandId, backendProfile, waitingFor: "agentrun-runner-job-create", valuesPrinted: false,
|
||||
});
|
||||
const runnerJobInput = buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities });
|
||||
const runnerJobInput = buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities, backendProfile });
|
||||
try {
|
||||
runnerJob = await agentRunJson(fetchImpl, managerUrl, "/api/v1/runs/" + encodeURIComponent(runId) + "/runner-jobs", { method: "POST", body: runnerJobInput, timeoutMs });
|
||||
} catch (error) {
|
||||
@@ -933,8 +933,8 @@ async function resolveOwnerApiKey({ params, options, now }) {
|
||||
if (!key) return "";
|
||||
return text(key.displaySecret ?? "");
|
||||
}
|
||||
function buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities = null }) {
|
||||
const baseTransient = buildAgentRunTransientEnv(env);
|
||||
function buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, toolCapabilities = null, backendProfile }) {
|
||||
const baseTransient = buildAgentRunTransientEnv(env, { providerProfile: backendProfile, parentTraceId: traceId });
|
||||
const hwpodAllowed = toolCapabilityAllowed(toolCapabilities, "hwpod");
|
||||
const transientEnv = ownerApiKey && hwpodAllowed
|
||||
? baseTransient.concat([{ name: "HWLAB_API_KEY", value: ownerApiKey, sensitive: true }])
|
||||
@@ -953,7 +953,9 @@ function buildAgentRunRunnerJobInput({ env, traceId, commandId, ownerApiKey, too
|
||||
};
|
||||
}
|
||||
|
||||
function buildAgentRunTransientEnv(env = process.env) {
|
||||
function buildAgentRunTransientEnv(env = process.env, options = {}) {
|
||||
const providerProfile = firstNonEmpty(options.providerProfile);
|
||||
const parentTraceId = firstNonEmpty(options.parentTraceId);
|
||||
const entries = [];
|
||||
for (const name of [
|
||||
"HWLAB_RUNTIME_API_URL",
|
||||
@@ -967,6 +969,8 @@ function buildAgentRunTransientEnv(env = process.env) {
|
||||
const value = firstNonEmpty(env[name]);
|
||||
if (value) entries.push({ name, value, sensitive: false });
|
||||
}
|
||||
if (providerProfile) entries.push({ name: "HWLAB_CODE_AGENT_PROVIDER_PROFILE", value: providerProfile, sensitive: false });
|
||||
if (parentTraceId) entries.push({ name: "HWLAB_CODE_AGENT_PARENT_TRACE_ID", value: parentTraceId, sensitive: false });
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,9 @@ bun scripts/hwlab-code-agent-cli.ts result <traceId>
|
||||
bun scripts/hwlab-code-agent-cli.ts trace <traceId> [--full]
|
||||
```
|
||||
|
||||
输出均为 JSON。`spawn` 创建 session + 提交 prompt,立即返回 `sessionId` + `traceId`。`poll` 阻塞轮询至 terminal 或超时。
|
||||
`spawn` 的 profile 解析只认两种来源:显式 `--profile`,或环境变量 `HWLAB_CODE_AGENT_PROVIDER_PROFILE`。未提供时直接返回 `provider_profile_required`,不再静默回落 `deepseek`。
|
||||
|
||||
输出均为 JSON。`spawn` 创建 session + 提交 prompt,立即返回 `sessionId` + `traceId`,并暴露 `resolvedProviderProfile`、`profileSource`、`parentTraceId`。`poll` 阻塞轮询至 terminal 或超时。
|
||||
|
||||
### hwpod spec 自动继承
|
||||
|
||||
@@ -45,6 +47,15 @@ caserun 注入 .hwlab/hwpod-spec.yaml 到 Leader workspace
|
||||
-> Coder/Reviewer 拿到相同 spec
|
||||
```
|
||||
|
||||
provider profile 继承链:
|
||||
|
||||
```
|
||||
外层 AgentRun runner env 注入 HWLAB_CODE_AGENT_PROVIDER_PROFILE=当前 providerProfile
|
||||
-> Leader 调用 hwlab-code-agent spawn 且未显式传 --profile
|
||||
-> spawn 从同一环境变量继承 profile
|
||||
-> 子 agent 与父 agent 使用同一个 providerProfile
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 外部管理 CLI(G14 workspace 透传)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{
|
||||
"apiBaseUrl": "http://74.48.78.17:19666",
|
||||
"defaultProviderProfile": "deepseek",
|
||||
"defaultProjectId": "prj_hwpod_workbench",
|
||||
"defaultPollTimeoutMs": 300000
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ async function main() {
|
||||
process.stderr.write(JSON.stringify({
|
||||
ok: false,
|
||||
usage: {
|
||||
spawn: "bun scripts/hwlab-code-agent-cli.ts spawn --message '...' [--profile deepseek]",
|
||||
spawn: "HWLAB_CODE_AGENT_PROVIDER_PROFILE=PROFILE bun scripts/hwlab-code-agent-cli.ts spawn --message '...' [--profile PROFILE]",
|
||||
poll: "bun scripts/hwlab-code-agent-cli.ts poll <traceId> [--timeout 600000]",
|
||||
result: "bun scripts/hwlab-code-agent-cli.ts result <traceId>",
|
||||
trace: "bun scripts/hwlab-code-agent-cli.ts trace <traceId> [--full]"
|
||||
|
||||
@@ -13,11 +13,13 @@ const configPath = path.join(SKILL_ROOT, "config.json");
|
||||
|
||||
interface Config {
|
||||
apiBaseUrl: string;
|
||||
defaultProviderProfile: string;
|
||||
defaultProjectId: string;
|
||||
defaultPollTimeoutMs: number;
|
||||
}
|
||||
|
||||
const INHERITED_PROVIDER_PROFILE_ENV = "HWLAB_CODE_AGENT_PROVIDER_PROFILE";
|
||||
const PARENT_TRACE_ID_ENV = "HWLAB_CODE_AGENT_PARENT_TRACE_ID";
|
||||
|
||||
let _cfg: Config | null = null;
|
||||
function config(): Config {
|
||||
if (!_cfg) {
|
||||
@@ -27,11 +29,22 @@ function config(): Config {
|
||||
throw new Error(`hwlab-code-agent: failed to load config from ${configPath}`);
|
||||
}
|
||||
if (!_cfg.apiBaseUrl) throw new Error("hwlab-code-agent: config.apiBaseUrl is required");
|
||||
if (!_cfg.defaultProviderProfile) throw new Error("hwlab-code-agent: config.defaultProviderProfile is required");
|
||||
}
|
||||
return _cfg;
|
||||
}
|
||||
|
||||
function textValue(value: string | undefined): string {
|
||||
return String(value ?? "").trim();
|
||||
}
|
||||
|
||||
function resolveProviderProfile(args: Record<string, string | undefined>) {
|
||||
const explicit = textValue(args.profile || args.providerProfile);
|
||||
if (explicit) return { profile: explicit, source: "explicit" };
|
||||
const inherited = textValue(process.env[INHERITED_PROVIDER_PROFILE_ENV]);
|
||||
if (inherited) return { profile: inherited, source: "env" };
|
||||
fail("provider_profile_required", `spawn requires --profile or ${INHERITED_PROVIDER_PROFILE_ENV}`);
|
||||
}
|
||||
|
||||
// ---- workspace files auto-inheritance ----
|
||||
type WorkspaceFile = { path: string; content: string; encoding: "utf8" };
|
||||
|
||||
@@ -97,7 +110,8 @@ export interface SpawnResult {
|
||||
|
||||
export async function spawn(args: Record<string, string | undefined>): Promise<void> {
|
||||
const cfg = config();
|
||||
const profile = args.profile || cfg.defaultProviderProfile;
|
||||
const resolvedProfile = resolveProviderProfile(args);
|
||||
const profile = resolvedProfile.profile;
|
||||
const projectId = args.projectId || cfg.defaultProjectId;
|
||||
const message = args.message || (args.messageFile ? readFileSync(args.messageFile, "utf-8") : null);
|
||||
if (!message) fail("message_required", "--message or --message-file required");
|
||||
@@ -130,6 +144,10 @@ export async function spawn(args: Record<string, string | undefined>): Promise<v
|
||||
out({
|
||||
ok: true, action: "spawn",
|
||||
sessionId, traceId, conversationId,
|
||||
providerProfile: profile,
|
||||
resolvedProviderProfile: profile,
|
||||
profileSource: resolvedProfile.source,
|
||||
parentTraceId: textValue(process.env[PARENT_TRACE_ID_ENV]) || null,
|
||||
accepted: r.ok,
|
||||
acceptedBody: b,
|
||||
pollCommand: `bun scripts/hwlab-code-agent-cli.ts poll ${traceId}`,
|
||||
|
||||
Reference in New Issue
Block a user