Skip to content

Commit 36a50dd

Browse files
committed
Merge branch 'main' into sdk-example
2 parents 9258106 + 73a0d35 commit 36a50dd

File tree

14 files changed

+746
-148
lines changed

14 files changed

+746
-148
lines changed

backend/src/templates/agent-list.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ export const agentTemplates: Record<AgentTemplateType | string, AgentTemplate> =
2222
{
2323
[AgentTemplateTypes.base]: {
2424
id: AgentTemplateTypes.base,
25-
...base(models.openrouter_gpt5),
25+
...base(models.openrouter_claude_sonnet_4),
2626
},
2727
[AgentTemplateTypes.base_lite]: {
2828
id: AgentTemplateTypes.base_lite,
29-
...base(models.openrouter_gemini2_5_flash),
29+
...base(models.openrouter_gpt5),
3030
},
3131
[AgentTemplateTypes.base_max]: {
3232
id: AgentTemplateTypes.base_max,

backend/src/templates/base-prompts.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -84,22 +84,17 @@ Messages from the system are surrounded by <system>${closeXml('system')} or <sys
8484
- Create an impressive demonstration showcasing web development capabilities
8585
8686
- **Don't summarize your changes** Omit summaries as much as possible. Be extremely concise when explaining the changes you made. There's no need to write a long explanation of what you did. Keep it to 1-2 two sentences max.
87-
- **end_turn:** Use end_turn only when waiting for the user's next input or when the task is fully complete; never immediately after planning or non-final tools (read_files, code_search, spawn_agents, think_deeply, create_plan, add_subgoal, update_subgoal, or diagnostic run_terminal_command).
88-
89-
90-
91-
92-
- **FINALLY, YOU MUST USE THE END TURN TOOL** When you have fully answered the user _or_ you are explicitly waiting for the user's next typed input, always conclude the message with a standalone ${getToolCallString('end_turn', {})} tool call (surrounded by its required blank lines). This should be at the end of your message, e.g.:
87+
- **Ending Your Response:** Your aim should be to completely fulfill the user's request before using ending your response. DO NOT END TURN IF YOU ARE STILL WORKING ON THE USER'S REQUEST. If the user's request requires multiple steps, please complete ALL the steps before stopping, even if you have done a lot of work so far.
88+
- **FINALLY, YOU MUST USE THE END TURN TOOL** When you have fully answered the user _or_ you are explicitly waiting for the user's next typed input, always conclude the message with a standalone \`${getToolCallString('end_turn', {})}\` tool call (surrounded by its required blank lines). This should be at the end of your message, e.g.:
9389
<example>
9490
User: Hi
95-
Assisistant: Hello, what can I do for you today?\n\n${getToolCallString('end_turn', {})}
91+
Assisistant: Hello, what can I do for you today?\\n\\n${getToolCallString('end_turn', {})}
9692
${closeXml('example')}
9793
98-
99-
100-
- **Finally:** When waiting for the user's next input or fully done, end with a standalone ${getToolCallString('end_turn', {})} (with required blank lines); e.g.:
10194
## Verifying Your Changes at the End of Your Response
95+
10296
### User has a \`codebuff.json\`
97+
10398
If the user has a \`codebuff.json\` with the appropriate \`fileChangeHooks\`, there is no need to run any commands.
10499
105100
If the \`fileChangeHooks\` are not configured, inform the user about the \`fileChangeHooks\` parameter.
@@ -229,9 +224,9 @@ export const baseAgentUserInputPrompt = (model: Model) => {
229224
PLACEHOLDER.KNOWLEDGE_FILES_CONTENTS +
230225
'\n\n<system_instructions>' +
231226
buildArray(
232-
'Proceed toward the user request and any subgoals. Please either 1. clarify the request or 2. complete the entire user request. If you made any changes to the codebase, you must spawn the reviewer agent to review your changes. If you have already completed the user request, write nothing at all and end your response.',
227+
'Proceed toward the user request and any subgoals. Please either 1. clarify the request or 2. complete the entire user request. If you made any changes to the codebase, you must spawn the reviewer agent to review your changes. Then, finally you must use the end_turn tool at the end of your response. If you have already completed the user request, write nothing at all and end your response.',
233228

234-
"Ask clarifying questions only when ambiguity would materially change the implementation; otherwise make a reasonable assumption (state it briefly) and proceed, or ask one targeted, non-blocking question. When clarifying, do not spawn the reviewer or other agents yet. Wait for the user's reply so you don't hide information.",
229+
"If there are multiple ways the user's request could be interpreted that would lead to very different outcomes, ask at least one clarifying question that will help you understand what they are really asking for, and then use the end_turn tool.",
235230

236231
'Use the spawn_agents tool to spawn subagents to help you complete the user request. You can spawn as many subagents as you want.',
237232

@@ -287,8 +282,7 @@ export const baseAgentUserInputPrompt = (model: Model) => {
287282
(isFlash || isGeminiPro) &&
288283
'You must use the spawn_agents tool to spawn subagents to help you complete the user request. You can spawn as many subagents as you want. It is a good idea to spawn a file explorer agent first to explore the codebase. Finally, you must spawn the reviewer agent to review your code changes.',
289284

290-
"Use end_turn only when waiting for the user's next input or fully done; never immediately after planning or non-final tools (read_files, code_search, spawn_agents, think_deeply, create_plan, add_subgoal, update_subgoal, or a non-final run_terminal_command).",
291-
'Never call end_turn immediately after read_files, code_search, spawn_agents, think_deeply, create_plan, add_subgoal, update_subgoal, or a non-final run_terminal_command; keep working or ask one concise question first.',
285+
'Finally, you must use the end_turn tool at the end of your response when you have completed the user request or want the user to respond to your message.',
292286
).join('\n\n') +
293287
closeXml('system_instructions')
294288
)

common/src/websockets/websocket-client.ts

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -228,27 +228,9 @@ export class APIRealtimeClient {
228228
}
229229

230230
async sendAction(action: ClientAction) {
231-
try {
232-
return await this.sendMessage('action', {
233-
data: action,
234-
})
235-
} catch (e) {
236-
// Print the error message for debugging.
237-
console.error(
238-
'Error sending action:',
239-
action.type,
240-
typeof e === 'object' && e !== null && 'message' in e ? e.message : e,
241-
)
242-
243-
console.log()
244-
console.log('Codebuff is exiting due to an error.')
245-
console.log('Make sure you are on the latest version of Codebuff!')
246-
console.log('-----------------------------------')
247-
console.log('Please run: npm install -g codebuff')
248-
console.log('-----------------------------------')
249-
250-
process.exit(1)
251-
}
231+
return await this.sendMessage('action', {
232+
data: action,
233+
})
252234
}
253235

254236
subscribe<T extends ServerAction['type']>(

npm-app/src/client.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,31 @@ import type { ProjectFileContext } from '@codebuff/common/util/file'
107107

108108
const LOW_BALANCE_THRESHOLD = 100
109109

110+
async function sendActionAndHandleError(
111+
ws: APIRealtimeClient,
112+
action: ClientAction,
113+
) {
114+
try {
115+
return await ws.sendAction(action)
116+
} catch (e) {
117+
// Print the error message for debugging.
118+
console.error(
119+
'Error sending action:',
120+
action.type,
121+
typeof e === 'object' && e !== null && 'message' in e ? e.message : e,
122+
)
123+
124+
console.log()
125+
console.log('Codebuff is exiting due to an error.')
126+
console.log('Make sure you are on the latest version of Codebuff!')
127+
console.log('-----------------------------------')
128+
console.log('Please run: npm install -g codebuff')
129+
console.log('-----------------------------------')
130+
131+
process.exit(1)
132+
}
133+
}
134+
110135
const WARNING_CONFIG = {
111136
[UserState.LOGGED_OUT]: {
112137
message: () => `Type "login" to unlock full access and get free credits!`,
@@ -750,7 +775,7 @@ export class Client {
750775
const { filePaths, requestId } = a
751776
const files = getFiles(filePaths)
752777

753-
this.webSocket.sendAction({
778+
sendActionAndHandleError(this.webSocket, {
754779
type: 'read-files-response',
755780
files,
756781
requestId,
@@ -778,7 +803,7 @@ export class Client {
778803
'User input ID mismatch - rejecting tool call request',
779804
)
780805

781-
this.webSocket.sendAction({
806+
sendActionAndHandleError(this.webSocket, {
782807
type: 'tool-call-response',
783808
requestId,
784809
success: false,
@@ -804,7 +829,7 @@ export class Client {
804829
if (this.userInputId) {
805830
Spinner.get().start('Processing results...')
806831
}
807-
this.webSocket.sendAction({
832+
sendActionAndHandleError(this.webSocket, {
808833
type: 'tool-call-response',
809834
requestId,
810835
success: true,
@@ -823,7 +848,7 @@ export class Client {
823848

824849
// Send error response back to backend
825850
Spinner.get().start('Fixing...')
826-
this.webSocket.sendAction({
851+
sendActionAndHandleError(this.webSocket, {
827852
type: 'tool-call-response',
828853
requestId,
829854
success: false,
@@ -1032,7 +1057,7 @@ export class Client {
10321057
repoUrl: loggerContext.repoUrl,
10331058
// repoName: loggerContext.repoName,
10341059
}
1035-
this.webSocket.sendAction(action)
1060+
sendActionAndHandleError(this.webSocket, action)
10361061

10371062
return {
10381063
responsePromise,
@@ -1116,7 +1141,7 @@ export class Client {
11161141
(id) => id !== this.userInputId,
11171142
)
11181143

1119-
this.webSocket.sendAction({
1144+
sendActionAndHandleError(this.webSocket, {
11201145
type: 'cancel-user-input',
11211146
authToken: this.user?.authToken,
11221147
promptId: this.userInputId,
@@ -1554,7 +1579,7 @@ Go to https://www.codebuff.com/config for more information.`) +
15541579
// Add repoUrl here as per the diff for client.ts
15551580
repoUrl: loggerContext.repoUrl,
15561581
}
1557-
this.webSocket.sendAction(initAction)
1582+
sendActionAndHandleError(this.webSocket, initAction)
15581583

15591584
await this.fetchStoredApiKeyTypes()
15601585
}

sdk/CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22

33
All notable changes to the @codebuff/sdk package will be documented in this file.
44

5-
## [0.0.1] - 2025-01-05
5+
## [0.1.5] - 2025-08-09
6+
7+
### Added
8+
- Complete `CodebuffClient`
9+
- Better docs
10+
- New `run()` api
11+
12+
## [0.0.1] - 2025-08-05
613

714
### Added
815
- Initial release of the Codebuff SDK

sdk/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,52 @@ const run2 = await client.run({
6060
// event includes streamed updates like assistant messages and tool calls
6161
console.log('event:', event)
6262
},
63+
64+
// Custom agents (optional)
65+
agentConfigs: [
66+
{
67+
id: 'my-awesome-agent',
68+
model: 'openai/gpt-5',
69+
displayName: 'My awesome agent'
70+
instructionsPrompt: 'Do something awesome'
71+
// ... other AgentConfig properties
72+
},
73+
],
6374
})
6475
```
6576

77+
## API Reference
78+
79+
### `client.run(options)`
80+
81+
Runs a Codebuff agent with the specified options.
82+
83+
#### Parameters
84+
85+
- **`agent`** (string, required): The agent to run. Use `'base'` for the default agent, or specify a custom agent ID if you made your own agent config.
86+
87+
- **`prompt`** (string, required): The user prompt describing what you want the agent to do.
88+
89+
- **`params`** (object, optional): Additional parameters for the agent. Most agents don't use this, but some custom agents can take a JSON object as input in addition to the user prompt string.
90+
91+
- **`handleEvent`** (function, optional): Callback function that receives every event during execution (assistant messages, tool calls, etc.). This allows you to stream the agent's progress in real-time. We will likely add a token-by-token streaming callback in the future.
92+
93+
- **`previousRun`** (object, optional): JSON state returned from a previous `run()` call. Use this to continue a conversation or session with the agent, maintaining context from previous interactions.
94+
95+
- **`projectFiles`** (object, optional): All the files in your project as a plain JavaScript object. Keys should be the full path from your current directory to each file, and values should be the string contents of the file. Example: `{ "src/index.ts": "console.log('hi')" }`. This helps Codebuff pick good source files for context. Note: This parameter was previously named `allFiles` but has been renamed for clarity.
96+
97+
- **`knowledgeFiles`** (object, optional): Knowledge files to inject into every `run()` call. Uses the same schema as `projectFiles` - keys are file paths and values are file contents. These files are added directly to the agent's context.
98+
99+
- **`agentConfigs`** (array, optional): Array of custom agent configurations. Each object should satisfy the AgentConfig type.
100+
- **`maxAgentSteps`** (number, optional): Maximum number of steps the agent can take before stopping. Use this as a safety measure in case your agent starts going off the rails. A reasonable number is around 20.
101+
102+
#### Returns
103+
104+
Returns a Promise that resolves to a `RunState` object containing:
105+
106+
- `sessionState`: The current session state that can be passed to subsequent runs
107+
- `toolResults`: Results from any tools that were executed during the run
108+
66109
## License
67110

68111
MIT

sdk/package.json

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,27 @@
22
"name": "@codebuff/sdk",
33
"private": false,
44
"access": "public",
5-
"version": "0.1.3",
5+
"version": "0.1.6",
66
"description": "Official SDK for Codebuff — AI coding agent & framework",
77
"license": "MIT",
88
"type": "module",
9-
"main": "./dist/index.js",
10-
"types": "./dist/index.d.ts",
9+
"main": "./dist/sdk/src/index.js",
10+
"types": "./dist/sdk/src/index.d.ts",
1111
"exports": {
1212
".": {
13-
"types": "./dist/index.d.ts",
14-
"import": "./dist/index.js",
15-
"default": "./dist/index.js"
13+
"types": "./dist/sdk/src/index.d.ts",
14+
"import": "./dist/sdk/src/index.js",
15+
"default": "./dist/sdk/src/index.js"
1616
}
1717
},
1818
"files": [
1919
"dist",
20-
"README.md"
20+
"README.md",
21+
"CHANGELOG.md"
2122
],
2223
"scripts": {
23-
"build": "tsc",
24+
"build": "bun run copy-types && tsc",
25+
"copy-types": "mkdir -p src/types && cp ../common/src/util/types/agent-config.d.ts src/types/agent-config.ts && cp ../common/src/util/types/tools.d.ts src/types/tools.ts",
2426
"clean": "rm -rf dist",
2527
"prepare-dist": "node scripts/publish.js --dry-run",
2628
"publish-sdk": "node scripts/publish.js --public",

sdk/scripts/publish.js

Lines changed: 10 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -25,74 +25,34 @@ function run(command, options = {}) {
2525
function main() {
2626
const args = process.argv.slice(2)
2727
const isDryRun = args.includes('--dry-run')
28-
28+
2929
log('Starting SDK publishing process...')
30-
30+
3131
// Clean and build
3232
log('Cleaning previous build...')
3333
run('bun run clean')
34-
34+
3535
log('Building TypeScript...')
3636
run('bun run build')
37-
38-
// Prepare package.json for publishing
39-
log('Preparing package.json for publishing...')
40-
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'))
41-
42-
// No workspace dependencies to handle anymore
43-
44-
// Update paths for publishing from dist directory
45-
packageJson.main = './sdk/src/index.js'
46-
packageJson.types = './sdk/src/index.d.ts'
47-
packageJson.exports = {
48-
'.': {
49-
types: './sdk/src/index.d.ts',
50-
import: './sdk/src/index.js',
51-
default: './sdk/src/index.js'
52-
}
53-
}
54-
55-
// Update files field to include all built files
56-
packageJson.files = [
57-
'sdk/',
58-
'common/',
59-
'README.md',
60-
'CHANGELOG.md'
61-
]
62-
63-
// Write the modified package.json to dist
64-
fs.writeFileSync('dist/package.json', JSON.stringify(packageJson, null, 2))
65-
66-
// Copy other files
67-
log('Copying additional files...')
68-
const filesToCopy = ['README.md', 'CHANGELOG.md']
69-
70-
for (const file of filesToCopy) {
71-
if (fs.existsSync(file)) {
72-
fs.copyFileSync(file, `dist/${file}`)
73-
log(`Copied ${file}`)
74-
}
75-
}
76-
37+
7738
// Verify the package
7839
log('Verifying package contents...')
79-
run('npm pack --dry-run', { cwd: 'dist' })
80-
40+
run('npm pack --dry-run')
41+
8142
if (isDryRun) {
8243
log('Dry run complete! Package is ready for publishing.')
8344
log('To publish for real, run: bun run publish-sdk')
8445
return
8546
}
86-
47+
8748
// Publish
8849
log('Publishing to npm...')
89-
const publishCommand = 'npm publish'
90-
run(publishCommand, { cwd: 'dist' })
50+
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'))
51+
run('npm publish')
9152
log('✅ SDK published successfully!')
9253
log(`📦 Package: ${packageJson.name}@${packageJson.version}`)
9354
}
94-
55+
9556
if (import.meta.url === `file://${process.argv[1]}`) {
9657
main()
9758
}
98-

0 commit comments

Comments
 (0)