agentlily-runtime is the execution layer for AgentLily instances in Lily
Protocol, the autonomous agent finance infrastructure being built on Stellar.
This repository is intentionally designed as an open-source-ready runtime foundation, not a completed runtime product. It provides:
- A modular TypeScript runtime architecture
- One real happy-path execution flow for contributors to study and extend
- Strict typing, tests, linting, and CI scaffolding
- Clear extension points for unfinished systems
The current implementation demonstrates a narrow, credible runtime path:
- Create an
AgentRuntime - Start the runtime and register tools
- Build a runtime context for a task
- Execute a task through the task runner and action executor
- Invoke a typed tool
- Persist lightweight in-memory task history (or durable JSON file history via memoryStoragePath)
- Emit runtime events and structured log entries
This gives contributors a working reference path without locking the project into premature architecture.
The following areas are scaffolded with interfaces, types, or placeholders and are expected to become contributor work:
- Wallet-aware and payment-aware actions
- Persistent database and vector storage backends (basic file-based JSON persistence is supported via JsonFileMemoryStore)
- Model provider integrations (an
OpenAICompatibleModelProviderscaffold is available for experimentation; note that it is scaffolded and intentionally not production-complete) - Runtime policy engines and approval flows
- Long-running orchestration and scheduling
- Distributed execution and durable coordination
- Identity-aware execution logic
- Rich tracing, metrics, and production observability
src/
actions/ Minimal action execution flow
agents/ Agent instance lifecycle scaffolding
errors/ Typed runtime errors
events/ Runtime event model and event bus
guards/ Runtime assertions and guardrails
logger/ Structured logger abstraction
memory/ In-memory store plus storage interface
providers/ Model/provider abstraction layer
runtime/ Bootstrap, context, and runtime composition
state/ Runtime state interface
tasks/ Task runner and task types
tools/ Tool contracts and registry
tests/ Foundation and happy-path tests
npm install
npm run build
npm run testExample:
import { AgentRuntime } from "@lily-protocol/agentlily-runtime";
const runtime = new AgentRuntime({
runtimeId: "local-dev"
});
runtime.registerTool({
name: "echo",
description: "Returns a string payload for test execution",
async execute(input) {
return { echoed: String(input.payload.message ?? "") };
}
});
await runtime.start();
const result = await runtime.executeTask({
agentId: "agent-demo",
taskId: "task-001",
toolName: "echo",
input: "Send a greeting",
payload: { message: "hello lily" }
});
console.log(result.output);agentlily-runtime exposes an event system via RuntimeEventBus to support observability, audit logs, and tracing adapters.
| Event Name | Description | Key Payload Fields |
|---|---|---|
runtime.started |
Emitted once when runtime.start() succeeds |
runtimeId, occurredAt |
runtime.stopped |
Emitted when runtime.stop() completes |
runtimeId, occurredAt |
runtime.task.received |
Emitted when a task is accepted for execution | runtimeId, taskId, agentId |
runtime.task.completed |
Emitted when a task executes successfully | runtimeId, taskId, agentId, toolName, durationMs |
runtime.task.failed |
Emitted when task execution fails | runtimeId, taskId, agentId, reason |
runtime.tool.invoked |
Emitted when an individual tool action is invoked | runtimeId, taskId, agentId, toolName, invokedAt |
runtime.internal.error |
Emitted when an event listener throws an unhandled error | eventName, errorMessage, occurredAt |
You can inject a custom RuntimeEventBus during initialization or subscribe directly via runtime.eventBus:
import {
AgentRuntime,
RuntimeEventBus
} from "@lily-protocol/agentlily-runtime";
const eventBus = new RuntimeEventBus();
// Subscribe to task completion and failure events
const unsubscribeCompleted = eventBus.on("runtime.task.completed", (event) => {
console.log(
`Task ${event.payload.taskId} completed in ${event.payload.durationMs}ms`
);
});
const unsubscribeFailed = eventBus.on("runtime.task.failed", (event) => {
console.error(`Task ${event.payload.taskId} failed: ${event.payload.reason}`);
});
// Single-fire listener
eventBus.once("runtime.started", (event) => {
console.log(`Runtime started at ${event.payload.occurredAt}`);
});
const runtime = new AgentRuntime({
runtimeId: "monitored-runtime",
eventBus
});
await runtime.start();
// Unsubscribe when no longer needed
unsubscribeCompleted();
unsubscribeFailed();npm run buildcompiles the librarynpm run lintruns ESLintnpm run typecheckruns TypeScript in no-emit modenpm run testruns Vitest with coveragenpm run verifyruns formatting, linting, typecheck, and tests
Good first contributions should add depth without collapsing extension points. Examples:
- Add a new memory backend that implements
MemoryStore - Introduce runtime policies around tool allowlists
- Add an event sink or tracing adapter
- Implement a model provider adapter with tests
- Expand task lifecycle states beyond the current happy path
Maintainers can immediately create issues around:
- Provider adapters
- Runtime policies
- Persistent storage
- Wallet-aware execution boundaries
- Observability
- Documentation examples
- Test matrix expansion
The backlog section in the final delivery summary from this setup provides a ready-made issue starter list.