Skip to content

Commit 399d7f6

Browse files
committed
fix(agents): forward model maxTokens by default
1 parent 41bbc4c commit 399d7f6

3 files changed

Lines changed: 88 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Docs: https://docs.openclaw.ai
2323

2424
### Fixes
2525

26+
- Agents/models: forward model `maxTokens` as the default output-token limit for OpenAI-compatible Responses and Completions transports when no runtime override is provided, preventing provider defaults from silently truncating larger outputs. (#76645) Thanks @joeyfrasier.
2627
- Gateway/update: run `doctor --non-interactive --fix` after Control UI global package updates before reporting success, so legacy config is migrated before the gateway restart. Thanks @stevenchouai.
2728
- Gateway/cron: stop a lazy cron startup that loses a hot-reload race, preventing the old cron service from starting after reload has already replaced cron state.
2829
- CLI/plugins: warn when npm plugin installs remain shadowed by a failing config-selected source and surface the repair path in `plugins doctor`. Thanks @LindalyX-Lee.

src/agents/openai-transport-stream.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,31 @@ describe("openai transport stream", () => {
995995
expect(params.input?.[0]).toMatchObject({ role: "developer" });
996996
});
997997

998+
it("uses model maxTokens for Responses params when runtime maxTokens is omitted", () => {
999+
const params = buildOpenAIResponsesParams(
1000+
{
1001+
id: "gpt-5.4",
1002+
name: "GPT-5.4",
1003+
api: "openai-responses",
1004+
provider: "openai",
1005+
baseUrl: "https://api.openai.com/v1",
1006+
reasoning: true,
1007+
input: ["text"],
1008+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
1009+
contextWindow: 200000,
1010+
maxTokens: 65_536,
1011+
} satisfies Model<"openai-responses">,
1012+
{
1013+
systemPrompt: "system",
1014+
messages: [],
1015+
tools: [],
1016+
} as never,
1017+
undefined,
1018+
) as { max_output_tokens?: unknown };
1019+
1020+
expect(params.max_output_tokens).toBe(65_536);
1021+
});
1022+
9981023
it("uses top-level instructions for Codex responses and strips unsupported ChatGPT params", () => {
9991024
const params = buildOpenAIResponsesParams(
10001025
{
@@ -2373,6 +2398,57 @@ describe("openai transport stream", () => {
23732398
expect(params).not.toHaveProperty("max_completion_tokens");
23742399
});
23752400

2401+
it("uses model maxTokens for OpenAI completions params when runtime maxTokens is omitted", () => {
2402+
const params = buildOpenAICompletionsParams(
2403+
{
2404+
id: "gpt-5.4",
2405+
name: "GPT-5.4",
2406+
api: "openai-completions",
2407+
provider: "openai",
2408+
baseUrl: "https://api.openai.com/v1",
2409+
reasoning: true,
2410+
input: ["text"],
2411+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
2412+
contextWindow: 200000,
2413+
maxTokens: 65_536,
2414+
} satisfies Model<"openai-completions">,
2415+
{
2416+
systemPrompt: "system",
2417+
messages: [],
2418+
tools: [],
2419+
} as never,
2420+
undefined,
2421+
);
2422+
2423+
expect(params.max_completion_tokens).toBe(65_536);
2424+
expect(params).not.toHaveProperty("max_tokens");
2425+
});
2426+
2427+
it("uses model maxTokens with max_tokens completions compat when runtime maxTokens is omitted", () => {
2428+
const params = buildOpenAICompletionsParams(
2429+
{
2430+
id: "zai-org/GLM-4.7-TEE",
2431+
name: "GLM 4.7 TEE",
2432+
api: "openai-completions",
2433+
provider: "chutes",
2434+
reasoning: true,
2435+
input: ["text"],
2436+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
2437+
contextWindow: 200000,
2438+
maxTokens: 65_536,
2439+
} as never,
2440+
{
2441+
systemPrompt: "system",
2442+
messages: [],
2443+
tools: [],
2444+
} as never,
2445+
undefined,
2446+
);
2447+
2448+
expect(params.max_tokens).toBe(65_536);
2449+
expect(params).not.toHaveProperty("max_completion_tokens");
2450+
});
2451+
23762452
it("omits strict tool shaping for Z.ai default-route completions providers", () => {
23772453
const params = buildOpenAICompletionsParams(
23782454
{

src/agents/openai-transport-stream.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -981,8 +981,9 @@ export function buildOpenAIResponsesParams(
981981
...(isCodexResponses ? { instructions: buildOpenAICodexResponsesInstructions(context) } : {}),
982982
...(metadata ? { metadata } : {}),
983983
};
984-
if (options?.maxTokens) {
985-
params.max_output_tokens = options.maxTokens;
984+
const effectiveMaxTokens = options?.maxTokens || model.maxTokens;
985+
if (effectiveMaxTokens) {
986+
params.max_output_tokens = effectiveMaxTokens;
986987
}
987988
if (options?.temperature !== undefined) {
988989
params.temperature = options.temperature;
@@ -1863,11 +1864,14 @@ export function buildOpenAICompletionsParams(
18631864
if (compat.supportsPromptCacheKey && cacheRetention !== "none" && options?.sessionId) {
18641865
params.prompt_cache_key = options.sessionId;
18651866
}
1866-
if (options?.maxTokens) {
1867-
if (compat.maxTokensField === "max_tokens") {
1868-
params.max_tokens = options.maxTokens;
1869-
} else {
1870-
params.max_completion_tokens = options.maxTokens;
1867+
{
1868+
const effectiveMaxTokens = options?.maxTokens || model.maxTokens;
1869+
if (effectiveMaxTokens) {
1870+
if (compat.maxTokensField === "max_tokens") {
1871+
params.max_tokens = effectiveMaxTokens;
1872+
} else {
1873+
params.max_completion_tokens = effectiveMaxTokens;
1874+
}
18711875
}
18721876
}
18731877
if (options?.temperature !== undefined) {

0 commit comments

Comments
 (0)