Skip to content

Commit 101ac6f

Browse files
authored
ref: Use diagnostics channel for anthropic wrapper (#1679)
Migrates anthropic wrapper to use diagnostic channels.
1 parent aa2045f commit 101ac6f

14 files changed

Lines changed: 152 additions & 538 deletions

e2e/scenarios/anthropic-instrumentation/assertions.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,31 @@ export function defineAnthropicInstrumentationAssertions(options: {
330330
).toBe("string");
331331
});
332332

333+
test(
334+
"captures trace for client.messages.create().withResponse()",
335+
testConfig,
336+
() => {
337+
const root = findLatestSpan(events, ROOT_NAME);
338+
const operation = findLatestSpan(
339+
events,
340+
"anthropic-create-with-response-operation",
341+
);
342+
const span = findAnthropicSpan(events, operation?.span.id, [
343+
"anthropic.messages.create",
344+
]);
345+
346+
expect(operation).toBeDefined();
347+
expect(span).toBeDefined();
348+
expect(operation?.span.parentIds).toEqual([root?.span.id ?? ""]);
349+
expect(span?.row.metadata).toMatchObject({
350+
provider: "anthropic",
351+
});
352+
expect(
353+
typeof (span?.row.metadata as { model?: unknown } | undefined)?.model,
354+
).toBe("string");
355+
},
356+
);
357+
333358
test("captures trace for sending an attachment", testConfig, () => {
334359
const root = findLatestSpan(events, ROOT_NAME);
335360
const operation = findLatestSpan(

e2e/scenarios/anthropic-instrumentation/scenario.impl.mjs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,27 @@ async function runAnthropicInstrumentationScenario(
5151
});
5252
});
5353

54+
await runOperation(
55+
"anthropic-create-with-response-operation",
56+
"create-with-response",
57+
async () => {
58+
const response = await client.messages
59+
.create({
60+
model: ANTHROPIC_MODEL,
61+
max_tokens: 16,
62+
temperature: 0,
63+
messages: [
64+
{
65+
role: "user",
66+
content: "Reply with exactly WITH_RESPONSE.",
67+
},
68+
],
69+
})
70+
.withResponse();
71+
void response.data;
72+
},
73+
);
74+
5475
await runOperation(
5576
"anthropic-attachment-operation",
5677
"attachment",

js/src/instrumentation/core/channel-definitions.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export type ChannelKind = "async" | "sync-stream";
1313
type ChannelTypeInfo<
1414
TArgs extends EventArguments,
1515
TResult,
16-
TExtra extends object = Record<string, never>,
16+
TExtra extends object = Record<string, unknown>,
1717
TChunk = never,
1818
TKind extends ChannelKind = "async",
1919
> = {
@@ -27,7 +27,7 @@ type ChannelTypeInfo<
2727
export type ChannelSpec<
2828
TArgs extends EventArguments,
2929
TResult,
30-
TExtra extends object = Record<string, never>,
30+
TExtra extends object = Record<string, unknown>,
3131
TChunk = never,
3232
TKind extends ChannelKind = "async",
3333
> = ChannelTypeInfo<TArgs, TResult, TExtra, TChunk, TKind> & {
@@ -129,10 +129,10 @@ type BaseTypedChannel<TSpec extends AnyChannelSpec> = TSpec & {
129129

130130
export type TypedAsyncChannel<TSpec extends AnyAsyncChannelSpec> =
131131
BaseTypedChannel<TSpec> & {
132-
tracePromise<TResult extends ResultOf<TSpec>>(
133-
fn: () => Promise<TResult>,
132+
tracePromise<TReturn extends PromiseLike<ResultOf<TSpec>>>(
133+
fn: () => TReturn,
134134
context: StartOf<TSpec>,
135-
): Promise<TResult>;
135+
): TReturn;
136136
};
137137

138138
export type TypedSyncStreamChannel<TSpec extends AnySyncStreamChannelSpec> =
@@ -152,7 +152,7 @@ type ChannelSpecMap = Record<string, AnyChannelSpec>;
152152
export function channel<
153153
TArgs extends EventArguments,
154154
TResult,
155-
TExtra extends object = Record<string, never>,
155+
TExtra extends object = Record<string, unknown>,
156156
TChunk = never,
157157
>(spec: {
158158
channelName: string;
@@ -161,7 +161,7 @@ export function channel<
161161
export function channel<
162162
TArgs extends EventArguments,
163163
TResult,
164-
TExtra extends object = Record<string, never>,
164+
TExtra extends object = Record<string, unknown>,
165165
TChunk = never,
166166
>(spec: {
167167
channelName: string;
@@ -208,15 +208,15 @@ export function defineChannels<T extends ChannelSpecMap>(
208208
{
209209
...asyncSpec,
210210
tracingChannel,
211-
tracePromise: <TResult>(
212-
fn: () => Promise<TResult>,
211+
tracePromise: <TReturn extends Promise<ResultOf<typeof asyncSpec>>>(
212+
fn: () => TReturn,
213213
context: StartOf<AnyAsyncChannelSpec>,
214214
) =>
215215
tracingChannel().tracePromise(
216216
fn,
217217
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
218218
context as ChannelMessage<AnyAsyncChannelSpec>,
219-
),
219+
) as TReturn,
220220
} as AnyAsyncChannel,
221221
];
222222
}

js/src/instrumentation/core/channel-tracing.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type SpanState = {
3737
export type AsyncChannelSpanConfig<TChannel extends AnyAsyncChannel> =
3838
ChannelConfig & {
3939
extractInput: (
40-
args: [...ArgsOf<TChannel>],
40+
args: [...ArgsOf<TChannel>, ...any[]],
4141
event: StartOf<TChannel>,
4242
span: Span,
4343
) => {
@@ -67,7 +67,7 @@ type StreamingResult<TChannel extends AnyAsyncChannel> = Exclude<
6767
export type StreamingChannelSpanConfig<TChannel extends AnyAsyncChannel> =
6868
ChannelConfig & {
6969
extractInput: (
70-
args: [...ArgsOf<TChannel>],
70+
args: [...ArgsOf<TChannel>, ...any[]],
7171
event: StartOf<TChannel>,
7272
span: Span,
7373
) => {
@@ -109,7 +109,7 @@ export type StreamingChannelSpanConfig<TChannel extends AnyAsyncChannel> =
109109
export type SyncStreamChannelSpanConfig<TChannel extends AnySyncStreamChannel> =
110110
ChannelConfig & {
111111
extractInput: (
112-
args: [...ArgsOf<TChannel>],
112+
args: [...ArgsOf<TChannel>, ...any[]],
113113
event: StartOf<TChannel>,
114114
span: Span,
115115
) => {
@@ -166,7 +166,7 @@ function startSpanForEvent<
166166
>(
167167
config: ChannelConfig & {
168168
extractInput: (
169-
args: [...ArgsOf<TChannel>],
169+
args: [...ArgsOf<TChannel>, ...any[]],
170170
event: StartOf<TChannel>,
171171
span: Span,
172172
) => {
@@ -210,7 +210,7 @@ function ensureSpanStateForEvent<
210210
states: WeakMap<object, SpanState>,
211211
config: ChannelConfig & {
212212
extractInput: (
213-
args: [...ArgsOf<TChannel>],
213+
args: [...ArgsOf<TChannel>, ...any[]],
214214
event: StartOf<TChannel>,
215215
span: Span,
216216
) => {
@@ -239,7 +239,7 @@ function bindCurrentSpanStoreToStart<
239239
states: WeakMap<object, SpanState>,
240240
config: ChannelConfig & {
241241
extractInput: (
242-
args: [...ArgsOf<TChannel>],
242+
args: [...ArgsOf<TChannel>, ...any[]],
243243
event: StartOf<TChannel>,
244244
span: Span,
245245
) => {

js/src/instrumentation/core/types.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,22 +91,25 @@ export interface ErrorEvent extends BaseContext {
9191
export interface TypedStartEvent<
9292
TArguments extends EventArguments = unknown[],
9393
> extends BaseContext {
94-
arguments: [...TArguments];
94+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
95+
arguments: [...TArguments, ...any[]];
9596
}
9697

9798
export interface TypedEndEvent<
9899
TResult = unknown,
99100
TArguments extends EventArguments = unknown[],
100101
> extends BaseContext {
101102
result: TResult;
102-
arguments?: [...TArguments];
103+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
104+
arguments?: [...TArguments, ...any[]];
103105
}
104106

105107
export interface TypedErrorEvent<
106108
TArguments extends EventArguments = unknown[],
107109
> extends BaseContext {
108110
error: Error;
109-
arguments?: [...TArguments];
111+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
112+
arguments?: [...TArguments, ...any[]];
110113
}
111114

112115
// eslint-disable-next-line @typescript-eslint/no-empty-object-type

js/src/instrumentation/plugins/anthropic-channels.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const anthropicChannels = defineChannels("@anthropic-ai/sdk", {
1111
messagesCreate: channel<
1212
[AnthropicCreateParams],
1313
AnthropicResult,
14-
Record<string, never>,
14+
Record<string, unknown>,
1515
AnthropicStreamEvent
1616
>({
1717
channelName: "messages.create",
@@ -20,7 +20,7 @@ export const anthropicChannels = defineChannels("@anthropic-ai/sdk", {
2020
betaMessagesCreate: channel<
2121
[AnthropicCreateParams],
2222
AnthropicResult,
23-
Record<string, never>,
23+
Record<string, unknown>,
2424
AnthropicStreamEvent
2525
>({
2626
channelName: "beta.messages.create",

js/src/instrumentation/plugins/anthropic-plugin.ts

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { BasePlugin } from "../core";
22
import { traceStreamingChannel, unsubscribeAll } from "../core/channel-tracing";
33
import { Attachment } from "../../logger";
44
import { SpanTypeAttribute, isObject } from "../../../util/index";
5-
import { getCurrentUnixTimestamp } from "../../util";
5+
import { filterFrom, getCurrentUnixTimestamp } from "../../util";
66
import { finalizeAnthropicTokens } from "../../wrappers/anthropic-tokens-util";
77
import { anthropicChannels } from "./anthropic-channels";
88
import type {
@@ -411,19 +411,3 @@ function coalesceInput(
411411
}
412412
return input;
413413
}
414-
415-
/**
416-
* Filter out specified fields from an object.
417-
*/
418-
function filterFrom(
419-
obj: Record<string, unknown>,
420-
fieldsToRemove: string[],
421-
): Record<string, unknown> {
422-
const result: Record<string, unknown> = {};
423-
for (const [key, value] of Object.entries(obj)) {
424-
if (!fieldsToRemove.includes(key)) {
425-
result[key] = value;
426-
}
427-
}
428-
return result;
429-
}

js/src/instrumentation/plugins/openrouter-channels.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export const openRouterChannels = defineChannels("@openrouter/sdk", {
2323
chatSend: channel<
2424
[OpenRouterChatCreateParams],
2525
OpenRouterChatResult,
26-
Record<string, never>,
26+
Record<string, unknown>,
2727
OpenRouterChatCompletionChunk
2828
>({
2929
channelName: "chat.send",
@@ -41,7 +41,7 @@ export const openRouterChannels = defineChannels("@openrouter/sdk", {
4141
betaResponsesSend: channel<
4242
[OpenRouterResponsesCreateParams],
4343
OpenRouterResponsesResult,
44-
Record<string, never>,
44+
Record<string, unknown>,
4545
OpenRouterResponseStreamEvent
4646
>({
4747
channelName: "beta.responses.send",

js/src/isomorph.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,12 +123,12 @@ export interface IsoTracingChannel<
123123
...args: Parameters<F>
124124
): ReturnType<F>;
125125
// eslint-disable-next-line @typescript-eslint/no-explicit-any
126-
tracePromise<F extends (...args: any[]) => any>(
126+
tracePromise<F extends (...args: any[]) => PromiseLike<any>>(
127127
fn: F,
128128
message?: M,
129129
thisArg?: ThisParameterType<F>,
130130
...args: Parameters<F>
131-
): Promise<Awaited<ReturnType<F>>>;
131+
): ReturnType<F>;
132132
// eslint-disable-next-line @typescript-eslint/no-explicit-any
133133
traceCallback<F extends (...args: any[]) => any>(
134134
fn: F,
@@ -203,13 +203,14 @@ class DefaultTracingChannel<M> implements IsoTracingChannel<M> {
203203
return fn.apply(thisArg, args);
204204
}
205205
// eslint-disable-next-line @typescript-eslint/no-explicit-any
206-
tracePromise<F extends (...args: any[]) => any>(
206+
tracePromise<F extends (...args: any[]) => PromiseLike<any>>(
207207
fn: F,
208208
_message?: M,
209209
thisArg?: ThisParameterType<F>,
210210
...args: Parameters<F>
211-
): Promise<Awaited<ReturnType<F>>> {
212-
return Promise.resolve(fn.apply(thisArg, args));
211+
): ReturnType<F> {
212+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions, @typescript-eslint/no-explicit-any
213+
return fn.apply(thisArg, args) as any;
213214
}
214215
// eslint-disable-next-line @typescript-eslint/no-explicit-any
215216
traceCallback<F extends (...args: any[]) => any>(
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
2+
export type AnyFn = (this: any, ...args: any[]) => any;
3+
4+
export type TypedApplyProxyHandler<TTarget extends AnyFn> = Omit<
5+
ProxyHandler<TTarget>,
6+
"apply"
7+
> & {
8+
apply: (
9+
target: TTarget,
10+
thisArg: ThisParameterType<TTarget>,
11+
argArray: Parameters<TTarget>,
12+
) => ReturnType<TTarget>;
13+
};
14+
15+
/**
16+
* Literally `Proxy` that has a typed `apply` based on the `target`.
17+
*/
18+
export const TypedApplyProxy: new <TTarget extends AnyFn>(
19+
target: TTarget,
20+
handler: TypedApplyProxyHandler<TTarget>,
21+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
22+
) => TTarget = Proxy as unknown as new <TTarget extends AnyFn>(
23+
target: TTarget,
24+
handler: TypedApplyProxyHandler<TTarget>,
25+
) => TTarget;

0 commit comments

Comments
 (0)