@carbon-js/sdk 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai/anthropic/event-factory.d.mts +2 -0
- package/dist/ai/anthropic/event-factory.mjs +4 -2
- package/dist/ai/anthropic/fns/message-create.d.mts +1 -0
- package/dist/ai/anthropic/fns/message-create.mjs +2 -1
- package/dist/ai/anthropic/fns/message-stream.d.mts +1 -0
- package/dist/ai/anthropic/fns/message-stream.mjs +2 -1
- package/dist/ai/anthropic/wrap.d.mts +1 -0
- package/dist/ai/openai/event-factory.d.mts +2 -0
- package/dist/ai/openai/event-factory.mjs +6 -4
- package/dist/ai/openai/fns/chat-completions-create.d.mts +1 -0
- package/dist/ai/openai/fns/chat-completions-create.mjs +2 -1
- package/dist/ai/openai/fns/chat-completions-run-tools.d.mts +1 -0
- package/dist/ai/openai/fns/chat-completions-run-tools.mjs +3 -2
- package/dist/ai/openai/fns/chat-completions-stream.d.mts +1 -0
- package/dist/ai/openai/fns/chat-completions-stream.mjs +2 -1
- package/dist/ai/openai/fns/response-create.d.mts +1 -0
- package/dist/ai/openai/fns/response-create.mjs +2 -1
- package/dist/ai/openai/fns/response-stream.d.mts +1 -0
- package/dist/ai/openai/fns/response-stream.mjs +2 -1
- package/dist/ai/openai/wrap.d.mts +1 -0
- package/dist/ai/vercel/event-factory.d.mts +2 -1
- package/dist/ai/vercel/event-factory.mjs +9 -5
- package/dist/ai/vercel/fns/tool-loop-agent.d.mts +1 -0
- package/dist/ai/vercel/recorder.d.mts +4 -0
- package/dist/ai/vercel/recorder.mjs +15 -5
- package/dist/ai/vercel/utils/telemetry.d.mts +1 -0
- package/dist/ai/vercel/utils/telemetry.mjs +15 -12
- package/dist/ai/vercel/wrap.d.mts +1 -0
- package/dist/ai.d.mts +1 -0
- package/dist/core/carbon.d.mts +3 -0
- package/dist/core/carbon.mjs +18 -0
- package/dist/core/tools/wrap-tool.mjs +1 -1
- package/dist/core/utils/build-events.mjs +1 -1
- package/dist/core/utils/call-scope.d.mts +11 -0
- package/dist/core/utils/call-scope.mjs +15 -0
- package/dist/core/utils/instrumentation.d.mts +2 -2
- package/dist/core/utils/instrumentation.mjs +3 -3
- package/dist/index.d.mts +1 -0
- package/dist/internal/schema/events.d.mts +19 -17
- package/dist/internal/schema/events.mjs +11 -4
- package/dist/lib/constants.d.mts +3 -0
- package/dist/lib/constants.mjs +5 -0
- package/package.json +1 -1
|
@@ -6,8 +6,10 @@ import 'zod';
|
|
|
6
6
|
type T_LlmOutput = NonNullable<T_LLMEvent["properties"]["llm"]["output"]>;
|
|
7
7
|
declare class AnthropicEventFactory {
|
|
8
8
|
private readonly carbonObject?;
|
|
9
|
+
private readonly baseURL?;
|
|
9
10
|
constructor(args: {
|
|
10
11
|
carbonObject?: T_CarbonObject;
|
|
12
|
+
baseURL?: string;
|
|
11
13
|
});
|
|
12
14
|
createMessageEvents(args: {
|
|
13
15
|
body: MessageCreateParamsBase;
|
|
@@ -4,8 +4,10 @@ import { createSdkInstrumentation } from "../../core/utils/instrumentation.mjs";
|
|
|
4
4
|
import { stringify } from "../../utils/stringify.mjs";
|
|
5
5
|
class AnthropicEventFactory {
|
|
6
6
|
carbonObject;
|
|
7
|
+
baseURL;
|
|
7
8
|
constructor(args) {
|
|
8
9
|
this.carbonObject = args.carbonObject;
|
|
10
|
+
this.baseURL = args.baseURL;
|
|
9
11
|
}
|
|
10
12
|
createMessageEvents(args) {
|
|
11
13
|
const usage = toAnthropicAiUsage({ usage: args.message?.usage });
|
|
@@ -17,10 +19,10 @@ class AnthropicEventFactory {
|
|
|
17
19
|
instrumentation: createSdkInstrumentation({
|
|
18
20
|
sourceFunction: args.sourceFunction,
|
|
19
21
|
sourcePackage: "@anthropic-ai/sdk",
|
|
20
|
-
|
|
22
|
+
source: "anthropic"
|
|
21
23
|
}),
|
|
22
24
|
llm: {
|
|
23
|
-
|
|
25
|
+
...this.baseURL ? { apiUrl: this.baseURL } : {},
|
|
24
26
|
model: String(args.message?.model ?? args.body.model ?? "unknown"),
|
|
25
27
|
input: {
|
|
26
28
|
prompt: stringify({ value: args.body.messages }),
|
|
@@ -6,6 +6,7 @@ import 'zod';
|
|
|
6
6
|
import '../../../core/runtime.mjs';
|
|
7
7
|
import '../../../core/transport/types.mjs';
|
|
8
8
|
import '../../../core/tools/wrap-tool.mjs';
|
|
9
|
+
import '../../../core/utils/call-scope.mjs';
|
|
9
10
|
|
|
10
11
|
declare function createWrappedMessageCreate(args: {
|
|
11
12
|
client: Anthropic;
|
|
@@ -5,7 +5,8 @@ function createWrappedMessageCreate(args) {
|
|
|
5
5
|
return ((body, requestOptions) => {
|
|
6
6
|
const { carbon: carbonObject, ...anthropicBody } = body;
|
|
7
7
|
const factory = new AnthropicEventFactory({
|
|
8
|
-
carbonObject
|
|
8
|
+
carbonObject,
|
|
9
|
+
baseURL: args.client.baseURL
|
|
9
10
|
});
|
|
10
11
|
const startTimeMs = Date.now();
|
|
11
12
|
let messagePromise;
|
|
@@ -6,6 +6,7 @@ import 'zod';
|
|
|
6
6
|
import '../../../core/runtime.mjs';
|
|
7
7
|
import '../../../core/transport/types.mjs';
|
|
8
8
|
import '../../../core/tools/wrap-tool.mjs';
|
|
9
|
+
import '../../../core/utils/call-scope.mjs';
|
|
9
10
|
|
|
10
11
|
declare function createWrappedMessageStream(args: {
|
|
11
12
|
client: Anthropic;
|
|
@@ -5,7 +5,8 @@ function createWrappedMessageStream(args) {
|
|
|
5
5
|
return ((body, requestOptions) => {
|
|
6
6
|
const { carbon: carbonObject, ...anthropicBody } = body;
|
|
7
7
|
const factory = new AnthropicEventFactory({
|
|
8
|
-
carbonObject
|
|
8
|
+
carbonObject,
|
|
9
|
+
baseURL: args.client.baseURL
|
|
9
10
|
});
|
|
10
11
|
const startTimeMs = Date.now();
|
|
11
12
|
let messageStream;
|
|
@@ -7,6 +7,7 @@ import 'zod';
|
|
|
7
7
|
import '../../core/runtime.mjs';
|
|
8
8
|
import '../../core/transport/types.mjs';
|
|
9
9
|
import '../../core/tools/wrap-tool.mjs';
|
|
10
|
+
import '../../core/utils/call-scope.mjs';
|
|
10
11
|
|
|
11
12
|
declare const wrapAnthropicSdk: (client: Anthropic, carbon: Carbon) => T_WrappedAnthropicSdk;
|
|
12
13
|
|
|
@@ -7,8 +7,10 @@ import 'zod';
|
|
|
7
7
|
type T_LlmOutput = NonNullable<T_LLMEvent["properties"]["llm"]["output"]>;
|
|
8
8
|
declare class OpenAIEventFactory {
|
|
9
9
|
private readonly carbonObject?;
|
|
10
|
+
private readonly baseURL?;
|
|
10
11
|
constructor(args: {
|
|
11
12
|
carbonObject?: T_CarbonObject;
|
|
13
|
+
baseURL?: string;
|
|
12
14
|
});
|
|
13
15
|
createResponseEvents(args: {
|
|
14
16
|
body: Partial<ResponseCreateParamsBase>;
|
|
@@ -4,8 +4,10 @@ import { createSdkInstrumentation } from "../../core/utils/instrumentation.mjs";
|
|
|
4
4
|
import { stringify } from "../../utils/stringify.mjs";
|
|
5
5
|
class OpenAIEventFactory {
|
|
6
6
|
carbonObject;
|
|
7
|
+
baseURL;
|
|
7
8
|
constructor(args) {
|
|
8
9
|
this.carbonObject = args.carbonObject;
|
|
10
|
+
this.baseURL = args.baseURL;
|
|
9
11
|
}
|
|
10
12
|
createResponseEvents(args) {
|
|
11
13
|
const usage = toResponseAiUsage({ usage: args.response?.usage });
|
|
@@ -17,10 +19,10 @@ class OpenAIEventFactory {
|
|
|
17
19
|
instrumentation: createSdkInstrumentation({
|
|
18
20
|
sourceFunction: args.sourceFunction,
|
|
19
21
|
sourcePackage: "openai",
|
|
20
|
-
|
|
22
|
+
source: "openai"
|
|
21
23
|
}),
|
|
22
24
|
llm: {
|
|
23
|
-
|
|
25
|
+
...this.baseURL ? { apiUrl: this.baseURL } : {},
|
|
24
26
|
model: String(args.response?.model ?? args.body.model ?? "unknown"),
|
|
25
27
|
input: this.createResponseLlmInput({ body: args.body }),
|
|
26
28
|
output: {
|
|
@@ -49,10 +51,10 @@ class OpenAIEventFactory {
|
|
|
49
51
|
instrumentation: createSdkInstrumentation({
|
|
50
52
|
sourceFunction: args.sourceFunction,
|
|
51
53
|
sourcePackage: "openai",
|
|
52
|
-
|
|
54
|
+
source: "openai"
|
|
53
55
|
}),
|
|
54
56
|
llm: {
|
|
55
|
-
|
|
57
|
+
...this.baseURL ? { apiUrl: this.baseURL } : {},
|
|
56
58
|
model: String(args.completion?.model ?? args.body.model ?? "unknown"),
|
|
57
59
|
input: this.createChatCompletionLlmInput({ body: args.body }),
|
|
58
60
|
output: {
|
|
@@ -6,6 +6,7 @@ import 'zod';
|
|
|
6
6
|
import '../../../core/runtime.mjs';
|
|
7
7
|
import '../../../core/transport/types.mjs';
|
|
8
8
|
import '../../../core/tools/wrap-tool.mjs';
|
|
9
|
+
import '../../../core/utils/call-scope.mjs';
|
|
9
10
|
|
|
10
11
|
declare function createWrappedChatCompletionCreate(args: {
|
|
11
12
|
client: OpenAI;
|
|
@@ -6,7 +6,8 @@ function createWrappedChatCompletionCreate(args) {
|
|
|
6
6
|
return ((body, requestOptions) => {
|
|
7
7
|
const { carbon: carbonObject, [SKIP_CAPTURE_FIELD]: skipCapture, ...openAiBody } = body;
|
|
8
8
|
const factory = new OpenAIEventFactory({
|
|
9
|
-
carbonObject
|
|
9
|
+
carbonObject,
|
|
10
|
+
baseURL: args.client.baseURL
|
|
10
11
|
});
|
|
11
12
|
const startTimeMs = Date.now();
|
|
12
13
|
const bodyWithUsage = openAiBody.stream ? {
|
|
@@ -6,6 +6,7 @@ import 'zod';
|
|
|
6
6
|
import '../../../core/runtime.mjs';
|
|
7
7
|
import '../../../core/transport/types.mjs';
|
|
8
8
|
import '../../../core/tools/wrap-tool.mjs';
|
|
9
|
+
import '../../../core/utils/call-scope.mjs';
|
|
9
10
|
|
|
10
11
|
declare function createWrappedChatCompletionRunTools(args: {
|
|
11
12
|
client: OpenAI;
|
|
@@ -17,7 +17,8 @@ function createWrappedChatCompletionRunTools(args) {
|
|
|
17
17
|
[SKIP_CAPTURE_FIELD]: true
|
|
18
18
|
};
|
|
19
19
|
const factory = new OpenAIEventFactory({
|
|
20
|
-
carbonObject: tracedCarbonObject
|
|
20
|
+
carbonObject: tracedCarbonObject,
|
|
21
|
+
baseURL: args.client.baseURL
|
|
21
22
|
});
|
|
22
23
|
const startTimeMs = Date.now();
|
|
23
24
|
let runner;
|
|
@@ -87,7 +88,7 @@ function attachRunToolsCapture(args) {
|
|
|
87
88
|
instrumentation: createSdkInstrumentation({
|
|
88
89
|
sourceFunction: "chat.completions.runTools",
|
|
89
90
|
sourcePackage: "openai",
|
|
90
|
-
|
|
91
|
+
source: "openai"
|
|
91
92
|
}),
|
|
92
93
|
startTimeMs: toolCall?.startTimeMs ?? endTimeMs,
|
|
93
94
|
status: createOkStatus(),
|
|
@@ -6,6 +6,7 @@ import 'zod';
|
|
|
6
6
|
import '../../../core/runtime.mjs';
|
|
7
7
|
import '../../../core/transport/types.mjs';
|
|
8
8
|
import '../../../core/tools/wrap-tool.mjs';
|
|
9
|
+
import '../../../core/utils/call-scope.mjs';
|
|
9
10
|
|
|
10
11
|
declare function createWrappedChatCompletionStream(args: {
|
|
11
12
|
client: OpenAI;
|
|
@@ -6,6 +6,7 @@ import 'zod';
|
|
|
6
6
|
import '../../../core/runtime.mjs';
|
|
7
7
|
import '../../../core/transport/types.mjs';
|
|
8
8
|
import '../../../core/tools/wrap-tool.mjs';
|
|
9
|
+
import '../../../core/utils/call-scope.mjs';
|
|
9
10
|
|
|
10
11
|
declare function createWrappedResponseCreate(args: {
|
|
11
12
|
client: OpenAI;
|
|
@@ -5,7 +5,8 @@ function createWrappedResponseCreate(args) {
|
|
|
5
5
|
return ((body, requestOptions) => {
|
|
6
6
|
const { carbon: carbonObject, ...openAiBody } = body;
|
|
7
7
|
const factory = new OpenAIEventFactory({
|
|
8
|
-
carbonObject
|
|
8
|
+
carbonObject,
|
|
9
|
+
baseURL: args.client.baseURL
|
|
9
10
|
});
|
|
10
11
|
const startTimeMs = Date.now();
|
|
11
12
|
let responsePromise;
|
|
@@ -6,6 +6,7 @@ import 'zod';
|
|
|
6
6
|
import '../../../core/runtime.mjs';
|
|
7
7
|
import '../../../core/transport/types.mjs';
|
|
8
8
|
import '../../../core/tools/wrap-tool.mjs';
|
|
9
|
+
import '../../../core/utils/call-scope.mjs';
|
|
9
10
|
|
|
10
11
|
declare function createWrappedResponseStream(args: {
|
|
11
12
|
client: OpenAI;
|
|
@@ -5,7 +5,8 @@ function createWrappedResponseStream(args) {
|
|
|
5
5
|
return ((body, requestOptions) => {
|
|
6
6
|
const { carbon: carbonObject, ...openAiBody } = body;
|
|
7
7
|
const factory = new OpenAIEventFactory({
|
|
8
|
-
carbonObject
|
|
8
|
+
carbonObject,
|
|
9
|
+
baseURL: args.client.baseURL
|
|
9
10
|
});
|
|
10
11
|
const startTimeMs = Date.now();
|
|
11
12
|
let responseStream;
|
|
@@ -7,6 +7,7 @@ import 'zod';
|
|
|
7
7
|
import '../../core/runtime.mjs';
|
|
8
8
|
import '../../core/transport/types.mjs';
|
|
9
9
|
import '../../core/tools/wrap-tool.mjs';
|
|
10
|
+
import '../../core/utils/call-scope.mjs';
|
|
10
11
|
|
|
11
12
|
declare const wrapOpenAISdk: (client: OpenAI, carbon: Carbon) => T_WrappedOpenAISdk;
|
|
12
13
|
|
|
@@ -6,7 +6,7 @@ import 'zod';
|
|
|
6
6
|
type T_VercelRecordingMode = "generate" | "stream";
|
|
7
7
|
type T_LlmInputEvent = OnStartEvent | OnFinishEvent | OnStepStartEvent | OnStepFinishEvent | OnToolCallStartEvent | OnToolCallFinishEvent;
|
|
8
8
|
type T_PendingLlmEvent = Pick<T_LLMEvent, "id" | "startTimeMs"> & {
|
|
9
|
-
|
|
9
|
+
apiUrl?: NonNullable<T_LLMEvent["properties"]["llm"]["apiUrl"]>;
|
|
10
10
|
input: NonNullable<T_LLMEvent["properties"]["llm"]["input"]>;
|
|
11
11
|
model: T_LLMEvent["properties"]["llm"]["model"];
|
|
12
12
|
};
|
|
@@ -36,6 +36,7 @@ declare class VercelEventFactory {
|
|
|
36
36
|
startTimeMs?: number;
|
|
37
37
|
}): T_PendingToolEvent;
|
|
38
38
|
createCompletedLlmEvent(args: {
|
|
39
|
+
apiUrl?: string;
|
|
39
40
|
endTimeMs: number;
|
|
40
41
|
event?: OnFinishEvent | OnStepFinishEvent;
|
|
41
42
|
pendingLlm: T_PendingLlmEvent;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildLlmEvent, buildToolEvent } from "../../core/utils/build-events.mjs";
|
|
2
2
|
import { EMPTY_AI_USAGE } from "../../core/utils/build-events.mjs";
|
|
3
3
|
import { createSdkInstrumentation } from "../../core/utils/instrumentation.mjs";
|
|
4
|
+
import { CONSTANTS } from "../../lib/constants.mjs";
|
|
4
5
|
import { generateId } from "../../utils/ids.mjs";
|
|
5
6
|
import { stringify } from "../../utils/stringify.mjs";
|
|
6
7
|
class VercelEventFactory {
|
|
@@ -22,7 +23,6 @@ class VercelEventFactory {
|
|
|
22
23
|
system: "",
|
|
23
24
|
tools: []
|
|
24
25
|
},
|
|
25
|
-
gateway: "unknown",
|
|
26
26
|
model: "unknown",
|
|
27
27
|
startTimeMs: args.startTimeMs ?? Date.now()
|
|
28
28
|
};
|
|
@@ -41,7 +41,10 @@ class VercelEventFactory {
|
|
|
41
41
|
tools: "tools" in args.event ? args.event.tools : void 0
|
|
42
42
|
})
|
|
43
43
|
},
|
|
44
|
-
|
|
44
|
+
// The Vercel AI Gateway is the only serving base URL we can name without an instrumented fetch;
|
|
45
|
+
// every other provider's base URL is captured via carbon.fetch, like the OpenAI/Anthropic
|
|
46
|
+
// wrappers. Ingest resolves the provider + cost from this apiUrl.
|
|
47
|
+
...args.event.model?.provider === "gateway" ? { apiUrl: CONSTANTS.vercel.gatewayBaseUrl } : {},
|
|
45
48
|
model: args.event.model?.modelId ?? "unknown",
|
|
46
49
|
startTimeMs: args.startTimeMs ?? Date.now()
|
|
47
50
|
};
|
|
@@ -55,6 +58,7 @@ class VercelEventFactory {
|
|
|
55
58
|
};
|
|
56
59
|
}
|
|
57
60
|
createCompletedLlmEvent(args) {
|
|
61
|
+
const apiUrl = args.pendingLlm.apiUrl ?? args.apiUrl;
|
|
58
62
|
return buildLlmEvent({
|
|
59
63
|
context: this.carbonObject?.context,
|
|
60
64
|
additionalProperties: this.carbonObject?.additionalProperties,
|
|
@@ -63,10 +67,10 @@ class VercelEventFactory {
|
|
|
63
67
|
instrumentation: createSdkInstrumentation({
|
|
64
68
|
sourceFunction: this.sourceFunction,
|
|
65
69
|
sourcePackage: "ai",
|
|
66
|
-
|
|
70
|
+
source: "vercel"
|
|
67
71
|
}),
|
|
68
72
|
llm: {
|
|
69
|
-
|
|
73
|
+
...apiUrl ? { apiUrl } : {},
|
|
70
74
|
model: args.pendingLlm.model,
|
|
71
75
|
input: args.pendingLlm.input,
|
|
72
76
|
output: {
|
|
@@ -94,7 +98,7 @@ class VercelEventFactory {
|
|
|
94
98
|
instrumentation: createSdkInstrumentation({
|
|
95
99
|
sourceFunction: this.sourceFunction,
|
|
96
100
|
sourcePackage: "ai",
|
|
97
|
-
|
|
101
|
+
source: "vercel"
|
|
98
102
|
}),
|
|
99
103
|
startTimeMs: args.pendingTool.startTimeMs,
|
|
100
104
|
status: args.status,
|
|
@@ -7,6 +7,7 @@ import 'zod';
|
|
|
7
7
|
import '../../../core/runtime.mjs';
|
|
8
8
|
import '../../../core/transport/types.mjs';
|
|
9
9
|
import '../../../core/tools/wrap-tool.mjs';
|
|
10
|
+
import '../../../core/utils/call-scope.mjs';
|
|
10
11
|
|
|
11
12
|
type T_CreateWrappedToolLoopAgent = {
|
|
12
13
|
ToolLoopAgent: typeof vercelSdk.ToolLoopAgent;
|
|
@@ -7,6 +7,7 @@ import '../../internal/schema/events.mjs';
|
|
|
7
7
|
import 'zod';
|
|
8
8
|
import '../../core/transport/types.mjs';
|
|
9
9
|
import '../../core/tools/wrap-tool.mjs';
|
|
10
|
+
import '../../core/utils/call-scope.mjs';
|
|
10
11
|
|
|
11
12
|
declare class VercelRecorder {
|
|
12
13
|
private readonly completedEvents;
|
|
@@ -14,6 +15,7 @@ declare class VercelRecorder {
|
|
|
14
15
|
private readonly llmEventsByStep;
|
|
15
16
|
private readonly carbon;
|
|
16
17
|
private readonly toolEventsById;
|
|
18
|
+
private apiUrl;
|
|
17
19
|
private isRecorded;
|
|
18
20
|
private startTimeMs;
|
|
19
21
|
constructor(args: {
|
|
@@ -22,6 +24,8 @@ declare class VercelRecorder {
|
|
|
22
24
|
mode: T_VercelRecordingMode;
|
|
23
25
|
sourceFunction: string;
|
|
24
26
|
});
|
|
27
|
+
recordApiUrl(apiUrl: string): void;
|
|
28
|
+
private completeLlm;
|
|
25
29
|
createIntegration(): TelemetryIntegration;
|
|
26
30
|
recordError(args: {
|
|
27
31
|
error: unknown;
|
|
@@ -9,6 +9,7 @@ class VercelRecorder {
|
|
|
9
9
|
llmEventsByStep = /* @__PURE__ */ new Map();
|
|
10
10
|
carbon;
|
|
11
11
|
toolEventsById = /* @__PURE__ */ new Map();
|
|
12
|
+
apiUrl;
|
|
12
13
|
isRecorded = false;
|
|
13
14
|
startTimeMs = Date.now();
|
|
14
15
|
constructor(args) {
|
|
@@ -19,6 +20,15 @@ class VercelRecorder {
|
|
|
19
20
|
});
|
|
20
21
|
this.carbon = args.carbon;
|
|
21
22
|
}
|
|
23
|
+
// T_CallScope: a Carbon-capturing provider fetch records the request URL here; the completed
|
|
24
|
+
// event carries it as `apiUrl` so ingest resolves the serving provider via genai. First request
|
|
25
|
+
// wins (retries and multi-step calls share one provider).
|
|
26
|
+
recordApiUrl(apiUrl) {
|
|
27
|
+
this.apiUrl ??= apiUrl;
|
|
28
|
+
}
|
|
29
|
+
completeLlm(args) {
|
|
30
|
+
return this.factory.createCompletedLlmEvent({ ...args, apiUrl: this.apiUrl });
|
|
31
|
+
}
|
|
22
32
|
createIntegration() {
|
|
23
33
|
return bindTelemetryIntegration({
|
|
24
34
|
onStart: () => {
|
|
@@ -64,7 +74,7 @@ class VercelRecorder {
|
|
|
64
74
|
this.toolEventsById.clear();
|
|
65
75
|
for (const pendingLlm of this.llmEventsByStep.values()) {
|
|
66
76
|
this.completedEvents.push(
|
|
67
|
-
this.
|
|
77
|
+
this.completeLlm({
|
|
68
78
|
endTimeMs,
|
|
69
79
|
pendingLlm,
|
|
70
80
|
status
|
|
@@ -74,7 +84,7 @@ class VercelRecorder {
|
|
|
74
84
|
this.llmEventsByStep.clear();
|
|
75
85
|
if (this.completedEvents.length === 0) {
|
|
76
86
|
this.completedEvents.push(
|
|
77
|
-
this.
|
|
87
|
+
this.completeLlm({
|
|
78
88
|
endTimeMs,
|
|
79
89
|
pendingLlm: this.factory.createFallbackPendingLlmEvent({
|
|
80
90
|
startTimeMs: this.startTimeMs
|
|
@@ -107,7 +117,7 @@ class VercelRecorder {
|
|
|
107
117
|
const endTimeMs = Date.now();
|
|
108
118
|
for (const [stepNumber, pendingLlm] of this.llmEventsByStep) {
|
|
109
119
|
this.completedEvents.push(
|
|
110
|
-
this.
|
|
120
|
+
this.completeLlm({
|
|
111
121
|
endTimeMs,
|
|
112
122
|
event: event.steps.find((step) => step.stepNumber === stepNumber) ?? event,
|
|
113
123
|
pendingLlm,
|
|
@@ -118,7 +128,7 @@ class VercelRecorder {
|
|
|
118
128
|
this.llmEventsByStep.clear();
|
|
119
129
|
if (!this.completedEvents.some((completedEvent) => completedEvent.type === "llm")) {
|
|
120
130
|
this.completedEvents.push(
|
|
121
|
-
this.
|
|
131
|
+
this.completeLlm({
|
|
122
132
|
endTimeMs,
|
|
123
133
|
event,
|
|
124
134
|
pendingLlm: this.factory.createPendingLlmEvent({
|
|
@@ -179,7 +189,7 @@ class VercelRecorder {
|
|
|
179
189
|
event: args.event
|
|
180
190
|
});
|
|
181
191
|
this.completedEvents.push(
|
|
182
|
-
this.
|
|
192
|
+
this.completeLlm({
|
|
183
193
|
endTimeMs: args.endTimeMs,
|
|
184
194
|
event: args.event,
|
|
185
195
|
pendingLlm,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CARBON_CALL_SCOPE } from "../../../core/utils/call-scope.mjs";
|
|
1
2
|
import { isPromiseLike } from "../../../utils/promise.mjs";
|
|
2
3
|
import { VercelRecorder } from "../recorder.mjs";
|
|
3
4
|
const runWithCarbonTelemetry = (args) => {
|
|
@@ -12,19 +13,21 @@ const runWithCarbonTelemetry = (args) => {
|
|
|
12
13
|
args: aiArgs,
|
|
13
14
|
recorder
|
|
14
15
|
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
return CARBON_CALL_SCOPE.run(recorder, () => {
|
|
17
|
+
try {
|
|
18
|
+
const result = args.run(aiArgsWithCarbonTelemetry);
|
|
19
|
+
if (isPromiseLike({ value: result })) {
|
|
20
|
+
return Promise.resolve(result).catch(async (error) => {
|
|
21
|
+
recorder.recordError({ error });
|
|
22
|
+
throw error;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return result;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
recorder.recordError({ error });
|
|
28
|
+
throw error;
|
|
22
29
|
}
|
|
23
|
-
|
|
24
|
-
} catch (error) {
|
|
25
|
-
recorder.recordError({ error });
|
|
26
|
-
throw error;
|
|
27
|
-
}
|
|
30
|
+
});
|
|
28
31
|
};
|
|
29
32
|
const addCarbonTelemetry = (args) => {
|
|
30
33
|
const telemetry = args.args.experimental_telemetry;
|
|
@@ -7,6 +7,7 @@ import 'zod';
|
|
|
7
7
|
import '../../core/runtime.mjs';
|
|
8
8
|
import '../../core/transport/types.mjs';
|
|
9
9
|
import '../../core/tools/wrap-tool.mjs';
|
|
10
|
+
import '../../core/utils/call-scope.mjs';
|
|
10
11
|
|
|
11
12
|
declare const wrapVercelSdk: (ai: typeof vercelSdk, carbon: Carbon) => T_WrappedVercelSdk;
|
|
12
13
|
|
package/dist/ai.d.mts
CHANGED
|
@@ -8,6 +8,7 @@ import 'zod';
|
|
|
8
8
|
import './core/runtime.mjs';
|
|
9
9
|
import './core/transport/types.mjs';
|
|
10
10
|
import './core/tools/wrap-tool.mjs';
|
|
11
|
+
import './core/utils/call-scope.mjs';
|
|
11
12
|
import './ai/anthropic/types.mjs';
|
|
12
13
|
import '@anthropic-ai/sdk';
|
|
13
14
|
import './ai/openai/types.mjs';
|
package/dist/core/carbon.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { T_CarbonObject } from './schema/carbon-object.mjs';
|
|
2
2
|
import { T_CarbonRuntimeOptions } from './runtime.mjs';
|
|
3
3
|
import { T_WrapToolArgs } from './tools/wrap-tool.mjs';
|
|
4
|
+
import { T_FetchFn } from './utils/call-scope.mjs';
|
|
4
5
|
import { T as T_LLMEvent, b as T_ToolEvent, a as T_Event } from '../internal/schema/events.mjs';
|
|
5
6
|
import './transport/types.mjs';
|
|
6
7
|
import 'zod';
|
|
@@ -21,6 +22,8 @@ declare class Carbon {
|
|
|
21
22
|
}): void;
|
|
22
23
|
createTraceId(): `${string}-${string}-${string}-${string}-${string}`;
|
|
23
24
|
wrapTool<T_Args extends unknown[], T_Result>(args: T_WrapToolArgs<T_Args, T_Result>): (...callArgs: [...T_Args, (T_CarbonObject | undefined)?]) => T_Result;
|
|
25
|
+
readonly fetch: T_FetchFn;
|
|
26
|
+
wrapFetch(inner: T_FetchFn): T_FetchFn;
|
|
24
27
|
flushPendingEvents(): Promise<void>;
|
|
25
28
|
}
|
|
26
29
|
|
package/dist/core/carbon.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CarbonRuntime } from "./runtime.mjs";
|
|
2
2
|
import { createWrappedTool } from "./tools/wrap-tool.mjs";
|
|
3
|
+
import { CARBON_CALL_SCOPE, urlFromFetchInput } from "./utils/call-scope.mjs";
|
|
3
4
|
import { generateId } from "../utils/ids.mjs";
|
|
4
5
|
class Carbon {
|
|
5
6
|
runtime;
|
|
@@ -26,6 +27,23 @@ class Carbon {
|
|
|
26
27
|
}
|
|
27
28
|
});
|
|
28
29
|
}
|
|
30
|
+
// A drop-in `fetch` that records the real request URL of the in-flight wrapped call (so ingest
|
|
31
|
+
// resolves the serving provider from the captured base URL via genai), then delegates to the
|
|
32
|
+
// global fetch. Pass it to any AI SDK provider: `createOpenAI({ fetch: carbon.fetch })`. Resolves
|
|
33
|
+
// `globalThis.fetch` at call time so it composes with whatever else patched it (Next, Sentry, …).
|
|
34
|
+
fetch = (input, init) => {
|
|
35
|
+
CARBON_CALL_SCOPE.recordApiUrl(urlFromFetchInput(input));
|
|
36
|
+
return globalThis.fetch(input, init);
|
|
37
|
+
};
|
|
38
|
+
// Compose Carbon's URL capture with a customer's own fetch — the provider `fetch` option REPLACES
|
|
39
|
+
// the global fetch, so a customer who already passes one wraps it here:
|
|
40
|
+
// `createOpenAI({ fetch: carbon.wrapFetch(myFetch) })`.
|
|
41
|
+
wrapFetch(inner) {
|
|
42
|
+
return (input, init) => {
|
|
43
|
+
CARBON_CALL_SCOPE.recordApiUrl(urlFromFetchInput(input));
|
|
44
|
+
return inner(input, init);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
29
47
|
flushPendingEvents() {
|
|
30
48
|
return this.runtime.shutdown();
|
|
31
49
|
}
|
|
@@ -90,7 +90,7 @@ function captureToolResult(args) {
|
|
|
90
90
|
instrumentation: createSdkInstrumentation({
|
|
91
91
|
sourceFunction: "wrapTool",
|
|
92
92
|
sourcePackage: "ai",
|
|
93
|
-
|
|
93
|
+
source: "vercel"
|
|
94
94
|
}),
|
|
95
95
|
startTimeMs: args.startTimeMs,
|
|
96
96
|
status: args.status ?? createOkStatus(),
|
|
@@ -81,7 +81,7 @@ function buildBaseEvent(args) {
|
|
|
81
81
|
instrumentation: args.instrumentation ?? createSdkInstrumentation({
|
|
82
82
|
sourceFunction: "manual",
|
|
83
83
|
sourcePackage: "ai",
|
|
84
|
-
|
|
84
|
+
source: "vercel"
|
|
85
85
|
}),
|
|
86
86
|
startTimeMs: args.startTimeMs,
|
|
87
87
|
status: args.status,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type T_CallScope = {
|
|
2
|
+
recordApiUrl: (apiUrl: string) => void;
|
|
3
|
+
};
|
|
4
|
+
declare const CARBON_CALL_SCOPE: {
|
|
5
|
+
run<T_Result>(scope: T_CallScope, fn: () => T_Result): T_Result;
|
|
6
|
+
recordApiUrl(apiUrl: string): void;
|
|
7
|
+
};
|
|
8
|
+
type T_FetchFn = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
9
|
+
declare const urlFromFetchInput: (input: RequestInfo | URL) => string;
|
|
10
|
+
|
|
11
|
+
export { CARBON_CALL_SCOPE, type T_CallScope, type T_FetchFn, urlFromFetchInput };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
const storage = new AsyncLocalStorage();
|
|
3
|
+
const CARBON_CALL_SCOPE = {
|
|
4
|
+
run(scope, fn) {
|
|
5
|
+
return storage.run(scope, fn);
|
|
6
|
+
},
|
|
7
|
+
recordApiUrl(apiUrl) {
|
|
8
|
+
storage.getStore()?.recordApiUrl(apiUrl);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
const urlFromFetchInput = (input) => typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
12
|
+
export {
|
|
13
|
+
CARBON_CALL_SCOPE,
|
|
14
|
+
urlFromFetchInput
|
|
15
|
+
};
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { f as T_EventBase } from '../../internal/schema/events.mjs';
|
|
2
2
|
import 'zod';
|
|
3
3
|
|
|
4
|
-
type
|
|
4
|
+
type T_Source = T_EventBase["instrumentation"]["source"];
|
|
5
5
|
type T_SourcePackage = T_EventBase["instrumentation"]["sourcePackage"];
|
|
6
6
|
declare function createSdkInstrumentation(args: {
|
|
7
7
|
sourceFunction?: string;
|
|
8
8
|
sourcePackage: T_SourcePackage;
|
|
9
|
-
|
|
9
|
+
source: T_Source;
|
|
10
10
|
}): T_EventBase["instrumentation"];
|
|
11
11
|
|
|
12
12
|
export { createSdkInstrumentation };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
function createSdkInstrumentation(args) {
|
|
2
2
|
return {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
vendor: "carbon",
|
|
4
|
+
vendorPackage: "sdk",
|
|
5
5
|
sourceFunction: args.sourceFunction,
|
|
6
6
|
sourcePackage: args.sourcePackage,
|
|
7
|
-
|
|
7
|
+
source: args.source
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
export {
|
package/dist/index.d.mts
CHANGED
|
@@ -6,5 +6,6 @@ export { CarbonIngestError, HttpTransport } from './core/transport/http-transpor
|
|
|
6
6
|
export { MemoryTransport } from './core/transport/memory-transport.mjs';
|
|
7
7
|
export { T_EventBatch, T_EventTransport } from './core/transport/types.mjs';
|
|
8
8
|
export { T_WrapToolArgs } from './core/tools/wrap-tool.mjs';
|
|
9
|
+
import './core/utils/call-scope.mjs';
|
|
9
10
|
import './internal/schema/events.mjs';
|
|
10
11
|
import 'zod';
|
|
@@ -44,9 +44,9 @@ declare const Z_EventBase: z.ZodObject<{
|
|
|
44
44
|
}, z.core.$strip>>;
|
|
45
45
|
}, z.core.$strip>;
|
|
46
46
|
instrumentation: z.ZodObject<{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
47
|
+
vendor: z.ZodUnion<readonly [z.ZodLiteral<"carbon">]>;
|
|
48
|
+
vendorPackage: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"sdk">]>>;
|
|
49
|
+
source: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"anthropic">, z.ZodLiteral<"vercel">]>;
|
|
50
50
|
sourcePackage: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"@anthropic-ai/sdk">, z.ZodLiteral<"ai">]>;
|
|
51
51
|
sourceFunction: z.ZodOptional<z.ZodString>;
|
|
52
52
|
}, z.core.$strip>;
|
|
@@ -77,9 +77,9 @@ declare const Z_LLMEvent: z.ZodObject<{
|
|
|
77
77
|
}, z.core.$strip>>;
|
|
78
78
|
}, z.core.$strip>;
|
|
79
79
|
instrumentation: z.ZodObject<{
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
vendor: z.ZodUnion<readonly [z.ZodLiteral<"carbon">]>;
|
|
81
|
+
vendorPackage: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"sdk">]>>;
|
|
82
|
+
source: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"anthropic">, z.ZodLiteral<"vercel">]>;
|
|
83
83
|
sourcePackage: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"@anthropic-ai/sdk">, z.ZodLiteral<"ai">]>;
|
|
84
84
|
sourceFunction: z.ZodOptional<z.ZodString>;
|
|
85
85
|
}, z.core.$strip>;
|
|
@@ -93,8 +93,9 @@ declare const Z_LLMEvent: z.ZodObject<{
|
|
|
93
93
|
type: z.ZodLiteral<"llm">;
|
|
94
94
|
properties: z.ZodObject<{
|
|
95
95
|
llm: z.ZodObject<{
|
|
96
|
-
gateway: z.ZodOptional<z.ZodString>;
|
|
97
96
|
provider: z.ZodOptional<z.ZodString>;
|
|
97
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
98
|
+
creator: z.ZodOptional<z.ZodString>;
|
|
98
99
|
model: z.ZodString;
|
|
99
100
|
input: z.ZodOptional<z.ZodObject<{
|
|
100
101
|
system: z.ZodString;
|
|
@@ -159,9 +160,9 @@ declare const Z_ToolEvent: z.ZodObject<{
|
|
|
159
160
|
}, z.core.$strip>>;
|
|
160
161
|
}, z.core.$strip>;
|
|
161
162
|
instrumentation: z.ZodObject<{
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
vendor: z.ZodUnion<readonly [z.ZodLiteral<"carbon">]>;
|
|
164
|
+
vendorPackage: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"sdk">]>>;
|
|
165
|
+
source: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"anthropic">, z.ZodLiteral<"vercel">]>;
|
|
165
166
|
sourcePackage: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"@anthropic-ai/sdk">, z.ZodLiteral<"ai">]>;
|
|
166
167
|
sourceFunction: z.ZodOptional<z.ZodString>;
|
|
167
168
|
}, z.core.$strip>;
|
|
@@ -200,9 +201,9 @@ declare const Z_Event: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
200
201
|
}, z.core.$strip>>;
|
|
201
202
|
}, z.core.$strip>;
|
|
202
203
|
instrumentation: z.ZodObject<{
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
204
|
+
vendor: z.ZodUnion<readonly [z.ZodLiteral<"carbon">]>;
|
|
205
|
+
vendorPackage: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"sdk">]>>;
|
|
206
|
+
source: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"anthropic">, z.ZodLiteral<"vercel">]>;
|
|
206
207
|
sourcePackage: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"@anthropic-ai/sdk">, z.ZodLiteral<"ai">]>;
|
|
207
208
|
sourceFunction: z.ZodOptional<z.ZodString>;
|
|
208
209
|
}, z.core.$strip>;
|
|
@@ -216,8 +217,9 @@ declare const Z_Event: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
216
217
|
type: z.ZodLiteral<"llm">;
|
|
217
218
|
properties: z.ZodObject<{
|
|
218
219
|
llm: z.ZodObject<{
|
|
219
|
-
gateway: z.ZodOptional<z.ZodString>;
|
|
220
220
|
provider: z.ZodOptional<z.ZodString>;
|
|
221
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
222
|
+
creator: z.ZodOptional<z.ZodString>;
|
|
221
223
|
model: z.ZodString;
|
|
222
224
|
input: z.ZodOptional<z.ZodObject<{
|
|
223
225
|
system: z.ZodString;
|
|
@@ -281,9 +283,9 @@ declare const Z_Event: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
281
283
|
}, z.core.$strip>>;
|
|
282
284
|
}, z.core.$strip>;
|
|
283
285
|
instrumentation: z.ZodObject<{
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
286
|
+
vendor: z.ZodUnion<readonly [z.ZodLiteral<"carbon">]>;
|
|
287
|
+
vendorPackage: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"sdk">]>>;
|
|
288
|
+
source: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"anthropic">, z.ZodLiteral<"vercel">]>;
|
|
287
289
|
sourcePackage: z.ZodUnion<readonly [z.ZodLiteral<"openai">, z.ZodLiteral<"@anthropic-ai/sdk">, z.ZodLiteral<"ai">]>;
|
|
288
290
|
sourceFunction: z.ZodOptional<z.ZodString>;
|
|
289
291
|
}, z.core.$strip>;
|
|
@@ -27,9 +27,11 @@ const Z_EventContext = z.object({
|
|
|
27
27
|
userId: z.string().optional()
|
|
28
28
|
});
|
|
29
29
|
const Z_EventInstrumentation = z.object({
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
// The telemetry vendor — who produced this event. Always Carbon.
|
|
31
|
+
vendor: z.union([z.literal("carbon")]),
|
|
32
|
+
vendorPackage: z.union([z.literal("sdk")]).optional(),
|
|
33
|
+
// The SDK family the customer instrumented — the wrapper that captured the call.
|
|
34
|
+
source: z.union([z.literal("openai"), z.literal("anthropic"), z.literal("vercel")]),
|
|
33
35
|
sourcePackage: z.union([z.literal("openai"), z.literal("@anthropic-ai/sdk"), z.literal("ai")]),
|
|
34
36
|
sourceFunction: z.string().optional()
|
|
35
37
|
});
|
|
@@ -58,8 +60,13 @@ const Z_LLMEvent = Z_EventBase.extend({
|
|
|
58
60
|
type: z.literal("llm"),
|
|
59
61
|
properties: z.object({
|
|
60
62
|
llm: z.object({
|
|
61
|
-
|
|
63
|
+
// The serving platform that executed the request (e.g. "openai", "openrouter", "vercel"),
|
|
64
|
+
// resolved at ingest from `apiUrl`. Industry term: "provider".
|
|
62
65
|
provider: z.string().optional(),
|
|
66
|
+
// The API base URL the SDK captured; ingest resolves `provider` from it.
|
|
67
|
+
apiUrl: z.string().optional(),
|
|
68
|
+
// The model's maker / author (e.g. "anthropic", "alibaba"), resolved at ingest from the model id.
|
|
69
|
+
creator: z.string().optional(),
|
|
63
70
|
model: z.string(),
|
|
64
71
|
input: z.object({
|
|
65
72
|
system: z.string(),
|
package/dist/lib/constants.d.mts
CHANGED
package/dist/lib/constants.mjs
CHANGED
|
@@ -14,6 +14,11 @@ const CONSTANTS = {
|
|
|
14
14
|
},
|
|
15
15
|
errors: {
|
|
16
16
|
warnThrottleMs: 6e4
|
|
17
|
+
},
|
|
18
|
+
// The Vercel AI Gateway base URL the wrapper stamps for gateway calls; ingest resolves the serving
|
|
19
|
+
// provider + cost from it (its api_pattern matches in the model catalog).
|
|
20
|
+
vercel: {
|
|
21
|
+
gatewayBaseUrl: "https://ai-gateway.vercel.sh/v1"
|
|
17
22
|
}
|
|
18
23
|
};
|
|
19
24
|
export {
|