Skip to content

Commit 6508679

Browse files
committed
Project write and git workspace tools for coding agents
AbilityToolProjections only exposed read-only workspace tools (workspace_ls/read/grep/etc.) as model-facing tools, so agents in sandbox and chat runs could never receive file-mutating tools — the model had no write tool to call and would either fail or fabricate edits. Project the mutating workspace tools (workspace_write, workspace_edit, workspace_apply_patch, workspace_delete, and the git add/commit/push and worktree/PR tools), each gated behind requires_opt_in so a read-only task never receives file-mutating tools by default. They surface only when named via allow_only or an allow-mode tool policy. Extends the projection smoke test to assert the write tools project with requires_opt_in set.
1 parent cbe9f2b commit 6508679

2 files changed

Lines changed: 55 additions & 0 deletions

File tree

inc/Tools/AbilityToolProjections.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,23 @@ public static function projected_tools(): array {
5151
'workspace_read' => self::workspace('datamachine-code/workspace-read'),
5252
'workspace_grep' => self::workspace('datamachine-code/workspace-grep'),
5353

54+
'workspace_write' => self::workspace_write('datamachine-code/workspace-write'),
55+
'workspace_edit' => self::workspace_write('datamachine-code/workspace-edit'),
56+
'workspace_apply_patch' => self::workspace_write('datamachine-code/workspace-apply-patch'),
57+
'workspace_delete' => self::workspace_write('datamachine-code/workspace-delete'),
58+
'workspace_git_status' => self::workspace_write('datamachine-code/workspace-git-status'),
59+
'workspace_git_log' => self::workspace_write('datamachine-code/workspace-git-log'),
60+
'workspace_git_diff' => self::workspace_write('datamachine-code/workspace-git-diff'),
61+
'workspace_git_pull' => self::workspace_write('datamachine-code/workspace-git-pull'),
62+
'workspace_git_add' => self::workspace_write('datamachine-code/workspace-git-add'),
63+
'workspace_git_commit' => self::workspace_write('datamachine-code/workspace-git-commit'),
64+
'workspace_git_push' => self::workspace_write('datamachine-code/workspace-git-push'),
65+
'workspace_git_rebase' => self::workspace_write('datamachine-code/workspace-git-rebase'),
66+
'workspace_git_reset' => self::workspace_write('datamachine-code/workspace-git-reset'),
67+
'workspace_worktree_add' => self::workspace_write('datamachine-code/workspace-worktree-add'),
68+
'workspace_pr_status' => self::workspace_write('datamachine-code/workspace-pr-status'),
69+
'workspace_pr_rebase' => self::workspace_write('datamachine-code/workspace-pr-rebase'),
70+
5471
'list_github_issues' => self::github('datamachine-code/list-github-issues'),
5572
'get_github_issue' => self::github('datamachine-code/get-github-issue'),
5673
'list_github_pulls' => self::github('datamachine-code/list-github-pulls'),
@@ -80,6 +97,23 @@ private static function workspace( string $ability ): array {
8097
);
8198
}
8299

100+
/**
101+
* Build a mutating workspace projection declaration.
102+
*
103+
* Write/git workspace tools require explicit opt-in (via `allow_only` or an
104+
* allow-mode tool policy) before they are exposed to a model request, so a
105+
* read-only inspection task never receives file-mutating tools by default.
106+
*
107+
* @return array<string,mixed>
108+
*/
109+
private static function workspace_write( string $ability ): array {
110+
return array(
111+
'ability' => $ability,
112+
'modes' => array( 'chat', 'pipeline' ),
113+
'requires_opt_in' => true,
114+
);
115+
}
116+
83117
/**
84118
* Build a GitHub projection declaration.
85119
*

tests/smoke-ability-tool-projections.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,27 @@ function dmc_projection_find_data_machine_conversation_manager(): ?string {
133133
$assert("{$tool_name} does not duplicate parameter schema", ! array_key_exists('parameters', $declaration));
134134
}
135135

136+
// Write/git workspace tools must be projected so coding agents can mutate
137+
// files, but gated behind explicit opt-in so read-only tasks never receive
138+
// file-mutating tools by default.
139+
$expected_write = array(
140+
'workspace_write' => 'datamachine-code/workspace-write',
141+
'workspace_edit' => 'datamachine-code/workspace-edit',
142+
'workspace_apply_patch' => 'datamachine-code/workspace-apply-patch',
143+
'workspace_delete' => 'datamachine-code/workspace-delete',
144+
'workspace_git_add' => 'datamachine-code/workspace-git-add',
145+
'workspace_git_commit' => 'datamachine-code/workspace-git-commit',
146+
'workspace_git_push' => 'datamachine-code/workspace-git-push',
147+
);
148+
149+
foreach ( $expected_write as $tool_name => $ability_slug ) {
150+
$declaration = $tools[ $tool_name ] ?? array();
151+
$assert("{$tool_name} is projected", isset($tools[ $tool_name ]));
152+
$assert("{$tool_name} points at canonical ability", $ability_slug === ( $declaration['ability'] ?? '' ));
153+
$assert("{$tool_name} is available to chat", in_array('chat', $declaration['modes'] ?? array(), true));
154+
$assert("{$tool_name} requires opt-in", true === ( $declaration['requires_opt_in'] ?? false ));
155+
}
156+
136157
$workspace_result = dmc_projection_normalize_tool_result(
137158
array(
138159
'success' => true,

0 commit comments

Comments
 (0)