import * as Effect from "effect/Effect";
import { MAX_MEMORIES } from "../shared/memory.ts";
import { MAX_TASKS } from "../shared/tasks.ts";
import { AgentFailure, agentCall } from "./agent-io.ts";
const messages = {
invalid_model: "Select a supported provider and model",
invalid_effort: "Select a supported effort for this model",
provider_disabled: "Enable OpenRouter in Settings before using this provider",
credential_unreadable:
"Stored provider API key cannot be read; replace it in settings",
credential_save_failed: "Provider API key could not be saved",
conversation_missing: "Conversation not found",
memory_deleted: "Memory was deleted",
memory_full: `Memory limit reached (${MAX_MEMORIES}). Delete a fact first.`,
memory_edit_conflict:
"Memory changed or was deleted. Reload memories before editing.",
memory_delete_conflict: "Memory changed. Reload memories before deleting.",
task_deleted: "Task was deleted",
task_creation_conflict:
"Task creation ID was already used for different input",
task_past: "New one-off task needs a future instant",
task_full: `Task limit reached (${MAX_TASKS})`,
};
export type OperationError = keyof typeof messages;
export class OperationFailure extends AgentFailure {
readonly code: OperationError;
constructor(code: OperationError) {
super({ message: messages[code] });
this.code = code;
}
}
export type OperationResult =
{ ok: true; value: A } | { ok: false; error: OperationError };
// Like the registry boundary, transport declared failures as plain codes.
// Unexpected errors stay rejected and are sanitized by the calling RPC adapter.
export function operationResult(
program: Effect.Effect,
): Promise> {
return Effect.runPromise(
program.pipe(
Effect.catchDefect((error) =>
error instanceof OperationFailure
? Effect.fail(error)
: Effect.die(error),
),
Effect.map((value): OperationResult => ({ ok: true, value })),
Effect.catch((error) =>
error instanceof OperationFailure
? Effect.succeed>({ ok: false, error: error.code })
: Effect.fail(error),
),
),
);
}
export function operationCall(call: () => PromiseLike>) {
return agentCall(call).pipe(
Effect.flatMap((result) =>
result.ok
? Effect.succeed(result.value)
: Effect.fail(new OperationFailure(result.error)),
),
);
}