Skip to content
Open
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
3 changes: 2 additions & 1 deletion inc/Cli/Commands/PendingActionsCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public function list( array $args, array $assoc_args ): void {
WP_CLI::error( $result->get_error_message() );
}

$rows = is_array( $result['actions'] ?? null ) ? $result['actions'] : array();
$rows = PendingActionInspectionAbility::normalize_action_rows( is_array( $result['actions'] ?? null ) ? $result['actions'] : array() );

$fields = array( 'action_id', 'kind', 'summary', 'status', 'agent_id', 'created_by', 'created_at_iso', 'expires_at_iso' );
$this->format_items( $rows, $fields, $assoc_args, 'action_id' );
Expand Down Expand Up @@ -124,6 +124,7 @@ public function get( array $args, array $assoc_args ): void {
WP_CLI::error( 'Pending action not found.' );
}

$action = PendingActionInspectionAbility::normalize_action_row( $action );
$format = $assoc_args['format'] ?? 'json';
WP_CLI\Utils\format_items( $format, array( $action ), array_keys( $action ) );
}
Expand Down
23 changes: 14 additions & 9 deletions inc/Engine/AI/Actions/PendingActionHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ public static function stage( array $args ): array {
$context = isset( $args['context'] ) && is_array( $args['context'] ) ? $args['context'] : array();
$action_id = isset( $args['action_id'] ) ? (string) $args['action_id'] : '';
$grants = isset( $args['resolver_grants'] ) && is_array( $args['resolver_grants'] ) ? $args['resolver_grants'] : array();
$metadata = isset( $args['metadata'] ) && is_array( $args['metadata'] ) ? $args['metadata'] : array();

if ( '' === $kind ) {
return array(
Expand All @@ -91,6 +92,18 @@ public static function stage( array $args ): array {
$grants = apply_filters( 'datamachine_pending_action_resolver_grants', $grants, $args );
$grants = is_array( $grants ) ? array_values( array_filter( $grants, 'is_array' ) ) : array();

$datamachine_metadata = isset( $metadata['datamachine'] ) && is_array( $metadata['datamachine'] ) ? $metadata['datamachine'] : array();
$metadata['datamachine'] = array_merge(
$datamachine_metadata,
array(
'agent_id' => $agent_id,
'created_by' => $user_id,
'context' => $context,
'resolver_grants' => $grants,
'resolve_with' => 'resolve_pending_action',
)
);

$payload = array(
'kind' => $kind,
'summary' => wp_strip_all_tags( $summary ),
Expand All @@ -102,15 +115,7 @@ public static function stage( array $args ): array {
'created_by' => $user_id,
'creator' => $user_id > 0 ? 'user:' . $user_id : null,
'context' => $context,
'metadata' => array(
'datamachine' => array(
'agent_id' => $agent_id,
'created_by' => $user_id,
'context' => $context,
'resolver_grants' => $grants,
'resolve_with' => 'resolve_pending_action',
),
),
'metadata' => $metadata,
);
if ( isset( $args['ttl'] ) ) {
$payload['ttl'] = (int) $args['ttl'];
Expand Down
65 changes: 63 additions & 2 deletions inc/Engine/AI/Actions/PendingActionInspectionAbility.php
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public static function list_actions( array $input ): array {

return array(
'success' => true,
'actions' => is_array( $result['actions'] ?? null ) ? $result['actions'] : array(),
'actions' => self::normalize_action_rows( is_array( $result['actions'] ?? null ) ? $result['actions'] : array() ),
);
}

Expand Down Expand Up @@ -195,10 +195,71 @@ public static function get_action( array $input ): array {

return array(
'success' => true,
'action' => $action,
'action' => self::normalize_action_row( $action ),
);
}

/**
* Normalize action rows for frontend/CLI inspection.
*
* @param array<int,array<string,mixed>> $actions Canonical action rows.
* @return array<int,array<string,mixed>> Rows with stable flattened Data Machine fields.
*/
public static function normalize_action_rows( array $actions ): array {
return array_map( array( self::class, 'normalize_action_row' ), array_values( array_filter( $actions, 'is_array' ) ) );
}

/**
* Normalize one canonical pending-action row for frontend/CLI inspection.
*
* Agents API rows are intentionally generic. Data Machine consumers also need
* stable scalar fields for table output, filtering evidence, and review UIs.
*
* @param array<string,mixed> $action Canonical action row.
* @return array<string,mixed> Normalized action row.
*/
public static function normalize_action_row( array $action ): array {
$metadata = isset( $action['metadata'] ) && is_array( $action['metadata'] ) ? $action['metadata'] : array();
$datamachine = isset( $metadata['datamachine'] ) && is_array( $metadata['datamachine'] ) ? $metadata['datamachine'] : array();
$context = isset( $datamachine['context'] ) && is_array( $datamachine['context'] ) ? $datamachine['context'] : array();
$workspace = isset( $action['workspace'] ) && is_array( $action['workspace'] ) ? $action['workspace'] : array();

$action['preview_data'] = $action['preview'] ?? $action['preview_data'] ?? array();
$action['agent_id'] = isset( $datamachine['agent_id'] ) ? (int) $datamachine['agent_id'] : self::id_from_canonical_ref( $action['agent'] ?? null, 'agent' );
$action['created_by'] = isset( $datamachine['created_by'] ) ? (int) $datamachine['created_by'] : self::id_from_canonical_ref( $action['creator'] ?? null, 'user' );
$action['context'] = $context;
$action['workspace_type'] = isset( $workspace['workspace_type'] ) ? (string) $workspace['workspace_type'] : null;
$action['workspace_id'] = isset( $workspace['workspace_id'] ) ? (string) $workspace['workspace_id'] : null;
$action['created_at_iso'] = isset( $action['created_at'] ) ? (string) $action['created_at'] : null;
$action['expires_at_iso'] = isset( $action['expires_at'] ) ? $action['expires_at'] : null;
$action['resolved_at_iso'] = isset( $action['resolved_at'] ) ? $action['resolved_at'] : null;
$action['audit_context'] = isset( $datamachine['audit_context'] ) && is_array( $datamachine['audit_context'] ) ? $datamachine['audit_context'] : array();
$action['principal_context'] = isset( $action['audit_context']['principal_context'] ) && is_array( $action['audit_context']['principal_context'] ) ? $action['audit_context']['principal_context'] : array();
$action['resolve_with'] = isset( $datamachine['resolve_with'] ) ? (string) $datamachine['resolve_with'] : 'resolve_pending_action';
$action['resolve_params'] = array(
'action_id' => (string) ( $action['action_id'] ?? '' ),
'decision' => '<accepted|rejected>',
);

return $action;
}

/**
* Extract numeric IDs from canonical refs such as agent:7 or user:12.
*
* @param mixed $value Canonical ref.
* @param string $prefix Expected prefix.
* @return int Positive ID or 0.
*/
private static function id_from_canonical_ref( $value, string $prefix ): int {
if ( ! is_string( $value ) ) {
return 0;
}

$match = array();
return preg_match( '/^' . preg_quote( $prefix, '/' ) . ':(\d+)$/', $value, $match ) ? (int) $match[1] : 0;
}

/**
* Ability callback: summarize actions.
*/
Expand Down
Loading
Loading