agent-state for AI agents
Give your AI agents shared state.
Copy, paste, run. Works with Claude, OpenAI, Gemini.
how-it-works
define
Register save_state and read_state as tools your LLM can call.
handle
When the LLM calls a tool, your handler sends the request to echoValue DB API.
share
Any agent with the same token can read and write. Shared state, zero config.
full-example
Copy, paste, run. Swap the SDK for OpenAI or Gemini — the tool schema is the same.
# pip install anthropic requests
import requests
from anthropic import Anthropic
# Get a free token: curl https://api.echovalue.dev/token -d 'token=new'
TOKEN = "your-echovalue-token"
BASE = "https://api.echovalue.dev/kv"
# 1. Define the tools
tools = [
{
"name": "save_state",
"description": "Save a key-value pair to shared agent state",
"input_schema": {
"type": "object",
"properties": {
"group": {"type": "string", "description": "Namespace / bucket"},
"key": {"type": "string", "description": "Identifier"},
"value": {"type": "string", "description": "Data to store"},
"ttl": {"type": "integer", "description": "Expiry in seconds"}
},
"required": ["group", "key", "value"]
}
},
{
"name": "read_state",
"description": "Read a value from shared agent state",
"input_schema": {
"type": "object",
"properties": {
"group": {"type": "string", "description": "Namespace / bucket"},
"key": {"type": "string", "description": "Identifier"}
},
"required": ["group", "key"]
}
}
]
# 2. Handle tool calls → echoValue API
def run_tool(name, args):
headers = {"x-token": TOKEN}
if name == "save_state":
ttl = args.get("ttl", 86400)
r = requests.post(
f"{BASE}/{args['group']}/{args['key']}?ttl={ttl}",
data=args["value"], headers=headers)
return r.text
if name == "read_state":
r = requests.get(
f"{BASE}/{args['group']}/{args['key']}",
headers=headers)
return r.text
# 3. Run the agent
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Save status=done for the import pipeline"}]
)
# 4. Process tool calls from the response
for block in response.content:
if block.type == "tool_use":
result = run_tool(block.name, block.input)
print(f"{block.name} → {result}")
# save_state → OK
// npm install @anthropic-ai/sdk
import Anthropic from "@anthropic-ai/sdk";
// Get a free token: curl https://api.echovalue.dev/token -d 'token=new'
const TOKEN = "your-echovalue-token";
const BASE = "https://api.echovalue.dev/kv";
// 1. Define the tools
const tools: Anthropic.Tool[] = [
{
name: "save_state",
description: "Save a key-value pair to shared agent state",
input_schema: {
type: "object" as const,
properties: {
group: { type: "string", description: "Namespace / bucket" },
key: { type: "string", description: "Identifier" },
value: { type: "string", description: "Data to store" },
ttl: { type: "integer", description: "Expiry in seconds" },
},
required: ["group", "key", "value"],
},
},
{
name: "read_state",
description: "Read a value from shared agent state",
input_schema: {
type: "object" as const,
properties: {
group: { type: "string", description: "Namespace / bucket" },
key: { type: "string", description: "Identifier" },
},
required: ["group", "key"],
},
},
];
// 2. Handle tool calls → echoValue API
async function runTool(name: string, args: Record<string, any>) {
const headers = { "x-token": TOKEN };
if (name === "save_state") {
const ttl = args.ttl ?? 86400;
const res = await fetch(
`${BASE}/${args.group}/${args.key}?ttl=${ttl}`,
{ method: "POST", body: args.value, headers }
);
return res.text();
}
if (name === "read_state") {
const res = await fetch(
`${BASE}/${args.group}/${args.key}`,
{ headers }
);
return res.text();
}
}
// 3. Run the agent
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
tools,
messages: [{ role: "user", content: "Save status=done for the import pipeline" }],
});
// 4. Process tool calls from the response
for (const block of response.content) {
if (block.type === "tool_use") {
const result = await runTool(block.name, block.input as Record<string, any>);
console.log(`${block.name} → ${result}`);
// save_state → OK
}
}
get-started
Free tier includes 100 operations. No registration. No credit card.