@carbon-js/sdk 0.0.2 → 0.0.4
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 -1
- package/dist/ai/anthropic/event-factory.mjs +4 -2
- package/dist/ai/openai/event-factory.d.mts +3 -2
- package/dist/ai/openai/event-factory.mjs +14 -6
- package/dist/ai/openai/fns/chat-completions-run-tools.mjs +6 -3
- package/dist/ai/vercel/event-factory.d.mts +2 -2
- package/dist/ai/vercel/event-factory.mjs +7 -5
- package/dist/core/carbon.d.mts +1 -1
- package/dist/core/carbon.mjs +1 -1
- package/dist/core/events/event-buffer.d.mts +3 -0
- package/dist/core/events/event-buffer.mjs +3 -0
- package/dist/core/runtime.d.mts +23 -5
- package/dist/core/runtime.mjs +130 -10
- package/dist/core/tools/wrap-tool.mjs +2 -2
- package/dist/core/transport/http-transport.d.mts +4 -0
- package/dist/core/transport/http-transport.mjs +22 -2
- package/dist/core/utils/build-events.mjs +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/internal/schema/events.d.mts +14 -14
- package/dist/internal/schema/events.mjs +5 -5
- package/dist/lib/constants.d.mts +5 -0
- package/dist/lib/constants.mjs +6 -1
- package/package.json +2 -3
- package/dist/internal/schema/index.mjs +0 -1
|
@@ -3,6 +3,7 @@ import { T as T_LLMEvent, a as T_Event } from '../../internal/schema/events.mjs'
|
|
|
3
3
|
import { MessageCreateParamsBase, Message } from '@anthropic-ai/sdk/resources/messages/messages';
|
|
4
4
|
import 'zod';
|
|
5
5
|
|
|
6
|
+
type T_LlmOutput = NonNullable<T_LLMEvent["properties"]["llm"]["output"]>;
|
|
6
7
|
declare class AnthropicEventFactory {
|
|
7
8
|
private readonly carbonObject?;
|
|
8
9
|
constructor(args: {
|
|
@@ -12,7 +13,7 @@ declare class AnthropicEventFactory {
|
|
|
12
13
|
body: MessageCreateParamsBase;
|
|
13
14
|
endTimeMs: number;
|
|
14
15
|
message?: Message;
|
|
15
|
-
mode?:
|
|
16
|
+
mode?: T_LlmOutput["mode"];
|
|
16
17
|
sourceFunction?: string;
|
|
17
18
|
startTimeMs: number;
|
|
18
19
|
status: T_LLMEvent["status"];
|
|
@@ -75,7 +75,9 @@ function getToolDescriptions(args) {
|
|
|
75
75
|
}
|
|
76
76
|
function getReasoning(args) {
|
|
77
77
|
const thinking = args.content?.filter((block) => block.type === "thinking").map((block) => block.thinking).filter((text) => text.length > 0);
|
|
78
|
-
return stringify({
|
|
78
|
+
return stringify({
|
|
79
|
+
value: thinking && thinking.length > 0 ? thinking : void 0
|
|
80
|
+
});
|
|
79
81
|
}
|
|
80
82
|
function getResponseText(args) {
|
|
81
83
|
if (!args.content) {
|
|
@@ -88,7 +90,7 @@ function getToolCalls(args) {
|
|
|
88
90
|
return [];
|
|
89
91
|
}
|
|
90
92
|
return args.content.filter((block) => block.type === "tool_use" || block.type === "server_tool_use").map((block) => ({
|
|
91
|
-
|
|
93
|
+
input: stringify({ value: block.input }),
|
|
92
94
|
name: block.name
|
|
93
95
|
}));
|
|
94
96
|
}
|
|
@@ -4,6 +4,7 @@ import { ChatCompletionCreateParamsBase, ChatCompletion } from 'openai/resources
|
|
|
4
4
|
import { ResponseCreateParamsBase, Response } from 'openai/resources/responses/responses';
|
|
5
5
|
import 'zod';
|
|
6
6
|
|
|
7
|
+
type T_LlmOutput = NonNullable<T_LLMEvent["properties"]["llm"]["output"]>;
|
|
7
8
|
declare class OpenAIEventFactory {
|
|
8
9
|
private readonly carbonObject?;
|
|
9
10
|
constructor(args: {
|
|
@@ -12,7 +13,7 @@ declare class OpenAIEventFactory {
|
|
|
12
13
|
createResponseEvents(args: {
|
|
13
14
|
body: Partial<ResponseCreateParamsBase>;
|
|
14
15
|
endTimeMs: number;
|
|
15
|
-
mode?:
|
|
16
|
+
mode?: T_LlmOutput["mode"];
|
|
16
17
|
response?: Response;
|
|
17
18
|
sourceFunction?: string;
|
|
18
19
|
startTimeMs: number;
|
|
@@ -22,7 +23,7 @@ declare class OpenAIEventFactory {
|
|
|
22
23
|
body: ChatCompletionCreateParamsBase;
|
|
23
24
|
completion?: ChatCompletion;
|
|
24
25
|
endTimeMs: number;
|
|
25
|
-
mode?:
|
|
26
|
+
mode?: T_LlmOutput["mode"];
|
|
26
27
|
sourceFunction?: string;
|
|
27
28
|
startTimeMs: number;
|
|
28
29
|
status: T_LLMEvent["status"];
|
|
@@ -25,7 +25,9 @@ class OpenAIEventFactory {
|
|
|
25
25
|
input: this.createResponseLlmInput({ body: args.body }),
|
|
26
26
|
output: {
|
|
27
27
|
mode: args.mode ?? "generate",
|
|
28
|
-
reasoning: stringify({
|
|
28
|
+
reasoning: stringify({
|
|
29
|
+
value: getResponseReasoning({ response: args.response })
|
|
30
|
+
}),
|
|
29
31
|
response: getResponseOutputText({ response: args.response }),
|
|
30
32
|
toolCalls: getResponseToolCalls({ response: args.response })
|
|
31
33
|
},
|
|
@@ -56,9 +58,13 @@ class OpenAIEventFactory {
|
|
|
56
58
|
output: {
|
|
57
59
|
mode: args.mode ?? "generate",
|
|
58
60
|
reasoning: "",
|
|
59
|
-
response: stringify({
|
|
61
|
+
response: stringify({
|
|
62
|
+
value: args.completion?.choices[0]?.message.content
|
|
63
|
+
}),
|
|
60
64
|
toolCalls: args.completion?.choices[0]?.message.tool_calls?.map((toolCall) => ({
|
|
61
|
-
|
|
65
|
+
input: stringify({
|
|
66
|
+
value: toolCall.type === "function" ? toolCall.function.arguments : toolCall.custom.input
|
|
67
|
+
}),
|
|
62
68
|
name: toolCall.type === "function" ? toolCall.function.name : toolCall.custom.name
|
|
63
69
|
})) ?? []
|
|
64
70
|
},
|
|
@@ -83,7 +89,9 @@ class OpenAIEventFactory {
|
|
|
83
89
|
);
|
|
84
90
|
return {
|
|
85
91
|
prompt: stringify({ value: args.body.messages }),
|
|
86
|
-
system: stringify({
|
|
92
|
+
system: stringify({
|
|
93
|
+
value: systemMessages.length > 0 ? systemMessages : void 0
|
|
94
|
+
}),
|
|
87
95
|
tools: getChatCompletionToolDescriptions({ tools: args.body.tools })
|
|
88
96
|
};
|
|
89
97
|
}
|
|
@@ -168,7 +176,7 @@ function getResponseToolCalls(args) {
|
|
|
168
176
|
if (output.type === "function_call") {
|
|
169
177
|
return [
|
|
170
178
|
{
|
|
171
|
-
|
|
179
|
+
input: output.arguments,
|
|
172
180
|
name: output.name
|
|
173
181
|
}
|
|
174
182
|
];
|
|
@@ -176,7 +184,7 @@ function getResponseToolCalls(args) {
|
|
|
176
184
|
if (output.type === "custom_tool_call") {
|
|
177
185
|
return [
|
|
178
186
|
{
|
|
179
|
-
|
|
187
|
+
input: output.input,
|
|
180
188
|
name: output.name
|
|
181
189
|
}
|
|
182
190
|
];
|
|
@@ -18,7 +18,10 @@ function createWrappedChatCompletionRunTools(args) {
|
|
|
18
18
|
const startTimeMs = Date.now();
|
|
19
19
|
let runner;
|
|
20
20
|
try {
|
|
21
|
-
runner = runTools(
|
|
21
|
+
runner = runTools(
|
|
22
|
+
bodyWithInternalCapture,
|
|
23
|
+
requestOptions
|
|
24
|
+
);
|
|
22
25
|
} catch (error) {
|
|
23
26
|
args.carbon.captureEvents({
|
|
24
27
|
events: factory.createChatCompletionEvents({
|
|
@@ -85,9 +88,9 @@ function attachRunToolsCapture(args) {
|
|
|
85
88
|
startTimeMs: toolCall?.startTimeMs ?? endTimeMs,
|
|
86
89
|
status: createOkStatus(),
|
|
87
90
|
tool: {
|
|
88
|
-
|
|
91
|
+
input: toolCall?.args ?? "",
|
|
89
92
|
name: toolCall?.name ?? "unknown",
|
|
90
|
-
|
|
93
|
+
output: stringify({ value: result })
|
|
91
94
|
},
|
|
92
95
|
traceId: args.carbonObject?.traceId
|
|
93
96
|
})
|
|
@@ -7,11 +7,11 @@ 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
|
gateway: NonNullable<T_LLMEvent["properties"]["llm"]["gateway"]>;
|
|
10
|
-
input: T_LLMEvent["properties"]["llm"]["input"]
|
|
10
|
+
input: NonNullable<T_LLMEvent["properties"]["llm"]["input"]>;
|
|
11
11
|
model: T_LLMEvent["properties"]["llm"]["model"];
|
|
12
12
|
};
|
|
13
13
|
type T_PendingToolEvent = Pick<T_ToolEvent, "id" | "startTimeMs"> & {
|
|
14
|
-
|
|
14
|
+
input: T_ToolEvent["properties"]["tool"]["input"];
|
|
15
15
|
toolName: T_ToolEvent["properties"]["tool"]["name"];
|
|
16
16
|
};
|
|
17
17
|
declare class VercelEventFactory {
|
|
@@ -34,7 +34,9 @@ class VercelEventFactory {
|
|
|
34
34
|
prompt: stringify({
|
|
35
35
|
value: "messages" in args.event && args.event.messages ? args.event.messages : "prompt" in args.event ? args.event.prompt : void 0
|
|
36
36
|
}),
|
|
37
|
-
system: stringify({
|
|
37
|
+
system: stringify({
|
|
38
|
+
value: "system" in args.event ? args.event.system : void 0
|
|
39
|
+
}),
|
|
38
40
|
tools: getToolDescriptions({
|
|
39
41
|
tools: "tools" in args.event ? args.event.tools : void 0
|
|
40
42
|
})
|
|
@@ -46,8 +48,8 @@ class VercelEventFactory {
|
|
|
46
48
|
}
|
|
47
49
|
createPendingToolEvent(args) {
|
|
48
50
|
return {
|
|
49
|
-
args: stringify({ value: args.event.toolCall.input }),
|
|
50
51
|
id: generateId(),
|
|
52
|
+
input: stringify({ value: args.event.toolCall.input }),
|
|
51
53
|
startTimeMs: args.startTimeMs ?? Date.now(),
|
|
52
54
|
toolName: args.event.toolCall.toolName
|
|
53
55
|
};
|
|
@@ -72,7 +74,7 @@ class VercelEventFactory {
|
|
|
72
74
|
reasoning: stringify({ value: args.event?.reasoningText }),
|
|
73
75
|
response: stringify({ value: args.event?.text }),
|
|
74
76
|
toolCalls: args.event?.toolCalls.map((toolCall) => ({
|
|
75
|
-
|
|
77
|
+
input: stringify({ value: toolCall.input }),
|
|
76
78
|
name: toolCall.toolName
|
|
77
79
|
})) ?? []
|
|
78
80
|
},
|
|
@@ -97,9 +99,9 @@ class VercelEventFactory {
|
|
|
97
99
|
startTimeMs: args.pendingTool.startTimeMs,
|
|
98
100
|
status: args.status,
|
|
99
101
|
tool: {
|
|
100
|
-
|
|
102
|
+
input: args.pendingTool.input,
|
|
101
103
|
name: args.pendingTool.toolName,
|
|
102
|
-
|
|
104
|
+
output: stringify({ value: args.output })
|
|
103
105
|
},
|
|
104
106
|
traceId: this.traceId
|
|
105
107
|
});
|
package/dist/core/carbon.d.mts
CHANGED
|
@@ -21,7 +21,7 @@ declare class Carbon {
|
|
|
21
21
|
}): void;
|
|
22
22
|
createTraceId(): `${string}-${string}-${string}-${string}-${string}`;
|
|
23
23
|
wrapTool<T_Args extends unknown[], T_Result>(args: T_WrapToolArgs<T_Args, T_Result>): (...callArgs: [...T_Args, (T_CarbonObject | undefined)?]) => T_Result;
|
|
24
|
-
|
|
24
|
+
flushPendingEvents(): Promise<void>;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export { Carbon, type T_CarbonOptions, T_WrapToolArgs };
|
package/dist/core/carbon.mjs
CHANGED
|
@@ -6,6 +6,9 @@ class EventBuffer {
|
|
|
6
6
|
drain(args = {}) {
|
|
7
7
|
return this.pendingEvents.splice(0, args.count ?? this.pendingEvents.length);
|
|
8
8
|
}
|
|
9
|
+
peek(args = {}) {
|
|
10
|
+
return this.pendingEvents.slice(0, args.count ?? this.pendingEvents.length);
|
|
11
|
+
}
|
|
9
12
|
prepend(args) {
|
|
10
13
|
this.pendingEvents.unshift(...args.events);
|
|
11
14
|
}
|
package/dist/core/runtime.d.mts
CHANGED
|
@@ -2,33 +2,51 @@ import { a as T_Event } from '../internal/schema/events.mjs';
|
|
|
2
2
|
import { T_EventTransport } from './transport/types.mjs';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
|
+
type T_CarbonErrorContext = {
|
|
6
|
+
disposition: "dropped" | "retained";
|
|
7
|
+
error: unknown;
|
|
8
|
+
events: T_Event[];
|
|
9
|
+
};
|
|
5
10
|
type T_CarbonRuntimeOptions = {
|
|
6
11
|
baseUrl?: string;
|
|
7
12
|
apiKey?: string;
|
|
8
13
|
bufferBatchSize?: number;
|
|
14
|
+
bufferMaxBatchBytes?: number;
|
|
9
15
|
bufferMaxTimeMs?: number;
|
|
16
|
+
maxBufferedEvents?: number;
|
|
17
|
+
onError?: (args: T_CarbonErrorContext) => void;
|
|
10
18
|
transport?: T_EventTransport;
|
|
11
19
|
};
|
|
12
|
-
type T_RecordEvents = {
|
|
13
|
-
events: T_Event[];
|
|
14
|
-
};
|
|
15
20
|
declare class CarbonRuntime {
|
|
16
21
|
private readonly buffer;
|
|
17
22
|
private readonly bufferBatchSize;
|
|
23
|
+
private readonly bufferMaxBatchBytes;
|
|
18
24
|
private readonly bufferMaxTimeMs;
|
|
25
|
+
private readonly maxBufferedEvents;
|
|
26
|
+
private readonly onError?;
|
|
19
27
|
private readonly transport;
|
|
28
|
+
private readonly warnedAtMsByKey;
|
|
20
29
|
private flushPromise;
|
|
21
30
|
private flushTimer;
|
|
22
31
|
private isShuttingDown;
|
|
23
32
|
constructor(args: T_CarbonRuntimeOptions);
|
|
24
|
-
recordEvents(args:
|
|
33
|
+
recordEvents(args: {
|
|
34
|
+
events: T_Event[];
|
|
35
|
+
}): void;
|
|
25
36
|
flush(): Promise<void>;
|
|
26
37
|
shutdown(): Promise<void>;
|
|
27
38
|
private flushNextBatch;
|
|
28
39
|
private sendDrainedEvents;
|
|
40
|
+
private enforceBufferCap;
|
|
41
|
+
private reportError;
|
|
29
42
|
private flushOrSchedule;
|
|
30
43
|
private scheduleFlush;
|
|
31
44
|
private clearFlushTimer;
|
|
45
|
+
private shouldFlushBeforeAdding;
|
|
46
|
+
private assertEventFitsBatch;
|
|
47
|
+
private drainNextTransportBatch;
|
|
48
|
+
private peekNextTransportBatch;
|
|
49
|
+
private getBatchBytes;
|
|
32
50
|
}
|
|
33
51
|
|
|
34
|
-
export { CarbonRuntime, type T_CarbonRuntimeOptions };
|
|
52
|
+
export { CarbonRuntime, type T_CarbonErrorContext, type T_CarbonRuntimeOptions };
|
package/dist/core/runtime.mjs
CHANGED
|
@@ -1,24 +1,40 @@
|
|
|
1
1
|
import { EventBuffer } from "./events/event-buffer.mjs";
|
|
2
2
|
import { CONSTANTS } from "../lib/constants.mjs";
|
|
3
|
-
import { HttpTransport } from "./transport/http-transport.mjs";
|
|
4
|
-
import { Z_Event } from "../internal/schema/
|
|
3
|
+
import { CarbonIngestError, HttpTransport } from "./transport/http-transport.mjs";
|
|
4
|
+
import { Z_Event } from "../internal/schema/events.mjs";
|
|
5
5
|
class CarbonRuntime {
|
|
6
6
|
buffer = new EventBuffer();
|
|
7
7
|
bufferBatchSize;
|
|
8
|
+
bufferMaxBatchBytes;
|
|
8
9
|
bufferMaxTimeMs;
|
|
10
|
+
maxBufferedEvents;
|
|
11
|
+
onError;
|
|
9
12
|
transport;
|
|
13
|
+
warnedAtMsByKey = /* @__PURE__ */ new Map();
|
|
10
14
|
flushPromise = null;
|
|
11
15
|
flushTimer = null;
|
|
12
16
|
isShuttingDown = false;
|
|
13
17
|
constructor(args) {
|
|
14
18
|
this.bufferBatchSize = args.bufferBatchSize ?? CONSTANTS.buffer.batchSize;
|
|
19
|
+
this.bufferMaxBatchBytes = args.bufferMaxBatchBytes ?? CONSTANTS.buffer.maxBatchBytes;
|
|
15
20
|
this.bufferMaxTimeMs = args.bufferMaxTimeMs ?? CONSTANTS.buffer.maxTimeMs;
|
|
21
|
+
this.maxBufferedEvents = args.maxBufferedEvents ?? CONSTANTS.buffer.maxBufferedEvents;
|
|
22
|
+
this.onError = args.onError;
|
|
16
23
|
if (!Number.isInteger(this.bufferBatchSize) || this.bufferBatchSize <= 0) {
|
|
17
24
|
throw new Error("batchSize must be a positive integer.");
|
|
18
25
|
}
|
|
26
|
+
if (!Number.isFinite(this.bufferMaxBatchBytes) || this.bufferMaxBatchBytes <= 0) {
|
|
27
|
+
throw new Error("maxBatchBytes must be greater than 0.");
|
|
28
|
+
}
|
|
29
|
+
if (this.bufferMaxBatchBytes > CONSTANTS.buffer.maxBatchBytes) {
|
|
30
|
+
throw new Error("maxBatchBytes must not exceed the SDK batch limit.");
|
|
31
|
+
}
|
|
19
32
|
if (!Number.isFinite(this.bufferMaxTimeMs) || this.bufferMaxTimeMs < 0) {
|
|
20
33
|
throw new Error("maxBufferTimeMs must be greater than or equal to 0.");
|
|
21
34
|
}
|
|
35
|
+
if (!Number.isInteger(this.maxBufferedEvents) || this.maxBufferedEvents <= 0) {
|
|
36
|
+
throw new Error("maxBufferedEvents must be a positive integer.");
|
|
37
|
+
}
|
|
22
38
|
this.transport = args.transport ?? new HttpTransport({
|
|
23
39
|
apiKey: args.apiKey,
|
|
24
40
|
baseUrl: args.baseUrl
|
|
@@ -26,7 +42,14 @@ class CarbonRuntime {
|
|
|
26
42
|
}
|
|
27
43
|
recordEvents(args) {
|
|
28
44
|
const events = args.events.map((event) => Z_Event.parse(event));
|
|
29
|
-
this.
|
|
45
|
+
events.forEach((event) => this.assertEventFitsBatch({ event }));
|
|
46
|
+
for (const event of events) {
|
|
47
|
+
if (this.shouldFlushBeforeAdding({ event })) {
|
|
48
|
+
void this.flush().catch(() => void 0);
|
|
49
|
+
}
|
|
50
|
+
this.buffer.add({ events: [event] });
|
|
51
|
+
}
|
|
52
|
+
this.enforceBufferCap();
|
|
30
53
|
this.flushOrSchedule();
|
|
31
54
|
}
|
|
32
55
|
async flush() {
|
|
@@ -54,7 +77,7 @@ class CarbonRuntime {
|
|
|
54
77
|
if (this.buffer.length === 0) {
|
|
55
78
|
return;
|
|
56
79
|
}
|
|
57
|
-
const events = this.
|
|
80
|
+
const events = this.drainNextTransportBatch();
|
|
58
81
|
this.flushPromise = this.sendDrainedEvents({
|
|
59
82
|
allowBackgroundScheduling: args.allowBackgroundScheduling,
|
|
60
83
|
events
|
|
@@ -62,7 +85,7 @@ class CarbonRuntime {
|
|
|
62
85
|
return this.flushPromise;
|
|
63
86
|
}
|
|
64
87
|
async sendDrainedEvents(args) {
|
|
65
|
-
let
|
|
88
|
+
let didSettleBatch = false;
|
|
66
89
|
let shouldRetry = false;
|
|
67
90
|
try {
|
|
68
91
|
await this.transport.sendBatch({
|
|
@@ -70,24 +93,59 @@ class CarbonRuntime {
|
|
|
70
93
|
events: args.events
|
|
71
94
|
}
|
|
72
95
|
});
|
|
73
|
-
|
|
96
|
+
didSettleBatch = true;
|
|
74
97
|
} catch (error) {
|
|
98
|
+
shouldRetry = isRetryableTransportError(error);
|
|
99
|
+
if (!shouldRetry) {
|
|
100
|
+
didSettleBatch = true;
|
|
101
|
+
this.reportError({ disposition: "dropped", error, events: args.events });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
75
104
|
this.buffer.prepend({ events: args.events });
|
|
76
|
-
|
|
77
|
-
|
|
105
|
+
this.reportError({ disposition: "retained", error, events: args.events });
|
|
106
|
+
this.enforceBufferCap();
|
|
78
107
|
throw error;
|
|
79
108
|
} finally {
|
|
80
109
|
this.flushPromise = null;
|
|
81
110
|
const canScheduleBackgroundFlush = args.allowBackgroundScheduling && !this.isShuttingDown;
|
|
82
111
|
if (shouldRetry && canScheduleBackgroundFlush) {
|
|
83
112
|
this.scheduleFlush({ delayMs: this.bufferMaxTimeMs });
|
|
84
|
-
} else if (
|
|
113
|
+
} else if (didSettleBatch && canScheduleBackgroundFlush) {
|
|
85
114
|
this.flushOrSchedule();
|
|
86
115
|
}
|
|
87
116
|
}
|
|
88
117
|
}
|
|
118
|
+
enforceBufferCap() {
|
|
119
|
+
const overflowCount = this.buffer.length - this.maxBufferedEvents;
|
|
120
|
+
if (overflowCount <= 0) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const droppedEvents = this.buffer.drain({ count: overflowCount });
|
|
124
|
+
this.reportError({
|
|
125
|
+
disposition: "dropped",
|
|
126
|
+
error: new Error("Carbon event buffer is full. Oldest events were dropped."),
|
|
127
|
+
events: droppedEvents
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
reportError(args) {
|
|
131
|
+
if (this.onError) {
|
|
132
|
+
try {
|
|
133
|
+
this.onError(args);
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const key = getErrorKey(args.error);
|
|
139
|
+
const lastWarnedAtMs = this.warnedAtMsByKey.get(key);
|
|
140
|
+
if (lastWarnedAtMs !== void 0 && Date.now() - lastWarnedAtMs < CONSTANTS.errors.warnThrottleMs) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
this.warnedAtMsByKey.set(key, Date.now());
|
|
144
|
+
console.warn(formatErrorWarning(args));
|
|
145
|
+
}
|
|
89
146
|
flushOrSchedule() {
|
|
90
|
-
|
|
147
|
+
const nextTransportBatch = this.peekNextTransportBatch();
|
|
148
|
+
if (this.buffer.length >= this.bufferBatchSize || nextTransportBatch.length < this.buffer.length || this.getBatchBytes({ events: nextTransportBatch }) >= this.bufferMaxBatchBytes) {
|
|
91
149
|
void this.flush().catch(() => void 0);
|
|
92
150
|
return;
|
|
93
151
|
}
|
|
@@ -113,6 +171,68 @@ class CarbonRuntime {
|
|
|
113
171
|
clearTimeout(this.flushTimer);
|
|
114
172
|
this.flushTimer = null;
|
|
115
173
|
}
|
|
174
|
+
shouldFlushBeforeAdding(args) {
|
|
175
|
+
if (this.buffer.length === 0) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
if (this.buffer.length >= this.bufferBatchSize) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
const events = [...this.buffer.peek({ count: this.bufferBatchSize - 1 }), args.event];
|
|
182
|
+
return events.length > this.bufferBatchSize || this.getBatchBytes({ events }) > this.bufferMaxBatchBytes;
|
|
183
|
+
}
|
|
184
|
+
assertEventFitsBatch(args) {
|
|
185
|
+
if (this.getBatchBytes({ events: [args.event] }) > this.bufferMaxBatchBytes) {
|
|
186
|
+
throw new Error("Event exceeds maxBatchBytes.");
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
drainNextTransportBatch() {
|
|
190
|
+
for (let count = Math.min(this.bufferBatchSize, this.buffer.length); count > 0; count -= 1) {
|
|
191
|
+
const events = this.buffer.peek({ count });
|
|
192
|
+
if (this.getBatchBytes({ events }) <= this.bufferMaxBatchBytes) {
|
|
193
|
+
return this.buffer.drain({ count });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
throw new Error("Buffered event exceeds maxBatchBytes.");
|
|
197
|
+
}
|
|
198
|
+
peekNextTransportBatch() {
|
|
199
|
+
for (let count = Math.min(this.bufferBatchSize, this.buffer.length); count > 0; count -= 1) {
|
|
200
|
+
const events = this.buffer.peek({ count });
|
|
201
|
+
if (this.getBatchBytes({ events }) <= this.bufferMaxBatchBytes) {
|
|
202
|
+
return events;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
getBatchBytes(args) {
|
|
208
|
+
return new TextEncoder().encode(
|
|
209
|
+
JSON.stringify({
|
|
210
|
+
events: args.events
|
|
211
|
+
})
|
|
212
|
+
).byteLength;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function isRetryableTransportError(error) {
|
|
216
|
+
if (typeof error === "object" && error !== null && "retryable" in error) {
|
|
217
|
+
return typeof error.retryable === "boolean" ? error.retryable : true;
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
function getErrorKey(error) {
|
|
222
|
+
if (error instanceof CarbonIngestError) {
|
|
223
|
+
return error.errorId ?? String(error.status);
|
|
224
|
+
}
|
|
225
|
+
if (error instanceof Error) {
|
|
226
|
+
return `${error.name}:${error.message}`;
|
|
227
|
+
}
|
|
228
|
+
return String(error);
|
|
229
|
+
}
|
|
230
|
+
function formatErrorWarning(args) {
|
|
231
|
+
const message = args.error instanceof Error ? args.error.message : String(args.error);
|
|
232
|
+
if (args.disposition === "dropped") {
|
|
233
|
+
return `Carbon dropped ${args.events.length} event(s): ${message}`;
|
|
234
|
+
}
|
|
235
|
+
return `Carbon failed to deliver ${args.events.length} event(s) and will retry: ${message}`;
|
|
116
236
|
}
|
|
117
237
|
export {
|
|
118
238
|
CarbonRuntime
|
|
@@ -96,9 +96,9 @@ function captureToolResult(args) {
|
|
|
96
96
|
status: args.status ?? createOkStatus(),
|
|
97
97
|
traceId: args.carbon?.traceId,
|
|
98
98
|
tool: {
|
|
99
|
-
|
|
99
|
+
input: stringify({ value: serializeToolArgs({ args: args.args }) }),
|
|
100
100
|
name: args.name,
|
|
101
|
-
|
|
101
|
+
output: stringify({ value: args.result })
|
|
102
102
|
}
|
|
103
103
|
})
|
|
104
104
|
});
|
|
@@ -10,9 +10,13 @@ type T_HttpTransport = {
|
|
|
10
10
|
timeoutMs?: number;
|
|
11
11
|
};
|
|
12
12
|
declare class CarbonIngestError extends Error {
|
|
13
|
+
readonly details?: string;
|
|
14
|
+
readonly errorId?: string;
|
|
13
15
|
readonly retryable: boolean;
|
|
14
16
|
readonly status: number;
|
|
15
17
|
constructor(args: {
|
|
18
|
+
details?: string;
|
|
19
|
+
errorId?: string;
|
|
16
20
|
status: number;
|
|
17
21
|
});
|
|
18
22
|
}
|
|
@@ -2,11 +2,17 @@ import { CONSTANTS } from "../../lib/constants.mjs";
|
|
|
2
2
|
import { retry } from "../../utils/retry.mjs";
|
|
3
3
|
import { runWithTimeout } from "../../utils/timeout.mjs";
|
|
4
4
|
class CarbonIngestError extends Error {
|
|
5
|
+
details;
|
|
6
|
+
errorId;
|
|
5
7
|
retryable;
|
|
6
8
|
status;
|
|
7
9
|
constructor(args) {
|
|
8
|
-
super(
|
|
10
|
+
super(
|
|
11
|
+
args.details ? `Carbon ingest failed with status ${args.status}: ${args.details}` : `Carbon ingest failed with status ${args.status}`
|
|
12
|
+
);
|
|
9
13
|
this.name = "CarbonIngestError";
|
|
14
|
+
this.details = args.details;
|
|
15
|
+
this.errorId = args.errorId;
|
|
10
16
|
this.status = args.status;
|
|
11
17
|
this.retryable = [408, 409, 425, 429].includes(args.status) || args.status >= 500;
|
|
12
18
|
}
|
|
@@ -51,7 +57,10 @@ class HttpTransport {
|
|
|
51
57
|
signal
|
|
52
58
|
});
|
|
53
59
|
if (!response.ok) {
|
|
54
|
-
throw new CarbonIngestError({
|
|
60
|
+
throw new CarbonIngestError({
|
|
61
|
+
status: response.status,
|
|
62
|
+
...await parseIngestErrorBody({ response })
|
|
63
|
+
});
|
|
55
64
|
}
|
|
56
65
|
}
|
|
57
66
|
});
|
|
@@ -60,6 +69,17 @@ class HttpTransport {
|
|
|
60
69
|
});
|
|
61
70
|
}
|
|
62
71
|
}
|
|
72
|
+
async function parseIngestErrorBody({ response }) {
|
|
73
|
+
try {
|
|
74
|
+
const body = await response.json();
|
|
75
|
+
return {
|
|
76
|
+
details: typeof body.error?.details === "string" ? body.error.details : void 0,
|
|
77
|
+
errorId: typeof body.error?.id === "string" ? body.error.id : void 0
|
|
78
|
+
};
|
|
79
|
+
} catch {
|
|
80
|
+
return {};
|
|
81
|
+
}
|
|
82
|
+
}
|
|
63
83
|
function getApiKey(args) {
|
|
64
84
|
const apiKey = args.apiKey ?? process.env.CARBON_API_KEY;
|
|
65
85
|
if (!apiKey) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { generateId } from "../../utils/ids.mjs";
|
|
2
2
|
import { createSdkInstrumentation } from "./instrumentation.mjs";
|
|
3
|
-
import { Z_Event } from "../../internal/schema/
|
|
3
|
+
import { Z_Event } from "../../internal/schema/events.mjs";
|
|
4
4
|
const EMPTY_AI_USAGE = {
|
|
5
5
|
inputTokenDetails: {
|
|
6
6
|
cacheReadTokens: 0,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export { Carbon, T_CarbonOptions } from './core/carbon.mjs';
|
|
2
|
+
export { T_CarbonErrorContext } from './core/runtime.mjs';
|
|
2
3
|
export { T_CarbonContext, T_CarbonObject } from './core/schema/carbon-object.mjs';
|
|
3
4
|
export { FileTransport } from './core/transport/file-transport.mjs';
|
|
4
5
|
export { CarbonIngestError, HttpTransport } from './core/transport/http-transport.mjs';
|
|
5
6
|
export { MemoryTransport } from './core/transport/memory-transport.mjs';
|
|
6
7
|
export { T_EventBatch, T_EventTransport } from './core/transport/types.mjs';
|
|
7
8
|
export { T_WrapToolArgs } from './core/tools/wrap-tool.mjs';
|
|
8
|
-
import './core/runtime.mjs';
|
|
9
9
|
import './internal/schema/events.mjs';
|
|
10
10
|
import 'zod';
|
|
@@ -96,15 +96,15 @@ declare const Z_LLMEvent: z.ZodObject<{
|
|
|
96
96
|
gateway: z.ZodOptional<z.ZodString>;
|
|
97
97
|
provider: z.ZodOptional<z.ZodString>;
|
|
98
98
|
model: z.ZodString;
|
|
99
|
-
input: z.ZodObject<{
|
|
99
|
+
input: z.ZodOptional<z.ZodObject<{
|
|
100
100
|
system: z.ZodString;
|
|
101
101
|
prompt: z.ZodString;
|
|
102
102
|
tools: z.ZodArray<z.ZodObject<{
|
|
103
103
|
name: z.ZodString;
|
|
104
104
|
description: z.ZodOptional<z.ZodString>;
|
|
105
105
|
}, z.core.$strip>>;
|
|
106
|
-
}, z.core.$strip
|
|
107
|
-
output: z.ZodObject<{
|
|
106
|
+
}, z.core.$strip>>;
|
|
107
|
+
output: z.ZodOptional<z.ZodObject<{
|
|
108
108
|
mode: z.ZodEnum<{
|
|
109
109
|
generate: "generate";
|
|
110
110
|
stream: "stream";
|
|
@@ -113,9 +113,9 @@ declare const Z_LLMEvent: z.ZodObject<{
|
|
|
113
113
|
response: z.ZodOptional<z.ZodString>;
|
|
114
114
|
toolCalls: z.ZodArray<z.ZodObject<{
|
|
115
115
|
name: z.ZodString;
|
|
116
|
-
|
|
116
|
+
input: z.ZodOptional<z.ZodString>;
|
|
117
117
|
}, z.core.$strip>>;
|
|
118
|
-
}, z.core.$strip
|
|
118
|
+
}, z.core.$strip>>;
|
|
119
119
|
usage: z.ZodObject<{
|
|
120
120
|
inputTokens: z.ZodNumber;
|
|
121
121
|
inputTokenDetails: z.ZodObject<{
|
|
@@ -176,8 +176,8 @@ declare const Z_ToolEvent: z.ZodObject<{
|
|
|
176
176
|
properties: z.ZodObject<{
|
|
177
177
|
tool: z.ZodObject<{
|
|
178
178
|
name: z.ZodString;
|
|
179
|
-
|
|
180
|
-
|
|
179
|
+
input: z.ZodOptional<z.ZodString>;
|
|
180
|
+
output: z.ZodOptional<z.ZodString>;
|
|
181
181
|
}, z.core.$strip>;
|
|
182
182
|
}, z.core.$strip>;
|
|
183
183
|
}, z.core.$strip>;
|
|
@@ -219,15 +219,15 @@ declare const Z_Event: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
219
219
|
gateway: z.ZodOptional<z.ZodString>;
|
|
220
220
|
provider: z.ZodOptional<z.ZodString>;
|
|
221
221
|
model: z.ZodString;
|
|
222
|
-
input: z.ZodObject<{
|
|
222
|
+
input: z.ZodOptional<z.ZodObject<{
|
|
223
223
|
system: z.ZodString;
|
|
224
224
|
prompt: z.ZodString;
|
|
225
225
|
tools: z.ZodArray<z.ZodObject<{
|
|
226
226
|
name: z.ZodString;
|
|
227
227
|
description: z.ZodOptional<z.ZodString>;
|
|
228
228
|
}, z.core.$strip>>;
|
|
229
|
-
}, z.core.$strip
|
|
230
|
-
output: z.ZodObject<{
|
|
229
|
+
}, z.core.$strip>>;
|
|
230
|
+
output: z.ZodOptional<z.ZodObject<{
|
|
231
231
|
mode: z.ZodEnum<{
|
|
232
232
|
generate: "generate";
|
|
233
233
|
stream: "stream";
|
|
@@ -236,9 +236,9 @@ declare const Z_Event: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
236
236
|
response: z.ZodOptional<z.ZodString>;
|
|
237
237
|
toolCalls: z.ZodArray<z.ZodObject<{
|
|
238
238
|
name: z.ZodString;
|
|
239
|
-
|
|
239
|
+
input: z.ZodOptional<z.ZodString>;
|
|
240
240
|
}, z.core.$strip>>;
|
|
241
|
-
}, z.core.$strip
|
|
241
|
+
}, z.core.$strip>>;
|
|
242
242
|
usage: z.ZodObject<{
|
|
243
243
|
inputTokens: z.ZodNumber;
|
|
244
244
|
inputTokenDetails: z.ZodObject<{
|
|
@@ -298,8 +298,8 @@ declare const Z_Event: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
298
298
|
properties: z.ZodObject<{
|
|
299
299
|
tool: z.ZodObject<{
|
|
300
300
|
name: z.ZodString;
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
input: z.ZodOptional<z.ZodString>;
|
|
302
|
+
output: z.ZodOptional<z.ZodString>;
|
|
303
303
|
}, z.core.$strip>;
|
|
304
304
|
}, z.core.$strip>;
|
|
305
305
|
}, z.core.$strip>], "type">;
|
|
@@ -70,7 +70,7 @@ const Z_LLMEvent = Z_EventBase.extend({
|
|
|
70
70
|
description: z.string().optional()
|
|
71
71
|
})
|
|
72
72
|
)
|
|
73
|
-
}),
|
|
73
|
+
}).optional(),
|
|
74
74
|
output: z.object({
|
|
75
75
|
mode: z.enum(["generate", "stream"]),
|
|
76
76
|
reasoning: z.string().optional(),
|
|
@@ -78,10 +78,10 @@ const Z_LLMEvent = Z_EventBase.extend({
|
|
|
78
78
|
toolCalls: z.array(
|
|
79
79
|
z.object({
|
|
80
80
|
name: z.string(),
|
|
81
|
-
|
|
81
|
+
input: z.string().optional()
|
|
82
82
|
})
|
|
83
83
|
)
|
|
84
|
-
}),
|
|
84
|
+
}).optional(),
|
|
85
85
|
usage: Z_EventAiUsage,
|
|
86
86
|
cost: Z_EventLlmCost.optional()
|
|
87
87
|
})
|
|
@@ -92,8 +92,8 @@ const Z_ToolEvent = Z_EventBase.extend({
|
|
|
92
92
|
properties: z.object({
|
|
93
93
|
tool: z.object({
|
|
94
94
|
name: z.string(),
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
input: z.string().optional(),
|
|
96
|
+
output: z.string().optional()
|
|
97
97
|
})
|
|
98
98
|
})
|
|
99
99
|
});
|
package/dist/lib/constants.d.mts
CHANGED
package/dist/lib/constants.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const CONSTANTS = {
|
|
2
2
|
api: {
|
|
3
|
-
baseUrl: "https://
|
|
3
|
+
baseUrl: "https://ingest.oncarbon.site",
|
|
4
4
|
ingestPath: "/v1/ingest-events",
|
|
5
5
|
retryMaxAttempts: 2,
|
|
6
6
|
retryMaxElapsedMs: 3e4,
|
|
@@ -8,7 +8,12 @@ const CONSTANTS = {
|
|
|
8
8
|
},
|
|
9
9
|
buffer: {
|
|
10
10
|
batchSize: 50,
|
|
11
|
+
maxBatchBytes: 3.5 * 1024 * 1024,
|
|
12
|
+
maxBufferedEvents: 5e3,
|
|
11
13
|
maxTimeMs: 5e3
|
|
14
|
+
},
|
|
15
|
+
errors: {
|
|
16
|
+
warnThrottleMs: 6e4
|
|
12
17
|
}
|
|
13
18
|
};
|
|
14
19
|
export {
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carbon-js/sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"license": "MIT",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"exports": {
|
|
6
7
|
".": {
|
|
@@ -18,8 +19,6 @@
|
|
|
18
19
|
"dist"
|
|
19
20
|
],
|
|
20
21
|
"dependencies": {
|
|
21
|
-
"@ai-sdk/anthropic": "^3.0.79",
|
|
22
|
-
"@ai-sdk/openai": "^3.0.65",
|
|
23
22
|
"@anthropic-ai/sdk": "^0.96.0",
|
|
24
23
|
"ai": "^6.0.177",
|
|
25
24
|
"openai": "^6.37.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./events.mjs";
|