blob: 903da3d8098d5001ccf7cd9db127f256aa43b8b6 [file] [view]
# EventMesh Agent (v2 Streaming Agent Process)
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
The `eventmesh-agent` module is the v2 streaming-agent process: an independent JVM that
registers with a running EventMesh runtime, subscribes its private lite channel, and bridges
routed prompts to an OpenAI-compatible LLM gateway — streaming tokens back over the runtime
to the requesting client.
## Boot sequence
1. **Register** — `POST /agent/register` on the runtime traffic port; the runtime assigns the
agent its `agent-parent` + `client-reply-parent` (§5.2 of the v2 design).
2. **Subscribe** — the agent subscribes `agent.<agentId>` on its parent via the lite wire
(`subscribeLiteBytes`).
3. **Ready** — `POST /agent/ready` flips the registration ready; only now does matchmaking
route sessions to this agent (ready-before-route).
4. **Heartbeat** — a virtual thread refreshes the TTL and reports active sessions every
`agent.heartbeat.intervalMs`.
## Quick start
```shell
# 1. runtime (defaults: memory storage, traffic 10105)
./gradlew :eventmesh-runtime:runRuntime # or use the docker image
# 2. agent (needs an OpenAI-compatible endpoint)
LLM_BASE_URL=https://api.openai.com LLM_API_KEY=sk-... LLM_MODEL=gpt-4o-mini ./bin/start-agent.sh # from dist-agent/
```
Dev runner without a distribution: `./gradlew :eventmesh-agent:runAgent -Dllm.api.key=sk-...`.
## Configuration
All config is `-D` system properties; `bin/start-agent.sh` maps the `AGENT_*` / `LLM_*` env
vars (see `conf/agent.properties` for the full list).
| Key | Default | Description |
|---|---|---|
| `agent.runtime.url` | `http://localhost:10105` | Runtime traffic URL (control plane + lite wire) |
| `agent.id` | `agent-<ts>` | Agent identity; must be unique per process |
| `agent.capacity` | `100` | Advertised concurrent-stream capacity (matchmaking input) |
| `agent.heartbeat.intervalMs` | `10000` | Heartbeat cadence |
| `agent.heartbeat.failLimit` | `6` | Consecutive heartbeat failures before the process exits (supervisor restarts it) |
| `agent.conversation.maxHistory` | `20` | Per-conversation message sliding window |
| `agent.conversation.maxConversations` | `1000` | Live-conversation bound; least-recently-used conversations are evicted |
| `llm.base.url` | `https://api.openai.com` | OpenAI-compatible gateway base URL |
| `llm.api.key` | _(empty)_ | Bearer key — **required**; empty fails fast at boot |
| `llm.api.key.optional` | `false` | Opt-out of the empty-key fail-fast (mock gateways) |
| `llm.model` | `gpt-4o-mini` | Default model; per-request model overrides win |
## Reliability behavior
- **Fail-fast on empty LLM key** — an agent without a usable key would fail every routed
request after registering READY, so boot refuses (unless `llm.api.key.optional=true`).
- **Heartbeat failure limit** — after `agent.heartbeat.failLimit` consecutive failures the
process exits nonzero (the runtime TTL has evicted the registration by then; a zombie
serves nothing). Supervisors (systemd / K8s) restart it.
- **Bounded conversations** — each conversation keeps a sliding window of turns, and the
store evicts least-recently-used conversations past `agent.conversation.maxConversations`,
bounding agent memory on long-lived processes.
## Limitations
- Conversation history is process-local (lost on restart); persistence is an explicit TODO.
- Mode-1 (streaming calls) only — mode-2 pub/sub sessions are not routed to agents.
- One LLM gateway per process (`llm.base.url`); multi-provider routing is future work.