diff --git a/src/Channels/register-agents-chat-ability.php b/src/Channels/register-agents-chat-ability.php index bd71896..abca198 100644 --- a/src/Channels/register-agents-chat-ability.php +++ b/src/Channels/register-agents-chat-ability.php @@ -205,9 +205,23 @@ function agents_chat_dispatch( array $input ) { WP_Agent_Chat_Run_Control::start_run( $result_run_id, $resolved_session_id, array( 'agent' => $agent ) ); } - $status = ! empty( $result['completed'] ) || ! array_key_exists( 'completed', $result ) - ? WP_Agent_Chat_Run_Control::STATUS_COMPLETED - : WP_Agent_Chat_Run_Control::STATUS_RUNNING; + $result_status = WP_Agent_Chat_Run_Control::normalize_status( $result['status'] ?? '' ); + if ( WP_Agent_Chat_Run_Control::STATUS_FAILED === $result_status ) { + $status = WP_Agent_Chat_Run_Control::STATUS_FAILED; + } elseif ( ! empty( $result['completed'] ) || ! array_key_exists( 'completed', $result ) ) { + $status = WP_Agent_Chat_Run_Control::STATUS_COMPLETED; + } elseif ( in_array( + $result_status, + array( + WP_Agent_Chat_Run_Control::STATUS_RUNTIME_TOOL_PENDING, + WP_Agent_Chat_Run_Control::STATUS_APPROVAL_REQUIRED, + ), + true + ) ) { + $status = $result_status; + } else { + $status = WP_Agent_Chat_Run_Control::STATUS_RUNNING; + } WP_Agent_Chat_Run_Control::finish_run( $result_run_id, $status ); } diff --git a/src/Runtime/class-wp-agent-chat-run-control.php b/src/Runtime/class-wp-agent-chat-run-control.php index 6b3aa0c..045b0a9 100644 --- a/src/Runtime/class-wp-agent-chat-run-control.php +++ b/src/Runtime/class-wp-agent-chat-run-control.php @@ -14,13 +14,15 @@ */ class WP_Agent_Chat_Run_Control { - public const STATUS_QUEUED = 'queued'; - public const STATUS_RUNNING = 'running'; - public const STATUS_CANCELLING = 'cancelling'; - public const STATUS_CANCELLED = 'cancelled'; - public const STATUS_COMPLETED = 'completed'; - public const STATUS_FAILED = 'failed'; - private const OPTION_KEY = 'agents_api_chat_run_control'; + public const STATUS_QUEUED = 'queued'; + public const STATUS_RUNNING = 'running'; + public const STATUS_CANCELLING = 'cancelling'; + public const STATUS_CANCELLED = 'cancelled'; + public const STATUS_COMPLETED = 'completed'; + public const STATUS_FAILED = 'failed'; + public const STATUS_RUNTIME_TOOL_PENDING = 'runtime_tool_pending'; + public const STATUS_APPROVAL_REQUIRED = 'approval_required'; + private const OPTION_KEY = 'agents_api_chat_run_control'; /** @return string[] */ public static function statuses(): array { @@ -31,6 +33,8 @@ public static function statuses(): array { self::STATUS_CANCELLED, self::STATUS_COMPLETED, self::STATUS_FAILED, + self::STATUS_RUNTIME_TOOL_PENDING, + self::STATUS_APPROVAL_REQUIRED, ); } diff --git a/tests/chat-run-control-smoke.php b/tests/chat-run-control-smoke.php index df1d433..af28a72 100644 --- a/tests/chat-run-control-smoke.php +++ b/tests/chat-run-control-smoke.php @@ -139,6 +139,62 @@ static function ( $handler, array $input ) use ( &$captured_chat_input ) { $stored = AgentsAPI\AI\Channels\agents_get_chat_run( array( 'session_id' => 'session-1', 'run_id' => $chat['run_id'] ) ); agents_api_smoke_assert_equals( 'completed', $stored['status'] ?? null, 'chat dispatch records completed run by default', $failures, $passes ); +add_filter( + 'wp_agent_chat_handler', + static fn() => static fn( array $runtime_input ): array => array( + 'session_id' => $runtime_input['session_id'], + 'run_id' => $runtime_input['run_id'], + 'reply' => '', + 'completed' => false, + 'status' => 'runtime_tool_pending', + 'runtime_tool_pending' => array( + 'tool_name' => 'client/summarize', + 'tool_call_id' => 'call-pending-1', + ), + ), + 20, + 2 +); + +$pending_chat = AgentsAPI\AI\Channels\agents_chat_dispatch( + array( + 'agent' => 'demo-agent', + 'message' => 'Needs runtime tool', + 'session_id' => 'session-pending', + ) +); +$pending_stored = AgentsAPI\AI\Channels\agents_get_chat_run( array( 'session_id' => 'session-pending', 'run_id' => $pending_chat['run_id'] ) ); +agents_api_smoke_assert_equals( 'runtime_tool_pending', $pending_stored['status'] ?? null, 'chat dispatch keeps runtime-tool pending run addressable', $failures, $passes ); +agents_api_smoke_assert_equals( false, 'completed' === ( $pending_stored['status'] ?? null ), 'runtime-tool pending run is not marked completed', $failures, $passes ); + +add_filter( + 'wp_agent_chat_handler', + static fn() => static fn( array $runtime_input ): array => array( + 'session_id' => $runtime_input['session_id'], + 'run_id' => $runtime_input['run_id'], + 'reply' => '', + 'completed' => false, + 'status' => 'approval_required', + 'approval_required' => array( + 'type' => 'approval_required', + 'payload' => array( 'action_id' => 'approve-1' ), + ), + ), + 30, + 2 +); + +$approval_chat = AgentsAPI\AI\Channels\agents_chat_dispatch( + array( + 'agent' => 'demo-agent', + 'message' => 'Needs approval', + 'session_id' => 'session-approval', + ) +); +$approval_stored = AgentsAPI\AI\Channels\agents_get_chat_run( array( 'session_id' => 'session-approval', 'run_id' => $approval_chat['run_id'] ) ); +agents_api_smoke_assert_equals( 'approval_required', $approval_stored['status'] ?? null, 'chat dispatch keeps approval-required run addressable', $failures, $passes ); +agents_api_smoke_assert_equals( false, 'completed' === ( $approval_stored['status'] ?? null ), 'approval-required run is not marked completed', $failures, $passes ); + AgentsAPI\AI\WP_Agent_Chat_Run_Control::start_run( 'run-default-cancel', 'session-1' ); $default_cancelled = AgentsAPI\AI\Channels\agents_cancel_chat_run( array( 'session_id' => 'session-1', 'run_id' => 'run-default-cancel' ) ); agents_api_smoke_assert_equals( 'cancelling', $default_cancelled['status'] ?? null, 'default cancel marks running runs as cancelling', $failures, $passes );