Skip to content

Commit 7dd32b7

Browse files
authored
Execute imported runtime package agent (#1782)
* Bind imported runtime package agent identity (#1781) * Test imported runtime package selection
1 parent e9147ff commit 7dd32b7

8 files changed

Lines changed: 197 additions & 69 deletions

.github/workflows/agent-task-contracts.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ jobs:
5555
- run: npm run build
5656
- run: npm run test:agent-task-contracts
5757
- run: npm run test:runtime-sources-playground-integration
58-
env:
59-
WP_CODEBOX_RUN_NETWORK_INTEGRATION: "1"
6058
- run: npm run test:redaction
6159
- run: npm run test:production-boundary-enforcement
6260
- run: npm run test:runtime-tool-policy

packages/cli/src/agent-code.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,8 @@ $sandbox_external_runtime_package_import = wp_codebox_import_external_runtime_ag
110110
$sandbox_stack['external_runtime_package_import'] = $sandbox_external_runtime_package_import;
111111
if (!empty($sandbox_external_runtime_package_import['success']) && empty($sandbox_external_runtime_package_import['skipped'])) {
112112
$sandbox_imported_agent = (string) ($sandbox_external_runtime_package_import['identity']['slug'] ?? '');
113-
if (is_array($sandbox_runtime_task) && '' !== $sandbox_imported_agent) {
114-
$sandbox_runtime_task['input']['package']['slug'] = $sandbox_imported_agent;
115-
$sandbox_runtime_task['input']['package']['bootstrap_imported'] = true;
116-
$sandbox_runtime_task['input']['metadata']['imported_agent'] = array('slug' => $sandbox_imported_agent);
117-
}
113+
$sandbox_external_runtime_package_import = wp_codebox_bind_external_runtime_package_identity($sandbox_runtime_task, $sandbox_imported_agent, $sandbox_external_runtime_package_import);
114+
$sandbox_stack['external_runtime_package_import'] = $sandbox_external_runtime_package_import;
118115
}
119116
120117
add_filter('agents_chat_runtime_principal_permission', static function (bool $allowed, $principal, array $input): bool {
@@ -263,6 +260,31 @@ function wp_codebox_import_external_runtime_agent_package(array $runtime_task):
263260
}
264261
}
265262
263+
function wp_codebox_bind_external_runtime_package_identity(&$runtime_task, string $agent_slug, array $import): array {
264+
if (!is_array($runtime_task) || '' === $agent_slug) {
265+
return array('success' => false, 'error' => array('code' => 'wp_codebox_external_runtime_package_identity_missing', 'message' => 'Canonical runtime package import did not produce one agent identity.'));
266+
}
267+
$task_input = is_array($runtime_task['input'] ?? null) ? $runtime_task['input'] : null;
268+
$package = is_array($task_input['package'] ?? null) ? $task_input['package'] : null;
269+
$chat_input = is_array($task_input['input'] ?? null) ? $task_input['input'] : array();
270+
$metadata = is_array($task_input['metadata'] ?? null) ? $task_input['metadata'] : array();
271+
$requested_package_slug = is_array($package) ? (string) ($package['slug'] ?? '') : '';
272+
$requested_agent_slug = is_array($chat_input) ? (string) ($chat_input['agent'] ?? '') : '';
273+
$metadata_agent_slug = is_array($metadata['imported_agent'] ?? null) ? (string) ($metadata['imported_agent']['slug'] ?? '') : '';
274+
if (!is_array($package) || ('' !== $requested_package_slug && !hash_equals($agent_slug, $requested_package_slug)) || ('' !== $requested_agent_slug && !hash_equals($agent_slug, $requested_agent_slug)) || ('' !== $metadata_agent_slug && !hash_equals($agent_slug, $metadata_agent_slug))) {
275+
return array('success' => false, 'error' => array('code' => 'wp_codebox_external_runtime_package_identity_mismatch', 'message' => 'Runtime package execution must use the single agent identity verified during canonical import.'));
276+
}
277+
$package['slug'] = $agent_slug;
278+
$package['bootstrap_imported'] = true;
279+
$chat_input['agent'] = $agent_slug;
280+
$metadata['imported_agent'] = array('slug' => $agent_slug);
281+
$task_input['package'] = $package;
282+
$task_input['input'] = $chat_input;
283+
$task_input['metadata'] = $metadata;
284+
$runtime_task['input'] = $task_input;
285+
return $import;
286+
}
287+
266288
function wp_codebox_json_encode_agent_runtime_payload($value): string {
267289
$json = wp_json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE);
268290
if (false !== $json) {

packages/wordpress-plugin/src/class-wp-codebox-runtime-package-executor.php

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,17 @@ public function run( array $task ): array|WP_Error {
4141
return $imports;
4242
}
4343

44-
$agent_slug = $this->imported_agent_slug( $task );
44+
$agent_slug = $this->imported_agent_slug( $task, $imports );
4545
if ( is_wp_error( $agent_slug ) ) {
4646
return $agent_slug;
4747
}
48-
if ( '' !== $agent_slug ) {
49-
$input = is_array( $task['input'] ?? null ) ? $task['input'] : array();
50-
$input['agent'] = $agent_slug;
51-
$task['input'] = $input;
48+
$input = is_array( $task['input'] ?? null ) ? $task['input'] : array();
49+
$requested_agent = $this->string_value( $input['agent'] ?? '' );
50+
if ( '' !== $requested_agent && ! hash_equals( $agent_slug, $requested_agent ) ) {
51+
return new WP_Error( 'wp_codebox_runtime_package_agent_identity_mismatch', 'Runtime package execution must use the agent identity verified during import.', array( 'status' => 400 ) );
5252
}
53+
$input['agent'] = $agent_slug;
54+
$task['input'] = $input;
5355

5456
$result = $this->execute_workflow( $task );
5557
if ( is_wp_error( $result ) ) {
@@ -118,9 +120,6 @@ private function execute_workflow( array $task ): array|WP_Error {
118120
$ability = 'agents/chat';
119121
$input = is_array( $task['input'] ?? null ) ? $task['input'] : array();
120122
$package = is_array( $task['package'] ?? null ) ? $task['package'] : array();
121-
if ( ! isset( $input['agent'] ) && '' !== $this->string_value( $package['slug'] ?? '' ) ) {
122-
$input['agent'] = $this->string_value( $package['slug'] );
123-
}
124123
if ( ! isset( $input['message'] ) ) {
125124
$input['message'] = $this->string_value( $input['prompt'] ?? '' );
126125
}
@@ -149,16 +148,22 @@ private function execute_workflow( array $task ): array|WP_Error {
149148
return $result;
150149
}
151150

152-
/** @param array<string,mixed> $task Runtime package task. @return string|WP_Error */
153-
private function imported_agent_slug( array $task ): string|WP_Error {
151+
/** @param array<string,mixed> $task Runtime package task. @param array<int,array<string,mixed>> $imports Import results. @return string|WP_Error */
152+
private function imported_agent_slug( array $task, array $imports ): string|WP_Error {
154153
$package = is_array( $task['package'] ?? null ) ? $task['package'] : array();
154+
$imported_slugs = array_values( array_unique( array_filter( array_map( static fn( mixed $import ): string => is_array( $import ) && ! empty( $import['success'] ) ? trim( (string) ( $import['agent_slug'] ?? '' ) ) : '', $imports ) ) ) );
155+
if ( 1 !== count( $imports ) || 1 !== count( $imported_slugs ) ) {
156+
return new WP_Error( 'wp_codebox_runtime_package_imported_agent_unresolved', 'Runtime package import must resolve exactly one agent identity.', array( 'status' => 400 ) );
157+
}
158+
$slug = $imported_slugs[0];
159+
if ( ! hash_equals( $slug, $this->string_value( $package['slug'] ?? '' ) ) || ! function_exists( 'wp_get_agent' ) || ! wp_get_agent( $slug ) ) {
160+
return new WP_Error( 'wp_codebox_runtime_package_imported_agent_unresolved', 'The imported runtime package agent identity did not resolve exactly.', array( 'status' => 400 ) );
161+
}
155162
if ( empty( $package['bootstrap_imported'] ) ) {
156-
return '';
163+
return $slug;
157164
}
158-
$metadata = is_array( $task['metadata'] ?? null ) ? $task['metadata'] : array();
159-
$slug = $this->string_value( $metadata['imported_agent']['slug'] ?? '' );
160165
$bootstrap = is_array( $GLOBALS['wp_codebox_private_runtime_package_import'] ?? null ) ? $GLOBALS['wp_codebox_private_runtime_package_import'] : array();
161-
if ( '' === $slug || ! hash_equals( $slug, $this->string_value( $bootstrap['identity']['slug'] ?? '' ) ) || ! function_exists( 'wp_get_agent' ) || ! wp_get_agent( $slug ) ) {
166+
if ( ! hash_equals( $slug, $this->string_value( $bootstrap['identity']['slug'] ?? '' ) ) ) {
162167
return new WP_Error( 'wp_codebox_runtime_package_imported_agent_unresolved', 'The imported runtime package agent identity did not resolve exactly.', array( 'status' => 400 ) );
163168
}
164169

scripts/php-runtime-package-public-contract-smoke.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,13 +164,18 @@ function wp_get_ability( string $name ): ?WP_Codebox_Runtime_Package_Smoke_Abili
164164
);
165165
$GLOBALS['wp_codebox_runtime_package_registered_agents']['store-idea-agent'] = true;
166166
$bootstrap_task = $wpsg_like_task;
167-
$bootstrap_task['package']['slug'] = 'caller-controlled-agent';
168167
$bootstrap_task['package']['bootstrap_imported'] = true;
169-
$bootstrap_task['input']['agent'] = 'caller-controlled-agent';
168+
$bootstrap_task['input']['agent'] = 'store-idea-agent';
170169
$bootstrap = WP_Codebox_Abilities::run_runtime_package( $bootstrap_task + array( 'runtime_provider' => 'codebox-runtime-package' ) );
171170
assert( ! is_wp_error( $bootstrap ) );
172171
assert( 'store-idea-agent' === $GLOBALS['wp_codebox_runtime_package_smoke_input']['agent'] );
173172

173+
$spoofed_bootstrap_task = $bootstrap_task;
174+
$spoofed_bootstrap_task['input']['agent'] = 'caller-controlled-agent';
175+
$spoofed_bootstrap = WP_Codebox_Abilities::run_runtime_package( $spoofed_bootstrap_task + array( 'runtime_provider' => 'codebox-runtime-package' ) );
176+
assert( is_wp_error( $spoofed_bootstrap ) );
177+
assert( 'wp_codebox_runtime_package_agent_identity_mismatch' === $spoofed_bootstrap->get_error_code() );
178+
174179
file_put_contents( $staged_bundle_file, "tampered\n" );
175180
$tampered = WP_Codebox_Abilities::run_runtime_package( $wpsg_like_task + array( 'runtime_provider' => 'codebox-runtime-package' ) );
176181
assert( is_wp_error( $tampered ) );

tests/agent-no-data-machine-loop.test.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,16 +175,19 @@ assert.match(sandboxAgentCode, /'model' => \$configured_model/)
175175
const docsAgentDirectory = process.env.DOCS_AGENT_DIR
176176
const publicPackageBytes = docsAgentDirectory
177177
? await readFile(join(docsAgentDirectory, "bundles", "technical-docs-agent", "native", "technical-docs-maintenance-agent.agent.json"))
178-
: await readFile(new URL("./fixtures/external-native-package/flat-agent.agent.json", import.meta.url))
178+
: await readFile(new URL("./fixtures/external-native-package/technical-bootstrap-agent.agent.json", import.meta.url))
179179
const publicAgentSlug = canonicalExternalNativeAgentIdentity(publicPackageBytes).slug
180+
const skillsPackageBytes = await readFile(new URL("./fixtures/external-native-package/skills-agent.agent.json", import.meta.url))
181+
assert.deepEqual(canonicalExternalNativeAgentIdentity(skillsPackageBytes), { slug: "skills-agent" })
182+
assert.deepEqual(canonicalExternalNativeAgentIdentity(publicPackageBytes), { slug: docsAgentDirectory ? "technical-docs-maintenance-agent" : "technical-bootstrap-agent" })
180183
const publicPackageDigest = `sha256-bytes-v1:${await import("node:crypto").then(({ createHash }) => createHash("sha256").update(publicPackageBytes).digest("hex"))}`
181184
const bootstrapCode = await resolveSandboxTaskCode({
182185
task: "Say hello",
183186
agent: "wp-codebox-sandbox",
184187
runtimeTask: {
185188
ability: "wp-codebox/run-runtime-package",
186189
input: {
187-
package: { slug: "caller-controlled-agent", source: "public-external-package", bootstrap: { encoding: "base64", bytes: publicPackageBytes.toString("base64"), digest: publicPackageDigest } },
190+
package: { slug: publicAgentSlug, source: "public-external-package", bootstrap: { encoding: "base64", bytes: publicPackageBytes.toString("base64"), digest: publicPackageDigest } },
188191
},
189192
},
190193
sandboxToolPolicy: { schema: "wp-codebox/sandbox-tool-policy/v1", version: 1, tools: [] },
@@ -211,6 +214,30 @@ assert.match(bootstrapCode, /wp_codebox_import_external_runtime_agent_package/)
211214
assert.ok(bootstrapCode.indexOf("wp_codebox_import_external_runtime_agent_package") < bootstrapCode.indexOf("wp_codebox_resolve_runtime_task_ability"))
212215
assert.match(bootstrapCode, /base64_decode\(\$bootstrap\['bytes'\], true\)/)
213216

217+
const spoofedBootstrapCode = await resolveSandboxTaskCode({
218+
task: "Say hello",
219+
agent: "wp-codebox-sandbox",
220+
runtimeTask: {
221+
ability: "wp-codebox/run-runtime-package",
222+
input: {
223+
package: { slug: publicAgentSlug, source: "public-external-package", bootstrap: { encoding: "base64", bytes: publicPackageBytes.toString("base64"), digest: publicPackageDigest } },
224+
input: { agent: "caller-controlled-agent" },
225+
},
226+
},
227+
sandboxToolPolicy: { schema: "wp-codebox/sandbox-tool-policy/v1", version: 1, tools: [] },
228+
})
229+
const spoofedBootstrapOutput = execFileSync("php", ["-r", `${phpPreamble}
230+
function wp_agent_import_runtime_bundles($bundles, $options) {
231+
$package = json_decode((string) file_get_contents((string) ($bundles[0]['source'] ?? '')), true);
232+
$slug = $package['agent']['agent_slug'] ?? '';
233+
WP_Agents_Registry::get_instance()->register($slug, array('source' => 'canonical-importer'));
234+
return array(array('success' => true, 'agent_slug' => $slug));
235+
}
236+
${spoofedBootstrapCode}`], { encoding: "utf8" })
237+
const spoofedBootstrap = JSON.parse(spoofedBootstrapOutput) as { agent_runtime?: { success?: boolean, error?: { code?: string } } }
238+
assert.equal(spoofedBootstrap.agent_runtime?.success, false)
239+
assert.equal(spoofedBootstrap.agent_runtime?.error?.code, "wp_codebox_external_runtime_package_identity_mismatch")
240+
214241
const failedImportOutput = execFileSync("php", ["-r", `${phpPreamble}
215242
function wp_agent_import_runtime_bundles($bundles, $options) { $GLOBALS['external_source'] = $bundles[0]['source']; return array(array('success' => false)); }
216243
${bootstrapCode}`], {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"schema_version": 1,
3+
"bundle_slug": "skills-agent",
4+
"bundle_version": "1.0.0",
5+
"agent": {
6+
"agent_slug": "skills-agent",
7+
"agent_name": "Skills Agent",
8+
"description": "Fixture for a package that supplies skills through enabled tools.",
9+
"agent_config": {
10+
"instructions": "SKILLS PACKAGE INSTRUCTION",
11+
"enabled_tools": ["workspace_read", "workspace_write"],
12+
"modes": ["chat", "task"]
13+
}
14+
}
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"schema_version": 1,
3+
"bundle_slug": "technical-bootstrap-agent",
4+
"bundle_version": "1.0.0",
5+
"agent": {
6+
"agent_slug": "technical-bootstrap-agent",
7+
"agent_name": "Technical Bootstrap Agent",
8+
"description": "Fixture for a technical documentation bootstrap package.",
9+
"agent_config": {
10+
"instructions": "TECHNICAL BOOTSTRAP PACKAGE INSTRUCTION",
11+
"enabled_tools": ["workspace_ls", "workspace_read", "workspace_write"],
12+
"tool_call_rules": [{"id": "require-write", "require_tool_use": true, "require_one_of": ["workspace_write"]}],
13+
"modes": ["chat"]
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)