From cohere-pack
Sets up GitHub Actions CI/CD for Cohere API v2 Node.js apps, with mocked unit tests and live integration tests for Chat, Embed, Rerank.
npx claudepluginhub jeremylongshore/claude-code-plugins-plus-skills --plugin cohere-packThis skill is limited to using the following tools:
Set up CI/CD pipelines with automated unit tests (mocked) and integration tests (real API) for Cohere API v2 applications.
Sets up Cohere API v2 local dev workflow with client wrapper, mock fixtures, Vitest tests, and tsx hot reload in TypeScript projects.
Configures GitHub Actions CI/CD pipelines for Anthropic Claude API integrations, with mock unit tests and live prompt regression tests using Python and pytest.
Sets up GitHub Actions workflows for Groq API: mocked unit tests, live integration tests, and model deprecation checks. For Node.js projects with vitest/jest.
Share bugs, ideas, or general feedback.
Set up CI/CD pipelines with automated unit tests (mocked) and integration tests (real API) for Cohere API v2 applications.
cohere-ai package installed# .github/workflows/cohere-ci.yml
name: Cohere CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
# Unit tests use mocked Cohere responses — no API key needed
integration-tests:
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
env:
CO_API_KEY: ${{ secrets.CO_API_KEY }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: Run Cohere integration tests
run: npm run test:integration
timeout-minutes: 5
# Store Cohere API key as a repo secret
gh secret set CO_API_KEY --body "your-production-key-here"
# Verify it was set
gh secret list
// tests/unit/cohere-chat.test.ts
import { describe, it, expect, vi, beforeEach } from 'vitest';
// Mock the entire SDK
vi.mock('cohere-ai', () => ({
CohereClientV2: vi.fn().mockImplementation(() => ({
chat: vi.fn().mockResolvedValue({
message: { content: [{ type: 'text', text: 'mocked response' }] },
finishReason: 'COMPLETE',
usage: { billedUnits: { inputTokens: 5, outputTokens: 3 } },
}),
embed: vi.fn().mockResolvedValue({
embeddings: { float: [[0.1, 0.2, 0.3]] },
}),
rerank: vi.fn().mockResolvedValue({
results: [{ index: 0, relevanceScore: 0.95 }],
}),
})),
}));
describe('Chat service', () => {
it('returns text from chat completion', async () => {
const { CohereClientV2 } = await import('cohere-ai');
const cohere = new CohereClientV2();
const response = await cohere.chat({
model: 'command-a-03-2025',
messages: [{ role: 'user', content: 'test' }],
});
expect(response.message?.content?.[0]?.text).toBe('mocked response');
expect(cohere.chat).toHaveBeenCalledWith(
expect.objectContaining({ model: 'command-a-03-2025' })
);
});
it('handles embed with correct input type', async () => {
const { CohereClientV2 } = await import('cohere-ai');
const cohere = new CohereClientV2();
const response = await cohere.embed({
model: 'embed-v4.0',
texts: ['test'],
inputType: 'search_document',
embeddingTypes: ['float'],
});
expect(response.embeddings.float).toHaveLength(1);
});
});
// tests/integration/cohere.test.ts
import { describe, it, expect } from 'vitest';
import { CohereClientV2 } from 'cohere-ai';
const hasApiKey = !!process.env.CO_API_KEY;
describe.skipIf(!hasApiKey)('Cohere Integration', () => {
const cohere = new CohereClientV2();
it('chat completion works', async () => {
const response = await cohere.chat({
model: 'command-r7b-12-2024', // cheapest model for CI
messages: [{ role: 'user', content: 'Reply with exactly: OK' }],
maxTokens: 5,
});
expect(response.message?.content?.[0]?.text).toBeTruthy();
expect(response.finishReason).toBe('COMPLETE');
}, 15_000);
it('embed generates vectors', async () => {
const response = await cohere.embed({
model: 'embed-v4.0',
texts: ['CI test embedding'],
inputType: 'search_document',
embeddingTypes: ['float'],
});
expect(response.embeddings.float[0].length).toBeGreaterThan(0);
}, 15_000);
it('rerank scores documents', async () => {
const response = await cohere.rerank({
model: 'rerank-v3.5',
query: 'machine learning',
documents: ['ML is AI', 'cooking recipes', 'deep learning'],
topN: 2,
});
expect(response.results).toHaveLength(2);
expect(response.results[0].relevanceScore).toBeGreaterThan(0.5);
}, 15_000);
});
{
"scripts": {
"test": "vitest --run",
"test:watch": "vitest --watch",
"test:integration": "COHERE_INTEGRATION=1 vitest --run tests/integration/",
"test:coverage": "vitest --run --coverage"
}
}
command-r7b-12-2024 (cheapest) for integration testsmaxTokens: 5 on all CI chat callsmain pushes (not PRs)| CI Issue | Cause | Solution |
|---|---|---|
| Secret not found | Missing GitHub secret | gh secret set CO_API_KEY |
| 429 in CI | Rate limited (trial key) | Reduce test count or upgrade key |
| Integration timeout | Slow API response | Set timeout-minutes: 5 |
| Flaky tests | API latency variance | Add retry in test setup |
For deployment patterns, see cohere-deploy-integration.