Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
1 change: 1 addition & 0 deletions agents-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
39 changes: 39 additions & 0 deletions docs/runtime-and-tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 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:

| 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 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.

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:
Expand Down
90 changes: 90 additions & 0 deletions src/Abilities/functions-ability-dispatch.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php
/**
* Public ability dispatch helpers.
*
* @package AgentsAPI
*/

defined( 'ABSPATH' ) || exit;

if ( ! function_exists( 'wp_agent_dispatch_ability' ) ) {
/**
* Dispatch a registered WordPress ability through the stable Agents API facade.
*
* 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<mixed> $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 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<mixed> $input Canonical runtime package run input.
* @return array<string,mixed>|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.'
);
}
}
12 changes: 12 additions & 0 deletions tests/runtime-package-run-contract-smoke.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 );