Skip to content

Commit 5fa94fe

Browse files
Bill LeoutsakosBill Leoutsakos
authored andcommitted
feat(pi): add update branch mode
1 parent d3a5831 commit 5fa94fe

13 files changed

Lines changed: 1121 additions & 191 deletions

File tree

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

Lines changed: 59 additions & 30 deletions
Large diffs are not rendered by default.

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

Lines changed: 105 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { PI_SEARCH_PROVIDERS } from '@/executor/handlers/pi/keys'
2222

2323
const searchProviderField = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'searchProvider')
2424
const searchApiKeyField = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'searchApiKey')
25+
const targetBranchField = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'targetBranch')
2526

2627
function searchKeyVisible(values: Record<string, unknown>): boolean {
2728
return evaluateSubBlockCondition(searchApiKeyField?.condition, values)
@@ -74,69 +75,73 @@ describe('Pi block search fields', () => {
7475
})
7576
})
7677

77-
describe('Pi Create PR Babysit surface', () => {
78-
it('offers exactly Create PR, Review Code, and Local Dev as top-level modes', () => {
78+
describe('Pi cloud authoring surface', () => {
79+
it('offers Create PR, Update Branch, Review Code, and Local Dev as top-level modes', () => {
7980
const mode = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'mode')
8081
const options =
8182
typeof mode?.options === 'function'
8283
? mode.options()
8384
: (mode?.options as Array<{ id: string }> | undefined)
8485

85-
expect(options?.map(({ id }) => id)).toEqual(['cloud', 'cloud_review', 'local'])
86+
expect(options?.map(({ id }) => id)).toEqual(['cloud', 'cloud_branch', 'cloud_review', 'local'])
8687
})
8788

88-
it('declares the toggle, required reviewer mentions, advanced rounds, and result outputs', () => {
89-
const toggle = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'babysitMode')
90-
const maxRounds = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'maxRounds')
91-
const mentions = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'reviewMentions')
92-
93-
expect(toggle).toMatchObject({
94-
type: 'switch',
95-
defaultValue: false,
96-
condition: { field: 'mode', value: 'cloud' },
97-
})
98-
expect(maxRounds).toMatchObject({
99-
type: 'short-input',
100-
defaultValue: '3',
101-
mode: 'advanced',
102-
condition: {
103-
field: 'mode',
104-
value: 'cloud',
105-
and: { field: 'babysitMode', value: true },
106-
},
107-
})
108-
expect(mentions).toMatchObject({
109-
type: 'short-input',
110-
defaultValue: '',
111-
hideDividerBefore: true,
112-
required: {
113-
field: 'mode',
114-
value: 'cloud',
115-
and: { field: 'babysitMode', value: true },
116-
},
117-
condition: {
118-
field: 'mode',
119-
value: 'cloud',
120-
and: { field: 'babysitMode', value: true },
121-
},
122-
})
123-
for (const output of [
124-
'rounds',
125-
'threadsClean',
126-
'checksGreen',
127-
'threadsResolved',
128-
'commitsPushed',
129-
'stopReason',
130-
]) {
131-
expect(PiBlock.outputs[output]).toMatchObject({
89+
it.each(['cloud', 'cloud_branch'])(
90+
'declares Babysit controls and outputs for %s',
91+
(authoringMode) => {
92+
const toggle = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'babysitMode')
93+
const maxRounds = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'maxRounds')
94+
const mentions = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'reviewMentions')
95+
96+
expect(toggle).toMatchObject({
97+
type: 'switch',
98+
defaultValue: false,
99+
condition: { field: 'mode', value: ['cloud', 'cloud_branch'] },
100+
})
101+
expect(maxRounds).toMatchObject({
102+
type: 'short-input',
103+
defaultValue: '3',
104+
mode: 'advanced',
132105
condition: {
133106
field: 'mode',
134-
value: 'cloud',
107+
value: ['cloud', 'cloud_branch'],
135108
and: { field: 'babysitMode', value: true },
136109
},
137110
})
111+
expect(mentions).toMatchObject({
112+
type: 'short-input',
113+
defaultValue: '',
114+
hideDividerBefore: true,
115+
required: {
116+
field: 'mode',
117+
value: ['cloud', 'cloud_branch'],
118+
and: { field: 'babysitMode', value: true },
119+
},
120+
condition: {
121+
field: 'mode',
122+
value: ['cloud', 'cloud_branch'],
123+
and: { field: 'babysitMode', value: true },
124+
},
125+
})
126+
for (const output of [
127+
'rounds',
128+
'threadsClean',
129+
'checksGreen',
130+
'threadsResolved',
131+
'commitsPushed',
132+
'stopReason',
133+
]) {
134+
expect(PiBlock.outputs[output]).toMatchObject({
135+
condition: {
136+
field: 'mode',
137+
value: ['cloud', 'cloud_branch'],
138+
and: { field: 'babysitMode', value: true },
139+
},
140+
})
141+
}
142+
expect(evaluateSubBlockCondition(toggle?.condition, { mode: authoringMode })).toBe(true)
138143
}
139-
})
144+
)
140145

141146
it('requires a task and hides Draft PR while Babysit Mode is enabled', () => {
142147
const task = PiBlock.subBlocks.find((subBlock) => subBlock.id === 'task')
@@ -157,4 +162,55 @@ describe('Pi Create PR Babysit surface', () => {
157162
expect(evaluateSubBlockCondition(pullNumber?.condition, { mode: 'cloud' })).toBe(false)
158163
expect(evaluateSubBlockCondition(pullNumber?.condition, { mode: 'cloud_review' })).toBe(true)
159164
})
165+
166+
it('requires the target branch only in Update Branch mode', () => {
167+
expect(targetBranchField?.type).toBe('short-input')
168+
expect(targetBranchField?.required).toBe(true)
169+
expect(evaluateSubBlockCondition(targetBranchField?.condition, { mode: 'cloud_branch' })).toBe(
170+
true
171+
)
172+
expect(evaluateSubBlockCondition(targetBranchField?.condition, { mode: 'cloud' })).toBe(false)
173+
expect(evaluateSubBlockCondition(targetBranchField?.condition, { mode: 'cloud_review' })).toBe(
174+
false
175+
)
176+
expect(evaluateSubBlockCondition(targetBranchField?.condition, { mode: 'local' })).toBe(false)
177+
})
178+
179+
it('declares the target branch input and branch output for cloud authoring modes', () => {
180+
expect(PiBlock.inputs.targetBranch).toBeDefined()
181+
expect(
182+
evaluateSubBlockCondition(PiBlock.outputs.branch.condition, { mode: 'cloud_branch' })
183+
).toBe(true)
184+
expect(evaluateSubBlockCondition(PiBlock.outputs.branch.condition, { mode: 'cloud' })).toBe(
185+
true
186+
)
187+
expect(
188+
evaluateSubBlockCondition(PiBlock.outputs.branch.condition, { mode: 'cloud_review' })
189+
).toBe(false)
190+
})
191+
192+
it('reuses skills and memory fields, including their dependent controls', () => {
193+
for (const id of [
194+
'skills',
195+
'memoryType',
196+
'conversationId',
197+
'slidingWindowSize',
198+
'slidingWindowTokens',
199+
]) {
200+
const field = PiBlock.subBlocks.find((subBlock) => subBlock.id === id)
201+
expect(
202+
evaluateSubBlockCondition(field?.condition, {
203+
mode: 'cloud_branch',
204+
memoryType: id === 'slidingWindowTokens' ? 'sliding_window_tokens' : 'sliding_window',
205+
})
206+
).toBe(true)
207+
}
208+
})
209+
210+
it('hides Create PR and Review Code-specific fields', () => {
211+
for (const id of ['baseBranch', 'branchName', 'draft', 'prTitle', 'prBody', 'pullNumber']) {
212+
const field = PiBlock.subBlocks.find((subBlock) => subBlock.id === id)
213+
expect(evaluateSubBlockCondition(field?.condition, { mode: 'cloud_branch' })).toBe(false)
214+
}
215+
})
160216
})

0 commit comments

Comments
 (0)