diff --git a/packages/agent-core/src/harness/agent-harness.ts b/packages/agent-core/src/harness/agent-harness.ts index 5d61ed9a4df7..0d3b173a639f 100644 --- a/packages/agent-core/src/harness/agent-harness.ts +++ b/packages/agent-core/src/harness/agent-harness.ts @@ -53,6 +53,8 @@ import { toError, } from "./types.js"; +// CoreAgentHarness coordinates session state, resources, tools, compaction, and +// streaming callbacks around the lower-level agent loop. function createUserMessage(text: string, images?: ImageContent[]): UserMessage { const content: Array<{ type: "text"; text: string } | ImageContent> = [{ type: "text", text }]; if (images) { @@ -209,6 +211,7 @@ interface AgentHarnessTurnState< activeTools: TTool[]; } +/** Stateful harness for running, steering, compacting, and navigating sessions. */ export class CoreAgentHarness< TSkill extends Skill = Skill, TPromptTemplate extends PromptTemplate = PromptTemplate, diff --git a/packages/agent-core/src/harness/session/memory-repo.ts b/packages/agent-core/src/harness/session/memory-repo.ts index 6bc7daefbced..8cb5994090a2 100644 --- a/packages/agent-core/src/harness/session/memory-repo.ts +++ b/packages/agent-core/src/harness/session/memory-repo.ts @@ -2,6 +2,7 @@ import { type Session, SessionError, type SessionMetadata, type SessionRepo } fr import { InMemorySessionStorage } from "./memory-storage.js"; import { createSessionId, createTimestamp, getEntriesToFork, toSession } from "./repo-utils.js"; +/** In-memory session repository for tests and ephemeral harness usage. */ export class InMemorySessionRepo implements SessionRepo { private sessions = new Map(); diff --git a/packages/agent-core/src/harness/session/repo-utils.ts b/packages/agent-core/src/harness/session/repo-utils.ts index 35f8162316d6..1aebf12be5cf 100644 --- a/packages/agent-core/src/harness/session/repo-utils.ts +++ b/packages/agent-core/src/harness/session/repo-utils.ts @@ -9,20 +9,24 @@ import { import { Session } from "./session.js"; import { uuidv7 } from "./uuid.js"; +/** Create a time-sortable session id. */ export function createSessionId(): string { return uuidv7(); } +/** Create a canonical session timestamp string. */ export function createTimestamp(): string { return new Date().toISOString(); } +/** Wrap a storage implementation in the Session facade. */ export function toSession( storage: SessionStorage, ): Session { return new Session(storage); } +/** Unwrap filesystem results into session errors with caller context. */ export function getFileSystemResultOrThrow( result: Result, message: string, @@ -34,6 +38,7 @@ export function getFileSystemResultOrThrow( return result.value; } +/** Select the entries copied into a forked session. */ export async function getEntriesToFork( storage: SessionStorage, options: { entryId?: string; position?: "before" | "at" }, @@ -49,6 +54,8 @@ export async function getEntriesToFork( if ((options.position ?? "before") === "at") { effectiveLeafId = target.id; } else { + // Fork-before only targets user turns so the fork starts where a new prompt + // can replace that turn without carrying its response. if (target.type !== "message" || target.message.role !== "user") { throw new SessionError( "invalid_fork_target", diff --git a/packages/agent-core/src/harness/session/timestamps.ts b/packages/agent-core/src/harness/session/timestamps.ts index 70214a18bf3c..daf260845312 100644 --- a/packages/agent-core/src/harness/session/timestamps.ts +++ b/packages/agent-core/src/harness/session/timestamps.ts @@ -1,3 +1,4 @@ +/** Parse an ISO-like session timestamp to milliseconds. */ export function parseSessionTimestampMs(value: unknown): number | undefined { if (typeof value !== "string" || !value.trim()) { return undefined; @@ -6,6 +7,7 @@ export function parseSessionTimestampMs(value: unknown): number | undefined { return Number.isFinite(parsed) ? parsed : undefined; } +/** Parse a required timestamp or throw a labeled validation error. */ export function requireSessionTimestampMs(value: string, label: string): number { const parsed = parseSessionTimestampMs(value); if (parsed === undefined) { diff --git a/packages/agent-core/src/harness/session/uuid.ts b/packages/agent-core/src/harness/session/uuid.ts index 02b9a303cc16..b998a8eeadac 100644 --- a/packages/agent-core/src/harness/session/uuid.ts +++ b/packages/agent-core/src/harness/session/uuid.ts @@ -1,6 +1,7 @@ let lastTimestamp = -Infinity; let sequence = 0; +// Small UUIDv7 generator for browser/node package builds without a runtime dep. function fillRandomBytes(bytes: Uint8Array): void { const crypto = globalThis.crypto; if (crypto?.getRandomValues) { @@ -12,6 +13,7 @@ function fillRandomBytes(bytes: Uint8Array): void { } } +/** Generate a monotonic UUIDv7 string. */ export function uuidv7(): string { const random = new Uint8Array(16); fillRandomBytes(random); @@ -21,6 +23,8 @@ export function uuidv7(): string { sequence = random[6] * 0x1000000 + random[7] * 0x10000 + random[8] * 0x100 + random[9]; lastTimestamp = timestamp; } else { + // Same-ms calls increment the sequence so generated ids remain sortable and + // unique even when random bytes repeat. sequence = (sequence + 1) >>> 0; if (sequence === 0) { lastTimestamp++; diff --git a/packages/agent-core/src/harness/utils/shell-output.ts b/packages/agent-core/src/harness/utils/shell-output.ts index a72b7fffa2a5..e8843911d3a2 100644 --- a/packages/agent-core/src/harness/utils/shell-output.ts +++ b/packages/agent-core/src/harness/utils/shell-output.ts @@ -9,6 +9,7 @@ import { } from "../types.js"; import { DEFAULT_MAX_BYTES, truncateTail } from "./truncate.js"; +/** Options for shell execution with combined stdout/stderr capture. */ export interface ShellCaptureOptions extends Omit< ExecutionEnvExecOptions, "onStdout" | "onStderr" @@ -16,6 +17,7 @@ export interface ShellCaptureOptions extends Omit< onChunk?: (chunk: string) => void; } +/** Captured shell result, with large output optionally spilled to a file. */ export interface ShellCaptureResult { output: string; exitCode: number | undefined; @@ -32,6 +34,7 @@ function toExecutionError(error: unknown): ExecutionError { return new ExecutionError("unknown", cause.message, cause); } +/** Remove control characters that make terminal/model output unsafe to replay. */ export function sanitizeBinaryOutput(str: string): string { return Array.from(str) .filter((char) => { @@ -53,6 +56,7 @@ export function sanitizeBinaryOutput(str: string): string { .join(""); } +/** Execute a command while keeping a bounded tail and optional full-output log. */ export async function executeShellWithCapture( env: ExecutionEnv, command: string, @@ -113,6 +117,8 @@ export async function executeShellWithCapture( totalBytes += encoder.encode(chunk).byteLength; const text = sanitizeBinaryOutput(chunk).replace(/\r/g, ""); if (totalBytes > DEFAULT_MAX_BYTES && !fullOutputPath) { + // Once the response-size budget is exceeded, start a durable log with + // everything captured so far and continue streaming only the bounded tail. ensureFullOutputFile(outputChunks.join("") + text); } else { appendFullOutput(text); diff --git a/packages/agent-core/src/index.ts b/packages/agent-core/src/index.ts index 415667004451..dd19409d8d70 100644 --- a/packages/agent-core/src/index.ts +++ b/packages/agent-core/src/index.ts @@ -1,3 +1,5 @@ +// Public agent-core package surface: agent loop, harness, session storage, +// compaction, execution envs, and utility helpers. export * from "./agent.js"; export * from "./agent-loop.js"; export * from "./node.js"; diff --git a/packages/agent-core/src/llm.ts b/packages/agent-core/src/llm.ts index 90cedd02eff0..00853799a328 100644 --- a/packages/agent-core/src/llm.ts +++ b/packages/agent-core/src/llm.ts @@ -1 +1,2 @@ +// LLM-core compatibility barrel for agent-core consumers. export * from "@openclaw/llm-core"; diff --git a/packages/agent-core/src/node.ts b/packages/agent-core/src/node.ts index 23ccae43bf3a..4ff3f5c62321 100644 --- a/packages/agent-core/src/node.ts +++ b/packages/agent-core/src/node.ts @@ -1,2 +1,3 @@ +// Node-specific agent-core entrypoint with the default Node execution env. export { NodeExecutionEnv } from "./harness/env/nodejs.js"; export * from "./index.js"; diff --git a/packages/agent-core/src/validation.ts b/packages/agent-core/src/validation.ts index 1812d9d4fd86..1368906b4779 100644 --- a/packages/agent-core/src/validation.ts +++ b/packages/agent-core/src/validation.ts @@ -1 +1,2 @@ +// Tool validation facade for callers that import validation from agent-core. export { validateToolArguments, validateToolCall } from "@openclaw/llm-core";