stillrunning-eve
v0.3.0
Published
One-file monitoring for Vercel eve agents. A drop-in eve hook that pings StillRunning on every run with duration, tokens, cost, model, and tool-call counts — and lets StillRunning alert when a scheduled agent silently stops running.
Maintainers
Readme
stillrunning-eve
One-file monitoring for Vercel eve agents.
Drop one hook into your agent and every run reports to StillRunning: start, success or failure, duration, tokens, cost, model, and tool-call counts. And because StillRunning models the expectation, not just the events, it alerts you when a scheduled agent silently stops running, the failure mode no event-driven alerting can see.
Install
npm install stillrunning-eveQuickstart
Create a workflow at stillrunning.ai/app/new, grab its token, then:
// agent/hooks/stillrunning.ts
import { stillrunning } from "stillrunning-eve";
export default stillrunning(); // reads STILLRUNNING_TOKENSet the env var and run your agent:
STILLRUNNING_TOKEN=<your-token> eve devThat's the entire integration. Every session now pings your StillRunning workflow.
Monitor scheduled runs only
Scheduled agents are where absence detection matters most. To monitor cron-triggered runs without reporting interactive chat turns:
export default stillrunning({ channels: ["schedule"] });Chat agents: use an on-demand monitor
An agent that runs when your users show up has no schedule to miss. Point it at a monitor created with mode on_demand and StillRunning stops expecting a cadence: a quiet night never marks it down, while every run still records duration, tokens, cost and model, failures still alert, and cost/duration anomalies and monthly budgets still apply.
// agent/hooks/stillrunning.ts
export default stillrunning(); // token points at an on_demand monitorOptional: split liveness from chat telemetry
Most agents want one monitor covering everything they do , one hook, no channel filter, one row on the dashboard. Start there.
The split below is worth it only when you genuinely need two different questions answered about the same agent: "is it still alive?" (absence alerts on a cron heartbeat) and "how are the real user runs going?" (no absence alerts). It costs you a second monitor, a second token and a second row, so reach for it when the heartbeat is real and you have verified it reports, not by default.
// agent/hooks/stillrunning.ts , scheduled monitor
export default stillrunning({ channels: ["schedule"] });// agent/hooks/stillrunning-chat.ts , on_demand monitor
export default stillrunning({
token: process.env.STILLRUNNING_CHAT_TOKEN,
excludeChannels: ["schedule"],
});excludeChannels is the complement of channels and wins when both are set. Prefer it on the on-demand side: it keeps reporting new user-facing channel kinds as your agent grows, where an allowlist would silently stop.
This pairing is worth keeping even though on-demand monitors exist. An on-demand monitor never times out, so on its own it cannot tell you the agent went dark, that is exactly what the scheduled half is for.
What gets reported
| eve event | StillRunning ping |
|---|---|
| session.started | start |
| turn.completed | success + durationMs, tokensIn/Out, costUsd, model, toolCalls |
| turn.failed / session.failed | fail + the error message |
Token and cost figures come from eve's step.completed usage data (eve computes costUsd per step via AI Gateway), accumulated per session. The model id comes from the runtime identity on session.started. Start and terminal pings share a run id and a trace id, so they correlate into one run and one replayable Outcome on your dashboard.
The conversation on each run
Each run's output carries the user's message and the agent's reply, which is what the dashboard renders in the run list and the timeline:
What does StillRunning do? → It watches your jobs and tells you when one stops.This is on by default, because a run row that shows what was asked and what came back is most of what makes an agent's history worth reading.
To turn it off, for agents handling anything you'd rather not send to a third party:
stillrunning({ captureText: false });With it off, no conversation text ever leaves your process. Every metric still reports , duration, tokens, cost, model and tool calls are unaffected by this switch, so you keep full monitoring either way. Long messages are truncated, never dropped.
Options
stillrunning({
token: "...", // default: STILLRUNNING_TOKEN env var
baseUrl: "...", // default: https://stillrunning.ai
channels: ["schedule"], // default: all channel kinds
excludeChannels: ["schedule"], // never report these; wins over `channels`
captureText: true, // record the conversation as the run's output; false to disable
pingTimeoutMs: 3000, // hard cap per ping
onError: (err) => {}, // transport errors (default: silent)
debug: true, // or STILLRUNNING_DEBUG=1
});The never-throw guarantee
eve escalates a thrown hook to turn.failed, which would fail the very run being monitored. This hook is built so that can't happen:
- Every handler swallows every error, including bugs in your
onErrorcallback. - Pings race a hard timeout, so a hung network call can't stall the agent.
- With no token configured it warns once and no-ops instead of throwing.
Worst case is a missed ping, which your workflow's grace window tolerates. Monitoring never breaks the thing it monitors.
License
MIT
