Skip to content
Open
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
148 changes: 148 additions & 0 deletions examples/copilot-sdk-tracing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#!/usr/bin/env -S npx ts-node
/**
* Openlayer tracing for the GitHub Copilot SDK.
*
* Run with:
* OPENLAYER_API_KEY=... \
* OPENLAYER_INFERENCE_PIPELINE_ID=... \
* GITHUB_TOKEN=$(gh auth token) \
* npx ts-node examples/copilot-sdk-tracing.ts
*
* Requires `@github/copilot-sdk` and a GitHub account with Copilot access.
*/
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';

import { openlayerEventHandler, traceCopilot } from '../src/lib/integrations/copilotSdk';

// eslint-disable-next-line @typescript-eslint/no-require-imports
const { CopilotClient, approveAll, defineTool } = require('@github/copilot-sdk');
// eslint-disable-next-line @typescript-eslint/no-require-imports
const { z } = require('zod');

/** A throwaway workspace so the agent has something real to look at. */
function makeWorkspace(): string {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'openlayer-copilot-'));
fs.writeFileSync(path.join(dir, 'app.ts'), 'export const greet = (n: string) => `hi ${n}`;\n');
fs.writeFileSync(path.join(dir, 'README.md'), '# Demo\n\nA tiny example project.\n');
return dir;
}

/**
* Scenario 1 — one line of setup traces every session.
*
* `traceCopilot()` patches `CopilotClient.prototype.createSession`, so you do
* not have to touch the code that builds sessions.
*/
async function basicSession() {
console.log('\n=== Scenario 1: one-line setup ===');
traceCopilot();

const workspace = makeWorkspace();
const client = new CopilotClient({ workingDirectory: workspace, logLevel: 'error' });
await client.start();
try {
const session = await client.createSession({
workingDirectory: workspace,
onPermissionRequest: approveAll,
});
const reply = await session.sendAndWait(
{ prompt: 'List the files here with bash, then summarize the project in one sentence.' },
280_000,
);
console.log('Assistant:', reply?.data?.content);
await session.disconnect();
} finally {
await client.stop();
}
}

/**
* Scenario 2 — an explicit handler, a client-side tool, and a subagent.
*
* Use `openlayerEventHandler()` when you build sessions yourself and want to
* be explicit about which ones are traced. It composes with your own
* `onEvent`: pass both and each still receives every event.
*/
async function toolsAndSubagent() {
console.log('\n=== Scenario 2: custom tool + subagent dispatch ===');

const getWeather = defineTool('get_weather', {
description: 'Get the current weather for a city.',
parameters: z.object({ city: z.string() }),
handler: ({ city }: { city: string }) => `It is 22C and sunny in ${city}.`,
});

const workspace = makeWorkspace();
const client = new CopilotClient({ workingDirectory: workspace, logLevel: 'error' });
await client.start();
try {
const session = await client.createSession({
workingDirectory: workspace,
onPermissionRequest: approveAll,
tools: [getWeather],
// An explicit handler instead of the global patch. Passing both is safe --
// traceCopilot() defers to a handler you supply rather than adding a
// second collector -- but one or the other is clearer.
onEvent: openlayerEventHandler({ truncateToolOutputChars: 4096 }),
});
const reply = await session.sendAndWait(
{
prompt:
'Do two things: call get_weather for Lisbon, and delegate to a subagent to ' +
'read app.ts and summarize it.',
},
280_000,
);
console.log('Assistant:', reply?.data?.content);
await session.disconnect();
} finally {
await client.stop();
}
}

/**
* Scenario 3 — several sends on one session.
*
* Each `send()` becomes its own Openlayer trace, and all of them share the
* Copilot session id, so they group into a single session in the UI.
*/
async function multiTurnSession() {
console.log('\n=== Scenario 3: multi-turn session grouping ===');

const workspace = makeWorkspace();
const client = new CopilotClient({ workingDirectory: workspace, logLevel: 'error' });
await client.start();
try {
const session = await client.createSession({
workingDirectory: workspace,
onPermissionRequest: approveAll,
onEvent: openlayerEventHandler(),
});
for (const prompt of ['What files are in this directory?', 'What does app.ts export?']) {
const reply = await session.sendAndWait({ prompt }, 280_000);
console.log(`Q: ${prompt}\nA: ${reply?.data?.content}\n`);
}
await session.disconnect();
} finally {
await client.stop();
}
}

async function main() {
for (const key of ['OPENLAYER_API_KEY', 'OPENLAYER_INFERENCE_PIPELINE_ID']) {
if (!process.env[key]) {
console.error(`Missing ${key}. Traces will not be published.`);
}
}
await basicSession();
await toolsAndSubagent();
await multiTurnSession();
console.log('\nDone — check your Openlayer inference pipeline for the traces.');
}

main().catch((err) => {
console.error(err);
process.exit(1);
});
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"devDependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.111",
"@arethetypeswrong/cli": "^0.17.0",
"@github/copilot-sdk": "^1.0.11",
"@google/genai": "^2.13.0",
"@langchain/community": "^1.1.29",
"@langchain/core": "^1.1.49",
Expand Down Expand Up @@ -95,6 +96,11 @@
"require": "./dist/lib/integrations/claudeAgentSdk.js",
"types": "./dist/lib/integrations/claudeAgentSdk.d.ts"
},
"./integrations/copilot-sdk": {
"import": "./dist/lib/integrations/copilotSdk.mjs",
"require": "./dist/lib/integrations/copilotSdk.js",
"types": "./dist/lib/integrations/copilotSdk.d.ts"
},
"./*.mjs": {
"default": "./dist/*.mjs"
},
Expand All @@ -108,6 +114,7 @@
},
"peerDependencies": {
"@anthropic-ai/claude-agent-sdk": "^0.2.111",
"@github/copilot-sdk": "^1.0.11",
"@google/genai": ">=1 <3",
"@langchain/community": ">=0.3.59 <2",
"@langchain/core": ">=0.3.80 <2",
Expand All @@ -128,6 +135,9 @@
},
"@langchain/langgraph": {
"optional": true
},
"@github/copilot-sdk": {
"optional": true
}
}
}
Loading
Loading