mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
agents: address execution correctness review fixes
This commit is contained in:
@@ -1503,6 +1503,21 @@ export async function runEmbeddedPiAgent(
|
||||
"Please try again, or increase `agents.defaults.llm.idleTimeoutSeconds` in your config (set to 0 to disable)."
|
||||
: "Request timed out before a response was generated. " +
|
||||
"Please try again, or increase `agents.defaults.timeoutSeconds` in your config.";
|
||||
const replayInvalid = resolveReplayInvalidFlag({
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
});
|
||||
const livenessState = resolveRunLivenessState({
|
||||
payloadCount: payloads.length,
|
||||
aborted,
|
||||
timedOut,
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
});
|
||||
attempt.setTerminalLifecycleMeta?.({
|
||||
replayInvalid,
|
||||
livenessState,
|
||||
});
|
||||
return {
|
||||
payloads: [
|
||||
{
|
||||
@@ -1516,17 +1531,8 @@ export async function runEmbeddedPiAgent(
|
||||
aborted,
|
||||
systemPromptReport: attempt.systemPromptReport,
|
||||
finalAssistantVisibleText,
|
||||
replayInvalid: resolveReplayInvalidFlag({
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
}),
|
||||
livenessState: resolveRunLivenessState({
|
||||
payloadCount: payloads.length,
|
||||
aborted,
|
||||
timedOut,
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
}),
|
||||
replayInvalid,
|
||||
livenessState,
|
||||
},
|
||||
didSendViaMessagingTool: attempt.didSendViaMessagingTool,
|
||||
didSendDeterministicApprovalPrompt: attempt.didSendDeterministicApprovalPrompt,
|
||||
@@ -1619,6 +1625,21 @@ export async function runEmbeddedPiAgent(
|
||||
};
|
||||
}
|
||||
if (incompleteTurnText) {
|
||||
const replayInvalid = resolveReplayInvalidFlag({
|
||||
attempt,
|
||||
incompleteTurnText,
|
||||
});
|
||||
const livenessState = resolveRunLivenessState({
|
||||
payloadCount: payloads.length,
|
||||
aborted,
|
||||
timedOut,
|
||||
attempt,
|
||||
incompleteTurnText,
|
||||
});
|
||||
attempt.setTerminalLifecycleMeta?.({
|
||||
replayInvalid,
|
||||
livenessState,
|
||||
});
|
||||
const incompleteStopReason = attempt.lastAssistant?.stopReason;
|
||||
log.warn(
|
||||
`incomplete turn detected: runId=${params.runId} sessionId=${params.sessionId} ` +
|
||||
@@ -1647,17 +1668,8 @@ export async function runEmbeddedPiAgent(
|
||||
aborted,
|
||||
systemPromptReport: attempt.systemPromptReport,
|
||||
finalAssistantVisibleText,
|
||||
replayInvalid: resolveReplayInvalidFlag({
|
||||
attempt,
|
||||
incompleteTurnText,
|
||||
}),
|
||||
livenessState: resolveRunLivenessState({
|
||||
payloadCount: payloads.length,
|
||||
aborted,
|
||||
timedOut,
|
||||
attempt,
|
||||
incompleteTurnText,
|
||||
}),
|
||||
replayInvalid,
|
||||
livenessState,
|
||||
},
|
||||
didSendViaMessagingTool: attempt.didSendViaMessagingTool,
|
||||
didSendDeterministicApprovalPrompt: attempt.didSendDeterministicApprovalPrompt,
|
||||
@@ -1684,6 +1696,21 @@ export async function runEmbeddedPiAgent(
|
||||
agentDir: params.agentDir,
|
||||
});
|
||||
}
|
||||
const replayInvalid = resolveReplayInvalidFlag({
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
});
|
||||
const livenessState = resolveRunLivenessState({
|
||||
payloadCount: payloads.length,
|
||||
aborted,
|
||||
timedOut,
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
});
|
||||
attempt.setTerminalLifecycleMeta?.({
|
||||
replayInvalid,
|
||||
livenessState,
|
||||
});
|
||||
return {
|
||||
payloads: payloadsWithToolMedia?.length ? payloadsWithToolMedia : undefined,
|
||||
meta: {
|
||||
@@ -1692,17 +1719,8 @@ export async function runEmbeddedPiAgent(
|
||||
aborted,
|
||||
systemPromptReport: attempt.systemPromptReport,
|
||||
finalAssistantVisibleText,
|
||||
replayInvalid: resolveReplayInvalidFlag({
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
}),
|
||||
livenessState: resolveRunLivenessState({
|
||||
payloadCount: payloads.length,
|
||||
aborted,
|
||||
timedOut,
|
||||
attempt,
|
||||
incompleteTurnText: null,
|
||||
}),
|
||||
replayInvalid,
|
||||
livenessState,
|
||||
// Handle client tool calls (OpenResponses hosted tools)
|
||||
// Propagate the LLM stop reason so callers (lifecycle events,
|
||||
// ACP bridge) can distinguish end_turn from max_tokens.
|
||||
|
||||
@@ -1447,6 +1447,7 @@ export async function runEmbeddedAttempt(
|
||||
getSuccessfulCronAdds,
|
||||
didSendViaMessagingTool,
|
||||
getLastToolError,
|
||||
setTerminalLifecycleMeta,
|
||||
getUsageTotals,
|
||||
getCompactionCount,
|
||||
} = subscription;
|
||||
@@ -2277,6 +2278,7 @@ export async function runEmbeddedAttempt(
|
||||
successfulCronAdds: getSuccessfulCronAdds(),
|
||||
}),
|
||||
itemLifecycle: getItemLifecycle(),
|
||||
setTerminalLifecycleMeta,
|
||||
aborted,
|
||||
timedOut,
|
||||
idleTimedOut,
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { PluginHookBeforeAgentStartResult } from "../../../plugins/types.js
|
||||
import type { MessagingToolSend } from "../../pi-embedded-messaging.js";
|
||||
import type { ToolErrorSummary } from "../../tool-error-summary.js";
|
||||
import type { NormalizedUsage } from "../../usage.js";
|
||||
import type { EmbeddedRunLivenessState } from "../types.js";
|
||||
import type { RunEmbeddedPiAgentParams } from "./params.js";
|
||||
import type { PreemptiveCompactionRoute } from "./preemptive-compaction.js";
|
||||
|
||||
@@ -98,4 +99,8 @@ export type EmbeddedRunAttemptResult = {
|
||||
completedCount: number;
|
||||
activeCount: number;
|
||||
};
|
||||
setTerminalLifecycleMeta?: (meta: {
|
||||
replayInvalid?: boolean;
|
||||
livenessState?: EmbeddedRunLivenessState;
|
||||
}) => void;
|
||||
};
|
||||
|
||||
@@ -68,7 +68,9 @@ export function handleAutoCompactionEnd(
|
||||
ctx.resetForCompactionRetry();
|
||||
ctx.log.debug(`embedded run compaction retry: runId=${ctx.params.runId}`);
|
||||
} else {
|
||||
ctx.state.livenessState = "working";
|
||||
if (!wasAborted) {
|
||||
ctx.state.livenessState = "working";
|
||||
}
|
||||
ctx.maybeResolveCompactionWait();
|
||||
clearStaleAssistantUsageOnSessionMessages(ctx);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
normalizeTextForComparison,
|
||||
} from "./pi-embedded-helpers.js";
|
||||
import type { BlockReplyPayload } from "./pi-embedded-payloads.js";
|
||||
import type { EmbeddedRunLivenessState } from "./pi-embedded-runner/types.js";
|
||||
import { createEmbeddedPiSessionEventHandler } from "./pi-embedded-subscribe.handlers.js";
|
||||
import { consumePendingToolMediaIntoReply } from "./pi-embedded-subscribe.handlers.messages.js";
|
||||
import type {
|
||||
@@ -776,6 +777,17 @@ export function subscribeEmbeddedPiSession(params: SubscribeEmbeddedPiSessionPar
|
||||
assistantTexts,
|
||||
toolMetas,
|
||||
unsubscribe,
|
||||
setTerminalLifecycleMeta: (meta: {
|
||||
replayInvalid?: boolean;
|
||||
livenessState?: EmbeddedRunLivenessState;
|
||||
}) => {
|
||||
if (typeof meta.replayInvalid === "boolean") {
|
||||
state.replayInvalid = meta.replayInvalid;
|
||||
}
|
||||
if (meta.livenessState) {
|
||||
state.livenessState = meta.livenessState;
|
||||
}
|
||||
},
|
||||
isCompacting: () => state.compactionInFlight || state.pendingCompactionRetry > 0,
|
||||
isCompactionInFlight: () => state.compactionInFlight,
|
||||
getMessagingToolSentTexts: () => messagingToolSentTexts.slice(),
|
||||
|
||||
@@ -166,7 +166,13 @@ export function normalizeOpenAIToolSchemas(
|
||||
return ctx.tools;
|
||||
}
|
||||
return ctx.tools.map((tool) => {
|
||||
if (!tool.parameters || typeof tool.parameters !== "object") {
|
||||
if (tool.parameters == null) {
|
||||
return {
|
||||
...tool,
|
||||
parameters: normalizeOpenAIStrictCompatSchema({}),
|
||||
};
|
||||
}
|
||||
if (typeof tool.parameters !== "object") {
|
||||
return tool;
|
||||
}
|
||||
return {
|
||||
@@ -292,13 +298,23 @@ function normalizeOpenAIStrictCompatSchemaRecursive(schema: unknown): unknown {
|
||||
return changed ? normalized : schema;
|
||||
}
|
||||
|
||||
export function findOpenAIStrictSchemaViolations(schema: unknown, path: string): string[] {
|
||||
export function findOpenAIStrictSchemaViolations(
|
||||
schema: unknown,
|
||||
path: string,
|
||||
options?: { requireObjectRoot?: boolean },
|
||||
): string[] {
|
||||
if (Array.isArray(schema)) {
|
||||
if (options?.requireObjectRoot) {
|
||||
return [`${path}.type`];
|
||||
}
|
||||
return schema.flatMap((item, index) =>
|
||||
findOpenAIStrictSchemaViolations(item, `${path}[${index}]`),
|
||||
);
|
||||
}
|
||||
if (!schema || typeof schema !== "object") {
|
||||
if (options?.requireObjectRoot) {
|
||||
return [`${path}.type`];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -363,8 +379,9 @@ export function inspectOpenAIToolSchemas(
|
||||
}
|
||||
return ctx.tools.flatMap((tool, toolIndex) => {
|
||||
const violations = findOpenAIStrictSchemaViolations(
|
||||
normalizeOpenAIStrictCompatSchema(tool.parameters),
|
||||
normalizeOpenAIStrictCompatSchema(tool.parameters ?? {}),
|
||||
`${tool.name}.parameters`,
|
||||
{ requireObjectRoot: true },
|
||||
);
|
||||
if (violations.length === 0) {
|
||||
return [];
|
||||
|
||||
@@ -63,6 +63,7 @@ const EXPECTED_SHARED_FAMILY_CONTRACTS: Record<string, ExpectedSharedFamilyContr
|
||||
},
|
||||
openai: {
|
||||
streamFamilies: ["openai-responses-defaults"],
|
||||
toolCompatFamilies: ["openai"],
|
||||
},
|
||||
opencode: {
|
||||
replayFamilies: ["passthrough-gemini"],
|
||||
|
||||
Reference in New Issue
Block a user