From b294f784a4d3f3985e79b228d7033978a62c8271 Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Sun, 21 Jun 2026 19:11:55 -0400 Subject: [PATCH 1/2] Add stable runtime invocation helpers --- README.md | 1 + agents-api.php | 1 + docs/runtime-and-tools.md | 39 +++++++++ src/Abilities/functions-ability-dispatch.php | 90 ++++++++++++++++++++ tests/runtime-package-run-contract-smoke.php | 12 +++ 5 files changed, 143 insertions(+) create mode 100644 src/Abilities/functions-ability-dispatch.php diff --git a/README.md b/README.md index 7c3d72b..42bd9ed 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ wp_register_agent( - `wp_agents_api_init` - `agents_api_loop_event` +- `wp_agent_dispatch_ability()` / `wp_agent_run_runtime_package()` - `wp_register_agent()` / `wp_get_agent()` / `wp_get_agents()` / `wp_has_agent()` / `wp_unregister_agent()` - `WP_Agent` - `WP_Agent_Runtime_Overrides` diff --git a/agents-api.php b/agents-api.php index b07c44e..b8dd8c9 100644 --- a/agents-api.php +++ b/agents-api.php @@ -124,6 +124,7 @@ require_once AGENTS_API_PATH . 'src/Runtime/class-wp-agent-compaction-conservation.php'; require_once AGENTS_API_PATH . 'src/Tools/class-wp-agent-tool-parameters.php'; require_once AGENTS_API_PATH . 'src/Abilities/class-wp-agent-ability-dispatcher.php'; +require_once AGENTS_API_PATH . 'src/Abilities/functions-ability-dispatch.php'; require_once AGENTS_API_PATH . 'src/Tools/class-wp-agent-tool-declaration.php'; require_once AGENTS_API_PATH . 'src/Tools/class-wp-agent-runtime-tool-policy.php'; require_once AGENTS_API_PATH . 'src/Tools/class-wp-agent-action-policy.php'; diff --git a/docs/runtime-and-tools.md b/docs/runtime-and-tools.md index 6267d42..d637954 100644 --- a/docs/runtime-and-tools.md +++ b/docs/runtime-and-tools.md @@ -50,6 +50,45 @@ Registered abilities: | `agents/get-task-run` | Read the canonical status/result for an addressable task run. | | `agents/cancel-task-run` | Request best-effort cancellation for an addressable task run. | +## Stable host import and invocation boundary + +Hosts that load generated runtime bundles should depend on the plugin or Composer +package bootstrap, then use public helpers and ability slugs. Runtime code should +not include files from `src/`, instantiate Agents API internals, or depend on +consumer-specific class names. + +Stable PHP helpers: + +| Helper | Purpose | +| --- | --- | +| `wp_agent_import_runtime_bundles( $bundle_specs, $input )` | Import one or more portable runtime bundle specs through the generic importer seam. | +| `wp_agent_run_runtime_package( $input )` | Invoke the canonical `agents/run-runtime-package` ability from in-process host code. | +| `wp_agent_dispatch_ability( $ability_name, $parameters )` | Dispatch any registered WordPress ability through the shared Agents API facade. | + +Example: + +```php +$import_results = wp_agent_import_runtime_bundles( + array( + array( 'source' => __DIR__ . '/bundles/example-agent.json' ), + ), + array( 'on_conflict' => 'upgrade' ) +); + +$run_result = wp_agent_run_runtime_package( + array( + 'package' => array( 'slug' => 'example-agent' ), + 'workflow' => array( 'id' => 'default' ), + 'input' => array( 'prompt' => 'Draft the site outline.' ), + ) +); +``` + +Provider-specific runtimes remain behind filters such as +`wp_agent_runtime_import_bundle` and `wp_agent_runtime_package_run_handler`. +Agents API owns the stable envelopes and dispatch seam; hosts own package +materialization, execution, storage, and product policy. + Executor providers register targets through `wp_agent_execution_targets` and dispatch handlers through `wp_agent_task_handler`, mirroring the `agents/chat` and `wp_agent_chat_handler` pattern: diff --git a/src/Abilities/functions-ability-dispatch.php b/src/Abilities/functions-ability-dispatch.php new file mode 100644 index 0000000..4e5c8b5 --- /dev/null +++ b/src/Abilities/functions-ability-dispatch.php @@ -0,0 +1,90 @@ + $parameters Ability input parameters. + * @return mixed|WP_Error Ability result, or an error before dispatch. + */ + function wp_agent_dispatch_ability( string $ability_name, array $parameters = array() ) { + if ( ! class_exists( 'AgentsAPI\\AI\\Abilities\\WP_Agent_Ability_Dispatcher' ) ) { + return new WP_Error( 'agents_api_ability_dispatcher_unavailable', 'The Agents API ability dispatcher is unavailable.' ); + } + + return AgentsAPI\AI\Abilities\WP_Agent_Ability_Dispatcher::dispatch( $ability_name, $parameters ); + } +} + +if ( ! function_exists( 'wp_agent_run_runtime_package' ) ) { + /** + * Run a portable runtime package through the canonical runtime package ability. + * + * This is the stable PHP import boundary for hosts that need to invoke a + * generated runtime bundle from in-process code. The helper prefers the + * Abilities API registry and only falls back to the dispatcher when the + * registry is not loaded, which keeps normal WordPress requests on the + * canonical `agents/run-runtime-package` path. + * + * @param array $input Canonical runtime package run input. + * @return array|WP_Error Runtime package result or dispatch error. + */ + function wp_agent_run_runtime_package( array $input ) { + $ability_name = defined( 'AgentsAPI\\AI\\AGENTS_RUN_RUNTIME_PACKAGE_ABILITY' ) + ? constant( 'AgentsAPI\\AI\\AGENTS_RUN_RUNTIME_PACKAGE_ABILITY' ) + : 'agents/run-runtime-package'; + $normalize_result = static function ( mixed $result ) { + if ( $result instanceof WP_Error ) { + return $result; + } + + if ( ! is_array( $result ) ) { + return new WP_Error( + 'agents_runtime_package_invalid_result', + 'The canonical agents/run-runtime-package ability returned an invalid result.' + ); + } + + $normalized = array(); + foreach ( $result as $key => $value ) { + if ( is_string( $key ) ) { + $normalized[ $key ] = $value; + } + } + + return $normalized; + }; + + if ( function_exists( 'wp_get_ability' ) ) { + $ability = wp_get_ability( $ability_name ); + if ( $ability instanceof WP_Ability ) { + return $normalize_result( $ability->execute( $input ) ); + } + + return new WP_Error( + 'agents_runtime_package_ability_unavailable', + 'The canonical agents/run-runtime-package ability is not registered.' + ); + } + + if ( function_exists( 'AgentsAPI\\AI\\agents_runtime_package_run_dispatch' ) ) { + return $normalize_result( AgentsAPI\AI\agents_runtime_package_run_dispatch( $input ) ); + } + + return new WP_Error( + 'agents_runtime_package_dispatcher_unavailable', + 'The Agents API runtime package dispatcher is unavailable.' + ); + } +} diff --git a/tests/runtime-package-run-contract-smoke.php b/tests/runtime-package-run-contract-smoke.php index 54fb915..e52077b 100644 --- a/tests/runtime-package-run-contract-smoke.php +++ b/tests/runtime-package-run-contract-smoke.php @@ -33,6 +33,7 @@ function is_wp_error( $value ): bool { require_once __DIR__ . '/../src/Runtime/class-wp-agent-runtime-package-run-request.php'; require_once __DIR__ . '/../src/Runtime/class-wp-agent-runtime-package-run-result.php'; require_once __DIR__ . '/../src/Runtime/register-runtime-package-run-ability.php'; +require_once __DIR__ . '/../src/Abilities/functions-ability-dispatch.php'; use AgentsAPI\AI\WP_Agent_Runtime_Package_Run_Request; use AgentsAPI\AI\WP_Agent_Runtime_Package_Run_Result; @@ -117,4 +118,15 @@ static function ( $handler, WP_Agent_Runtime_Package_Run_Request $handler_reques agents_api_smoke_assert_equals( 'build-site', is_array( $dispatch ) ? $dispatch['result']['workflow_id'] ?? '' : '', 'dispatcher passes workflow to handler', $failures, $passes ); agents_api_smoke_assert_equals( 'runtime log', is_array( $dispatch ) ? $dispatch['evidence_refs'][0]['label'] ?? '' : '', 'dispatcher preserves evidence refs', $failures, $passes ); +echo "\n[4] Public host helper invokes the canonical runtime package boundary:\n"; +$helper_dispatch = wp_agent_run_runtime_package( + array( + 'package' => array( 'slug' => 'site-builder' ), + 'workflow' => array( 'id' => 'build-site' ), + ) +); +agents_api_smoke_assert_equals( false, is_wp_error( $helper_dispatch ), 'public helper returns handler output', $failures, $passes ); +agents_api_smoke_assert_equals( 'succeeded', is_array( $helper_dispatch ) ? $helper_dispatch['status'] ?? '' : '', 'public helper preserves result status', $failures, $passes ); +agents_api_smoke_assert_equals( 'build-site', is_array( $helper_dispatch ) ? $helper_dispatch['result']['workflow_id'] ?? '' : '', 'public helper passes workflow to handler', $failures, $passes ); + agents_api_smoke_finish( 'Agents API runtime package run contract', $failures, $passes ); From a25a1d365c92ad30e1e550a778a40fff0ac7a9ab Mon Sep 17 00:00:00 2001 From: Chris Huber Date: Sun, 21 Jun 2026 19:19:49 -0400 Subject: [PATCH 2/2] Clarify runtime invocation docs --- docs/runtime-and-tools.md | 10 +++++----- src/Abilities/functions-ability-dispatch.php | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/runtime-and-tools.md b/docs/runtime-and-tools.md index d637954..c08fb44 100644 --- a/docs/runtime-and-tools.md +++ b/docs/runtime-and-tools.md @@ -52,10 +52,10 @@ Registered abilities: ## Stable host import and invocation boundary -Hosts that load generated runtime bundles should depend on the plugin or Composer -package bootstrap, then use public helpers and ability slugs. Runtime code should -not include files from `src/`, instantiate Agents API internals, or depend on -consumer-specific class names. +Hosts that load generated runtime bundles depend on the plugin or Composer +package bootstrap, then use public helpers and ability slugs. Runtime code calls +the stable helpers below and receives normalized runtime envelopes from Agents +API. Stable PHP helpers: @@ -84,7 +84,7 @@ $run_result = wp_agent_run_runtime_package( ); ``` -Provider-specific runtimes remain behind filters such as +Provider-specific runtimes connect through filters such as `wp_agent_runtime_import_bundle` and `wp_agent_runtime_package_run_handler`. Agents API owns the stable envelopes and dispatch seam; hosts own package materialization, execution, storage, and product policy. diff --git a/src/Abilities/functions-ability-dispatch.php b/src/Abilities/functions-ability-dispatch.php index 4e5c8b5..4a778bd 100644 --- a/src/Abilities/functions-ability-dispatch.php +++ b/src/Abilities/functions-ability-dispatch.php @@ -11,8 +11,8 @@ /** * Dispatch a registered WordPress ability through the stable Agents API facade. * - * Runtime bundles and generated host code should call this helper instead of - * importing Agents API internal classes or file paths. + * Runtime bundles and generated host code call this helper for ability + * invocation from in-process PHP. * * @param string $ability_name Registered ability name. * @param array $parameters Ability input parameters. @@ -31,7 +31,7 @@ function wp_agent_dispatch_ability( string $ability_name, array $parameters = ar /** * Run a portable runtime package through the canonical runtime package ability. * - * This is the stable PHP import boundary for hosts that need to invoke a + * This is the stable PHP import boundary for hosts that invoke a * generated runtime bundle from in-process code. The helper prefers the * Abilities API registry and only falls back to the dispatcher when the * registry is not loaded, which keeps normal WordPress requests on the