Skip to content

Commit 952dec8

Browse files
authored
Separate remote workspace backend guidance (#520)
* fix: separate remote workspace guidance * fix: align remote workspace result arrays
1 parent db30f6c commit 952dec8

4 files changed

Lines changed: 159 additions & 85 deletions

File tree

inc/Abilities/WorkspaceAbilities.php

Lines changed: 99 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,6 +2374,91 @@ public static function grepFiles( array $input ): array|\WP_Error {
23742374
);
23752375
}
23762376

2377+
/**
2378+
* Add model-facing next-tool guidance to remote workspace ability results.
2379+
*
2380+
* RemoteWorkspaceBackend returns domain state only; this adapter is the
2381+
* explicitly agent-facing layer that preserves CLI/tool loop guidance.
2382+
*
2383+
* @param string $operation Remote backend operation name.
2384+
* @param array<string,mixed>|\WP_Error $result Backend result.
2385+
* @return array<string,mixed>|\WP_Error
2386+
*/
2387+
private static function decorate_remote_workspace_result( string $operation, array|\WP_Error $result ): array|\WP_Error {
2388+
if ( is_wp_error($result) ) {
2389+
return $result;
2390+
}
2391+
2392+
$guidance = self::remote_workspace_guidance($operation, $result);
2393+
if ( empty($guidance) ) {
2394+
return $result;
2395+
}
2396+
2397+
return array_merge($result, $guidance);
2398+
}
2399+
2400+
/**
2401+
* @param array<string,mixed> $result Backend result.
2402+
* @return array<string,mixed>
2403+
*/
2404+
private static function remote_workspace_guidance( string $operation, array $result ): array {
2405+
$name = (string) ( $result['name'] ?? '' );
2406+
$handle = (string) ( $result['handle'] ?? $name );
2407+
2408+
switch ( $operation ) {
2409+
case 'clone_repo':
2410+
return array(
2411+
'conversation_state' => 'incomplete',
2412+
'next_required_tool' => 'workspace_worktree_add',
2413+
'next_required_args' => array( 'repo' => $name ),
2414+
);
2415+
2416+
case 'worktree_add':
2417+
return array(
2418+
'conversation_state' => 'incomplete',
2419+
'next_required_tool' => 'workspace_read or workspace_edit or workspace_write',
2420+
'next_required_args' => array( 'repo' => $handle ),
2421+
);
2422+
2423+
case 'write_file':
2424+
case 'edit_file':
2425+
return array(
2426+
'conversation_state' => 'incomplete',
2427+
'next_required_tool' => 'workspace_git_status',
2428+
'next_required_args' => array( 'name' => $name ),
2429+
);
2430+
2431+
case 'git_status':
2432+
return array(
2433+
'conversation_state' => 'incomplete',
2434+
'next_required_tool' => (int) ( $result['dirty'] ?? 0 ) > 0 ? 'workspace_git_commit' : 'workspace_edit or workspace_write',
2435+
'next_required_args' => array( 'name' => $name ),
2436+
);
2437+
2438+
case 'git_commit':
2439+
return array(
2440+
'conversation_state' => 'incomplete',
2441+
'next_required_tool' => 'workspace_git_push',
2442+
'next_required_args' => array(
2443+
'name' => $name,
2444+
'branch' => (string) ( $result['branch'] ?? '' ),
2445+
),
2446+
);
2447+
2448+
case 'git_push':
2449+
return array(
2450+
'conversation_state' => 'incomplete',
2451+
'next_required_tool' => 'create_github_pull_request',
2452+
'next_required_args' => array(
2453+
'repo' => (string) ( $result['repo'] ?? $result['github_repo'] ?? '' ),
2454+
'head' => (string) ( $result['branch'] ?? '' ),
2455+
),
2456+
);
2457+
}
2458+
2459+
return array();
2460+
}
2461+
23772462
/**
23782463
* Clone a git repository into the workspace.
23792464
*
@@ -2382,10 +2467,11 @@ public static function grepFiles( array $input ): array|\WP_Error {
23822467
*/
23832468
public static function cloneRepo( array $input ): array|\WP_Error {
23842469
if ( RemoteWorkspaceBackend::should_handle() ) {
2385-
return ( new RemoteWorkspaceBackend() )->clone_repo(
2470+
$result = ( new RemoteWorkspaceBackend() )->clone_repo(
23862471
$input['url'] ?? '',
23872472
$input['name'] ?? null
23882473
);
2474+
return self::decorate_remote_workspace_result('clone_repo', $result);
23892475
}
23902476

23912477
$workspace = new Workspace();
@@ -2432,11 +2518,12 @@ public static function removeRepo( array $input ): array|\WP_Error {
24322518
*/
24332519
public static function writeFile( array $input ): array|\WP_Error {
24342520
if ( RemoteWorkspaceBackend::should_handle() ) {
2435-
return ( new RemoteWorkspaceBackend() )->write_file(
2521+
$result = ( new RemoteWorkspaceBackend() )->write_file(
24362522
$input['repo'] ?? '',
24372523
$input['path'] ?? '',
24382524
$input['content'] ?? ''
24392525
);
2526+
return self::decorate_remote_workspace_result('write_file', $result);
24402527
}
24412528

24422529
$workspace = new Workspace();
@@ -2469,13 +2556,14 @@ public static function editFile( array $input ): array|\WP_Error {
24692556
}
24702557

24712558
if ( RemoteWorkspaceBackend::should_handle() ) {
2472-
return ( new RemoteWorkspaceBackend() )->edit_file(
2559+
$result = ( new RemoteWorkspaceBackend() )->edit_file(
24732560
$input['repo'] ?? '',
24742561
$input['path'] ?? '',
24752562
$old_string,
24762563
$new_string,
24772564
! empty($input['replace_all'])
24782565
);
2566+
return self::decorate_remote_workspace_result('edit_file', $result);
24792567
}
24802568

24812569
$workspace = new Workspace();
@@ -2545,7 +2633,8 @@ private static function gitRebaseOutputSchema(): array {
25452633
*/
25462634
public static function gitStatus( array $input ): array|\WP_Error {
25472635
if ( RemoteWorkspaceBackend::should_handle() ) {
2548-
return ( new RemoteWorkspaceBackend() )->git_status($input['name'] ?? '');
2636+
$result = ( new RemoteWorkspaceBackend() )->git_status($input['name'] ?? '');
2637+
return self::decorate_remote_workspace_result('git_status', $result);
25492638
}
25502639

25512640
$workspace = new Workspace();
@@ -2617,10 +2706,11 @@ public static function deletePath( array $input ): array|\WP_Error {
26172706
*/
26182707
public static function gitCommit( array $input ): array|\WP_Error {
26192708
if ( RemoteWorkspaceBackend::should_handle() ) {
2620-
return ( new RemoteWorkspaceBackend() )->git_commit(
2709+
$result = ( new RemoteWorkspaceBackend() )->git_commit(
26212710
$input['name'] ?? '',
26222711
$input['message'] ?? ''
26232712
);
2713+
return self::decorate_remote_workspace_result('git_commit', $result);
26242714
}
26252715

26262716
$workspace = new Workspace();
@@ -2639,11 +2729,12 @@ public static function gitCommit( array $input ): array|\WP_Error {
26392729
*/
26402730
public static function gitPush( array $input ): array|\WP_Error {
26412731
if ( RemoteWorkspaceBackend::should_handle() ) {
2642-
return ( new RemoteWorkspaceBackend() )->git_push(
2732+
$result = ( new RemoteWorkspaceBackend() )->git_push(
26432733
$input['name'] ?? '',
26442734
$input['remote'] ?? 'origin',
26452735
$input['branch'] ?? null
26462736
);
2737+
return self::decorate_remote_workspace_result('git_push', $result);
26472738
}
26482739

26492740
$workspace = new Workspace();
@@ -2736,11 +2827,12 @@ public static function prRebase( array $input ): array|\WP_Error {
27362827
*/
27372828
public static function worktreeAdd( array $input ): array|\WP_Error {
27382829
if ( RemoteWorkspaceBackend::should_handle() ) {
2739-
return ( new RemoteWorkspaceBackend() )->worktree_add(
2830+
$result = ( new RemoteWorkspaceBackend() )->worktree_add(
27402831
$input['repo'] ?? '',
27412832
$input['branch'] ?? '',
27422833
$input['from'] ?? null
27432834
);
2835+
return self::decorate_remote_workspace_result('worktree_add', $result);
27442836
}
27452837

27462838
$workspace = new Workspace();

inc/Workspace/RemoteWorkspaceBackend.php

Lines changed: 53 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,11 @@ public function clone_repo( string $url, ?string $name = null ): array|\WP_Error
5555
$this->save_state($state);
5656

5757
return array(
58-
'success' => true,
59-
'backend' => 'github_api',
60-
'name' => $name,
61-
'path' => 'github://' . $repo,
62-
'message' => sprintf('Registered %s as remote workspace "%s".', $repo, $name),
63-
'conversation_state' => 'incomplete',
64-
'next_required_tool' => 'workspace_worktree_add',
65-
'next_required_args' => array( 'repo' => $name ),
58+
'success' => true,
59+
'backend' => 'github_api',
60+
'name' => $name,
61+
'path' => 'github://' . $repo,
62+
'message' => sprintf('Registered %s as remote workspace "%s".', $repo, $name),
6663
);
6764
}
6865

@@ -97,17 +94,14 @@ public function worktree_add( string $repo_name, string $branch, ?string $from =
9794
$this->save_state($state);
9895

9996
return array(
100-
'success' => true,
101-
'backend' => 'github_api',
102-
'handle' => $handle,
103-
'path' => 'github://' . $repo . '#' . $branch,
104-
'branch' => $branch,
105-
'slug' => $slug,
106-
'created_branch' => true,
107-
'message' => sprintf('Registered remote workspace %s for %s.', $handle, $repo),
108-
'conversation_state' => 'incomplete',
109-
'next_required_tool' => 'workspace_read or workspace_edit or workspace_write',
110-
'next_required_args' => array( 'repo' => $handle ),
97+
'success' => true,
98+
'backend' => 'github_api',
99+
'handle' => $handle,
100+
'path' => 'github://' . $repo . '#' . $branch,
101+
'branch' => $branch,
102+
'slug' => $slug,
103+
'created_branch' => true,
104+
'message' => sprintf('Registered remote workspace %s for %s.', $handle, $repo),
111105
);
112106
}
113107

@@ -332,14 +326,12 @@ public function write_file( string $handle, string $path, string $content ): arr
332326
$this->save_state($state);
333327

334328
return array(
335-
'success' => true,
336-
'backend' => 'github_api',
337-
'path' => $path,
338-
'size' => strlen($content),
339-
'created' => true,
340-
'conversation_state' => 'incomplete',
341-
'next_required_tool' => 'workspace_git_status',
342-
'next_required_args' => array( 'name' => $context['handle'] ),
329+
'success' => true,
330+
'backend' => 'github_api',
331+
'name' => $context['handle'],
332+
'path' => $path,
333+
'size' => strlen($content),
334+
'created' => true,
343335
);
344336
}
345337

@@ -390,13 +382,11 @@ public function edit_file( string $handle, string $path, string $old_string, str
390382
}
391383

392384
return array(
393-
'success' => true,
394-
'backend' => 'github_api',
395-
'path' => $write['path'],
396-
'replacements' => $replace_all ? $count : 1,
397-
'conversation_state' => 'incomplete',
398-
'next_required_tool' => 'workspace_git_status',
399-
'next_required_args' => array( 'name' => $context['handle'] ),
385+
'success' => true,
386+
'backend' => 'github_api',
387+
'name' => $context['handle'],
388+
'path' => $write['path'],
389+
'replacements' => $replace_all ? $count : 1,
400390
);
401391
}
402392

@@ -494,20 +484,17 @@ public function git_status( string $handle ): array|\WP_Error {
494484

495485
$files = array_values(array_unique(array_values( (array) $context['changed_files'])));
496486
return array(
497-
'success' => true,
498-
'backend' => 'github_api',
499-
'name' => $handle,
500-
'repo' => $context['repo_name'],
501-
'is_worktree' => true,
502-
'path' => 'github://' . $context['repo'] . '#' . $context['branch'],
503-
'branch' => $context['branch'],
504-
'remote' => 'https://github.com/' . $context['repo'] . '.git',
505-
'commit' => '' !== $context['last_commit_sha'] ? $context['last_commit_sha'] : null,
506-
'dirty' => count($files),
507-
'files' => $files,
508-
'conversation_state' => 'incomplete',
509-
'next_required_tool' => count($files) > 0 ? 'workspace_git_commit' : 'workspace_edit or workspace_write',
510-
'next_required_args' => array( 'name' => $handle ),
487+
'success' => true,
488+
'backend' => 'github_api',
489+
'name' => $handle,
490+
'repo' => $context['repo_name'],
491+
'is_worktree' => true,
492+
'path' => 'github://' . $context['repo'] . '#' . $context['branch'],
493+
'branch' => $context['branch'],
494+
'remote' => 'https://github.com/' . $context['repo'] . '.git',
495+
'commit' => '' !== $context['last_commit_sha'] ? $context['last_commit_sha'] : null,
496+
'dirty' => count($files),
497+
'files' => $files,
511498
);
512499
}
513500

@@ -583,17 +570,12 @@ public function git_commit( string $handle, string $message ): array|\WP_Error {
583570
$this->save_state($state);
584571

585572
return array(
586-
'success' => true,
587-
'backend' => 'github_api',
588-
'name' => $handle,
589-
'commit' => $last_sha,
590-
'message' => sprintf('Committed remote workspace changes to %s.', $context['branch']),
591-
'conversation_state' => 'incomplete',
592-
'next_required_tool' => 'workspace_git_push',
593-
'next_required_args' => array(
594-
'name' => $handle,
595-
'branch' => $context['branch'],
596-
),
573+
'success' => true,
574+
'backend' => 'github_api',
575+
'name' => $handle,
576+
'branch' => $context['branch'],
577+
'commit' => $last_sha,
578+
'message' => sprintf('Committed remote workspace changes to %s.', $context['branch']),
597579
);
598580
}
599581

@@ -1043,24 +1025,18 @@ public function git_push( string $handle, string $remote = 'origin', ?string $br
10431025
$branch_url = '' !== $push_branch ? 'https://github.com/' . $context['repo'] . '/tree/' . rawurlencode($push_branch) : null;
10441026

10451027
return array(
1046-
'success' => true,
1047-
'kind' => 'branch_push',
1048-
'backend' => 'github_api',
1049-
'name' => $handle,
1050-
'repo' => $context['repo'],
1051-
'workspace_repo' => $context['repo_name'] ?? $handle,
1052-
'github_repo' => $context['repo'],
1053-
'remote' => $remote,
1054-
'branch' => $push_branch,
1055-
'url' => $branch_url,
1056-
'html_url' => $branch_url,
1057-
'message' => 'Remote workspace branch already updated via GitHub API.',
1058-
'conversation_state' => 'incomplete',
1059-
'next_required_tool' => 'create_github_pull_request',
1060-
'next_required_args' => array(
1061-
'repo' => $context['repo'],
1062-
'head' => $push_branch,
1063-
),
1028+
'success' => true,
1029+
'kind' => 'branch_push',
1030+
'backend' => 'github_api',
1031+
'name' => $handle,
1032+
'repo' => $context['repo'],
1033+
'workspace_repo' => $context['repo_name'] ?? $handle,
1034+
'github_repo' => $context['repo'],
1035+
'remote' => $remote,
1036+
'branch' => $push_branch,
1037+
'url' => $branch_url,
1038+
'html_url' => $branch_url,
1039+
'message' => 'Remote workspace branch already updated via GitHub API.',
10641040
);
10651041
}
10661042

0 commit comments

Comments
 (0)