Skip to content

Commit 8311caa

Browse files
mydeaclaude
andauthored
fix(node): Set the eve conversation id on model.started for eve 0.84+
eve 0.84 replaced the step.attempt.* instrumentation events with model.started/model.retried/model.settled, so eveInstrumentation no longer tagged AI spans with the conversation id on resumed steps. Its session stream also replaced session.waiting/turn.failed with delivery.settled, which the node-eve e2e helper waited for. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 1ffbccd commit 8311caa

3 files changed

Lines changed: 20 additions & 5 deletions

File tree

‎dev-packages/e2e-tests/test-applications/node-eve/tests/utils.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ export async function runAgentTurn(baseURL: string, message: string): Promise<st
3131
const { value, done } = await reader.read();
3232
if (done) break;
3333
buffer += decoder.decode(value, { stream: true });
34-
if (buffer.includes('"type":"session.waiting"') || buffer.includes('"type":"turn.failed"')) {
34+
// eve >= 0.84 settles each request with `delivery.settled`; older versions end on `session.waiting` / `turn.failed`
35+
if (
36+
buffer.includes('"type":"delivery.settled"') ||
37+
buffer.includes('"type":"session.waiting"') ||
38+
buffer.includes('"type":"turn.failed"')
39+
) {
3540
break;
3641
}
3742
}

‎packages/node/src/eve.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ interface EveInstrumentationProvider {
2626
events: {
2727
'turn.started': (event: { sessionId: string }) => void;
2828
'step.attempt.started': (event: { scope: { sessionId: string } }) => void;
29+
'model.started': (event: { scope: { sessionId: string } }) => void;
2930
};
3031
}
3132

@@ -46,8 +47,8 @@ interface EveInstrumentationProvider {
4647
* - runs `Sentry.init` with the given options at server startup (`setup`), adding
4748
* {@link eveIntegration} so gen_ai inputs/outputs are recorded by default (eve stamps every AI SDK
4849
* call with `recordInputs`/`recordOutputs: false`);
49-
* - tags each turn's AI spans with a Sentry conversation id via `turn.started` / `step.attempt.started`
50-
* events — the instrumentation-provider equivalent of `eveConversationHook`. Provider event handlers
50+
* - tags each turn's AI spans with a Sentry conversation id via `turn.started` and `step.attempt.started`
51+
* (eve < 0.84) / `model.started` (eve >= 0.84) events — the instrumentation-provider equivalent of `eveConversationHook`. Provider event handlers
5152
* receive the session id on the event (`event.sessionId` / `event.scope.sessionId`), unlike hook
5253
* handlers, which read it from their context.
5354
*/
@@ -65,6 +66,7 @@ export function eveInstrumentation(options: EveInstrumentationOptions = {}): Eve
6566
events: {
6667
'turn.started': event => setConversationIdFromSession(event.sessionId),
6768
'step.attempt.started': event => setConversationIdFromSession(event.scope.sessionId),
69+
'model.started': event => setConversationIdFromSession(event.scope.sessionId),
6870
},
6971
};
7072
}

‎packages/node/test/eve.test.ts‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ describe('eveInstrumentation', () => {
77
vi.restoreAllMocks();
88
});
99

10-
test('exposes a setup and turn.started / step.attempt.started events', () => {
10+
test('exposes a setup and turn.started / step.attempt.started / model.started events', () => {
1111
const provider = eveInstrumentation();
1212

1313
expect(typeof provider.setup).toBe('function');
14-
expect(Object.keys(provider.events).sort()).toEqual(['step.attempt.started', 'turn.started']);
14+
expect(Object.keys(provider.events).sort()).toEqual(['model.started', 'step.attempt.started', 'turn.started']);
1515
});
1616

1717
test('sets the session id as the conversation id from turn.started (event.sessionId)', () => {
@@ -30,6 +30,14 @@ describe('eveInstrumentation', () => {
3030
expect(setConversationId).toHaveBeenCalledWith('sess_resumed');
3131
});
3232

33+
test('sets it from model.started (event.scope.sessionId), which replaced step.attempt.started in eve 0.84', () => {
34+
const setConversationId = vi.spyOn(SentryCore, 'setConversationId').mockImplementation(() => undefined);
35+
36+
eveInstrumentation().events['model.started']({ scope: { sessionId: 'sess_model' } });
37+
38+
expect(setConversationId).toHaveBeenCalledWith('sess_model');
39+
});
40+
3341
test('honors a custom getConversationId', () => {
3442
const setConversationId = vi.spyOn(SentryCore, 'setConversationId').mockImplementation(() => undefined);
3543

0 commit comments

Comments
 (0)