Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 149 additions & 0 deletions packages/agent-eval/src/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const hasAnthropicCredentials = !!process.env.ANTHROPIC_API_KEY && hasSandbox;
const hasOpenAiCredentials = !!process.env.OPENAI_API_KEY && hasSandbox;
const hasGeminiCredentials = !!process.env.GEMINI_API_KEY && hasSandbox;
const hasCursorCredentials = !!process.env.CURSOR_API_KEY && hasSandbox;
const hasBubCredentials = !!process.env.BUB_API_KEY && hasSandbox;
// OpenCode credentials (only supports AI Gateway)
const hasOpenCodeCredentials = hasAiGatewayCredentials;

Expand Down Expand Up @@ -902,6 +903,154 @@ test('contains greeting', () => {
}, 300000); // 5 minute timeout
});

describe.skipIf(!hasBubCredentials)('Bub (Direct API) sandbox execution', () => {
it('can run a simple eval with Bub', async () => {
// Create a simple test fixture
const fixtureDir = join(TEST_DIR, 'simple-eval-bub');
mkdirSync(join(fixtureDir, 'src'), { recursive: true });

writeFileSync(
join(fixtureDir, 'PROMPT.md'),
'Add a function called greet that returns "Hello from Bub!"'
);
writeFileSync(
join(fixtureDir, 'EVAL.ts'),
`
import { test, expect } from 'vitest';
import { readFileSync } from 'fs';

test('greet exists', () => {
const content = readFileSync('src/index.ts', 'utf-8');
expect(content).toContain('greet');
});
`
);
writeFileSync(
join(fixtureDir, 'package.json'),
JSON.stringify({
name: 'simple-eval-bub',
type: 'module',
scripts: { build: 'tsc' },
devDependencies: { typescript: '^5.0.0', vitest: '^2.1.0' },
})
);
writeFileSync(
join(fixtureDir, 'tsconfig.json'),
JSON.stringify({
compilerOptions: {
target: 'ES2020',
module: 'ESNext',
moduleResolution: 'bundler',
outDir: 'dist',
},
include: ['src'],
})
);

const fixture = loadFixture(TEST_DIR, 'simple-eval-bub');

const result = await runSingleEval(fixture, {
agent: 'bub',
model: 'openrouter:qwen/qwen3-coder-next',
timeout: 180,
apiKey: process.env.BUB_API_KEY!,
scripts: ['build'],
});

// Verify result structure
expect(result.result.duration).toBeGreaterThan(0);
expect(result.result.status).toBeDefined();
// Agent must actually succeed - not just return a result
if (result.result.status === 'failed') {
console.error('Agent failed with error:', result.result.error);
}
expect(result.result.status).toBe('passed');

// Verify output content exists (if available)
if (result.outputContent) {
expect(typeof result.outputContent).toBe('object');
}
}, 300000); // 5 minute timeout

it('verifies Bub result output structure matches expected format', async () => {
// Create a simple test fixture
const fixtureDir = join(TEST_DIR, 'result-structure-bub');
mkdirSync(join(fixtureDir, 'src'), { recursive: true });

writeFileSync(
join(fixtureDir, 'PROMPT.md'),
'Create a simple hello.ts file that exports a greeting constant.'
);
writeFileSync(
join(fixtureDir, 'EVAL.ts'),
`
import { test, expect } from 'vitest';
import { readFileSync, existsSync } from 'fs';

test('hello.ts exists', () => {
expect(existsSync('src/hello.ts')).toBe(true);
});

test('contains greeting', () => {
const content = readFileSync('src/hello.ts', 'utf-8');
expect(content).toContain('greeting');
});
`
);
writeFileSync(
join(fixtureDir, 'package.json'),
JSON.stringify({
name: 'result-structure-bub',
type: 'module',
scripts: { build: 'tsc' },
devDependencies: { typescript: '^5.0.0', vitest: '^2.1.0' },
})
);
writeFileSync(
join(fixtureDir, 'tsconfig.json'),
JSON.stringify({
compilerOptions: {
target: 'ES2020',
module: 'ESNext',
moduleResolution: 'bundler',
outDir: 'dist',
},
include: ['src'],
})
);

const fixture = loadFixture(TEST_DIR, 'result-structure-bub');

const result = await runSingleEval(fixture, {
agent: 'bub',
model: 'openrouter:qwen/qwen3-coder-next',
timeout: 180,
apiKey: process.env.BUB_API_KEY!,
scripts: ['build'],
});

// Verify EvalRunData structure
expect(result).toHaveProperty('result');
expect(result.result).toHaveProperty('status');
expect(result.result).toHaveProperty('duration');

// Verify optional properties have correct types when present
if (result.result.error) {
expect(typeof result.result.error).toBe('string');
}

// Verify output content structure if present
if (result.outputContent) {
if (result.outputContent.eval) {
expect(typeof result.outputContent.eval).toBe('string');
}
if (result.outputContent.scripts?.build) {
expect(typeof result.outputContent.scripts.build).toBe('string');
}
}
}, 300000); // 5 minute timeout
});

describe.skipIf(!hasOpenCodeCredentials)('OpenCode (Vercel AI Gateway) sandbox execution', () => {
it('can run a simple eval with OpenCode', async () => {
// Create a simple test fixture
Expand Down
Loading