fix: stabilize notes and reasoning replay
This commit is contained in:
@@ -27,3 +27,19 @@ index 188a8294f26fe1bfe3fb298a7f58e4d8eaf2a529..a3aeb6a7ff53bc4f7f44362adb950b2c
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
function mapStopReason(status) {
|
function mapStopReason(status) {
|
||||||
|
diff --git a/dist/providers/openai-responses.js b/dist/providers/openai-responses.js
|
||||||
|
index 7b58a79c989abc76bb8fc9e99fb49126e5fd7de4..a1a7f35ad47975dc1268d1a0c2078b0b651e97b4 100644
|
||||||
|
--- a/dist/providers/openai-responses.js
|
||||||
|
+++ b/dist/providers/openai-responses.js
|
||||||
|
@@ -396,9 +396,10 @@ function convertMessages(model, context) {
|
||||||
|
}
|
||||||
|
else if (msg.role === "assistant") {
|
||||||
|
const output = [];
|
||||||
|
+ const hasAssistantText = msg.content.some((block) => block.type === "text");
|
||||||
|
for (const block of msg.content) {
|
||||||
|
// Do not submit thinking blocks if the completion had an error (i.e. abort)
|
||||||
|
- if (block.type === "thinking" && msg.stopReason !== "error") {
|
||||||
|
+ if (block.type === "thinking" && msg.stopReason !== "error" && hasAssistantText) {
|
||||||
|
if (block.thinkingSignature) {
|
||||||
|
const reasoningItem = JSON.parse(block.thinkingSignature);
|
||||||
|
output.push(reasoningItem);
|
||||||
|
|||||||
@@ -639,8 +639,10 @@ describe("doctor", () => {
|
|||||||
([message, title]) =>
|
([message, title]) =>
|
||||||
title === "Sandbox" &&
|
title === "Sandbox" &&
|
||||||
typeof message === "string" &&
|
typeof message === "string" &&
|
||||||
message.includes('agents.list (id "work") sandbox docker') &&
|
message
|
||||||
message.includes('scope resolves to "shared"'),
|
.replace(/\s+/g, " ")
|
||||||
|
.includes('agents.list (id "work") sandbox docker') &&
|
||||||
|
message.replace(/\s+/g, " ").includes('scope resolves to "shared"'),
|
||||||
),
|
),
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import {
|
import { intro as clackIntro, outro as clackOutro } from "@clack/prompts";
|
||||||
intro as clackIntro,
|
|
||||||
outro as clackOutro,
|
|
||||||
} from "@clack/prompts";
|
|
||||||
import {
|
import {
|
||||||
resolveAgentWorkspaceDir,
|
resolveAgentWorkspaceDir,
|
||||||
resolveDefaultAgentId,
|
resolveDefaultAgentId,
|
||||||
@@ -39,8 +36,8 @@ import { runGatewayUpdate } from "../infra/update-runner.js";
|
|||||||
import { runCommandWithTimeout } from "../process/exec.js";
|
import { runCommandWithTimeout } from "../process/exec.js";
|
||||||
import type { RuntimeEnv } from "../runtime.js";
|
import type { RuntimeEnv } from "../runtime.js";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
|
||||||
import { note } from "../terminal/note.js";
|
import { note } from "../terminal/note.js";
|
||||||
|
import { stylePromptTitle } from "../terminal/prompt-style.js";
|
||||||
import { sleep } from "../utils.js";
|
import { sleep } from "../utils.js";
|
||||||
import {
|
import {
|
||||||
DEFAULT_GATEWAY_DAEMON_RUNTIME,
|
DEFAULT_GATEWAY_DAEMON_RUNTIME,
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import { note as clackNote } from "@clack/prompts";
|
import { note as clackNote } from "@clack/prompts";
|
||||||
|
import { visibleWidth } from "./ansi.js";
|
||||||
import { stylePromptTitle } from "./prompt-style.js";
|
import { stylePromptTitle } from "./prompt-style.js";
|
||||||
|
|
||||||
const ANSI_ESCAPE = /\u001b\[[0-9;]*m/g;
|
|
||||||
|
|
||||||
function visibleLength(value: string): number {
|
|
||||||
return Array.from(value.replace(ANSI_ESCAPE, "")).length;
|
|
||||||
}
|
|
||||||
|
|
||||||
function splitLongWord(word: string, maxLen: number): string[] {
|
function splitLongWord(word: string, maxLen: number): string[] {
|
||||||
if (maxLen <= 0) return [word];
|
if (maxLen <= 0) return [word];
|
||||||
const chars = Array.from(word);
|
const chars = Array.from(word);
|
||||||
@@ -25,8 +20,8 @@ function wrapLine(line: string, maxWidth: number): string[] {
|
|||||||
const content = match?.[3] ?? "";
|
const content = match?.[3] ?? "";
|
||||||
const firstPrefix = `${indent}${bullet}`;
|
const firstPrefix = `${indent}${bullet}`;
|
||||||
const nextPrefix = `${indent}${bullet ? " ".repeat(bullet.length) : ""}`;
|
const nextPrefix = `${indent}${bullet ? " ".repeat(bullet.length) : ""}`;
|
||||||
const firstWidth = Math.max(10, maxWidth - visibleLength(firstPrefix));
|
const firstWidth = Math.max(10, maxWidth - visibleWidth(firstPrefix));
|
||||||
const nextWidth = Math.max(10, maxWidth - visibleLength(nextPrefix));
|
const nextWidth = Math.max(10, maxWidth - visibleWidth(nextPrefix));
|
||||||
|
|
||||||
const words = content.split(/\s+/).filter(Boolean);
|
const words = content.split(/\s+/).filter(Boolean);
|
||||||
const lines: string[] = [];
|
const lines: string[] = [];
|
||||||
@@ -36,7 +31,7 @@ function wrapLine(line: string, maxWidth: number): string[] {
|
|||||||
|
|
||||||
for (const word of words) {
|
for (const word of words) {
|
||||||
if (!current) {
|
if (!current) {
|
||||||
if (visibleLength(word) > available) {
|
if (visibleWidth(word) > available) {
|
||||||
const parts = splitLongWord(word, available);
|
const parts = splitLongWord(word, available);
|
||||||
const first = parts.shift() ?? "";
|
const first = parts.shift() ?? "";
|
||||||
lines.push(prefix + first);
|
lines.push(prefix + first);
|
||||||
@@ -50,7 +45,7 @@ function wrapLine(line: string, maxWidth: number): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const candidate = `${current} ${word}`;
|
const candidate = `${current} ${word}`;
|
||||||
if (visibleLength(candidate) <= available) {
|
if (visibleWidth(candidate) <= available) {
|
||||||
current = candidate;
|
current = candidate;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -59,7 +54,7 @@ function wrapLine(line: string, maxWidth: number): string[] {
|
|||||||
prefix = nextPrefix;
|
prefix = nextPrefix;
|
||||||
available = nextWidth;
|
available = nextWidth;
|
||||||
|
|
||||||
if (visibleLength(word) > available) {
|
if (visibleWidth(word) > available) {
|
||||||
const parts = splitLongWord(word, available);
|
const parts = splitLongWord(word, available);
|
||||||
const first = parts.shift() ?? "";
|
const first = parts.shift() ?? "";
|
||||||
lines.push(prefix + first);
|
lines.push(prefix + first);
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import {
|
|||||||
text,
|
text,
|
||||||
} from "@clack/prompts";
|
} from "@clack/prompts";
|
||||||
import { createCliProgress } from "../cli/progress.js";
|
import { createCliProgress } from "../cli/progress.js";
|
||||||
|
import { note as emitNote } from "../terminal/note.js";
|
||||||
import {
|
import {
|
||||||
stylePromptHint,
|
stylePromptHint,
|
||||||
stylePromptMessage,
|
stylePromptMessage,
|
||||||
stylePromptTitle,
|
stylePromptTitle,
|
||||||
} from "../terminal/prompt-style.js";
|
} from "../terminal/prompt-style.js";
|
||||||
import { theme } from "../terminal/theme.js";
|
import { theme } from "../terminal/theme.js";
|
||||||
import { note as emitNote } from "../terminal/note.js";
|
|
||||||
import type { WizardProgress, WizardPrompter } from "./prompts.js";
|
import type { WizardProgress, WizardPrompter } from "./prompts.js";
|
||||||
import { WizardCancelledError } from "./prompts.js";
|
import { WizardCancelledError } from "./prompts.js";
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user