@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.
@@ -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?: T_LLMEvent["properties"]["llm"]["output"]["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({ value: thinking && thinking.length > 0 ? thinking : void 0 });
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
- args: stringify({ value: block.input }),
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?: T_LLMEvent["properties"]["llm"]["output"]["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?: T_LLMEvent["properties"]["llm"]["output"]["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({ value: getResponseReasoning({ response: args.response }) }),
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({ value: args.completion?.choices[0]?.message.content }),
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
- args: stringify({ value: toolCall.type === "function" ? toolCall.function.arguments : toolCall.custom.input }),
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({ value: systemMessages.length > 0 ? systemMessages : void 0 }),
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
- args: output.arguments,
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
- args: output.input,
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(bodyWithInternalCapture, requestOptions);
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
- args: toolCall?.args ?? "",
91
+ input: toolCall?.args ?? "",
89
92
  name: toolCall?.name ?? "unknown",
90
- result: stringify({ value: result })
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
- args: T_ToolEvent["properties"]["tool"]["args"];
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({ value: "system" in args.event ? args.event.system : void 0 }),
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
- args: stringify({ value: toolCall.input }),
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
- args: args.pendingTool.args,
102
+ input: args.pendingTool.input,
101
103
  name: args.pendingTool.toolName,
102
- result: stringify({ value: args.output })
104
+ output: stringify({ value: args.output })
103
105
  },
104
106
  traceId: this.traceId
105
107
  });
@@ -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
- flushPendingTraces(): Promise<void>;
24
+ flushPendingEvents(): Promise<void>;
25
25
  }
26
26
 
27
27
  export { Carbon, type T_CarbonOptions, T_WrapToolArgs };
@@ -26,7 +26,7 @@ class Carbon {
26
26
  }
27
27
  });
28
28
  }
29
- flushPendingTraces() {
29
+ flushPendingEvents() {
30
30
  return this.runtime.shutdown();
31
31
  }
32
32
  }
@@ -9,6 +9,9 @@ declare class EventBuffer {
9
9
  drain(args?: {
10
10
  count?: number;
11
11
  }): T_Event[];
12
+ peek(args?: {
13
+ count?: number;
14
+ }): T_Event[];
12
15
  prepend(args: {
13
16
  events: T_Event[];
14
17
  }): void;
@@ -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
  }
@@ -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: T_RecordEvents): void;
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 };
@@ -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/index.mjs";
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.buffer.add({ events });
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.buffer.drain({ count: this.bufferBatchSize });
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 didSend = false;
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
- didSend = true;
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
- const retryable = typeof error === "object" && error !== null && "retryable" in error ? error.retryable : true;
77
- shouldRetry = typeof retryable === "boolean" ? retryable : true;
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 (didSend && canScheduleBackgroundFlush) {
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
- if (this.buffer.length >= this.bufferBatchSize) {
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
- args: stringify({ value: serializeToolArgs({ args: args.args }) }),
99
+ input: stringify({ value: serializeToolArgs({ args: args.args }) }),
100
100
  name: args.name,
101
- result: stringify({ value: args.result })
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(`Carbon ingest failed with status ${args.status}`);
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({ status: response.status });
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/index.mjs";
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
- args: z.ZodOptional<z.ZodString>;
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
- args: z.ZodOptional<z.ZodString>;
180
- result: z.ZodOptional<z.ZodString>;
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
- args: z.ZodOptional<z.ZodString>;
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
- args: z.ZodOptional<z.ZodString>;
302
- result: z.ZodOptional<z.ZodString>;
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
- args: z.string().optional()
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
- args: z.string().optional(),
96
- result: z.string().optional()
95
+ input: z.string().optional(),
96
+ output: z.string().optional()
97
97
  })
98
98
  })
99
99
  });
@@ -8,8 +8,13 @@ type T_Constants = {
8
8
  };
9
9
  buffer: {
10
10
  batchSize: number;
11
+ maxBatchBytes: number;
12
+ maxBufferedEvents: number;
11
13
  maxTimeMs: number;
12
14
  };
15
+ errors: {
16
+ warnThrottleMs: number;
17
+ };
13
18
  };
14
19
  declare const CONSTANTS: T_Constants;
15
20
 
@@ -1,6 +1,6 @@
1
1
  const CONSTANTS = {
2
2
  api: {
3
- baseUrl: "https://api.carbonrow.com",
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.2",
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";