Skip to content

Commit 6632ecf

Browse files
authored
Merge pull request #1003 from Automattic/issue/1002-agent-runtime-signal
Add agent runtime execution signal
2 parents c502d08 + b4484e8 commit 6632ecf

4 files changed

Lines changed: 87 additions & 2 deletions

File tree

packages/runtime-core/src/agent-task-recipe.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type { TaskInput } from "./task-input.js"
77
import { isPlainObject, stringList, stripUndefined } from "./object-utils.js"
88
import type { WorkspaceRecipe, WorkspaceRecipeMount, WorkspaceRecipeStagedFile } from "./runtime-contracts.js"
99

10+
const AGENT_RUNTIME_ENV = { WP_CODEBOX_AGENT_RUNTIME: "1" }
11+
1012
/**
1113
* Consumer-facing agent-task request fields accepted by the reusable recipe builder.
1214
*
@@ -113,7 +115,7 @@ export function buildAgentTaskRecipe(input: AgentTaskRunInput, taskInput: TaskIn
113115
...componentPlugins(input.component_contracts, artifacts),
114116
...providerPlugins,
115117
].filter(Boolean),
116-
runtimeEnv: runtimeEnv(input),
118+
runtimeEnv: { ...runtimeEnv(input), ...AGENT_RUNTIME_ENV },
117119
secretEnv: stringList(input.secret_env),
118120
stagedFiles: stagedFiles.length > 0 ? stagedFiles : undefined,
119121
agent_bundles: Array.isArray(input.agent_bundles) && input.agent_bundles.length > 0 ? input.agent_bundles : undefined,

packages/wordpress-plugin/src/class-wp-codebox-host-recipe-builder.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
final class WP_Codebox_Host_Recipe_Builder {
1111

12+
private const AGENT_RUNTIME_ENV = array( 'WP_CODEBOX_AGENT_RUNTIME' => '1' );
13+
1214
/**
1315
* @param array<int,array<string,mixed>> $paths Component contracts.
1416
* @param array<string,mixed> $input Ability input.
@@ -97,7 +99,7 @@ public function build( array $paths, array $input, array $task_prompts, string $
9799
'inherit' => $adapters['inheritance_request']( $input ),
98100
'inheritance' => $inheritance,
99101
'extra_plugins' => array_merge( $adapters['component_plugins']( $paths ), $provider_plugins ),
100-
'runtimeEnv' => $adapters['runtime_env']( $input ),
102+
'runtimeEnv' => array_merge( $adapters['runtime_env']( $input ), self::AGENT_RUNTIME_ENV ),
101103
'secretEnv' => $adapters['secret_env_names']( $input, $inheritance ),
102104
);
103105
if ( ! empty( $agent_bundles ) ) {
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import assert from "node:assert/strict"
2+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs"
3+
import { tmpdir } from "node:os"
4+
import { join } from "node:path"
5+
import { buildAgentTaskRecipe } from "../packages/runtime-core/src/agent-task-recipe.js"
6+
import { normalizeTaskInput } from "../packages/runtime-core/src/task-input.js"
7+
import { runRecipeRunCommand } from "../packages/cli/src/commands/recipe-run.js"
8+
9+
const root = mkdtempSync(join(tmpdir(), "wp-codebox-agent-runtime-signal-smoke-"))
10+
11+
try {
12+
const agentRecipe = buildAgentTaskRecipe({
13+
goal: "report agent runtime signal",
14+
runtime_env: { EXISTING_RUNTIME_ENV: "preserved", WP_CODEBOX_AGENT_RUNTIME: "caller-value" },
15+
}, normalizeTaskInput({ goal: "report agent runtime signal" }), "latest")
16+
assert.equal(agentRecipe.inputs?.runtimeEnv?.WP_CODEBOX_AGENT_RUNTIME, "1")
17+
assert.equal(agentRecipe.inputs?.runtimeEnv?.EXISTING_RUNTIME_ENV, "preserved")
18+
assert.ok(!agentRecipe.inputs?.secretEnv?.includes("WP_CODEBOX_AGENT_RUNTIME"))
19+
20+
agentRecipe.workflow.steps = [{
21+
command: "wp-codebox.agent-sandbox-run",
22+
args: [
23+
"task=report agent runtime signal",
24+
"code=echo getenv('WP_CODEBOX_AGENT_RUNTIME') ?: 'unset';",
25+
],
26+
}]
27+
const agentRecipePath = join(root, "agent-runtime-recipe.json")
28+
writeFileSync(agentRecipePath, JSON.stringify(agentRecipe, null, 2))
29+
30+
const agentOutput = await runRecipe(agentRecipePath)
31+
assert.equal(agentOutput.success, true)
32+
const agentPayload = JSON.parse(String(agentOutput.executions?.[0]?.stdout ?? "{}")) as { output?: string }
33+
assert.equal(agentPayload.output, "1")
34+
35+
const frontendRecipePath = join(root, "frontend-run-php-recipe.json")
36+
writeFileSync(frontendRecipePath, JSON.stringify({
37+
schema: "wp-codebox/workspace-recipe/v1",
38+
runtime: { backend: "wordpress-playground", wp: "latest", blueprint: { steps: [] } },
39+
inputs: {},
40+
workflow: {
41+
steps: [{
42+
command: "wordpress.run-php",
43+
args: ["code=echo getenv('WP_CODEBOX_AGENT_RUNTIME') ?: 'unset';"],
44+
}],
45+
},
46+
}, null, 2))
47+
48+
const frontendOutput = await runRecipe(frontendRecipePath)
49+
assert.equal(frontendOutput.success, true)
50+
assert.equal(frontendOutput.executions?.[0]?.stdout, "unset")
51+
52+
console.log("agent-runtime-signal-smoke: ok")
53+
} finally {
54+
rmSync(root, { recursive: true, force: true })
55+
}
56+
57+
async function runRecipe(recipePath: string): Promise<{ success?: boolean; executions?: Array<{ stdout?: string }> }> {
58+
const output = await captureStdout(async () => await runRecipeRunCommand(["--recipe", recipePath, "--json"]))
59+
return JSON.parse(output) as { success?: boolean; executions?: Array<{ stdout?: string }> }
60+
}
61+
62+
async function captureStdout(callback: () => Promise<unknown>): Promise<string> {
63+
const originalWrite = process.stdout.write.bind(process.stdout)
64+
let stdout = ""
65+
;(process.stdout.write as typeof process.stdout.write) = ((chunk: string | Uint8Array, encodingOrCallback?: BufferEncoding | ((error?: Error | null) => void), callback?: (error?: Error | null) => void) => {
66+
stdout += typeof chunk === "string" ? chunk : chunk.toString()
67+
if (typeof encodingOrCallback === "function") {
68+
encodingOrCallback()
69+
} else if (callback) {
70+
callback()
71+
}
72+
return true
73+
}) as typeof process.stdout.write
74+
try {
75+
await callback()
76+
return stdout
77+
} finally {
78+
process.stdout.write = originalWrite
79+
}
80+
}

scripts/smoke-manifest.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export const smokeGroups = {
7878
description: "Agent task, fanout, and delegation contract smoke checks.",
7979
commands: [
8080
tsxSmoke("agent-runtime-workload-normalizer-smoke"),
81+
tsxSmoke("agent-runtime-signal-smoke"),
8182
tsxSmoke("agent-sandbox-incomplete-scope-smoke"),
8283
tsxSmoke("recipe-run-summary-smoke"),
8384
tsxSmoke("fanout-contract-smoke"),

0 commit comments

Comments
 (0)