@kenkaiiii/gg-ai 5.67.1 → 5.68.1

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
@@ -186,8 +186,24 @@ interface Usage {
186
186
  webFetchRequests?: number;
187
187
  };
188
188
  }
189
+ interface PreparedContext {
190
+ /** Read-only observation after generic sanitization/image limiting, before provider encoding.
191
+ * Do not log or retain these messages: they may contain secrets and image data. */
192
+ messages: readonly Message[];
193
+ tools: readonly {
194
+ name: string;
195
+ description: string;
196
+ parameters: Record<string, unknown>;
197
+ }[];
198
+ imagesBefore: number;
199
+ imagesAfter: number;
200
+ /** First message whose images were removed for this request, or null. */
201
+ firstImageDropMessage: number | null;
202
+ }
189
203
  interface StreamOptions {
190
204
  provider: Provider;
205
+ /** Optional, synchronous diagnostics observer. Exceptions cannot fail a model request. */
206
+ onContextPrepared?: (context: PreparedContext) => void;
191
207
  model: string;
192
208
  messages: Message[];
193
209
  tools?: Tool[];
@@ -245,6 +261,14 @@ interface StreamOptions {
245
261
  * stalls — broken SSE connections (transient CDN / proxy issues) often
246
262
  * recover when the same request is issued over a plain HTTP request/response. */
247
263
  streaming?: boolean;
264
+ /** Cache prewarm (Anthropic only; other providers ignore it). Sends the exact
265
+ * same request prefix (system, tools, messages, thinking, betas) with
266
+ * `max_tokens: 1` over a non-streaming request so the prompt cache is written
267
+ * before the user's next real turn. If the configured thinking mode cannot be
268
+ * kept identical at `max_tokens: 1` (budget thinking requires
269
+ * budget_tokens < max_tokens), no request is sent and the response has
270
+ * zero usage with stopReason "end_turn". */
271
+ prewarm?: boolean;
248
272
  /** Override the User-Agent sent with OAuth-authenticated Anthropic requests.
249
273
  * Anthropic's OAuth edge rejects requests whose claude-cli version lags too
250
274
  * far behind the real Claude Code release; callers that track the live
@@ -574,7 +598,8 @@ type JsonSchema = Record<string, unknown>;
574
598
  declare function resolveToolSchema(tool: Tool): JsonSchema;
575
599
 
576
600
  /**
577
- * Cap historical images before provider dispatch, removing the oldest first.
601
+ * Cap historical images before provider dispatch, removing the oldest first, in batches so the
602
+ * cached conversation prefix stays byte-identical between requests.
578
603
  * The persisted/live conversation is never mutated; only modified messages and
579
604
  * tool results are cloned for the outgoing request.
580
605
  */
@@ -685,4 +710,4 @@ interface PalsuProviderConfig {
685
710
  */
686
711
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
687
712
 
688
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, 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, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
713
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, 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 PreparedContext, 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, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
package/dist/index.d.ts CHANGED
@@ -186,8 +186,24 @@ interface Usage {
186
186
  webFetchRequests?: number;
187
187
  };
188
188
  }
189
+ interface PreparedContext {
190
+ /** Read-only observation after generic sanitization/image limiting, before provider encoding.
191
+ * Do not log or retain these messages: they may contain secrets and image data. */
192
+ messages: readonly Message[];
193
+ tools: readonly {
194
+ name: string;
195
+ description: string;
196
+ parameters: Record<string, unknown>;
197
+ }[];
198
+ imagesBefore: number;
199
+ imagesAfter: number;
200
+ /** First message whose images were removed for this request, or null. */
201
+ firstImageDropMessage: number | null;
202
+ }
189
203
  interface StreamOptions {
190
204
  provider: Provider;
205
+ /** Optional, synchronous diagnostics observer. Exceptions cannot fail a model request. */
206
+ onContextPrepared?: (context: PreparedContext) => void;
191
207
  model: string;
192
208
  messages: Message[];
193
209
  tools?: Tool[];
@@ -245,6 +261,14 @@ interface StreamOptions {
245
261
  * stalls — broken SSE connections (transient CDN / proxy issues) often
246
262
  * recover when the same request is issued over a plain HTTP request/response. */
247
263
  streaming?: boolean;
264
+ /** Cache prewarm (Anthropic only; other providers ignore it). Sends the exact
265
+ * same request prefix (system, tools, messages, thinking, betas) with
266
+ * `max_tokens: 1` over a non-streaming request so the prompt cache is written
267
+ * before the user's next real turn. If the configured thinking mode cannot be
268
+ * kept identical at `max_tokens: 1` (budget thinking requires
269
+ * budget_tokens < max_tokens), no request is sent and the response has
270
+ * zero usage with stopReason "end_turn". */
271
+ prewarm?: boolean;
248
272
  /** Override the User-Agent sent with OAuth-authenticated Anthropic requests.
249
273
  * Anthropic's OAuth edge rejects requests whose claude-cli version lags too
250
274
  * far behind the real Claude Code release; callers that track the live
@@ -574,7 +598,8 @@ type JsonSchema = Record<string, unknown>;
574
598
  declare function resolveToolSchema(tool: Tool): JsonSchema;
575
599
 
576
600
  /**
577
- * Cap historical images before provider dispatch, removing the oldest first.
601
+ * Cap historical images before provider dispatch, removing the oldest first, in batches so the
602
+ * cached conversation prefix stays byte-identical between requests.
578
603
  * The persisted/live conversation is never mutated; only modified messages and
579
604
  * tool results are cloned for the outgoing request.
580
605
  */
@@ -685,4 +710,4 @@ interface PalsuProviderConfig {
685
710
  */
686
711
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
687
712
 
688
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, 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, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
713
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, type ErrorSource, EventStream, type FormattedError, GGAIError, 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 PreparedContext, 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, resolveToolSchema, sanitizeMessagesForWire, setProviderDiagnostic, sliceHead, sliceTail, stream, toAnthropicMessages, toOpenAIMessages, toWellFormedText };
package/dist/index.js CHANGED
@@ -743,10 +743,17 @@ function countContextImages(messages) {
743
743
  }
744
744
  return count;
745
745
  }
746
+ var IMAGE_DROP_BATCH = 30;
747
+ function providerImageDropCount(imageCount2, budget) {
748
+ const overflow = imageCount2 - budget;
749
+ if (overflow <= 0) return 0;
750
+ const batch = Math.max(1, Math.min(IMAGE_DROP_BATCH, Math.floor(budget / 3)));
751
+ return Math.min(imageCount2, Math.ceil(overflow / batch) * batch);
752
+ }
746
753
  function clampProviderContextImages(messages, provider, supportsImages) {
747
754
  if (supportsImages === false) return messages;
748
755
  const budget = PROVIDER_IMAGE_BUDGETS[provider] ?? 5;
749
- let remainingToRemove = countContextImages(messages) - budget;
756
+ let remainingToRemove = providerImageDropCount(countContextImages(messages), budget);
750
757
  if (remainingToRemove <= 0) return messages;
751
758
  return messages.map((message) => {
752
759
  if (message.role === "user" && Array.isArray(message.content)) {
@@ -1376,7 +1383,7 @@ function streamAnthropic(options) {
1376
1383
  async function* runStream(options) {
1377
1384
  const client = createClient(options);
1378
1385
  const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
1379
- const useStreaming = options.streaming !== false;
1386
+ const useStreaming = options.streaming !== false && !options.prewarm;
1380
1387
  const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
1381
1388
  const supportsFirstPartyToolExtras = !options.baseUrl || options.baseUrl.includes("api.anthropic.com");
1382
1389
  const downgradedImages = downgradeUnsupportedImages(options.messages, options.supportsImages);
@@ -1400,6 +1407,17 @@ async function* runStream(options) {
1400
1407
  outputConfig = t.outputConfig;
1401
1408
  }
1402
1409
  }
1410
+ if (options.prewarm) {
1411
+ const budget = thinking?.budget_tokens;
1412
+ if (budget != null && budget >= 1) {
1413
+ return {
1414
+ message: { role: "assistant", content: [] },
1415
+ stopReason: "end_turn",
1416
+ usage: { inputTokens: 0, outputTokens: 0 }
1417
+ };
1418
+ }
1419
+ maxTokens = 1;
1420
+ }
1403
1421
  const params = {
1404
1422
  model: options.model,
1405
1423
  max_tokens: maxTokens,
@@ -3830,6 +3848,41 @@ function sanitizeMessagesForWire(messages) {
3830
3848
  return sanitized ?? messages;
3831
3849
  }
3832
3850
 
3851
+ // src/utils/context-observation.ts
3852
+ function imageCount(message) {
3853
+ if (!message || !Array.isArray(message.content)) return 0;
3854
+ if (message.role === "user")
3855
+ return message.content.filter((part) => part.type === "image").length;
3856
+ if (message.role !== "tool") return 0;
3857
+ return message.content.reduce(
3858
+ (count, result) => count + (Array.isArray(result.content) ? result.content.filter((part) => part.type === "image").length : 0),
3859
+ 0
3860
+ );
3861
+ }
3862
+ function observePreparedContext(before, after, tools) {
3863
+ let imagesBefore = 0;
3864
+ let imagesAfter = 0;
3865
+ let firstImageDropMessage = null;
3866
+ for (let index = 0; index < before.length; index++) {
3867
+ const oldCount = imageCount(before[index]);
3868
+ const newCount = imageCount(after[index]);
3869
+ imagesBefore += oldCount;
3870
+ imagesAfter += newCount;
3871
+ if (firstImageDropMessage === null && newCount < oldCount) firstImageDropMessage = index;
3872
+ }
3873
+ return {
3874
+ messages: after,
3875
+ tools: tools.map((tool) => ({
3876
+ name: tool.name,
3877
+ description: tool.description,
3878
+ parameters: resolveToolSchema(tool)
3879
+ })),
3880
+ imagesBefore,
3881
+ imagesAfter,
3882
+ firstImageDropMessage
3883
+ };
3884
+ }
3885
+
3833
3886
  // src/stream.ts
3834
3887
  var GLM_CODING_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
3835
3888
  var KIMI_CODE_USER_AGENT = `kimi-code-cli/${process.env.KIMI_CODE_VERSION ?? "1.0.11"}`;
@@ -3977,6 +4030,14 @@ function stream(options) {
3977
4030
  options.provider,
3978
4031
  options.supportsImages
3979
4032
  );
4033
+ if (options.onContextPrepared) {
4034
+ try {
4035
+ options.onContextPrepared(
4036
+ observePreparedContext(wireMessages, messages, options.tools ?? [])
4037
+ );
4038
+ } catch {
4039
+ }
4040
+ }
3980
4041
  return entry.stream(messages === options.messages ? options : { ...options, messages });
3981
4042
  }
3982
4043
  function stripMessageProvenance(messages) {