Skip to content

Commit ae2c0cd

Browse files
committed
fix(sdk): require timeout attribution for provider errors
1 parent 2f4080f commit ae2c0cd

3 files changed

Lines changed: 44 additions & 4 deletions

File tree

packages/sdk/src/client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ function runStatusFromWaitPayload(payload: unknown): RunResult["status"] {
6161
const pendingError = record.pendingError === true;
6262
const timeoutPhase =
6363
typeof record.timeoutPhase === "string" ? record.timeoutPhase.toLowerCase() : undefined;
64-
const statusAlreadyTimeoutAttributed = status === "timeout" || status === "error";
64+
const statusAlreadyTimeoutAttributed = status === "timeout" || status === "timed_out";
6565
const hardTimeout =
6666
!pendingError &&
6767
((record.providerStarted === true && statusAlreadyTimeoutAttributed) ||

packages/sdk/src/index.test.ts

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,24 @@ describe("OpenClaw SDK", () => {
182182
expect(result.error?.message).toBe("provider request timed out");
183183
});
184184

185+
it("does not map provider-started wait errors to timed_out without timeout attribution", async () => {
186+
const transport = new FakeTransport({
187+
"agent.wait": {
188+
status: "error",
189+
runId: "run_provider_error",
190+
providerStarted: true,
191+
error: "provider authentication failed",
192+
},
193+
});
194+
const oc = new OpenClaw({ transport });
195+
196+
const result = await oc.runs.wait("run_provider_error");
197+
198+
expect(result.runId).toBe("run_provider_error");
199+
expect(result.status).toBe("failed");
200+
expect(result.error?.message).toBe("provider authentication failed");
201+
});
202+
185203
it("does not treat successful provider-started wait snapshots as timed_out", async () => {
186204
const transport = new FakeTransport({
187205
"agent.wait": {
@@ -1150,9 +1168,31 @@ describe("OpenClaw SDK", () => {
11501168
providerStarted: true,
11511169
});
11521170

1153-
const hardTimeoutEnd = normalizeGatewayEvent({
1171+
const providerStartedError = normalizeGatewayEvent({
11541172
event: "agent",
11551173
seq: 8,
1174+
payload: {
1175+
runId: "run_1",
1176+
stream: "lifecycle",
1177+
ts,
1178+
data: {
1179+
phase: "error",
1180+
error: "provider authentication failed",
1181+
providerStarted: true,
1182+
},
1183+
},
1184+
});
1185+
expect(providerStartedError.type).toBe("run.failed");
1186+
expect(providerStartedError.runId).toBe("run_1");
1187+
expect(providerStartedError.data).toEqual({
1188+
phase: "error",
1189+
error: "provider authentication failed",
1190+
providerStarted: true,
1191+
});
1192+
1193+
const hardTimeoutEnd = normalizeGatewayEvent({
1194+
event: "agent",
1195+
seq: 9,
11561196
payload: {
11571197
runId: "run_1",
11581198
stream: "lifecycle",
@@ -1174,7 +1214,7 @@ describe("OpenClaw SDK", () => {
11741214

11751215
const providerStartedEnd = normalizeGatewayEvent({
11761216
event: "agent",
1177-
seq: 9,
1217+
seq: 10,
11781218
payload: {
11791219
runId: "run_1",
11801220
stream: "lifecycle",

packages/sdk/src/normalize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function normalizeAgentEventType(payload: JsonObject): OpenClawEventType {
8686
return normalizeLifecycleEndEventType(data);
8787
}
8888
if (phase === "error") {
89-
if (hasHardTimeoutMetadata(data, true)) {
89+
if (hasHardTimeoutMetadata(data, false)) {
9090
return "run.timed_out";
9191
}
9292
return "run.failed";

0 commit comments

Comments
 (0)