@opencow-ai/opencow-agent-sdk 0.4.3 → 0.4.5
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/cli.mjs +340 -156
- package/dist/client.js +315 -131
- package/dist/lib/schemaSanitizer.d.ts +27 -6
- package/dist/lib/toolInputNullCoercion.d.ts +7 -4
- package/dist/providers/openai/capabilities.d.ts +8 -0
- package/dist/providers/openai/shim.d.ts +9 -2
- package/dist/sdk.js +315 -131
- package/package.json +1 -1
|
@@ -6,13 +6,34 @@
|
|
|
6
6
|
* issue #77:gpt 用 read 工具频繁出错)。让字段可空后,模型可以用 `null` 明确表达
|
|
7
7
|
* 「未提供」,再由入参解析层把 `null` 还原为缺省。
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* -
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
9
|
+
* 可空的两种写法没有「最大公约数」,必须按目标 provider 选择:
|
|
10
|
+
* - `'union'`(默认):`type: [T, "null"]`。OpenAI / Codex 的 **strict 结构化输出
|
|
11
|
+
* 只接受这种**(`nullable` 是 OpenAPI 扩展,不在其 JSON-Schema 子集里,会被
|
|
12
|
+
* strict 校验拒绝 400);DeepSeek / Kimi / Qwen 同样接受。
|
|
13
|
+
* - `'nullable'`:`nullable: true`。Gemini / Vertex 只接受这种,拒绝 type 数组。
|
|
14
|
+
*
|
|
15
|
+
* 注意 OpenAI chat(非 strict)会忽略 `nullable`,从而丢掉「可传 null」的提示,
|
|
16
|
+
* 退回 issue #77 的形态——所以对 OpenAI 路径必须用 `'union'`。Gemini 路径由调用方
|
|
17
|
+
* (normalizeSchemaForOpenAI)传 `'nullable'`,或经 splitTypeArrayToAnyOf 转换。
|
|
18
|
+
*
|
|
19
|
+
* 带 `enum`/`const` 的字段保持不动(避免自相矛盾);
|
|
20
|
+
* 无明确 `type` 的字段也保持不动(零回归)。
|
|
21
|
+
*/
|
|
22
|
+
export declare function makeSchemaNullable(schema: Record<string, unknown>, style?: 'union' | 'nullable'): Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* 把 type 数组改写为 **Gemini/Vertex** 能接受的形式——仅在目标是 Gemini 时调用
|
|
25
|
+
* (见 normalizeSchemaForOpenAI 的 geminiTarget 门控)。OpenAI/DeepSeek/Kimi 等接受
|
|
26
|
+
* type 数组、且对 OpenAI 而言 `nullable` 会被忽略,故对它们不应调用本函数。
|
|
27
|
+
*
|
|
28
|
+
* Gemini 侧约束:拒绝 type 数组,拒绝 anyOf + null,只接受 nullable: true。
|
|
29
|
+
*
|
|
30
|
+
* 转换策略:
|
|
31
|
+
* - `type: ["T", "null"]` → `{ type: "T", nullable: true, ...结构性关键字 }`
|
|
32
|
+
* - `type: ["T1", "T2", ...]`(>1 种非 null 类型)→ 拆为 anyOf,null 以 nullable 表达
|
|
33
|
+
*
|
|
34
|
+
* 不递归——由调用方(normalizeSchemaForOpenAI)的递归遍历负责嵌套层级。
|
|
14
35
|
*/
|
|
15
|
-
export declare function
|
|
36
|
+
export declare function splitTypeArrayToAnyOf(schema: Record<string, unknown>): Record<string, unknown>;
|
|
16
37
|
/**
|
|
17
38
|
* Sanitize JSON Schema into a shape OpenAI-compatible providers and Codex
|
|
18
39
|
* strict-mode tooling are more likely to accept. This strips provider-rejected
|
|
@@ -3,18 +3,21 @@ import type { z } from 'zod/v4';
|
|
|
3
3
|
* 解析工具入参,并对 strict provider 把可选字段强制为 nullable 后模型回传的 `null`
|
|
4
4
|
* 做兜底还原。
|
|
5
5
|
*
|
|
6
|
-
* 背景:OpenAI/Codex strict 模式要求每个属性都出现在 `required`,可选字段会被
|
|
6
|
+
* 背景:OpenAI/Codex/DeepSeek 等 strict 模式要求每个属性都出现在 `required`,可选字段会被
|
|
7
7
|
* `makeSchemaNullable` 标成可空(见 lib/schemaSanitizer.ts),模型遂用 `null` 表达
|
|
8
8
|
* 「未提供」。但工具的 Zod inputSchema 多用 `.optional()`(不接受 `null`),若直接
|
|
9
9
|
* `safeParse` 会得到 InputValidationError —— 这正是「① 让 wire schema 可空」必须搭配的
|
|
10
10
|
* 入参侧兜底(issue #79/#77)。
|
|
11
11
|
*
|
|
12
|
-
* 策略:先按原始 schema 解析;仅当「解析失败 且
|
|
13
|
-
*
|
|
12
|
+
* 策略:先按原始 schema 解析;仅当「解析失败 且 入参任意层级含 null」时,递归去掉这些
|
|
13
|
+
* null 属性再解析一次,且只有重试成功才采用重试结果。由此:
|
|
14
14
|
* - 真正接受 null 的 `.nullable()` 字段:原始即可解析 → 不触发重试 → `null` 保留;
|
|
15
15
|
* - 与 null 无关的真实校验错误:去 null 后仍失败 → 返回原始错误,不掩盖;
|
|
16
16
|
* - 可选非空字段被强制塞入的 `null`:去掉后变缺省,`.optional()` 通过。
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* 递归处理嵌套对象与数组元素——`human_form_input` 这类工具的可选字段藏在
|
|
19
|
+
* `variables[].min_value` 等数组元素内部,模型对不适用的字段(如文本框的数值范围)
|
|
20
|
+
* 习惯性回传 `null`,只剥顶层会漏掉它们、导致整个阻塞工具因校验失败被跳过(handler
|
|
21
|
+
* 不执行、不阻塞,对话直接溜到下一轮)。
|
|
19
22
|
*/
|
|
20
23
|
export declare function safeParseToolInputWithNullCoercion<T extends z.ZodType>(schema: T, input: unknown): ReturnType<T['safeParse']>;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { ModelOutputTokenCap, ProviderFeature } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* 判断最终目标是否为 Gemini/Vertex 系列。
|
|
4
|
+
*
|
|
5
|
+
* 这是 Gemini 专属适配(关闭并行工具调用、schema 用 nullable:true 而非 type 数组)的
|
|
6
|
+
* 统一判定入口。后端纯透传时 SDK 侧 family 恒为 openai,无法据此识别最终 provider,
|
|
7
|
+
* 因此依据 CLAUDE_CODE_USE_GEMINI 环境标志 + model 名两路信号判断。
|
|
8
|
+
*/
|
|
9
|
+
export declare function isGeminiTarget(model: string): boolean;
|
|
2
10
|
export declare function getOpenAICompatMaxOutputTokens(model: string): ModelOutputTokenCap | null;
|
|
3
11
|
export declare function getOpenAICompatContextWindow(model: string): number | null;
|
|
4
12
|
export declare function openAICompatSupports(feature: ProviderFeature, model: string): boolean;
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
import { type AnthropicStreamEvent, type ShimCreateParams } from '../../providers/codex/shim.js';
|
|
24
24
|
interface OpenAIMessage {
|
|
25
25
|
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
26
|
-
content?: string | Array<{
|
|
26
|
+
content?: string | null | Array<{
|
|
27
27
|
type: string;
|
|
28
28
|
text?: string;
|
|
29
29
|
image_url?: {
|
|
@@ -65,7 +65,7 @@ export declare function convertTools(tools: Array<{
|
|
|
65
65
|
name: string;
|
|
66
66
|
description?: string;
|
|
67
67
|
input_schema?: Record<string, unknown>;
|
|
68
|
-
}
|
|
68
|
+
}>, model?: string): OpenAITool[];
|
|
69
69
|
export declare function makeMessageId(): string;
|
|
70
70
|
/**
|
|
71
71
|
* Async generator that transforms an OpenAI SSE stream into
|
|
@@ -146,6 +146,13 @@ export declare function convertOpenAIResponseToAnthropic(data: {
|
|
|
146
146
|
};
|
|
147
147
|
extra_content?: Record<string, unknown>;
|
|
148
148
|
}>;
|
|
149
|
+
reasoning_content?: string | null;
|
|
150
|
+
reasoning?: string | null;
|
|
151
|
+
reasoning_details?: Array<{
|
|
152
|
+
type?: string;
|
|
153
|
+
content?: string;
|
|
154
|
+
summary?: string;
|
|
155
|
+
}> | null;
|
|
149
156
|
};
|
|
150
157
|
finish_reason?: string;
|
|
151
158
|
}>;
|