@kenkaiiii/gg-ai 4.3.38 → 4.3.40

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
@@ -23,10 +23,11 @@ interface ToolCall {
23
23
  name: string;
24
24
  args: Record<string, unknown>;
25
25
  }
26
+ type ToolResultContent = string | (TextContent | ImageContent)[];
26
27
  interface ToolResult {
27
28
  type: "tool_result";
28
29
  toolCallId: string;
29
- content: string;
30
+ content: ToolResultContent;
30
31
  isError?: boolean;
31
32
  }
32
33
  interface ServerToolCall {
@@ -174,6 +175,10 @@ interface StreamOptions {
174
175
  * where the default `globalThis.fetch` doesn't support streaming properly.
175
176
  * Passed directly to the underlying provider SDK. */
176
177
  fetch?: typeof globalThis.fetch;
178
+ /** Whether the target model supports image input. When false, image content
179
+ * in user messages and tool_result messages is downgraded to a text placeholder
180
+ * before being sent to the provider. Default: true. */
181
+ supportsImages?: boolean;
177
182
  /** Use streaming transport (default: true). When false, providers issue a
178
183
  * single non-streaming request and synthesize events from the full response.
179
184
  * The agent loop flips this to `false` as a fallback after repeated stream
@@ -368,4 +373,4 @@ interface PalsuProviderConfig {
368
373
  */
369
374
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
370
375
 
371
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, EventStream, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, 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 ToolResultMessage, type Usage, type UserMessage, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
376
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, EventStream, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, 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, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
package/dist/index.d.ts CHANGED
@@ -23,10 +23,11 @@ interface ToolCall {
23
23
  name: string;
24
24
  args: Record<string, unknown>;
25
25
  }
26
+ type ToolResultContent = string | (TextContent | ImageContent)[];
26
27
  interface ToolResult {
27
28
  type: "tool_result";
28
29
  toolCallId: string;
29
- content: string;
30
+ content: ToolResultContent;
30
31
  isError?: boolean;
31
32
  }
32
33
  interface ServerToolCall {
@@ -174,6 +175,10 @@ interface StreamOptions {
174
175
  * where the default `globalThis.fetch` doesn't support streaming properly.
175
176
  * Passed directly to the underlying provider SDK. */
176
177
  fetch?: typeof globalThis.fetch;
178
+ /** Whether the target model supports image input. When false, image content
179
+ * in user messages and tool_result messages is downgraded to a text placeholder
180
+ * before being sent to the provider. Default: true. */
181
+ supportsImages?: boolean;
177
182
  /** Use streaming transport (default: true). When false, providers issue a
178
183
  * single non-streaming request and synthesize events from the full response.
179
184
  * The agent loop flips this to `false` as a fallback after repeated stream
@@ -368,4 +373,4 @@ interface PalsuProviderConfig {
368
373
  */
369
374
  declare function registerPalsuProvider(config?: PalsuProviderConfig): PalsuProviderHandle;
370
375
 
371
- export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, EventStream, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, 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 ToolResultMessage, type Usage, type UserMessage, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
376
+ export { type AssistantMessage, type CacheRetention, type ContentPart, type DoneEvent, type ErrorEvent, EventStream, GGAIError, type ImageContent, type Message, type PalsuModelConfig, type PalsuModelHandle, type PalsuProviderConfig, type PalsuProviderHandle, type PalsuProviderState, type PalsuResponse, type PalsuResponseFactory, type Provider, type ProviderEntry, ProviderError, type ProviderStreamFn, type RawContent, 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, palsuAssistantMessage, palsuText, palsuThinking, palsuToolCall, providerRegistry, registerPalsuProvider, stream };
package/dist/index.js CHANGED
@@ -128,12 +128,70 @@ function zodToJsonSchema(schema) {
128
128
  }
129
129
 
130
130
  // src/providers/transform.ts
131
+ var NON_VISION_USER_IMAGE_PLACEHOLDER = "(image omitted: model does not support images)";
132
+ var NON_VISION_TOOL_IMAGE_PLACEHOLDER = "(tool image omitted: model does not support images)";
133
+ function stripImages(content, placeholder) {
134
+ const out = [];
135
+ let lastWasPlaceholder = false;
136
+ for (const block of content) {
137
+ if (block.type === "image") {
138
+ if (!lastWasPlaceholder) out.push({ type: "text", text: placeholder });
139
+ lastWasPlaceholder = true;
140
+ continue;
141
+ }
142
+ out.push(block);
143
+ lastWasPlaceholder = block.text === placeholder;
144
+ }
145
+ return out;
146
+ }
147
+ function downgradeUnsupportedImages(messages, supportsImages) {
148
+ if (supportsImages !== false) return messages;
149
+ return messages.map((msg) => {
150
+ if (msg.role === "user" && Array.isArray(msg.content)) {
151
+ return { ...msg, content: stripImages(msg.content, NON_VISION_USER_IMAGE_PLACEHOLDER) };
152
+ }
153
+ if (msg.role === "tool") {
154
+ return {
155
+ ...msg,
156
+ content: msg.content.map(
157
+ (tr) => Array.isArray(tr.content) ? {
158
+ ...tr,
159
+ content: stripImages(tr.content, NON_VISION_TOOL_IMAGE_PLACEHOLDER)
160
+ } : tr
161
+ )
162
+ };
163
+ }
164
+ return msg;
165
+ });
166
+ }
167
+ function toolResultText(content) {
168
+ if (typeof content === "string") return content;
169
+ return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
170
+ }
171
+ function toolResultImages(content) {
172
+ if (typeof content === "string") return [];
173
+ return content.filter((b) => b.type === "image");
174
+ }
131
175
  function toAnthropicCacheControl(retention, baseUrl) {
132
176
  const resolved = retention ?? "short";
133
177
  if (resolved === "none") return void 0;
134
178
  const ttl = resolved === "long" && (!baseUrl || baseUrl.includes("api.anthropic.com")) ? "1h" : void 0;
135
179
  return { type: "ephemeral", ...ttl && { ttl } };
136
180
  }
181
+ function toAnthropicToolResultContent(content) {
182
+ if (typeof content === "string") return content;
183
+ return content.map((block) => {
184
+ if (block.type === "text") return { type: "text", text: block.text };
185
+ return {
186
+ type: "image",
187
+ source: {
188
+ type: "base64",
189
+ media_type: block.mediaType,
190
+ data: block.data
191
+ }
192
+ };
193
+ });
194
+ }
137
195
  function toAnthropicMessages(messages, cacheControl) {
138
196
  let systemText;
139
197
  const out = [];
@@ -197,7 +255,7 @@ function toAnthropicMessages(messages, cacheControl) {
197
255
  content: msg.content.map((result) => ({
198
256
  type: "tool_result",
199
257
  tool_use_id: result.toolCallId,
200
- content: result.content,
258
+ content: toAnthropicToolResultContent(result.content),
201
259
  is_error: result.isError
202
260
  }))
203
261
  });
@@ -368,11 +426,29 @@ function toOpenAIMessages(messages, options) {
368
426
  continue;
369
427
  }
370
428
  if (msg.role === "tool") {
429
+ const imageBlocks = [];
371
430
  for (const result of msg.content) {
431
+ const text = toolResultText(result.content);
432
+ const images = toolResultImages(result.content);
433
+ const hasText = text.length > 0;
372
434
  out.push({
373
435
  role: "tool",
374
436
  tool_call_id: remapToolCallId(result.toolCallId, idMap),
375
- content: result.content
437
+ content: hasText ? text : "(see attached image)"
438
+ });
439
+ if (images.length > 0 && options?.supportsImages !== false) {
440
+ for (const img of images) {
441
+ imageBlocks.push({
442
+ type: "image_url",
443
+ image_url: { url: `data:${img.mediaType};base64,${img.data}` }
444
+ });
445
+ }
446
+ }
447
+ }
448
+ if (imageBlocks.length > 0) {
449
+ out.push({
450
+ role: "user",
451
+ content: [{ type: "text", text: "Attached image(s) from tool result:" }, ...imageBlocks]
376
452
  });
377
453
  }
378
454
  }
@@ -454,7 +530,8 @@ async function* runStream(options) {
454
530
  const isOAuth = options.apiKey?.startsWith("sk-ant-oat");
455
531
  const useStreaming = options.streaming !== false;
456
532
  const cacheControl = toAnthropicCacheControl(options.cacheRetention, options.baseUrl);
457
- const { system: rawSystem, messages } = toAnthropicMessages(options.messages, cacheControl);
533
+ const downgradedMessages = downgradeUnsupportedImages(options.messages, options.supportsImages);
534
+ const { system: rawSystem, messages } = toAnthropicMessages(downgradedMessages, cacheControl);
458
535
  const system = isOAuth ? [
459
536
  {
460
537
  type: "text",
@@ -846,9 +923,11 @@ async function* runStream2(options) {
846
923
  const useStreaming = options.streaming !== false;
847
924
  const client = createClient2(options);
848
925
  const usesThinkingParam = options.provider === "glm" || options.provider === "moonshot" || options.provider === "xiaomi";
849
- const messages = toOpenAIMessages(options.messages, {
926
+ const downgradedMessages = downgradeUnsupportedImages(options.messages, options.supportsImages);
927
+ const messages = toOpenAIMessages(downgradedMessages, {
850
928
  provider: options.provider,
851
- thinking: !!options.thinking
929
+ thinking: !!options.thinking,
930
+ supportsImages: options.supportsImages
852
931
  });
853
932
  const defaultTemp = options.provider === "glm" ? 0.6 : void 0;
854
933
  const effectiveTemp = options.temperature ?? defaultTemp;
@@ -1140,7 +1219,8 @@ function streamOpenAICodex(options) {
1140
1219
  async function* runStream3(options) {
1141
1220
  const baseUrl = (options.baseUrl || DEFAULT_BASE_URL).replace(/\/+$/, "");
1142
1221
  const url = `${baseUrl}/codex/responses`;
1143
- const { system, input } = toCodexInput(options.messages);
1222
+ const downgraded = downgradeUnsupportedImages(options.messages, options.supportsImages);
1223
+ const { system, input } = toCodexInput(downgraded, { supportsImages: options.supportsImages });
1144
1224
  const body = {
1145
1225
  model: options.model,
1146
1226
  store: false,
@@ -1360,7 +1440,11 @@ function remapCodexId(id, idMap) {
1360
1440
  idMap.set(id, mapped);
1361
1441
  return mapped;
1362
1442
  }
1363
- function toCodexInput(messages) {
1443
+ function codexToolResultText(content) {
1444
+ if (typeof content === "string") return content;
1445
+ return content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
1446
+ }
1447
+ function toCodexInput(messages, options) {
1364
1448
  let system;
1365
1449
  const input = [];
1366
1450
  const idMap = /* @__PURE__ */ new Map();
@@ -1413,12 +1497,33 @@ function toCodexInput(messages) {
1413
1497
  continue;
1414
1498
  }
1415
1499
  if (msg.role === "tool") {
1500
+ const toolImages = [];
1416
1501
  for (const result of msg.content) {
1417
1502
  const [callId] = result.toolCallId.includes("|") ? result.toolCallId.split("|", 2) : [result.toolCallId];
1503
+ const text = codexToolResultText(result.content);
1418
1504
  input.push({
1419
1505
  type: "function_call_output",
1420
1506
  call_id: remapCodexId(callId, idMap),
1421
- output: result.content
1507
+ output: text.length > 0 ? text : "(see attached image)"
1508
+ });
1509
+ if (options?.supportsImages !== false && Array.isArray(result.content)) {
1510
+ for (const block of result.content) {
1511
+ if (block.type === "image") toolImages.push(block);
1512
+ }
1513
+ }
1514
+ }
1515
+ if (toolImages.length > 0) {
1516
+ input.push({
1517
+ type: "message",
1518
+ role: "user",
1519
+ content: [
1520
+ { type: "input_text", text: "Attached image(s) from tool result:" },
1521
+ ...toolImages.map((img) => ({
1522
+ type: "input_image",
1523
+ detail: "auto",
1524
+ image_url: `data:${img.mediaType};base64,${img.data}`
1525
+ }))
1526
+ ]
1422
1527
  });
1423
1528
  }
1424
1529
  }