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
1 change: 1 addition & 0 deletions .agents/skills/instrumentation/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Map the change before editing:
- Promise/stream behavior must be preserved. Patches need to keep subclass/helper semantics intact.
- Contain instrumentation failures. Extraction/logging bugs should be logged or ignored as appropriate, but must not break the user call path.
- Use the SDK `debugLogger` for SDK instrumentation diagnostics. Do not call `console.*` directly from instrumentation code; direct console use should stay inside the debug logger implementation or another explicitly justified exception.
- Pass `Error` objects directly as `span.log({ error })` values. The SDK serializes errors correctly, so do not add local helpers that manually turn errors into message/stack strings unless an external API requires a non-`Error` representation.
- Log only the useful surface. Prefer narrow, stable payloads over dumping full request/response objects; exclude redundant or overly large data when possible.
- We want to limit our instrumentation to operations that are relevant for AI generations and operations (LLMs, embeddings, media generation, ...). Things like creating entities on platforms (CRUD for Workflows of Agent entities) is irrelevant to us.
- When building instrumentation, we should always have a vendored type/interface for what we are wrapping. The type or interface should not be larger than what is relevant to the instrumentation. The type or interface should be used for typing tracing channels and also should be used to assert the type on whatever is passed into wrappers as soon as the wrapper has verified that the passed in value is plausibly what should be wrapped.
Expand Down
5 changes: 5 additions & 0 deletions .changeset/eve-instrumentation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"braintrust": patch

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be a minor!

---

feat: Add Eve instrumentation helpers for Braintrust tracing
6 changes: 6 additions & 0 deletions e2e/config/pr-comment-scenarios.json
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,12 @@
{ "variantKey": "flue-v1-0-0-beta-3", "label": "v1.0.0-beta.3" }
]
},
{
"scenarioDirName": "eve-instrumentation",
"label": "Eve Instrumentation",
"metadataScenario": "eve-instrumentation",
"variants": [{ "variantKey": "eve-v0-20-0", "label": "v0.20.0" }]
},
{
"scenarioDirName": "github-copilot-instrumentation",
"label": "GitHub Copilot SDK Instrumentation",
Expand Down
4,392 changes: 4,392 additions & 0 deletions e2e/scenarios/eve-instrumentation/__cassettes__/eve-v0-20-0.cassette.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions e2e/scenarios/eve-instrumentation/agent/agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineAgent } from "eve";
import { createOpenAI } from "@ai-sdk/openai";

const openai = createOpenAI({
...(process.env.OPENAI_BASE_URL
? { baseURL: process.env.OPENAI_BASE_URL }
: {}),
});

export default defineAgent({
model: openai("gpt-5.4-mini"),
modelContextWindowTokens: 8_192,
});
15 changes: 15 additions & 0 deletions e2e/scenarios/eve-instrumentation/agent/hooks/braintrust.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { braintrustEveHook } from "braintrust";
import { defineState } from "eve/context";
import { defineHook } from "eve/hooks";

export default defineHook(
braintrustEveHook({
defineState,
metadata: {
scenario: "eve-instrumentation",
...(process.env.BRAINTRUST_E2E_RUN_ID
? { testRunId: process.env.BRAINTRUST_E2E_RUN_ID }
: {}),
},
}),
);
11 changes: 11 additions & 0 deletions e2e/scenarios/eve-instrumentation/agent/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
You are a deterministic fixture agent for Braintrust Eve instrumentation tests.

For every user task:

1. Call the researcher subagent exactly once with the full user message as the
message.
2. After the researcher result is available, call the read tool exactly once with
the URL https://eve.dev/docs/guides/instrumentation.
3. After the read result is available, answer with a single sentence that starts
with "Final answer from read:" and includes the researcher result, read title,
URL, and read excerpt.
14 changes: 14 additions & 0 deletions e2e/scenarios/eve-instrumentation/agent/instrumentation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { braintrustEveInstrumentation, initLogger } from "braintrust";
import { defineState } from "eve/context";
import { defineInstrumentation } from "eve/instrumentation";

export default defineInstrumentation(
braintrustEveInstrumentation({
defineState,
setup: ({ agentName }) => {
initLogger({
projectName: process.env.BRAINTRUST_E2E_PROJECT_NAME || agentName,
});
},
}),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createOpenAI } from "@ai-sdk/openai";
import { defineAgent } from "eve";

const openai = createOpenAI({
...(process.env.OPENAI_BASE_URL
? { baseURL: process.env.OPENAI_BASE_URL }
: {}),
});

export default defineAgent({
description:
"Research the Eve instrumentation documentation before the parent reads it.",
model: openai("gpt-5.4-mini"),
modelContextWindowTokens: 8_192,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { braintrustEveHook } from "braintrust";
import { defineState } from "eve/context";
import { defineHook } from "eve/hooks";

export default defineHook(
braintrustEveHook({
defineState,
metadata: {
scenario: "eve-instrumentation",
...(process.env.BRAINTRUST_E2E_RUN_ID
? { testRunId: process.env.BRAINTRUST_E2E_RUN_ID }
: {}),
},
}),
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
You are the deterministic researcher subagent for Braintrust Eve instrumentation tests.

For every task:

1. Call the search tool exactly once with the full task as the query.
2. After the search result is available, answer with a single sentence that starts
with "Researcher result:" and includes the search title and URL.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
description: "Searches the Eve instrumentation documentation fixture.",
inputSchema: z.object({
query: z.string(),
}),
async execute({ query }) {
return {
query,
title: "Eve instrumentation",
url: "https://eve.dev/docs/guides/instrumentation",
};
},
});
18 changes: 18 additions & 0 deletions e2e/scenarios/eve-instrumentation/agent/tools/read.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
description: "Reads a deterministic Eve documentation page fixture.",
inputSchema: z.object({
url: z.string(),
}),
async execute({ url }) {
return {
excerpt:
"Eve hooks expose runtime stream events that Braintrust maps into a nested turn trace.",
section: "Runtime context",
title: "Eve instrumentation",
url,
};
},
});
16 changes: 16 additions & 0 deletions e2e/scenarios/eve-instrumentation/agent/tools/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineTool } from "eve/tools";
import { z } from "zod";

export default defineTool({
description: "Searches the Eve instrumentation documentation fixture.",
inputSchema: z.object({
query: z.string(),
}),
async execute({ query }) {
return {
query,
title: "Eve instrumentation",
url: "https://eve.dev/docs/guides/instrumentation",
};
},
});
21 changes: 21 additions & 0 deletions e2e/scenarios/eve-instrumentation/cassette-filter.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @ts-check
export { filter } from "../ai-sdk-instrumentation/cassette-filter.mjs";

/** @type {import("@braintrust/seinfeld").RedactionSpec} */
export const redact = [
"paranoid",
{
redactResponse(response) {
return {
...response,
headers: Object.fromEntries(
Object.entries(response.headers).filter(
([key]) =>
key.toLowerCase() !== "openai-organization" &&
key.toLowerCase() !== "openai-project",
),
),
};
},
},
];
10 changes: 10 additions & 0 deletions e2e/scenarios/eve-instrumentation/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "eve-instrumentation-scenario",
"private": true,
"type": "module",
"dependencies": {
"@ai-sdk/openai": "4.0.0-beta.44",
"eve": "0.20.0",
"zod": "4.3.6"
}
}
Loading
Loading