Skip to content

Commit cff62fe

Browse files
committed
Integrate canopy wave instead of baseten for minimax provider
1 parent 567cdbb commit cff62fe

File tree

6 files changed

+604
-79
lines changed

6 files changed

+604
-79
lines changed

packages/internal/src/env-schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const serverEnvSchema = clientEnvSchema.extend({
77
OPENAI_API_KEY: z.string().min(1),
88
ANTHROPIC_API_KEY: z.string().min(1),
99
FIREWORKS_API_KEY: z.string().min(1),
10-
BASETEN_API_KEY: z.string().min(1).optional(),
10+
CANOPYWAVE_API_KEY: z.string().min(1).optional(),
1111
LINKUP_API_KEY: z.string().min(1),
1212
CONTEXT7_API_KEY: z.string().optional(),
1313
GRAVITY_API_KEY: z.string().min(1),
@@ -51,7 +51,7 @@ export const serverProcessEnv: ServerInput = {
5151
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
5252
ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY,
5353
FIREWORKS_API_KEY: process.env.FIREWORKS_API_KEY,
54-
BASETEN_API_KEY: process.env.BASETEN_API_KEY,
54+
CANOPYWAVE_API_KEY: process.env.CANOPYWAVE_API_KEY,
5555
LINKUP_API_KEY: process.env.LINKUP_API_KEY,
5656
CONTEXT7_API_KEY: process.env.CONTEXT7_API_KEY,
5757
GRAVITY_API_KEY: process.env.GRAVITY_API_KEY,

scripts/test-canopywave-e2e.ts

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env bun
2+
3+
/**
4+
* E2E test for CanopyWave integration via the Codebuff SDK.
5+
*
6+
* Creates a real agent run using the minimax model so the request
7+
* flows through our chat completions endpoint → CanopyWave → back with usage data.
8+
*
9+
* Usage:
10+
* bun scripts/test-canopywave-e2e.ts
11+
*/
12+
13+
import { CodebuffClient } from '@codebuff/sdk'
14+
15+
import type { AgentDefinition } from '@codebuff/sdk'
16+
import type { PrintModeEvent } from '@codebuff/common/types/print-mode'
17+
18+
const minimaxAgent: AgentDefinition = {
19+
id: 'canopywave-test-agent',
20+
model: 'minimax/minimax-m2.5',
21+
displayName: 'CanopyWave Test Agent',
22+
toolNames: ['end_turn'],
23+
instructionsPrompt: `You are a test agent. Respond with exactly "Hello from CanopyWave!" and nothing else. Then call the end_turn tool.`,
24+
}
25+
26+
async function main() {
27+
const apiKey = process.env.CODEBUFF_API_KEY
28+
if (!apiKey) {
29+
console.error('❌ CODEBUFF_API_KEY is not set.')
30+
console.error(' Example: CODEBUFF_API_KEY=<key> bun scripts/test-canopywave-e2e.ts')
31+
process.exit(1)
32+
}
33+
34+
console.log('🔌 CanopyWave E2E Test via Codebuff SDK')
35+
console.log('='.repeat(50))
36+
console.log()
37+
console.log(`Model: ${minimaxAgent.model}`)
38+
console.log(`Agent: ${minimaxAgent.id}`)
39+
console.log()
40+
41+
const client = new CodebuffClient({
42+
apiKey,
43+
cwd: process.cwd(),
44+
})
45+
46+
const events: PrintModeEvent[] = []
47+
let responseText = ''
48+
49+
const startTime = Date.now()
50+
51+
const result = await client.run({
52+
agent: minimaxAgent,
53+
prompt: 'Say hello',
54+
costMode: 'free',
55+
handleEvent: (event) => {
56+
events.push(event)
57+
if (event.type === 'text') {
58+
responseText += event.text
59+
process.stdout.write(event.text)
60+
} else if (event.type === 'reasoning_delta') {
61+
// Don't print reasoning, just note it
62+
} else if (event.type === 'error') {
63+
console.error(`\n❌ Error event: ${event.message}`)
64+
} else if (event.type === 'finish') {
65+
console.log('\n')
66+
}
67+
},
68+
handleStreamChunk: (chunk) => {
69+
if (typeof chunk === 'string') {
70+
// Already handled in handleEvent
71+
}
72+
},
73+
})
74+
75+
const elapsed = Date.now() - startTime
76+
77+
console.log(`── Results (${elapsed}ms) ──`)
78+
console.log()
79+
80+
if (result.output.type === 'error') {
81+
console.error(`❌ Run failed: ${result.output.message}`)
82+
if ('statusCode' in result.output) {
83+
console.error(` Status code: ${result.output.statusCode}`)
84+
}
85+
process.exit(1)
86+
}
87+
88+
console.log(`✅ Run succeeded!`)
89+
console.log(` Output type: ${result.output.type}`)
90+
console.log(` Response text: ${responseText.slice(0, 200)}`)
91+
console.log()
92+
93+
// Check session state for credits used
94+
const creditsUsed = result.sessionState?.mainAgentState.creditsUsed ?? 0
95+
console.log(`── Credits & Billing ──`)
96+
console.log(` Credits used: ${creditsUsed}`)
97+
console.log(` Cost (USD): $${(creditsUsed / 100).toFixed(4)}`)
98+
console.log()
99+
100+
// Summarize events
101+
const eventTypes = events.reduce((acc, e) => {
102+
acc[e.type] = (acc[e.type] ?? 0) + 1
103+
return acc
104+
}, {} as Record<string, number>)
105+
console.log(`── Event Summary ──`)
106+
for (const [type, count] of Object.entries(eventTypes)) {
107+
console.log(` ${type}: ${count}`)
108+
}
109+
console.log()
110+
111+
// Check for finish events which include cost info
112+
const finishEvents = events.filter((e) => e.type === 'finish')
113+
if (finishEvents.length > 0) {
114+
console.log(`── Finish Events ──`)
115+
for (const event of finishEvents) {
116+
console.log(JSON.stringify(event, null, 2))
117+
}
118+
console.log()
119+
}
120+
121+
// Print all events for debugging
122+
console.log(`── All Events (${events.length} total) ──`)
123+
for (const event of events) {
124+
if (event.type === 'text' || event.type === 'reasoning_delta') continue
125+
console.log(JSON.stringify(event))
126+
}
127+
console.log()
128+
129+
console.log('Done!')
130+
}
131+
132+
main().catch((error) => {
133+
console.error('Fatal error:', error)
134+
process.exit(1)
135+
})

0 commit comments

Comments
 (0)