mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 12:30:44 +00:00
fix: honor explicit strict-agentic retry contract
Honor explicit strict-agentic execution contracts for incomplete-turn retry guards across providers, including local/compatible models that opt in without relying on OpenAI model inference. Validation: - pnpm test src/agents/pi-embedded-runner/run.incomplete-turn.test.ts - pnpm check:changed - GitHub CI + parity gate green Thanks @ziomancer.
This commit is contained in:
@@ -87,6 +87,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Security/dotenv: block workspace `.env` overrides for Matrix, Mattermost, IRC, and Synology endpoint settings so cloned workspaces cannot redirect bundled connector traffic through local endpoint config. (#70240) Thanks @drobison00.
|
||||
- Telegram: require the same `/models` authorization for group model-picker callbacks, so unauthorized participants can no longer browse or change the session model through inline buttons. (#70235) Thanks @drobison00.
|
||||
- Agents/Pi: keep the filtered tool-name allowlist active for embedded OpenAI/OpenAI Codex GPT-5 runs and compaction sessions, so bundled and client tools still execute after the Pi `0.68.1` session-tool allowlist change instead of stopping at plan-only replies with no tool call. (#70281) Thanks @jalehman.
|
||||
- Agents/Pi: honor explicit `strict-agentic` execution contracts for incomplete-turn retry guards across providers, so manually opted-in local or compatible models get the same retry behavior without relying on OpenAI model inference. (#66750) Thanks @ziomancer.
|
||||
|
||||
## 2026.4.21
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ describe("runEmbeddedPiAgent incomplete-turn safety", () => {
|
||||
expect(result.payloads?.[0]?.text).toContain("Please try again");
|
||||
});
|
||||
|
||||
it("does not retry reasoning-only turns for non-openai assistant metadata", async () => {
|
||||
it("does not retry reasoning-only turns for non-strict-agentic providers", async () => {
|
||||
mockedClassifyFailoverReason.mockReturnValue(null);
|
||||
mockedRunEmbeddedAttempt.mockResolvedValueOnce(
|
||||
makeAttemptResult({
|
||||
@@ -386,8 +386,8 @@ describe("runEmbeddedPiAgent incomplete-turn safety", () => {
|
||||
|
||||
const result = await runEmbeddedPiAgent({
|
||||
...overflowBaseRunParams,
|
||||
provider: "openai",
|
||||
model: "gpt-5.4",
|
||||
provider: "anthropic",
|
||||
model: "sonnet-4.6",
|
||||
runId: "run-reasoning-only-provider-mismatch",
|
||||
});
|
||||
|
||||
|
||||
@@ -1709,6 +1709,7 @@ export async function runEmbeddedPiAgent(
|
||||
const nextPlanningOnlyRetryInstruction = resolvePlanningOnlyRetryInstruction({
|
||||
provider,
|
||||
modelId,
|
||||
executionContract,
|
||||
prompt: params.prompt,
|
||||
aborted,
|
||||
timedOut,
|
||||
@@ -1717,6 +1718,7 @@ export async function runEmbeddedPiAgent(
|
||||
const nextReasoningOnlyRetryInstruction = resolveReasoningOnlyRetryInstruction({
|
||||
provider: activeErrorContext.provider,
|
||||
modelId: activeErrorContext.model,
|
||||
executionContract,
|
||||
aborted,
|
||||
timedOut,
|
||||
attempt,
|
||||
@@ -1724,6 +1726,7 @@ export async function runEmbeddedPiAgent(
|
||||
const nextEmptyResponseRetryInstruction = resolveEmptyResponseRetryInstruction({
|
||||
provider: activeErrorContext.provider,
|
||||
modelId: activeErrorContext.model,
|
||||
executionContract,
|
||||
payloadCount,
|
||||
aborted,
|
||||
timedOut,
|
||||
|
||||
@@ -307,6 +307,7 @@ function shouldSkipPlanningOnlyRetry(params: {
|
||||
export function resolveReasoningOnlyRetryInstruction(params: {
|
||||
provider?: string;
|
||||
modelId?: string;
|
||||
executionContract?: string;
|
||||
aborted: boolean;
|
||||
timedOut: boolean;
|
||||
attempt: IncompleteTurnAttempt;
|
||||
@@ -319,6 +320,7 @@ export function resolveReasoningOnlyRetryInstruction(params: {
|
||||
!shouldApplyPlanningOnlyRetryGuard({
|
||||
provider: params.provider,
|
||||
modelId: params.modelId,
|
||||
executionContract: params.executionContract,
|
||||
})
|
||||
) {
|
||||
return null;
|
||||
@@ -341,6 +343,7 @@ export function resolveReasoningOnlyRetryInstruction(params: {
|
||||
export function resolveEmptyResponseRetryInstruction(params: {
|
||||
provider?: string;
|
||||
modelId?: string;
|
||||
executionContract?: string;
|
||||
payloadCount: number;
|
||||
aborted: boolean;
|
||||
timedOut: boolean;
|
||||
@@ -354,6 +357,7 @@ export function resolveEmptyResponseRetryInstruction(params: {
|
||||
!shouldApplyPlanningOnlyRetryGuard({
|
||||
provider: params.provider,
|
||||
modelId: params.modelId,
|
||||
executionContract: params.executionContract,
|
||||
})
|
||||
) {
|
||||
return null;
|
||||
@@ -374,7 +378,11 @@ export function resolveEmptyResponseRetryInstruction(params: {
|
||||
function shouldApplyPlanningOnlyRetryGuard(params: {
|
||||
provider?: string;
|
||||
modelId?: string;
|
||||
executionContract?: string;
|
||||
}): boolean {
|
||||
if (params.executionContract === "strict-agentic") {
|
||||
return true;
|
||||
}
|
||||
return isStrictAgenticSupportedProviderModel({
|
||||
provider: params.provider,
|
||||
modelId: params.modelId,
|
||||
@@ -531,6 +539,7 @@ export function resolvePlanningOnlyRetryLimit(
|
||||
export function resolvePlanningOnlyRetryInstruction(params: {
|
||||
provider?: string;
|
||||
modelId?: string;
|
||||
executionContract?: string;
|
||||
prompt?: string;
|
||||
aborted: boolean;
|
||||
timedOut: boolean;
|
||||
@@ -547,6 +556,7 @@ export function resolvePlanningOnlyRetryInstruction(params: {
|
||||
!shouldApplyPlanningOnlyRetryGuard({
|
||||
provider: params.provider,
|
||||
modelId: params.modelId,
|
||||
executionContract: params.executionContract,
|
||||
}) ||
|
||||
(typeof params.prompt === "string" && !isLikelyActionableUserPrompt(params.prompt)) ||
|
||||
params.aborted ||
|
||||
|
||||
Reference in New Issue
Block a user