@prestyj/ai 5.10.0 → 5.11.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.cts CHANGED
@@ -77,19 +77,31 @@ interface RawContent {
77
77
  data: Record<string, unknown>;
78
78
  }
79
79
  type ContentPart = TextContent | ThinkingContent | ImageContent | VideoContent | ToolCall | ServerToolCall | ServerToolResult | RawContent;
80
- interface SystemMessage {
80
+ type MessageProvenanceSource = "human" | "agent" | "runtime";
81
+ type MessageProvenanceKind = "prompt" | "steering" | "notification" | "completion_gate" | "review_follow_up" | "continuation" | "model_switch" | "automation" | "compaction_summary" | "compaction_ack";
82
+ type MessageProvenanceVisibility = "transcript" | "hidden" | "summary";
83
+ /** Internal message metadata. `stream()` removes it before provider dispatch. */
84
+ interface MessageProvenance {
85
+ source: MessageProvenanceSource;
86
+ kind: MessageProvenanceKind;
87
+ visibility: MessageProvenanceVisibility;
88
+ }
89
+ interface MessageMetadata {
90
+ provenance?: MessageProvenance;
91
+ }
92
+ interface SystemMessage extends MessageMetadata {
81
93
  role: "system";
82
94
  content: string;
83
95
  }
84
- interface UserMessage {
96
+ interface UserMessage extends MessageMetadata {
85
97
  role: "user";
86
98
  content: string | (TextContent | ImageContent | VideoContent)[];
87
99
  }
88
- interface AssistantMessage {
100
+ interface AssistantMessage extends MessageMetadata {
89
101
  role: "assistant";
90
102
  content: string | ContentPart[];
91
103
  }
92
- interface ToolResultMessage {
104
+ interface ToolResultMessage extends MessageMetadata {
93
105
  role: "tool";
94
106
  content: ToolResult[];
95
107
  }
@@ -161,7 +173,10 @@ interface StreamResponse {
161
173
  }
162
174
  interface Usage {
163
175
  inputTokens: number;
176
+ /** Total billed output tokens, including reasoning tokens when the provider reports them separately. */
164
177
  outputTokens: number;
178
+ /** Reasoning/thinking-token subset of outputTokens. */
179
+ reasoningTokens?: number;
165
180
  cacheRead?: number;
166
181
  cacheWrite?: number;
167
182
  serverToolUse?: {
@@ -490,6 +505,21 @@ declare function redactText(text: string, options?: RedactionOptions): string;
490
505
  */
491
506
  declare function redactValue<T>(value: T, options?: RedactionOptions): T;
492
507
 
508
+ /** True when the string contains at least one unpaired surrogate. */
509
+ declare function hasLoneSurrogate(text: string): boolean;
510
+ /** Replace unpaired surrogates with U+FFFD; returns the input when already valid. */
511
+ declare function toWellFormedText(text: string): string;
512
+ /** `text.slice(0, chars)` that never cuts an astral character in half. */
513
+ declare function sliceHead(text: string, chars: number): string;
514
+ /** `text.slice(-chars)` that never cuts an astral character in half. */
515
+ declare function sliceTail(text: string, chars: number): string;
516
+ /**
517
+ * Strip unpaired surrogates from everything headed for the wire. Returns the
518
+ * same array (and same message objects) when the history is already valid, so
519
+ * the clean path stays allocation-free.
520
+ */
521
+ declare function sanitizeMessagesForWire(messages: Message[]): Message[];
522
+
493
523
  /**
494
524
  * Provider-level diagnostic hook. Mirrors the pattern used by gg-agent's
495
525
  * setStreamDiagnostic — the host app wires a callback (typically writing to
@@ -612,4 +642,4 @@ interface PalsuProviderConfig {
612
642
  */
613
643
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
614
644
 
615
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
645
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
package/dist/index.d.ts CHANGED
@@ -77,19 +77,31 @@ interface RawContent {
77
77
  data: Record<string, unknown>;
78
78
  }
79
79
  type ContentPart = TextContent | ThinkingContent | ImageContent | VideoContent | ToolCall | ServerToolCall | ServerToolResult | RawContent;
80
- interface SystemMessage {
80
+ type MessageProvenanceSource = "human" | "agent" | "runtime";
81
+ type MessageProvenanceKind = "prompt" | "steering" | "notification" | "completion_gate" | "review_follow_up" | "continuation" | "model_switch" | "automation" | "compaction_summary" | "compaction_ack";
82
+ type MessageProvenanceVisibility = "transcript" | "hidden" | "summary";
83
+ /** Internal message metadata. `stream()` removes it before provider dispatch. */
84
+ interface MessageProvenance {
85
+ source: MessageProvenanceSource;
86
+ kind: MessageProvenanceKind;
87
+ visibility: MessageProvenanceVisibility;
88
+ }
89
+ interface MessageMetadata {
90
+ provenance?: MessageProvenance;
91
+ }
92
+ interface SystemMessage extends MessageMetadata {
81
93
  role: "system";
82
94
  content: string;
83
95
  }
84
- interface UserMessage {
96
+ interface UserMessage extends MessageMetadata {
85
97
  role: "user";
86
98
  content: string | (TextContent | ImageContent | VideoContent)[];
87
99
  }
88
- interface AssistantMessage {
100
+ interface AssistantMessage extends MessageMetadata {
89
101
  role: "assistant";
90
102
  content: string | ContentPart[];
91
103
  }
92
- interface ToolResultMessage {
104
+ interface ToolResultMessage extends MessageMetadata {
93
105
  role: "tool";
94
106
  content: ToolResult[];
95
107
  }
@@ -161,7 +173,10 @@ interface StreamResponse {
161
173
  }
162
174
  interface Usage {
163
175
  inputTokens: number;
176
+ /** Total billed output tokens, including reasoning tokens when the provider reports them separately. */
164
177
  outputTokens: number;
178
+ /** Reasoning/thinking-token subset of outputTokens. */
179
+ reasoningTokens?: number;
165
180
  cacheRead?: number;
166
181
  cacheWrite?: number;
167
182
  serverToolUse?: {
@@ -490,6 +505,21 @@ declare function redactText(text: string, options?: RedactionOptions): string;
490
505
  */
491
506
  declare function redactValue<T>(value: T, options?: RedactionOptions): T;
492
507
 
508
+ /** True when the string contains at least one unpaired surrogate. */
509
+ declare function hasLoneSurrogate(text: string): boolean;
510
+ /** Replace unpaired surrogates with U+FFFD; returns the input when already valid. */
511
+ declare function toWellFormedText(text: string): string;
512
+ /** `text.slice(0, chars)` that never cuts an astral character in half. */
513
+ declare function sliceHead(text: string, chars: number): string;
514
+ /** `text.slice(-chars)` that never cuts an astral character in half. */
515
+ declare function sliceTail(text: string, chars: number): string;
516
+ /**
517
+ * Strip unpaired surrogates from everything headed for the wire. Returns the
518
+ * same array (and same message objects) when the history is already valid, so
519
+ * the clean path stays allocation-free.
520
+ */
521
+ declare function sanitizeMessagesForWire(messages: Message[]): Message[];
522
+
493
523
  /**
494
524
  * Provider-level diagnostic hook. Mirrors the pattern used by gg-agent's
495
525
  * setStreamDiagnostic — the host app wires a callback (typically writing to
@@ -612,4 +642,4 @@ interface PalsuProviderConfig {
612
642
  */
613
643
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
614
644
 
615
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, setProviderDiagnostic, stream, toAnthropicMessages, toOpenAIMessages };
645
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, EZCoderAIError, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, type ImageContent, type Message, type MessageProvenance, type MessageProvenanceKind, type MessageProvenanceSource, type MessageProvenanceVisibility, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderDiagnosticFn, type ProviderEntry, ProviderError, type ProviderStreamFn, REDACTED as REDACTION_MARKER, type RawContent, type RedactionOptions, type ServerToolCall, type ServerToolCallEvent, type ServerToolDefinition, type ServerToolResult, type ServerToolResultEvent, type StopReason, type StreamEvent, type StreamOptions, type StreamResponse, StreamResult, type SystemMessage, type TextContent, type TextDeltaEvent, type ThinkingContent, type ThinkingDeltaEvent, type ThinkingLevel, type Tool, type ToolCall, type ToolCallDeltaEvent, type ToolCallDoneEvent, type ToolChoice, type ToolResult, type ToolResultContent, type ToolResultMessage, type Usage, type UserMessage, type VideoContent, clampProviderContextImages, classifyProviderError, environmentSecrets, formatError, formatErrorForDisplay, hasLoneSurrogate, isHardBillingMessage, isUsageLimitError, localWireModelId, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, prewarmAnthropicCache, providerRegistry, redactText, redactValue, registerPalsuProvider, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
package/dist/index.js CHANGED
@@ -3319,14 +3319,16 @@ async function* runStream4(options) {
3319
3319
  let thinkingAccum = "";
3320
3320
  let stopReason = "end_turn";
3321
3321
  let inputTokens = 0;
3322
- let outputTokens = 0;
3322
+ let candidateTokens = 0;
3323
+ let reasoningTokens = 0;
3323
3324
  let cacheRead = 0;
3324
3325
  let toolIndex = 0;
3325
3326
  const handleResponse = function* (chunk) {
3326
3327
  const usage = usageFromResponse(chunk);
3327
3328
  if (usage) {
3328
3329
  inputTokens = usage.promptTokenCount ?? inputTokens;
3329
- outputTokens = usage.candidatesTokenCount ?? outputTokens;
3330
+ candidateTokens = usage.candidatesTokenCount ?? candidateTokens;
3331
+ reasoningTokens = usage.thoughtsTokenCount ?? reasoningTokens;
3330
3332
  cacheRead = usage.cachedContentTokenCount ?? cacheRead;
3331
3333
  }
3332
3334
  const reason = finishReasonFromResponse(chunk);
@@ -3382,6 +3384,7 @@ async function* runStream4(options) {
3382
3384
  }
3383
3385
  if (pendingToolCalls.length > 0) stopReason = "tool_use";
3384
3386
  const adjustedInputTokens = Math.max(0, inputTokens - cacheRead);
3387
+ const outputTokens = candidateTokens + reasoningTokens;
3385
3388
  const streamResponse = {
3386
3389
  message: {
3387
3390
  role: "assistant",
@@ -3391,6 +3394,7 @@ async function* runStream4(options) {
3391
3394
  usage: {
3392
3395
  inputTokens: adjustedInputTokens,
3393
3396
  outputTokens,
3397
+ ...reasoningTokens > 0 ? { reasoningTokens } : {},
3394
3398
  ...cacheRead > 0 ? { cacheRead } : {}
3395
3399
  }
3396
3400
  };
@@ -3439,6 +3443,140 @@ var ProviderRegistryImpl = class {
3439
3443
  };
3440
3444
  var providerRegistry = new ProviderRegistryImpl();
3441
3445
 
3446
+ // src/utils/well-formed.ts
3447
+ var LONE_SURROGATE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
3448
+ var LONE_SURROGATE_GLOBAL = new RegExp(LONE_SURROGATE, "g");
3449
+ var REPLACEMENT = "\uFFFD";
3450
+ function hasLoneSurrogate(text) {
3451
+ const isWellFormed = text.isWellFormed;
3452
+ if (typeof isWellFormed === "function") return !isWellFormed.call(text);
3453
+ return LONE_SURROGATE.test(text);
3454
+ }
3455
+ function toWellFormedText(text) {
3456
+ if (!hasLoneSurrogate(text)) return text;
3457
+ const toWellFormed = text.toWellFormed;
3458
+ if (typeof toWellFormed === "function") return toWellFormed.call(text);
3459
+ return text.replace(LONE_SURROGATE_GLOBAL, REPLACEMENT);
3460
+ }
3461
+ function isHighSurrogate(code) {
3462
+ return code !== void 0 && code >= 55296 && code <= 56319;
3463
+ }
3464
+ function isLowSurrogate(code) {
3465
+ return code !== void 0 && code >= 56320 && code <= 57343;
3466
+ }
3467
+ function sliceHead(text, chars) {
3468
+ if (chars <= 0) return "";
3469
+ if (chars >= text.length) return text;
3470
+ const end = isHighSurrogate(text.charCodeAt(chars - 1)) ? chars - 1 : chars;
3471
+ return text.slice(0, end);
3472
+ }
3473
+ function sliceTail(text, chars) {
3474
+ if (chars <= 0) return "";
3475
+ if (chars >= text.length) return text;
3476
+ const start = text.length - chars;
3477
+ return text.slice(isLowSurrogate(text.charCodeAt(start)) ? start + 1 : start);
3478
+ }
3479
+ function sanitizeJsonValue(value) {
3480
+ if (typeof value === "string") return toWellFormedText(value);
3481
+ if (Array.isArray(value)) {
3482
+ let changed = false;
3483
+ const next = value.map((item) => {
3484
+ const sanitized = sanitizeJsonValue(item);
3485
+ if (sanitized !== item) changed = true;
3486
+ return sanitized;
3487
+ });
3488
+ return changed ? next : value;
3489
+ }
3490
+ if (value !== null && typeof value === "object") {
3491
+ let changed = false;
3492
+ const next = {};
3493
+ for (const [key, item] of Object.entries(value)) {
3494
+ const sanitizedKey = toWellFormedText(key);
3495
+ const sanitized = sanitizeJsonValue(item);
3496
+ if (sanitizedKey !== key || sanitized !== item) changed = true;
3497
+ next[sanitizedKey] = sanitized;
3498
+ }
3499
+ return changed ? next : value;
3500
+ }
3501
+ return value;
3502
+ }
3503
+ function sanitizeRecord(value) {
3504
+ return sanitizeJsonValue(value);
3505
+ }
3506
+ function sanitizePart(part) {
3507
+ switch (part.type) {
3508
+ case "text":
3509
+ case "thinking": {
3510
+ const text = toWellFormedText(part.text);
3511
+ return text === part.text ? part : { ...part, text };
3512
+ }
3513
+ case "tool_call": {
3514
+ const args = sanitizeRecord(part.args);
3515
+ return args === part.args ? part : { ...part, args };
3516
+ }
3517
+ case "server_tool_call": {
3518
+ const input = sanitizeJsonValue(part.input);
3519
+ return input === part.input ? part : { ...part, input };
3520
+ }
3521
+ case "server_tool_result": {
3522
+ const data = sanitizeJsonValue(part.data);
3523
+ return data === part.data ? part : { ...part, data };
3524
+ }
3525
+ case "raw": {
3526
+ const data = sanitizeRecord(part.data);
3527
+ return data === part.data ? part : { ...part, data };
3528
+ }
3529
+ default:
3530
+ return part;
3531
+ }
3532
+ }
3533
+ function sanitizeParts(parts) {
3534
+ let changed = false;
3535
+ const next = parts.map((part) => {
3536
+ const sanitized = sanitizePart(part);
3537
+ if (sanitized !== part) changed = true;
3538
+ return sanitized;
3539
+ });
3540
+ return changed ? next : parts;
3541
+ }
3542
+ function sanitizeToolResultContent(content) {
3543
+ if (typeof content === "string") return toWellFormedText(content);
3544
+ return sanitizeParts(content);
3545
+ }
3546
+ function sanitizeToolResults(results) {
3547
+ let changed = false;
3548
+ const next = results.map((result) => {
3549
+ const content = sanitizeToolResultContent(result.content);
3550
+ if (content === result.content) return result;
3551
+ changed = true;
3552
+ return { ...result, content };
3553
+ });
3554
+ return changed ? next : results;
3555
+ }
3556
+ function sanitizeMessage(message) {
3557
+ if (message.role === "tool") {
3558
+ const content2 = sanitizeToolResults(message.content);
3559
+ return content2 === message.content ? message : { ...message, content: content2 };
3560
+ }
3561
+ if (typeof message.content === "string") {
3562
+ const content2 = toWellFormedText(message.content);
3563
+ return content2 === message.content ? message : { ...message, content: content2 };
3564
+ }
3565
+ const content = sanitizeParts(message.content);
3566
+ return content === message.content ? message : { ...message, content };
3567
+ }
3568
+ function sanitizeMessagesForWire(messages) {
3569
+ let sanitized;
3570
+ for (let index = 0; index < messages.length; index++) {
3571
+ const message = messages[index];
3572
+ const next = sanitizeMessage(message);
3573
+ if (next === message) continue;
3574
+ sanitized ??= messages.slice();
3575
+ sanitized[index] = next;
3576
+ }
3577
+ return sanitized ?? messages;
3578
+ }
3579
+
3442
3580
  // src/stream.ts
3443
3581
  var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
3444
3582
  var KIMI_CODE_USER_AGENT = `kimi-code-cli/${process.env.KIMI_CODE_VERSION ?? "1.0.11"}`;
@@ -3560,13 +3698,25 @@ function stream(options) {
3560
3698
  if (options.supportsVideo !== true && messagesContainVideo(options.messages)) {
3561
3699
  throw new VideoUnsupportedError();
3562
3700
  }
3701
+ const wireMessages = stripMessageProvenance(options.messages);
3563
3702
  const messages = clampProviderContextImages(
3564
- options.messages,
3703
+ sanitizeMessagesForWire(wireMessages),
3565
3704
  options.provider,
3566
3705
  options.supportsImages
3567
3706
  );
3568
3707
  return entry.stream(messages === options.messages ? options : { ...options, messages });
3569
3708
  }
3709
+ function stripMessageProvenance(messages) {
3710
+ let stripped;
3711
+ for (let index = 0; index < messages.length; index++) {
3712
+ const message = messages[index];
3713
+ if (!message.provenance) continue;
3714
+ stripped ??= messages.slice();
3715
+ const { provenance: _provenance, ...wireMessage } = message;
3716
+ stripped[index] = wireMessage;
3717
+ }
3718
+ return stripped ?? messages;
3719
+ }
3570
3720
  function messagesContainVideo(messages) {
3571
3721
  for (const msg of messages) {
3572
3722
  if (typeof msg.content === "string" || !Array.isArray(msg.content)) continue;
@@ -3951,6 +4101,7 @@ export {
3951
4101
  environmentSecrets,
3952
4102
  formatError,
3953
4103
  formatErrorForDisplay,
4104
+ hasLoneSurrogate,
3954
4105
  isHardBillingMessage,
3955
4106
  isUsageLimitError,
3956
4107
  localWireModelId,
@@ -3963,9 +4114,13 @@ export {
3963
4114
  redactText,
3964
4115
  redactValue,
3965
4116
  registerPalsuProvider,
4117
+ sanitizeMessagesForWire,
3966
4118
  setProviderDiagnostic,
4119
+ sliceHead,
4120
+ sliceTail,
3967
4121
  stream,
3968
4122
  toAnthropicMessages,
3969
- toOpenAIMessages
4123
+ toOpenAIMessages,
4124
+ toWellFormedText
3970
4125
  };
3971
4126
  //# sourceMappingURL=index.js.map