mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
refactor: canonicalize binary operation results (#106049)
* refactor(normalization-core): promote shared result type * refactor(agent-core): reuse canonical error coercion * refactor: discriminate internal operation results * docs: establish shared result convention * fix(agent-core): preserve error coercion facade * build: derive package entries from exports * fix(plugins): resolve shared result subpath * fix(ci): align Result integration guards * build: refresh plugin SDK API baseline * fix(agent-core): preserve toError compatibility
This commit is contained in:
committed by
GitHub
parent
2fc91410e8
commit
6df498c3cd
@@ -1,4 +1,5 @@
|
||||
// Agent Core module implements agent harness behavior.
|
||||
import { toErrorObject } from "@openclaw/normalization-core/error-coercion";
|
||||
import type {
|
||||
AssistantMessage,
|
||||
ImageContent,
|
||||
@@ -52,13 +53,7 @@ import type {
|
||||
Session,
|
||||
Skill,
|
||||
} from "./types.js";
|
||||
import {
|
||||
AgentHarnessError,
|
||||
BranchSummaryError,
|
||||
CompactionError,
|
||||
SessionError,
|
||||
toError,
|
||||
} from "./types.js";
|
||||
import { AgentHarnessError, BranchSummaryError, CompactionError, SessionError } from "./types.js";
|
||||
|
||||
// CoreAgentHarness coordinates session state, resources, tools, compaction, and
|
||||
// streaming callbacks around the lower-level agent loop.
|
||||
@@ -164,7 +159,7 @@ function normalizeHarnessError(
|
||||
if (error instanceof AgentHarnessError) {
|
||||
return error;
|
||||
}
|
||||
const cause = toError(error);
|
||||
const cause = toErrorObject(error, "Non-Error thrown");
|
||||
if (cause instanceof SessionError) {
|
||||
return new AgentHarnessError("session", cause.message, cause);
|
||||
}
|
||||
@@ -672,7 +667,7 @@ export class CoreAgentHarness<
|
||||
);
|
||||
} catch (failureError) {
|
||||
const cause = new AggregateError(
|
||||
[toError(error), toError(failureError)],
|
||||
[error, failureError].map((value) => toErrorObject(value, "Non-Error thrown")),
|
||||
"Agent run failed and failure reporting failed",
|
||||
);
|
||||
throw new AgentHarnessError("unknown", cause.message, cause);
|
||||
@@ -1130,17 +1125,17 @@ export class CoreAgentHarness<
|
||||
try {
|
||||
await this.emitQueueUpdate();
|
||||
} catch (error) {
|
||||
errors.push(toError(error));
|
||||
errors.push(toErrorObject(error, "Non-Error thrown"));
|
||||
}
|
||||
try {
|
||||
await this.waitForIdle();
|
||||
} catch (error) {
|
||||
errors.push(toError(error));
|
||||
errors.push(toErrorObject(error, "Non-Error thrown"));
|
||||
}
|
||||
try {
|
||||
await this.emitOwn({ type: "abort", clearedSteer, clearedFollowUp });
|
||||
} catch (error) {
|
||||
errors.push(toError(error));
|
||||
errors.push(toErrorObject(error, "Non-Error thrown"));
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
const cause =
|
||||
|
||||
+5
-5
@@ -17,6 +17,7 @@ import {
|
||||
import { tmpdir } from "node:os";
|
||||
import { basename, isAbsolute, join, resolve } from "node:path";
|
||||
import { createInterface } from "node:readline";
|
||||
import { toErrorObject } from "@openclaw/normalization-core/error-coercion";
|
||||
import {
|
||||
type ExecutionEnv,
|
||||
ExecutionError,
|
||||
@@ -26,7 +27,6 @@ import {
|
||||
type FileKind,
|
||||
ok,
|
||||
type Result,
|
||||
toError,
|
||||
} from "../types.js";
|
||||
import { killProcessTree } from "./kill-tree.js";
|
||||
|
||||
@@ -100,7 +100,7 @@ function toFileError(error: unknown, path?: string): FileError {
|
||||
if (error instanceof FileError) {
|
||||
return error;
|
||||
}
|
||||
const cause = toError(error);
|
||||
const cause = toErrorObject(error, "Non-Error thrown");
|
||||
if (isNodeError(error)) {
|
||||
const message = error.message;
|
||||
switch (error.code) {
|
||||
@@ -342,7 +342,7 @@ export class NodeExecutionEnv implements ExecutionEnv {
|
||||
windowsHide: true,
|
||||
});
|
||||
} catch (error) {
|
||||
const cause = toError(error);
|
||||
const cause = toErrorObject(error, "Non-Error thrown");
|
||||
settle(err(new ExecutionError("spawn_error", cause.message, cause)));
|
||||
return;
|
||||
}
|
||||
@@ -373,7 +373,7 @@ export class NodeExecutionEnv implements ExecutionEnv {
|
||||
try {
|
||||
options?.onStdout?.(chunk);
|
||||
} catch (error) {
|
||||
const cause = toError(error);
|
||||
const cause = toErrorObject(error, "Non-Error thrown");
|
||||
callbackError = new ExecutionError("callback_error", cause.message, cause);
|
||||
onAbort();
|
||||
}
|
||||
@@ -383,7 +383,7 @@ export class NodeExecutionEnv implements ExecutionEnv {
|
||||
try {
|
||||
options?.onStderr?.(chunk);
|
||||
} catch (error) {
|
||||
const cause = toError(error);
|
||||
const cause = toErrorObject(error, "Non-Error thrown");
|
||||
callbackError = new ExecutionError("callback_error", cause.message, cause);
|
||||
onAbort();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Agent Core module implements jsonl storage behavior.
|
||||
import { toErrorObject } from "@openclaw/normalization-core/error-coercion";
|
||||
import type {
|
||||
FileError,
|
||||
FileSystem,
|
||||
@@ -6,7 +7,7 @@ import type {
|
||||
Result,
|
||||
SessionTreeEntry,
|
||||
} from "../types.js";
|
||||
import { SessionError, toError } from "../types.js";
|
||||
import { SessionError } from "../types.js";
|
||||
import {
|
||||
appendParentIdAfterEntry,
|
||||
BaseSessionStorage,
|
||||
@@ -69,7 +70,11 @@ function parseHeaderLine(line: string, filePath: string): SessionHeader {
|
||||
try {
|
||||
parsed = JSON.parse(line);
|
||||
} catch (error) {
|
||||
throw invalidSession(filePath, "first line is not a valid session header", toError(error));
|
||||
throw invalidSession(
|
||||
filePath,
|
||||
"first line is not a valid session header",
|
||||
toErrorObject(error, "Non-Error thrown"),
|
||||
);
|
||||
}
|
||||
if (!isRecord(parsed)) {
|
||||
throw invalidSession(filePath, "first line is not a valid session header");
|
||||
@@ -110,7 +115,12 @@ function parseEntryLine(line: string, filePath: string, lineNumber: number): Ses
|
||||
try {
|
||||
parsed = JSON.parse(line);
|
||||
} catch (error) {
|
||||
throw invalidEntry(filePath, lineNumber, "is not valid JSON", toError(error));
|
||||
throw invalidEntry(
|
||||
filePath,
|
||||
lineNumber,
|
||||
"is not valid JSON",
|
||||
toErrorObject(error, "Non-Error thrown"),
|
||||
);
|
||||
}
|
||||
if (!isRecord(parsed)) {
|
||||
throw invalidEntry(filePath, lineNumber, "is not a valid session entry");
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { toError } from "./types.js";
|
||||
|
||||
describe("toError", () => {
|
||||
it("preserves the shipped facade semantics", () => {
|
||||
const thrown = { code: "E_TEST", detail: "structured" };
|
||||
|
||||
const error = toError(thrown);
|
||||
|
||||
expect(error.message).toBe('{"code":"E_TEST","detail":"structured"}');
|
||||
expect(error).not.toHaveProperty("cause");
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,5 @@
|
||||
// Agent Core type module defines shared TypeScript contracts.
|
||||
import type { Result } from "@openclaw/normalization-core/result";
|
||||
import type {
|
||||
ImageContent,
|
||||
Model,
|
||||
@@ -11,20 +12,13 @@ import type { AgentEvent, AgentMessage, AgentTool, QueueMode, ThinkingLevel } fr
|
||||
import type { AgentCoreCompletionRuntimeDeps, AgentCoreRuntimeDeps } from "../runtime-deps.js";
|
||||
import type { Session } from "./session/session.js";
|
||||
|
||||
/** Result of a fallible operation. Expected failures are returned as `ok: false` instead of thrown. */
|
||||
export type Result<TValue, TError> = { ok: true; value: TValue } | { ok: false; error: TError };
|
||||
export { err, ok } from "@openclaw/normalization-core/result";
|
||||
export type { Result } from "@openclaw/normalization-core/result";
|
||||
|
||||
/** Create a successful {@link Result}. */
|
||||
export function ok<TValue, TError>(value: TValue): Result<TValue, TError> {
|
||||
return { ok: true, value };
|
||||
}
|
||||
|
||||
/** Create a failed {@link Result}. */
|
||||
export function err<TValue, TError>(error: TError): Result<TValue, TError> {
|
||||
return { ok: false, error };
|
||||
}
|
||||
|
||||
/** Normalize unknown thrown values into Error instances before using them as typed error causes. */
|
||||
/**
|
||||
* @deprecated Use `toErrorObject` from `@openclaw/normalization-core/error-coercion`.
|
||||
* Kept through the next major release for the shipped agent-core plugin API.
|
||||
*/
|
||||
export function toError(error: unknown): Error {
|
||||
if (error instanceof Error) {
|
||||
return error;
|
||||
|
||||
Reference in New Issue
Block a user