@acentric-cloud/agent
v0.3.0
Published
Framework agent author API and separate pure and fetch handler environments
Maintainers
Readme
@acentric-cloud/agent
The framework author API for Acentric Cloud. The framework's unpublished
@acentric/types types are mirrored here, with the same names and shapes.
Install with npm install --save-dev @acentric-cloud/agent.
An agent has a name, version, init(config, now) and
step(state, message, now). Optional pure functions are effects(state),
window(snapshot), view(state) and migrate(snapshot, config, from).
state contains exactly { snapshot, log, config }. Messages are input,
effect, config and migrated, delivered one at a time. Init, step and
migrate can reject with { error }. A rejection saves nothing.
Publish two self-contained ES modules. agent.js exports the pure agent
without handlers. handlers.js, when needed, exports a map of handler
names to { mode, run, timeoutMs?, maxAttempts? }. kinds on the pure agent
is an optional array of names, including runner kinds.
// agent.ts
import type { Agent } from '@acentric-cloud/agent';
type Snapshot = { turns: number };
export default {
name: 'echo',
version: '1',
init: () => ({ snapshot: { turns: 0 } }),
step(state, message) {
return message.type === 'input'
? {
snapshot: { turns: state.snapshot.turns + 1 },
append: [{ kind: 'echo', body: message.payload }],
}
: { snapshot: state.snapshot };
},
view: (state) => ({ turns: state.snapshot.turns }),
} satisfies Agent<Snapshot>;Effects are { key, kind, args, mode?, abort? }. Keys are single-use,
including timers. Keep pending work and partial results in the snapshot.
A key missing from the next effects list is cancelled without a result.
Keeping a key with abort: true fires its signal and still delivers its outcome.
Handlers declare mode: 'reissue' for repeatable work or mode: 'once' for
work that must never rerun after a lost run. They receive exactly
{ key, kind, args, attempt, signal, secrets, log }. Copy configuration and
snapshot data needed by handlers into their args. Secrets use get(name);
the log uses list({ after?, before?, kinds?, limit?, cursor? }) and returns
{ entries, cursor? }. A handler returns JSON, which becomes { ok } in an
effect message. Other outcomes are { failed: { code, error } } or
{ interrupted: true } for a lost once run.
RunnerKinds describes cloud's @timer: args { at: number }, result
null. at is an absolute millisecond in the same clock domain as now.
Use KindsOf<typeof handlers> & RunnerKinds to combine handler and runner
kinds, and HandlersFor<K> to type a separate handler map. Names starting
with @ are reserved for runners.
The package entry declares no globals. Extend
@acentric-cloud/agent/tsconfig/pure for pure files and
@acentric-cloud/agent/tsconfig/handlers for handlers. Use include to list
source files so the profiles' ambient declarations stay in place. The pure
profile has no I/O, Promise value, clock or randomness. Handlers have the
fetch web platform, including timers, AbortSignal, streams and crypto.
Node globals and Node modules are unavailable. Publication inspects the
bundled modules as well as checking their types.
test/echo.ts and test/model-loop.ts show pure entries with separate
*.handlers.ts entries. Model-loop queues inputs and partial tool outcomes
in its snapshot, uses a timer for retries and defines an interrupt input
that aborts its current effects.
The check:framework package script checks mutual type assignability with
$FRAMEWORK_DIR/packages/types/src, defaulting to the local agent-framework
checkout. It prints a skip when that checkout is absent. Rust owns the
separate generated src/wire.ts; the author API is exported by src/index.ts.
