Skip to content

Commit e3c2f5a

Browse files
committed
Merge branch 'main' into brandon/tui
2 parents 157f52e + 595d1e7 commit e3c2f5a

File tree

61 files changed

+722
-806
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+722
-806
lines changed

.agents/base2/base2-gpt-5.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const definition: SecretAgentDefinition = {
1515
'researcher-docs',
1616
'commander',
1717
'reviewer-gpt-5',
18-
'editor-gpt-5',
1918
'context-pruner',
2019
),
2120
}

.agents/base2/base2.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ export const createBase2: (
4242
'commander',
4343
'generate-plan',
4444
'reviewer',
45-
'editor',
4645
'context-pruner',
4746
),
4847

@@ -56,18 +55,6 @@ In between layers, you are encouraged to use the read_files tool to read files t
5655
5756
Continue to spawn layers of agents until have completed the user's request or require more information from the user.
5857
59-
## Example layers
60-
61-
The user asks you to implement a new feature. You respond in multiple steps:
62-
63-
1. Spawn file-pickers with different prompts to find relevant files; spawn a find-all-referencer to find more relevant files and answer questions about the codebase; spawn 1 docs researcher to find relevant docs.
64-
1a. Read all the relevant files using the read_files tool.
65-
2. Spawn one more file picker and one more find-all-referencer with different prompts to find relevant files.
66-
2a. Read all the relevant files using the read_files tool.
67-
3. Spawn a generate-plan agent to generate a plan for the changes.
68-
4. Use the str_replace or write_file tool to make the changes.
69-
5. Spawn a reviewer to review the changes.
70-
7158
## Spawning agents guidelines
7259
7360
- **Sequence agents properly:** Keep in mind dependencies when spawning different agents. Don't spawn agents in parallel that depend on each other. Be conservative sequencing agents so they can build on each other's insights:
@@ -77,7 +64,6 @@ The user asks you to implement a new feature. You respond in multiple steps:
7764
- Reviewers should be spawned after you have made your edits.
7865
- **No need to include context:** When prompting an agent, realize that many agents can already see the entire conversation history, so you can be brief in prompting them without needing to include context.
7966
- **Don't spawn reviewers for trivial changes or quick follow-ups:** You should spawn the reviewer for most changes, but not for little changes or simple follow-ups.
80-
- **Don't spawn editors unless asked to parallelize or use multiple agents:** The editor performs worse at editing and is not to be used most of the time.
8167
8268
# Core Mandates
8369
@@ -130,9 +116,23 @@ The following is the state of the git repository at the start of the conversatio
130116
${PLACEHOLDER.GIT_CHANGES_PROMPT}
131117
`,
132118

133-
instructionsPrompt: `Orchestrate the completion of the user's request using your specialized sub-agents. Take your time and be comprehensive.`,
119+
instructionsPrompt: `Orchestrate the completion of the user's request using your specialized sub-agents. Take your time and be comprehensive.
120+
121+
## Example response
122+
123+
The user asks you to implement a new feature. You respond in multiple steps:
124+
125+
1. Spawn file-pickers with different prompts to find relevant files; spawn a find-all-referencer to find more relevant files and answer questions about the codebase; spawn 1 docs researcher to find relevant docs.
126+
1a. Read all the relevant files using the read_files tool.
127+
2. Spawn one more file picker and one more find-all-referencer with different prompts to find relevant files.
128+
2a. Read all the relevant files using the read_files tool.
129+
3. Spawn a generate-plan agent to generate a plan for the changes.
130+
4. Use the str_replace or write_file tool to make the changes.
131+
5. Spawn a reviewer to review the changes.
132+
6. Fix any issues raised by the reviewer.
133+
7. Inform the user that you have completed the task in one sentence without a final summary.`,
134134

135-
stepPrompt: `Don't forget to spawn agents that could help, especially: the file-picker and find-all-referencer to get codebase context, the generate-plan agent to create a plan, and the reviewer to review changes. No need to provide any final summary.`,
135+
stepPrompt: `Don't forget to spawn agents that could help, especially: the file-picker and find-all-referencer to get codebase context, the generate-plan agent to create a plan, and the reviewer to review changes.`,
136136

137137
handleSteps: function* ({ prompt, params }) {
138138
let steps = 0
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { ToolCall } from 'types/agent-definition'
2+
import { publisher } from '../constants'
3+
4+
import {
5+
PLACEHOLDER,
6+
type SecretAgentDefinition,
7+
} from '../types/secret-agent-definition'
8+
9+
const definition: SecretAgentDefinition = {
10+
id: 'file-picker-max',
11+
displayName: 'Fletcher the File Fetcher',
12+
publisher,
13+
model: 'anthropic/claude-haiku-4.5',
14+
spawnerPrompt:
15+
'Spawn to find relevant files in a codebase related to the prompt. Cannot do string searches on the codebase.',
16+
inputSchema: {
17+
prompt: {
18+
type: 'string',
19+
description: 'A coding task to complete',
20+
},
21+
},
22+
outputMode: 'last_message',
23+
includeMessageHistory: false,
24+
toolNames: [],
25+
spawnableAgents: [],
26+
27+
systemPrompt: `You are an expert at finding relevant files in a codebase. ${PLACEHOLDER.FILE_TREE_PROMPT_SMALL}`,
28+
instructionsPrompt: `Instructions:
29+
- Don't use any tools.
30+
- Provide a short report of the locations in the codebase that could be helpful. Focus on the files that are most relevant to the user prompt.
31+
In your report, please give a very concise analysis that includes the full paths of files that are relevant and (briefly) how they could be useful.
32+
`.trim(),
33+
34+
handleSteps: function* ({ agentState, prompt, params }) {
35+
yield {
36+
toolName: 'find_files',
37+
input: { prompt: prompt ?? '' },
38+
} satisfies ToolCall
39+
yield 'STEP_ALL'
40+
},
41+
}
42+
43+
export default definition

backend/src/__tests__/cost-aggregation.integration.test.ts

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@ import * as agentRegistry from '../templates/agent-registry'
2020
import * as websocketAction from '../websockets/websocket-action'
2121

2222
import type { AgentTemplate } from '../templates/types'
23+
import type { ServerAction } from '@codebuff/common/actions'
2324
import type {
2425
AgentRuntimeDeps,
2526
AgentRuntimeScopedDeps,
2627
} from '@codebuff/common/types/contracts/agent-runtime'
28+
import type { SendActionFn } from '@codebuff/common/types/contracts/client'
2729
import type { ProjectFileContext } from '@codebuff/common/util/file'
28-
import type { WebSocket } from 'ws'
30+
import type { Mock } from 'bun:test'
2931

3032
const mockFileContext: ProjectFileContext = {
3133
projectRoot: '/test',
@@ -84,34 +86,17 @@ const mockFileContext: ProjectFileContext = {
8486
},
8587
}
8688

87-
class MockWebSocket {
88-
sentActions: any[] = []
89-
90-
send(msg: string) {
91-
// Capture sent messages for verification
92-
try {
93-
const parsed = JSON.parse(msg)
94-
if (parsed.type === 'action') {
95-
this.sentActions.push(parsed.data)
96-
}
97-
} catch {}
98-
}
99-
100-
close() {}
101-
on(event: string, listener: (...args: any[]) => void) {}
102-
removeListener(event: string, listener: (...args: any[]) => void) {}
103-
}
104-
10589
describe('Cost Aggregation Integration Tests', () => {
10690
let mockLocalAgentTemplates: Record<string, any>
107-
let mockWebSocket: MockWebSocket
10891
let agentRuntimeImpl: AgentRuntimeDeps
10992
let agentRuntimeScopedImpl: AgentRuntimeScopedDeps
11093

11194
beforeEach(async () => {
11295
agentRuntimeImpl = { ...TEST_AGENT_RUNTIME_IMPL }
113-
agentRuntimeScopedImpl = { ...TEST_AGENT_RUNTIME_SCOPED_IMPL }
114-
mockWebSocket = new MockWebSocket()
96+
agentRuntimeScopedImpl = {
97+
...TEST_AGENT_RUNTIME_SCOPED_IMPL,
98+
sendAction: mock(() => {}),
99+
}
115100

116101
// Setup mock agent templates
117102
mockLocalAgentTemplates = {
@@ -258,7 +243,6 @@ describe('Cost Aggregation Integration Tests', () => {
258243
const result = await mainPrompt({
259244
...agentRuntimeImpl,
260245
...agentRuntimeScopedImpl,
261-
ws: mockWebSocket as unknown as WebSocket,
262246
action,
263247
userId: TEST_USER_ID,
264248
clientSessionId: 'test-session',
@@ -294,17 +278,18 @@ describe('Cost Aggregation Integration Tests', () => {
294278
await websocketAction.callMainPrompt({
295279
...agentRuntimeImpl,
296280
...agentRuntimeScopedImpl,
297-
ws: mockWebSocket as unknown as WebSocket,
298281
action,
299282
userId: TEST_USER_ID,
300283
promptId: 'test-prompt',
301284
clientSessionId: 'test-session',
302285
})
303286

304287
// Verify final cost is included in prompt response
305-
const promptResponse = mockWebSocket.sentActions.find(
306-
(action) => action.type === 'prompt-response',
307-
)
288+
const promptResponse = (
289+
agentRuntimeScopedImpl.sendAction as Mock<SendActionFn>
290+
).mock.calls
291+
.map((call) => call[0].action)
292+
.find((action: ServerAction) => action.type === 'prompt-response') as any
308293

309294
expect(promptResponse).toBeDefined()
310295
expect(promptResponse.promptId).toBe('test-prompt')
@@ -363,7 +348,6 @@ describe('Cost Aggregation Integration Tests', () => {
363348
const result = await mainPrompt({
364349
...agentRuntimeImpl,
365350
...agentRuntimeScopedImpl,
366-
ws: mockWebSocket as unknown as WebSocket,
367351
action,
368352
userId: TEST_USER_ID,
369353
clientSessionId: 'test-session',
@@ -420,7 +404,6 @@ describe('Cost Aggregation Integration Tests', () => {
420404
result = await mainPrompt({
421405
...agentRuntimeImpl,
422406
...agentRuntimeScopedImpl,
423-
ws: mockWebSocket as unknown as WebSocket,
424407
action,
425408
userId: TEST_USER_ID,
426409
clientSessionId: 'test-session',
@@ -470,7 +453,6 @@ describe('Cost Aggregation Integration Tests', () => {
470453
await mainPrompt({
471454
...agentRuntimeImpl,
472455
...agentRuntimeScopedImpl,
473-
ws: mockWebSocket as unknown as WebSocket,
474456
action,
475457
userId: TEST_USER_ID,
476458
clientSessionId: 'test-session',
@@ -511,17 +493,18 @@ describe('Cost Aggregation Integration Tests', () => {
511493
await websocketAction.callMainPrompt({
512494
...agentRuntimeImpl,
513495
...agentRuntimeScopedImpl,
514-
ws: mockWebSocket as unknown as WebSocket,
515496
action,
516497
userId: TEST_USER_ID,
517498
promptId: 'test-prompt',
518499
clientSessionId: 'test-session',
519500
})
520501

521502
// Server should have reset the malicious value and calculated correct cost
522-
const promptResponse = mockWebSocket.sentActions.find(
523-
(action) => action.type === 'prompt-response',
524-
)
503+
const promptResponse = (
504+
agentRuntimeScopedImpl.sendAction as Mock<SendActionFn>
505+
).mock.calls
506+
.map((call) => call[0].action)
507+
.find((action) => action.type === 'prompt-response') as any
525508

526509
expect(promptResponse).toBeDefined()
527510
expect(promptResponse.sessionState.mainAgentState.creditsUsed).toBeLessThan(

backend/src/__tests__/cost-aggregation.test.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import { handleSpawnAgents } from '../tools/handlers/tool/spawn-agents'
2222

2323
import type { AgentState } from '@codebuff/common/types/session-state'
2424
import type { ProjectFileContext } from '@codebuff/common/util/file'
25-
import type { WebSocket } from 'ws'
2625

2726
const mockFileContext: ProjectFileContext = {
2827
projectRoot: '/test',
@@ -137,7 +136,6 @@ describe('Cost Aggregation System', () => {
137136
}
138137

139138
const mockValidatedState = {
140-
ws: new MockWebSocket() as unknown as WebSocket,
141139
fingerprintId: 'test-fingerprint',
142140
userId: 'test-user',
143141
agentTemplate: mockAgentTemplate,
@@ -212,7 +210,6 @@ describe('Cost Aggregation System', () => {
212210
}
213211

214212
const mockValidatedState = {
215-
ws: new MockWebSocket() as unknown as WebSocket,
216213
fingerprintId: 'test-fingerprint',
217214
userId: 'test-user',
218215
agentTemplate: mockAgentTemplate,
@@ -371,7 +368,6 @@ describe('Cost Aggregation System', () => {
371368

372369
// Mock subagent spawning that adds their costs
373370
const mockValidatedState = {
374-
ws: new MockWebSocket() as unknown as WebSocket,
375371
fingerprintId: 'test-fingerprint',
376372
userId: 'test-user',
377373
agentTemplate: mockAgentTemplate,

backend/src/__tests__/fast-rewrite.test.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import path from 'path'
22

33
import { TEST_USER_ID } from '@codebuff/common/old-constants'
4-
import { TEST_AGENT_RUNTIME_IMPL } from '@codebuff/common/testing/impl/agent-runtime'
4+
import {
5+
TEST_AGENT_RUNTIME_IMPL,
6+
TEST_AGENT_RUNTIME_SCOPED_IMPL,
7+
} from '@codebuff/common/testing/impl/agent-runtime'
58
import {
69
clearMockedModules,
710
mockModule,
@@ -11,11 +14,15 @@ import { createPatch } from 'diff'
1114

1215
import { rewriteWithOpenAI } from '../fast-rewrite'
1316

14-
import type { AgentRuntimeDeps } from '@codebuff/common/types/contracts/agent-runtime'
15-
16-
let agentRuntimeImpl: AgentRuntimeDeps
17+
import type {
18+
AgentRuntimeDeps,
19+
AgentRuntimeScopedDeps,
20+
} from '@codebuff/common/types/contracts/agent-runtime'
1721

1822
describe.skip('rewriteWithOpenAI', () => {
23+
let agentRuntimeImpl: AgentRuntimeDeps
24+
let agentRuntimeScopedImpl: AgentRuntimeScopedDeps
25+
1926
beforeAll(() => {
2027
// Mock database interactions
2128
mockModule('pg-pool', () => ({
@@ -40,6 +47,7 @@ describe.skip('rewriteWithOpenAI', () => {
4047

4148
beforeEach(() => {
4249
agentRuntimeImpl = { ...TEST_AGENT_RUNTIME_IMPL }
50+
agentRuntimeScopedImpl = { ...TEST_AGENT_RUNTIME_SCOPED_IMPL }
4351
})
4452

4553
afterAll(() => {
@@ -54,6 +62,7 @@ describe.skip('rewriteWithOpenAI', () => {
5462

5563
const result = await rewriteWithOpenAI({
5664
...agentRuntimeImpl,
65+
...agentRuntimeScopedImpl,
5766
oldContent: originalContent,
5867
editSnippet,
5968
clientSessionId: 'clientSessionId',

0 commit comments

Comments
 (0)