docs: document agent core package

This commit is contained in:
Peter Steinberger
2026-06-04 01:23:43 -04:00
parent aafdf67d39
commit bdfeece562
10 changed files with 28 additions and 0 deletions

View File

@@ -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,

View File

@@ -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<SessionMetadata, { id?: string }> {
private sessions = new Map<string, Session>();

View File

@@ -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<TMetadata extends SessionMetadata>(
storage: SessionStorage<TMetadata>,
): Session<TMetadata> {
return new Session(storage);
}
/** Unwrap filesystem results into session errors with caller context. */
export function getFileSystemResultOrThrow<TValue>(
result: Result<TValue, FileError>,
message: string,
@@ -34,6 +38,7 @@ export function getFileSystemResultOrThrow<TValue>(
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",

View File

@@ -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) {

View File

@@ -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++;

View File

@@ -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);

View File

@@ -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";

View File

@@ -1 +1,2 @@
// LLM-core compatibility barrel for agent-core consumers.
export * from "@openclaw/llm-core";

View File

@@ -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";

View File

@@ -1 +1,2 @@
// Tool validation facade for callers that import validation from agent-core.
export { validateToolArguments, validateToolCall } from "@openclaw/llm-core";