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
38 changes: 34 additions & 4 deletions inc/Engine/AI/Tools/ToolPolicyResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,12 @@ public function resolve( array $args ): array {
return array();
}

$agent_policy = $agent_id > 0 ? $this->getAgentToolPolicy( $agent_id ) : null;
$args = $this->withAgentPolicyAllowOnly( $args, $agent_policy );

// 1. Gather tools from Data Machine-owned sources.
$args['modes'] = $modes;
$tools = $this->gatherByModes( $modes, $args );

$agent_policy = $agent_id > 0 ? $this->getAgentToolPolicy( $agent_id ) : null;
$tools = $this->filterRuntimeToolsByPolicyOptIn( $tools, $args, $agent_policy );

// 2. Delegate generic mode/allow/deny/category policy resolution to Agents API.
Expand Down Expand Up @@ -188,6 +189,26 @@ private function filterRuntimeToolsByPolicyOptIn( array $tools, array $args, ?ar
return $tools;
}

/**
* Include explicit agent allow-policy tools in the early opt-in allow list.
*
* @param array $args Resolution args.
* @param array|null $agent_policy Optional persisted agent tool policy.
* @return array Resolution args.
*/
private function withAgentPolicyAllowOnly( array $args, ?array $agent_policy ): array {
if ( ! is_array( $agent_policy ) || \WP_Agent_Tool_Policy::MODE_ALLOW !== ( $agent_policy['mode'] ?? '' ) ) {
return $args;
}

$args['allow_only'] = array_values( array_unique( array_merge(
$this->policy_filter->string_list( $args['allow_only'] ?? array() ),
$this->policy_filter->string_list( $agent_policy['tools'] ?? array() )
) ) );

return $args;
}

/**
* Get tool policy from an agent's config.
*
Expand Down Expand Up @@ -295,7 +316,16 @@ public static function normalizeModes( mixed $modes ): array {
* @return bool True when the tool should be included.
*/
public static function isOptInToolAllowed( array $tool_config, string $tool_name, array $args ): bool {
return empty( $tool_config['requires_opt_in'] )
|| in_array( $tool_name, $args['allow_only'] ?? array(), true );
if ( empty( $tool_config['requires_opt_in'] ) ) {
return true;
}

$allowed = is_array( $args['allow_only'] ?? null ) ? $args['allow_only'] : array();
$policy = is_array( $args['tool_policy'] ?? null ) ? $args['tool_policy'] : null;
if ( is_array( $policy ) && \WP_Agent_Tool_Policy::MODE_ALLOW === ( $policy['mode'] ?? '' ) ) {
$allowed = array_merge( $allowed, is_array( $policy['tools'] ?? null ) ? $policy['tools'] : array() );
}

return in_array( $tool_name, $allowed, true );
}
}
11 changes: 11 additions & 0 deletions tests/tool-source-registry-smoke.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,17 @@ static function ( array $sources ): array {
array( 'allow_only' => array( 'durable_memory_tool' ) )
);
assert_source_equals( true, isset( $opt_in_baseline['durable_memory_tool'] ), 'pipeline mode picks up opt-in tool when allowlisted', $failures, $passes );
$opt_in_tool_policy = resolve_source_tools(
ToolPolicyResolver::MODE_PIPELINE,
new SourcePolicyToolManager(),
array(
'tool_policy' => array(
'mode' => 'allow',
'tools' => array( 'durable_memory_tool' ),
),
)
);
assert_source_equals( true, isset( $opt_in_tool_policy['durable_memory_tool'] ), 'pipeline mode picks up opt-in tool when allowed by tool policy', $failures, $passes );
$opt_in_no_allowlist = resolve_source_tools(
ToolPolicyResolver::MODE_PIPELINE,
new SourcePolicyToolManager()
Expand Down
Loading