Skip to content

Commit e89e48d

Browse files
[render preview][codecane] fix: dynamic agents (#208)
Co-authored-by: Codebuff <noreply@codebuff.com>
1 parent d56bf70 commit e89e48d

File tree

5 files changed

+42
-67
lines changed

5 files changed

+42
-67
lines changed

.github/workflows/npm-app-release-staging.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ jobs:
134134
new-version: ${{ needs.prepare-and-commit-staging.outputs.new_version }}
135135
artifact-name: updated-staging-package
136136
checkout-ref: ${{ github.event.pull_request.head.sha }}
137-
env-overrides: '{"NEXT_PUBLIC_CB_ENVIRONMENT": "prod", "NEXT_PUBLIC_BACKEND_URL": "backend-pr-187-cg9u.onrender.com"}'
137+
env-overrides: '{"NEXT_PUBLIC_CB_ENVIRONMENT": "prod", "NEXT_PUBLIC_BACKEND_URL": "backend-pr-208-n6sd.onrender.com"}'
138138
secrets: inherit
139139

140140
# Create GitHub prerelease with all binaries

backend/src/templates/dynamic-agent-service.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,12 @@ export class DynamicAgentService {
4848
const hasAgentTemplates = Object.keys(agentTemplates).length > 0
4949

5050
if (!hasAgentTemplates) {
51-
logger.debug('No agent templates found in fileContext')
5251
this.isLoaded = true
5352
return {
5453
templates: this.templates,
5554
validationErrors: this.validationErrors,
5655
}
5756
}
58-
5957
try {
6058
// Use agentTemplates from fileContext - keys are already full paths
6159
const jsonFiles = Object.keys(agentTemplates).filter((filePath) =>
@@ -88,6 +86,14 @@ export class DynamicAgentService {
8886

8987
this.isLoaded = true
9088

89+
const templateCount = Object.keys(this.templates).length
90+
if (templateCount > 0 && logger?.info) {
91+
logger.info(
92+
{ templateCount, agentIds: Object.keys(this.templates) },
93+
'Dynamic agents loaded successfully'
94+
)
95+
}
96+
9197
return {
9298
templates: this.templates,
9399
validationErrors: this.validationErrors,
@@ -277,6 +283,7 @@ export class DynamicAgentService {
277283
} catch (error) {
278284
const errorMessage =
279285
error instanceof Error ? error.message : 'Unknown error'
286+
280287
this.validationErrors.push({
281288
filePath,
282289
message: `Error in agent template ${filePath}: ${errorMessage}`,
@@ -326,7 +333,6 @@ export class DynamicAgentService {
326333

327334
return ''
328335
}
329-
330336
/**
331337
* Convert JSON schema to Zod schema format using json-schema-to-zod.
332338
* This is done once during loading to avoid repeated conversions.
@@ -396,14 +402,12 @@ export class DynamicAgentService {
396402

397403
return result
398404
}
399-
400405
/**
401406
* Get a specific agent template by type
402407
*/
403408
getTemplate(agentType: string): AgentTemplate | undefined {
404409
return this.templates[agentType]
405410
}
406-
407411
/**
408412
* Get all loaded dynamic agent templates
409413
*/

backend/src/tools/handlers/spawn-agents.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@ export const handleSpawnAgents = ((params: {
6969
)
7070
}
7171

72-
// Initialize registry and get all templates
73-
agentRegistry.initialize(fileContext)
74-
const allTemplates = agentRegistry.getAllTemplates()
75-
7672
const conversationHistoryMessage: CoreMessage = {
7773
role: 'user',
7874
content: `For context, the following is the conversation history between the user and an assistant:\n\n${JSON.stringify(
@@ -83,6 +79,16 @@ export const handleSpawnAgents = ((params: {
8379
}
8480

8581
const triggerSpawnAgents = async () => {
82+
// Initialize registry and get all templates
83+
await agentRegistry.initialize(fileContext)
84+
const allTemplates = agentRegistry.getAllTemplates()
85+
logger.debug(
86+
{
87+
availableAgentCount: Object.keys(allTemplates).length,
88+
requestedAgents: agents.map((a) => a.agent_type),
89+
},
90+
'Agent registry initialized for spawning'
91+
)
8692
const results = await Promise.allSettled(
8793
agents.map(async ({ agent_type: agentTypeStr, prompt, params }) => {
8894
if (!(agentTypeStr in allTemplates)) {

backend/src/websockets/websocket-action.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,9 +284,15 @@ const onInit = async (
284284
await dynamicAgentService.loadAgents(fileContext)
285285
allValidationErrors.push(...dynamicErrors)
286286

287+
if (dynamicErrors.length > 0 && logger?.warn) {
288+
logger.warn(
289+
{ errorCount: dynamicErrors.length },
290+
'Dynamic agent validation errors found'
291+
)
292+
}
293+
287294
// Get dynamic agent IDs for override validation
288295
const dynamicAgentIds = dynamicAgentService.getAgentTypes()
289-
290296
// Validate override templates with dynamic agent IDs
291297
const { validationErrors: overrideErrors } = validateAgentTemplateConfigs(
292298
agentTemplates,

npm-app/release-staging/index.js

Lines changed: 15 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,9 @@ function createConfig(packageName) {
2222
configDir,
2323
binaryName,
2424
binaryPath: path.join(configDir, binaryName),
25-
githubRepo: 'CodebuffAI/codebuff-community',
25+
2626
userAgent: `${packageName}-cli`,
2727
requestTimeout: 20000,
28-
isPrerelease: true, // codecane always looks for prereleases
2928
}
3029
}
3130

@@ -70,13 +69,6 @@ function httpGet(url, options = {}) {
7069
},
7170
}
7271

73-
// Add GitHub token if available
74-
const token = process.env.GITHUB_TOKEN
75-
if (token) {
76-
console.log('Using your GITHUB_TOKEN to download the latest version.')
77-
reqOptions.headers.Authorization = `Bearer ${token}`
78-
}
79-
8072
const req = https.get(reqOptions, (res) => {
8173
if (res.statusCode === 302 || res.statusCode === 301) {
8274
return httpGet(new URL(res.headers.location, url).href, options)
@@ -98,44 +90,17 @@ function httpGet(url, options = {}) {
9890

9991
async function getLatestVersion() {
10092
try {
93+
// Use the direct /latest endpoint for stable releases
10194
const res = await httpGet(
102-
`https://github.com/${CONFIG.githubRepo}/releases.atom`
95+
`https://registry.npmjs.org/${packageName}/latest`
10396
)
10497

10598
if (res.statusCode !== 200) return null
10699

107100
const body = await streamToString(res)
101+
const packageData = JSON.parse(body)
108102

109-
// Parse the Atom XML to extract releases
110-
const tagMatches = body.match(
111-
/<id>tag:github\.com,2008:Repository\/\d+\/([^<]+)<\/id>/g
112-
)
113-
114-
if (!tagMatches) return null
115-
116-
// Extract all version tags
117-
const versions = tagMatches
118-
.map((match) => {
119-
const tagMatch = match.match(
120-
/<id>tag:github\.com,2008:Repository\/\d+\/([^<]+)<\/id>/
121-
)
122-
return tagMatch ? tagMatch[1].replace(/^v/, '') : null
123-
})
124-
.filter(Boolean)
125-
126-
if (versions.length === 0) return null
127-
128-
// Filter versions based on whether we want prereleases or stable releases
129-
const filteredVersions = versions.filter((version) => {
130-
const isPrerelease = version.includes('-')
131-
return CONFIG.isPrerelease === isPrerelease
132-
})
133-
134-
if (filteredVersions.length === 0) return null
135-
136-
// Sort and return the latest version
137-
filteredVersions.sort(compareVersions)
138-
return filteredVersions[filteredVersions.length - 1]
103+
return packageData.version || null
139104
} catch (error) {
140105
return null
141106
}
@@ -284,7 +249,9 @@ async function downloadBinary(version) {
284249
throw new Error(`Unsupported platform: ${process.platform} ${process.arch}`)
285250
}
286251

287-
const downloadUrl = `https://github.com/${CONFIG.githubRepo}/releases/download/v${version}/${fileName}`
252+
// For now, we get version info from npm but still download binaries from GitHub
253+
// TODO: This assumes GitHub releases still exist with the same naming convention
254+
const downloadUrl = `https://github.com/CodebuffAI/codebuff-community/releases/download/v${version}/${fileName}`
288255

289256
// Ensure config directory exists
290257
fs.mkdirSync(CONFIG.configDir, { recursive: true })
@@ -413,14 +380,10 @@ async function checkForUpdates(runningProcess, exitListener) {
413380
await downloadBinary(latestVersion)
414381

415382
// Restart with new binary - this replaces the current process
416-
const newChild = spawn(
417-
CONFIG.binaryPath,
418-
process.argv.slice(2),
419-
{
420-
stdio: 'inherit',
421-
detached: false,
422-
}
423-
)
383+
const newChild = spawn(CONFIG.binaryPath, process.argv.slice(2), {
384+
stdio: 'inherit',
385+
detached: false,
386+
})
424387

425388
// Set up exit handler for the new process
426389
newChild.on('exit', (code) => {
@@ -448,13 +411,9 @@ async function main() {
448411
await ensureBinaryExists()
449412

450413
// Start the binary with codecane argument
451-
const child = spawn(
452-
CONFIG.binaryPath,
453-
process.argv.slice(2),
454-
{
455-
stdio: 'inherit',
456-
}
457-
)
414+
const child = spawn(CONFIG.binaryPath, process.argv.slice(2), {
415+
stdio: 'inherit',
416+
})
458417

459418
// Store reference to the exit listener so we can remove it during updates
460419
const exitListener = (code) => {

0 commit comments

Comments
 (0)