Skip to content

Commit 57ad12d

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
feat(pi): manage pull requests in update mode
1 parent ae5d5e4 commit 57ad12d

12 files changed

Lines changed: 681 additions & 224 deletions

File tree

apps/docs/content/docs/en/workflows/blocks/pi.mdx

Lines changed: 37 additions & 34 deletions
Large diffs are not rendered by default.

apps/sim/blocks/blocks/pi.test.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ describe('Pi block search fields', () => {
8686
})
8787

8888
describe('Pi cloud authoring surface', () => {
89-
it('offers Create PR, Update Branch, Review Code, and Local Dev as top-level modes', () => {
89+
it('offers Create PR, Update PR, Review Code, and Local Dev as top-level modes', () => {
9090
const mode = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'mode')
9191
const options =
9292
typeof mode?.options === 'function'
@@ -173,7 +173,7 @@ describe('Pi cloud authoring surface', () => {
173173
expect(evaluateSubBlockCondition(pullNumber?.condition, { mode: 'cloud_review' })).toBe(true)
174174
})
175175

176-
it('requires the target branch only in Update Branch mode', () => {
176+
it('requires the target branch only in Update PR mode', () => {
177177
expect(targetBranchField?.type).toBe('short-input')
178178
expect(targetBranchField?.required).toBe(true)
179179
expect(evaluateSubBlockCondition(targetBranchField?.condition, { mode: 'cloud_branch' })).toBe(
@@ -217,10 +217,22 @@ describe('Pi cloud authoring surface', () => {
217217
}
218218
})
219219

220-
it('hides Create PR and Review Code-specific fields', () => {
221-
for (const id of ['baseBranch', 'branchName', 'draft', 'prTitle', 'prBody', 'pullNumber']) {
220+
it('shows PR metadata controls and hides Create PR and Review Code-only fields', () => {
221+
for (const id of ['baseBranch', 'prTitle', 'prBody', 'prState']) {
222+
const field = PiBlock.subBlocks.find((subBlock) => subBlock.id === id)
223+
expect(evaluateSubBlockCondition(field?.condition, { mode: 'cloud_branch' })).toBe(true)
224+
}
225+
for (const id of ['branchName', 'draft', 'pullNumber']) {
222226
const field = PiBlock.subBlocks.find((subBlock) => subBlock.id === id)
223227
expect(evaluateSubBlockCondition(field?.condition, { mode: 'cloud_branch' })).toBe(false)
224228
}
229+
const prState = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'prState')
230+
expect(
231+
evaluateSubBlockCondition(prState?.condition, {
232+
mode: 'cloud_branch',
233+
babysitMode: true,
234+
})
235+
).toBe(false)
236+
expect(PiBlock.inputs.prState).toBeDefined()
225237
})
226238
})

apps/sim/blocks/blocks/pi.ts

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ const CLOUD_WITHOUT_BABYSIT: {
8181
value: 'cloud',
8282
and: { field: 'babysitMode', value: true, not: true },
8383
}
84+
const CLOUD_BRANCH_WITHOUT_BABYSIT: {
85+
field: 'mode'
86+
value: 'cloud_branch'
87+
and: { field: 'babysitMode'; value: true; not: true }
88+
} = {
89+
field: 'mode',
90+
value: 'cloud_branch',
91+
and: { field: 'babysitMode', value: true, not: true },
92+
}
8493
const LOCAL: { field: 'mode'; value: 'local' } = { field: 'mode', value: 'local' }
8594
const AUTHORING_MODES: {
8695
field: 'mode'
@@ -123,14 +132,14 @@ export const PiBlock: BlockConfig<PiResponse> = {
123132
description: 'Run an autonomous coding agent on a repo',
124133
authMode: AuthMode.ApiKey,
125134
longDescription:
126-
'The Pi Coding Agent runs the Pi harness against a real repository. Create PR spins up an isolated sandbox, clones a GitHub repo, edits with native shell + git, and opens a pull request; Update Branch checks out an existing remote branch and pushes commits back without force-pushing. Babysit Mode then keeps the pull request under watch, fixing trusted bot review threads and failing required checks in bounded rounds. Review Code checks out a pinned PR snapshot with read-only tools and posts a structured review with optional inline comments. Local Dev edits files on your own machine over SSH. Create PR, Update Branch, and Local Dev can reuse skills and multi-turn memory; Review Code runs without either because PR contents are untrusted. Any mode can optionally get one web_search tool backed by your own Exa, Serper, Parallel AI, or Firecrawl key; the agent writes its own queries, so repository content may reach the provider, and results are untrusted third-party data.',
135+
'The Pi Coding Agent runs the Pi harness against a real repository. Create PR spins up an isolated sandbox, clones a GitHub repo, edits with native shell + git, and opens a pull request; Update PR checks out an existing remote branch, pushes commits back without force-pushing, and creates or updates its pull request. Babysit Mode then keeps the pull request under watch, fixing trusted bot review threads and failing required checks in bounded rounds. Review Code checks out a pinned PR snapshot with read-only tools and posts a structured review with optional inline comments. Local Dev edits files on your own machine over SSH. Create PR, Update PR, and Local Dev can reuse skills and multi-turn memory; Review Code runs without either because PR contents are untrusted. Any mode can optionally get one web_search tool backed by your own Exa, Serper, Parallel AI, or Firecrawl key; the agent writes its own queries, so repository content may reach the provider, and results are untrusted third-party data.',
127136
bestPractices: `
128137
- Use Create PR for hands-off changes against a GitHub repo where a reviewable PR is the deliverable.
129-
- Use Update Branch to continue work on an existing remote branch, including one previously created by Pi.
130-
- Enable Babysit Mode on Create PR or Update Branch when trusted review bots and required checks should be monitored and fixed in bounded rounds.
138+
- Use Update PR to continue work on an existing remote branch and create or update its pull request.
139+
- Enable Babysit Mode on Create PR or Update PR when trusted review bots and required checks should be monitored and fixed in bounded rounds.
131140
- Use Review Code to analyze an existing PR and leave summary + inline review comments.
132141
- Use Local Dev to edit a repo on your own machine; expose the machine on a public hostname/tunnel so Sim can reach it over SSH.
133-
- Create PR and Update Branch require your own provider API key because the model runs in the sandbox. Review Code keeps the model key in Sim and can use either BYOK or a hosted key.
142+
- Create PR and Update PR require your own provider API key because the model runs in the sandbox. Review Code keeps the model key in Sim and can use either BYOK or a hosted key.
134143
- Internet Search is off by default and always needs your own key for the selected provider, entered on the block. There is no workspace BYOK fallback and no hosted key. Leave it on None unless the task genuinely needs external information.
135144
`,
136145
category: 'blocks',
@@ -160,9 +169,9 @@ export const PiBlock: BlockConfig<PiResponse> = {
160169
description: 'Runs in an isolated sandbox, clones your repo, and opens a PR',
161170
},
162171
{
163-
label: 'Update Branch',
172+
label: 'Update PR',
164173
id: 'cloud_branch',
165-
description: 'Checks out an existing branch, makes changes, and pushes commits back',
174+
description: 'Updates an existing branch and creates or updates its pull request',
166175
},
167176
{
168177
label: 'Review Code',
@@ -249,7 +258,7 @@ export const PiBlock: BlockConfig<PiResponse> = {
249258
paramVisibility: 'user-only',
250259
placeholder: 'GitHub personal access token',
251260
tooltip:
252-
'Personal access token used for GitHub access. Create PR needs clone/push/PR permissions; Update Branch needs clone/push permissions. With Babysit Mode, either also needs pull request, check/Actions read, thread write, and issue comment permissions. Review Code needs clone + review permissions.',
261+
'Personal access token used for GitHub access. Create PR and Update PR both need clone, push, and pull request read/write permissions. With Babysit Mode, either also needs check/Actions reads, thread writes, and issue comments. Review Code needs clone + review permissions.',
253262
required: true,
254263
condition: CLOUD_ANY,
255264
},
@@ -258,8 +267,9 @@ export const PiBlock: BlockConfig<PiResponse> = {
258267
title: 'Base Branch',
259268
type: 'short-input',
260269
placeholder: 'e.g., main (defaults to the repository default branch)',
261-
tooltip: 'The branch the pull request is opened against; the repo is cloned from it too.',
262-
condition: CLOUD,
270+
tooltip:
271+
'Create PR clones this branch and opens against it. Update PR changes an existing pull request only when set, or uses it when creating a missing pull request.',
272+
condition: CLOUD_AUTHORING,
263273
},
264274
{
265275
id: 'targetBranch',
@@ -277,7 +287,7 @@ export const PiBlock: BlockConfig<PiResponse> = {
277287
type: 'switch',
278288
defaultValue: false,
279289
description:
280-
'Use the branch PR, request the configured bot reviews, and fix trusted feedback and required checks in bounded rounds.',
290+
'Create or update the branch PR, request the configured bot reviews, and fix trusted feedback and required checks in bounded rounds.',
281291
condition: CLOUD_AUTHORING,
282292
},
283293
{
@@ -308,21 +318,36 @@ export const PiBlock: BlockConfig<PiResponse> = {
308318
mode: 'advanced',
309319
condition: CLOUD_WITHOUT_BABYSIT,
310320
},
321+
{
322+
id: 'prState',
323+
title: 'PR State',
324+
type: 'dropdown',
325+
defaultValue: 'preserve',
326+
options: [
327+
{ label: 'Leave unchanged', id: 'preserve' },
328+
{ label: 'Draft', id: 'draft' },
329+
{ label: 'Ready for review', id: 'ready' },
330+
],
331+
tooltip:
332+
'State for an existing pull request. When a pull request must be created, Leave unchanged uses the Create PR default and opens it as a draft.',
333+
mode: 'advanced',
334+
condition: CLOUD_BRANCH_WITHOUT_BABYSIT,
335+
},
311336
{
312337
id: 'prTitle',
313338
title: 'PR Title',
314339
type: 'short-input',
315-
placeholder: 'Generated from the run when blank',
340+
placeholder: 'Generated for a new PR; preserves an existing PR when blank',
316341
mode: 'advanced',
317-
condition: CLOUD,
342+
condition: CLOUD_AUTHORING,
318343
},
319344
{
320345
id: 'prBody',
321346
title: 'PR Body',
322347
type: 'long-input',
323-
placeholder: 'Generated from the run when blank',
348+
placeholder: 'Generated for a new PR; preserves an existing PR when blank',
324349
mode: 'advanced',
325-
condition: CLOUD,
350+
condition: CLOUD_AUTHORING,
326351
},
327352
{
328353
id: 'pullNumber',
@@ -546,19 +571,23 @@ export const PiBlock: BlockConfig<PiResponse> = {
546571
inputs: {
547572
mode: {
548573
type: 'string',
549-
description: 'Execution mode: Create PR, Update Branch, Review Code, or Local Dev',
574+
description: 'Execution mode: Create PR, Update PR, Review Code, or Local Dev',
550575
},
551576
task: { type: 'string', description: 'Instruction for the coding agent' },
552577
model: { type: 'string', description: 'AI model to use' },
553578
owner: { type: 'string', description: 'GitHub repository owner (cloud modes)' },
554579
repo: { type: 'string', description: 'GitHub repository name (cloud modes)' },
555580
githubToken: { type: 'string', description: 'GitHub token (cloud modes)' },
556-
baseBranch: { type: 'string', description: 'Base branch for the PR (Create PR)' },
581+
baseBranch: { type: 'string', description: 'Base branch for the pull request' },
557582
branchName: { type: 'string', description: 'Branch to create (Create PR)' },
558-
targetBranch: { type: 'string', description: 'Existing branch to update (Update Branch)' },
583+
targetBranch: { type: 'string', description: 'Existing branch to update (Update PR)' },
559584
draft: { type: 'boolean', description: 'Open the PR as a draft (Create PR)' },
560-
prTitle: { type: 'string', description: 'Pull request title (Create PR)' },
561-
prBody: { type: 'string', description: 'Pull request body (Create PR)' },
585+
prTitle: { type: 'string', description: 'Pull request title' },
586+
prBody: { type: 'string', description: 'Pull request body' },
587+
prState: {
588+
type: 'string',
589+
description: 'Existing pull request state: preserve, draft, or ready (Update PR)',
590+
},
562591
babysitMode: {
563592
type: 'boolean',
564593
description: 'Babysit trusted bot reviews and required checks after authoring',

apps/sim/executor/handlers/pi/backend.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,19 @@ export interface PiCloudBabysitOptions {
114114
executionId?: string
115115
}
116116

117-
/** Parameters for a cloud (E2B) Pi run that updates an existing branch. */
117+
export type PiPullRequestState = 'preserve' | 'draft' | 'ready'
118+
119+
/** Parameters for a cloud (E2B) Pi run that updates an existing branch and its pull request. */
118120
export interface PiCloudBranchRunParams extends PiContextualRunParams {
119121
mode: 'cloud_branch'
120122
owner: string
121123
repo: string
122124
githubToken: string
123125
targetBranch: string
126+
baseBranch?: string
127+
prTitle?: string
128+
prBody?: string
129+
prState: PiPullRequestState
124130
babysit?: PiCloudBabysitOptions
125131
}
126132

0 commit comments

Comments
 (0)