@core-ai/core-ai 0.3.0 → 0.5.0

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/index.d.ts CHANGED
@@ -31,10 +31,27 @@ type FilePart = {
31
31
  mimeType: string;
32
32
  filename?: string;
33
33
  };
34
+ type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'max';
35
+ type ReasoningConfig = {
36
+ effort: ReasoningEffort;
37
+ };
38
+ type AssistantTextPart = {
39
+ type: 'text';
40
+ text: string;
41
+ };
42
+ type ReasoningPart = {
43
+ type: 'reasoning';
44
+ text: string;
45
+ providerMetadata?: Record<string, unknown>;
46
+ };
47
+ type ToolCallPart = {
48
+ type: 'tool-call';
49
+ toolCall: ToolCall;
50
+ };
51
+ type AssistantContentPart = AssistantTextPart | ReasoningPart | ToolCallPart;
34
52
  type AssistantMessage = {
35
53
  role: 'assistant';
36
- content: string | null;
37
- toolCalls?: ToolCall[];
54
+ parts: AssistantContentPart[];
38
55
  };
39
56
  type ToolCall = {
40
57
  id: string;
@@ -75,6 +92,7 @@ type ModelConfig = {
75
92
  };
76
93
  type GenerateOptions = {
77
94
  messages: Message[];
95
+ reasoning?: ReasoningConfig;
78
96
  tools?: ToolSet;
79
97
  toolChoice?: ToolChoice;
80
98
  config?: ModelConfig;
@@ -82,7 +100,9 @@ type GenerateOptions = {
82
100
  signal?: AbortSignal;
83
101
  };
84
102
  type GenerateResult = {
103
+ parts: AssistantContentPart[];
85
104
  content: string | null;
105
+ reasoning: string | null;
86
106
  toolCalls: ToolCall[];
87
107
  finishReason: FinishReason;
88
108
  usage: ChatUsage;
@@ -92,6 +112,7 @@ type GenerateObjectOptions<TSchema extends z.ZodType> = {
92
112
  schema: TSchema;
93
113
  schemaName?: string;
94
114
  schemaDescription?: string;
115
+ reasoning?: ReasoningConfig;
95
116
  config?: ModelConfig;
96
117
  providerOptions?: Record<string, unknown>;
97
118
  signal?: AbortSignal;
@@ -106,31 +127,51 @@ type FinishReason = 'stop' | 'length' | 'tool-calls' | 'content-filter' | 'unkno
106
127
  /**
107
128
  * Token usage reported by the model after a chat completion.
108
129
  *
109
- * `outputTokens` is the **total** output token count, including both visible
110
- * text and any internal reasoning/thinking the model performed.
111
- * `reasoningTokens` is the subset of `outputTokens` consumed by reasoning.
112
- * For non-reasoning models (or providers that don't report it separately)
113
- * this will be `0`.
130
+ * `inputTokens` is always the **total** input token count, including cached
131
+ * reads and cache writes. Anthropic's `input_tokens` is normalized by adding
132
+ * `cache_read_input_tokens` and `cache_creation_input_tokens`.
114
133
  *
115
- * Provider mapping:
116
- * - **OpenAI**: `reasoningTokens` comes from `completion_tokens_details.reasoning_tokens`.
117
- * - **Google Gemini**: `reasoningTokens` comes from `thoughtsTokenCount`;
118
- * `outputTokens` = `candidatesTokenCount + thoughtsTokenCount`.
119
- * - **Anthropic**: `reasoningTokens` is always `0` (thinking tokens are
120
- * included in `output_tokens` but not reported separately by the API).
134
+ * `outputTokens` is always the **total** output token count, including both
135
+ * visible text and internal reasoning.
136
+ *
137
+ * `inputTokenDetails` and `outputTokenDetails` provide provider-independent
138
+ * breakdowns for cache and reasoning accounting.
121
139
  */
122
140
  type ChatUsage = {
123
- /** Number of tokens in the input prompt. */
141
+ /** Total input tokens, including cached and cache-write tokens. */
124
142
  inputTokens: number;
125
143
  /** Total output tokens, including both visible text and reasoning. */
126
144
  outputTokens: number;
127
- /** Tokens consumed by internal reasoning/thinking. Subset of `outputTokens`. */
128
- reasoningTokens: number;
129
- /** Sum of all tokens (`inputTokens + outputTokens`). */
130
- totalTokens: number;
145
+ /** Breakdown of input token categories. */
146
+ inputTokenDetails: ChatInputTokenDetails;
147
+ /** Breakdown of output token categories. */
148
+ outputTokenDetails: ChatOutputTokenDetails;
149
+ };
150
+ type ChatInputTokenDetails = {
151
+ /** Input tokens served from a prior cache entry. Subset of `inputTokens`. */
152
+ cacheReadTokens: number;
153
+ /**
154
+ * Input tokens written to cache for future reuse. Subset of `inputTokens`.
155
+ * Only Anthropic reports this; other providers report `0`.
156
+ */
157
+ cacheWriteTokens: number;
158
+ };
159
+ type ChatOutputTokenDetails = {
160
+ /**
161
+ * Tokens consumed by internal reasoning/thinking. Subset of `outputTokens`.
162
+ * Omitted when the provider does not report a breakdown.
163
+ */
164
+ reasoningTokens?: number;
131
165
  };
132
166
  type StreamEvent = {
133
- type: 'content-delta';
167
+ type: 'reasoning-start';
168
+ } | {
169
+ type: 'reasoning-delta';
170
+ text: string;
171
+ } | {
172
+ type: 'reasoning-end';
173
+ } | {
174
+ type: 'text-delta';
134
175
  text: string;
135
176
  } | {
136
177
  type: 'tool-call-start';
@@ -238,6 +279,12 @@ declare class StructuredOutputValidationError extends StructuredOutputError {
238
279
 
239
280
  declare function defineTool(options: ToolDefinition): ToolDefinition;
240
281
 
282
+ type ResultToMessageOptions = {
283
+ includeReasoning?: boolean;
284
+ };
285
+ declare function resultToMessage(result: GenerateResult, options?: ResultToMessageOptions): AssistantMessage;
286
+ declare function assistantMessage(content: string): AssistantMessage;
287
+
241
288
  type GenerateParams = GenerateOptions & {
242
289
  model: ChatModel;
243
290
  };
@@ -271,4 +318,4 @@ type GenerateImageParams = ImageGenerateOptions & {
271
318
  };
272
319
  declare function generateImage(params: GenerateImageParams): Promise<ImageGenerateResult>;
273
320
 
274
- export { type AssistantMessage, type ChatModel, type ChatUsage, type EmbedOptions, type EmbedResult, type EmbeddingModel, type EmbeddingUsage, type FilePart, type FinishReason, type GenerateObjectOptions, type GenerateObjectResult, type GenerateOptions, type GenerateResult, type GeneratedImage, type ImageGenerateOptions, type ImageGenerateResult, type ImageModel, type ImagePart, LLMError, type Message, type ModelConfig, type ObjectStreamEvent, ProviderError, type StreamEvent, type StreamObjectOptions, type StreamObjectResult, type StreamResult, StructuredOutputError, StructuredOutputNoObjectGeneratedError, StructuredOutputParseError, StructuredOutputValidationError, type SystemMessage, type TextPart, type ToolCall, type ToolChoice, type ToolDefinition, type ToolResultMessage, type ToolSet, type UserContentPart, type UserMessage, createObjectStreamResult, createStreamResult, defineTool, embed, generate, generateImage, generateObject, stream, streamObject };
321
+ export { type AssistantContentPart, type AssistantMessage, type AssistantTextPart, type ChatInputTokenDetails, type ChatModel, type ChatOutputTokenDetails, type ChatUsage, type EmbedOptions, type EmbedResult, type EmbeddingModel, type EmbeddingUsage, type FilePart, type FinishReason, type GenerateObjectOptions, type GenerateObjectResult, type GenerateOptions, type GenerateResult, type GeneratedImage, type ImageGenerateOptions, type ImageGenerateResult, type ImageModel, type ImagePart, LLMError, type Message, type ModelConfig, type ObjectStreamEvent, ProviderError, type ReasoningConfig, type ReasoningEffort, type ReasoningPart, type StreamEvent, type StreamObjectOptions, type StreamObjectResult, type StreamResult, StructuredOutputError, StructuredOutputNoObjectGeneratedError, StructuredOutputParseError, StructuredOutputValidationError, type SystemMessage, type TextPart, type ToolCall, type ToolCallPart, type ToolChoice, type ToolDefinition, type ToolResultMessage, type ToolSet, type UserContentPart, type UserMessage, assistantMessage, createObjectStreamResult, createStreamResult, defineTool, embed, generate, generateImage, generateObject, resultToMessage, stream, streamObject };
package/dist/index.js CHANGED
@@ -52,6 +52,22 @@ function defineTool(options) {
52
52
  return options;
53
53
  }
54
54
 
55
+ // src/result-to-message.ts
56
+ function resultToMessage(result, options) {
57
+ const includeReasoning = options?.includeReasoning ?? true;
58
+ const parts = includeReasoning ? [...result.parts] : result.parts.filter((part) => part.type !== "reasoning");
59
+ return {
60
+ role: "assistant",
61
+ parts
62
+ };
63
+ }
64
+ function assistantMessage(content) {
65
+ return {
66
+ role: "assistant",
67
+ parts: [{ type: "text", text: content }]
68
+ };
69
+ }
70
+
55
71
  // src/generate.ts
56
72
  async function generate(params) {
57
73
  if (params.messages.length === 0) {
@@ -103,8 +119,11 @@ function createObjectStreamResult(source) {
103
119
  let usage = {
104
120
  inputTokens: 0,
105
121
  outputTokens: 0,
106
- reasoningTokens: 0,
107
- totalTokens: 0
122
+ inputTokenDetails: {
123
+ cacheReadTokens: 0,
124
+ cacheWriteTokens: 0
125
+ },
126
+ outputTokenDetails: {}
108
127
  };
109
128
  try {
110
129
  for await (const event of source) {
@@ -164,28 +183,85 @@ function createStreamResult(source) {
164
183
  });
165
184
  let iteratorCreated = false;
166
185
  async function* iterate() {
167
- let content = "";
168
- const toolCalls = [];
186
+ const parts = [];
187
+ let textBuffer = "";
188
+ let reasoningBuffer = "";
189
+ let insideReasoning = false;
169
190
  let finishReason = "unknown";
170
191
  let usage = {
171
192
  inputTokens: 0,
172
193
  outputTokens: 0,
173
- reasoningTokens: 0,
174
- totalTokens: 0
194
+ inputTokenDetails: {
195
+ cacheReadTokens: 0,
196
+ cacheWriteTokens: 0
197
+ },
198
+ outputTokenDetails: {}
199
+ };
200
+ const flushText = () => {
201
+ if (textBuffer.length === 0) {
202
+ return;
203
+ }
204
+ parts.push({
205
+ type: "text",
206
+ text: textBuffer
207
+ });
208
+ textBuffer = "";
209
+ };
210
+ const flushReasoning = () => {
211
+ if (reasoningBuffer.length === 0) {
212
+ return;
213
+ }
214
+ parts.push({
215
+ type: "reasoning",
216
+ text: reasoningBuffer
217
+ });
218
+ reasoningBuffer = "";
175
219
  };
176
220
  for await (const event of source) {
177
- if (event.type === "content-delta") {
178
- content += event.text;
221
+ if (event.type === "reasoning-start") {
222
+ flushText();
223
+ flushReasoning();
224
+ insideReasoning = true;
225
+ } else if (event.type === "reasoning-delta") {
226
+ if (!insideReasoning) {
227
+ flushText();
228
+ insideReasoning = true;
229
+ }
230
+ reasoningBuffer += event.text;
231
+ } else if (event.type === "reasoning-end") {
232
+ flushReasoning();
233
+ insideReasoning = false;
234
+ } else if (event.type === "text-delta") {
235
+ if (insideReasoning) {
236
+ flushReasoning();
237
+ insideReasoning = false;
238
+ }
239
+ textBuffer += event.text;
179
240
  } else if (event.type === "tool-call-end") {
180
- toolCalls.push(event.toolCall);
241
+ flushText();
242
+ flushReasoning();
243
+ insideReasoning = false;
244
+ parts.push({
245
+ type: "tool-call",
246
+ toolCall: event.toolCall
247
+ });
181
248
  } else if (event.type === "finish") {
182
249
  finishReason = event.finishReason;
183
250
  usage = event.usage;
184
251
  }
185
252
  yield event;
186
253
  }
254
+ flushText();
255
+ flushReasoning();
256
+ const content = parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
257
+ const reasoning = parts.flatMap((part) => part.type === "reasoning" ? [part.text] : []).join("");
258
+ const toolCalls = parts.flatMap(
259
+ (part) => part.type === "tool-call" ? [part.toolCall] : []
260
+ );
187
261
  resolveResponse?.({
262
+ parts,
188
263
  content: content.length > 0 ? content : null,
264
+ reasoning: reasoning.length > 0 ? reasoning : null,
189
265
  toolCalls,
190
266
  finishReason,
191
267
  usage
@@ -241,6 +317,7 @@ export {
241
317
  StructuredOutputNoObjectGeneratedError,
242
318
  StructuredOutputParseError,
243
319
  StructuredOutputValidationError,
320
+ assistantMessage,
244
321
  createObjectStreamResult,
245
322
  createStreamResult,
246
323
  defineTool,
@@ -248,6 +325,7 @@ export {
248
325
  generate,
249
326
  generateImage,
250
327
  generateObject,
328
+ resultToMessage,
251
329
  stream,
252
330
  streamObject
253
331
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@core-ai/core-ai",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Type-safe LLM abstraction layer over native provider SDKs",
5
5
  "license": "MIT",
6
6
  "author": "Omnifact (https://omnifact.ai)",