@elyxndra/agent
v0.1.0
Published
Elyxndra's coding-agent brain: OpenAI-compatible streaming client (thinking + tool calls), tools (files, grep/glob, edit, patch, terminal, todo, ask, delegate, memory, web), MCP, modes, approvals, context budget, compaction, sessions, checkpoints. Host-ag
Maintainers
Readme
@elyxndra/agent
The coding-agent half of Elyxndra's shared brain, as a host-agnostic library: an OpenAI-compatible streaming client (thinking + tool calls), the tool set (files, search, exact-match edits, multi-file patches, terminal, task list, ask-user, sub-agents, project memory, web, MCP), the agent loop with Agent / Plan / Ask modes, approvals, a context budget with auto-compaction, sessions and per-message checkpoints. Node 20+, ESM, no native addons. It powers the Elyxndra Code VS Code / Cursor extension and the desktop chat app.
npm install @elyxndra/agentUsage
import { Agent, NodeHost, defaultConfig } from "@elyxndra/agent";
const host = new NodeHost({ root: "/path/to/project", memoryFile: "/path/to/memory.md" });
const agent = new Agent(
host,
{ ...defaultConfig(), endpoint: { baseUrl: "http://127.0.0.1:8080/v1" }, model: "qwen3-coder" },
{
onChange: () => render(agent.messages, agent.pendingInteraction),
onDelta: (id, content, reasoning) => appendToMessage(id, content, reasoning),
onPersist: (session) => saveSomewhere(session),
onFilesChanged: (paths) => reloadEditors(paths),
onError: (message) => showError(message),
},
);
await agent.refreshFacts(); // project snapshot for the system prompt (manifests, verify commands, git, rules files)
agent.mode = "agent"; // "agent" | "plan" | "ask"
agent.send("Add a --dry-run flag to the CLI and cover it with a test.");
// When a tool needs approval or the model asks a question, `pendingInteraction`
// is set and onChange fires; answer it from your UI:
agent.resolveInteraction({ kind: "approve" }); // | approveForSession | deny | { kind: "answer", text } | dismissWorks with any OpenAI-compatible server — the Elyxndra engine daemon, llama.cpp, LM Studio, Ollama, vLLM, MLX servers — and hosted endpoints (endpoint.apiKey).
What's inside
| Module | Exports |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| llm | streamChat, listModels, ThinkSplitter, ToolCallAssembler, buildBody — SSE streaming with reasoning_content / <think> support and tool-call fragment assembly |
| agent | Agent, AgentConfig, AgentEvents, defaultConfig — the loop: prompt → stream → tools (with approvals) → continue; modes; compaction; checkpoints (revert, reapply, restoreCheckpoint, revertAll); sub-agents (delegate) |
| tools, tools/files, tools/extra | ToolRegistry and the built-in tools; newChange records every edit as a FileChange (with stats) your UI can diff and revert |
| host, nodeHost | the Host interface (file system, shell, memory) and NodeHost, a workspace-confined Node implementation (symlink-safe, .gitignore-aware) |
| prompt, facts | buildSystemPrompt (byte-stable per session so prefix caches hold) and detectFacts (manifests, verify commands, languages, git, AGENTS.md / CLAUDE.md / .cursorrules) |
| context | ContextBudget — token estimation calibrated from server usage, turn-aware trimming |
| streaming | DeltaBuffer, statsLine, applyFinalStats — coalesce deltas and turn final stats into a line + budget calibration |
| mcp | connectMCP — MCP servers over stdio, exposed as mcp__<server>__<tool> (minimal child environment unless fullEnv; the tools ask for approval unless approveMCP is off) |
| net | fetchPublic, assertPublicUrl, isPrivateAddress — outbound fetch for model-supplied URLs that refuses loopback/private/link-local/metadata destinations and re-checks every redirect hop |
| patch, diff | V4A multi-file patches (parsePatch, applyHunks); line diffs, hunks, stats |
| types | ChatMessage, Session, FileChange, ToolDefinition, makeMessage, isEmptyAssistant, attachment helpers |
Security defaults: every path is confined to the workspace; terminal, delete_file, the web tools and MCP tools ask for approval (DEFAULT_APPROVAL_REQUIRED, approveMCP); writes to .vscode/, .git/, .husky/, .github/workflows/ and .env* always ask (paths are normalised first, so src/../.git/x or .GIT/x cannot slip past); web_fetch only reaches public hosts; grep refuses patterns that can backtrack catastrophically; Stop cancels sub-agents and terminal children; config.readOnly hides every mutating tool (untrusted workspaces). See SECURITY.md.
Engines that key a prefix cache on a per-session header (MTPLX's X-MTPLX-Session-Id) are served by config.sessionHeaderName: the host names the header (it learns it from the engine's chatWire), the agent fills in the session id; any static headers (client name, auth) go in endpoint.headers.
Develop
npm test # vitest (offline)
ELYXNDRA_LIVE=1 npm run test:live # one real turn against a local server (ELYXNDRA_ENDPOINT, ELYXNDRA_MODEL)
npm run build # dist/ (ESM + .d.ts) via tsdownPart of the Elyxndra monorepo · MIT
