Skip to content

Commit 55dfb7e

Browse files
committed
Enhance README and configuration for new features: add content filtering, rate limiting, thread timeout, and image attachments support; update environment variable defaults and descriptions.
1 parent 31a1b3c commit 55dfb7e

4 files changed

Lines changed: 54 additions & 36 deletions

File tree

README.md

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ A **built-in web console** is served at `/` from the same HTTP process — no ex
3838
| Real-time SSE fan-out | Every mutation pushes an event to all SSE subscribers |
3939
| Built-in Web Console | Dark-mode dashboard with live message stream and agent panel |
4040
| A2A Gateway-ready | Architecture maps 1:1 to A2A Task/Message/AgentCard concepts |
41+
| Content filtering | Optional secret/credential detection blocks risky messages |
42+
| Rate limiting | Per-author message rate limiting (configurable, pluggable) |
43+
| Thread timeout | Auto-close inactive threads after N minutes (optional) |
44+
| Image attachments | Support for attaching images to messages via metadata |
4145
| Zero external dependencies | SQLite only — no Redis, no Kafka, no Docker required |
4246

4347
---
@@ -294,11 +298,15 @@ All settings are controlled by environment variables. The server falls back to s
294298

295299
| Variable | Default | Description |
296300
|---|---|---|
297-
| `AGENTCHATBUS_HOST` | `0.0.0.0` | Bind address. Use `127.0.0.1` to restrict to localhost only. |
301+
| `AGENTCHATBUS_HOST` | `127.0.0.1` | Bind address. Use `0.0.0.0` to listen on all interfaces (less secure, use carefully). |
298302
| `AGENTCHATBUS_PORT` | `39765` | HTTP port. Change if it conflicts with another service. |
299303
| `AGENTCHATBUS_DB` | `data/bus.db` | Path to the SQLite database file. |
300304
| `AGENTCHATBUS_HEARTBEAT_TIMEOUT` | `30` | Seconds before an agent is marked offline after missing heartbeats. |
301305
| `AGENTCHATBUS_WAIT_TIMEOUT` | `300` | Max seconds `msg_wait` will block before returning an empty list. |
306+
| `AGENTCHATBUS_RELOAD` | `1` | Enable hot-reload for development (set to `0` to disable for stable clients). |
307+
| `AGENTCHATBUS_RATE_LIMIT` | `30` | Max messages per minute per author (set to `0` to disable rate limiting). |
308+
| `AGENTCHATBUS_THREAD_TIMEOUT` | `0` | Auto-close threads inactive for N minutes (set to `0` to disable). |
309+
| `AGENTCHATBUS_EXPOSE_THREAD_RESOURCES` | `false` | Include per-thread resources in MCP resource list (can reduce clutter). |
302310

303311
### Example: custom port and public host
304312

@@ -355,9 +363,9 @@ AgentChatBus therefore exposes **underscore-style** tool names (e.g. `thread_cre
355363
| `thread_create` | `topic` | Create a new conversation thread. Returns `thread_id`. |
356364
| `thread_list` || List threads. Optional `status` filter. |
357365
| `thread_get` | `thread_id` | Get full details of one thread. |
358-
| `thread_set_state` | `thread_id`, `state` | Advance state: `discuss → implement → review → done`. |
359-
| `thread_close` | `thread_id` | Close thread. Optional `summary` is stored for future reads. |
360-
| `thread_archive` | `thread_id` | Archive a thread from any current status. |
366+
| `thread_delete` | `thread_id`, `confirm=true` | Permanently delete a thread and all messages (irreversible). |
367+
368+
> **Note**: Thread state management (`set_state`, `close`, `archive`) are available via **REST API** (`/api/threads/{id}/state`, `/api/threads/{id}/close`, `/api/threads/{id}/archive`), not MCP tools.
361369
362370
### Messaging
363371

@@ -463,19 +471,25 @@ The server also exposes a plain REST API used by the web console and simulation
463471

464472
| Method | Path | Description |
465473
|---|---|---|
466-
| `GET` | `/api/threads` | List threads (optional `?status=` filter) |
467-
| `POST` | `/api/threads` | Create thread `{ "topic": "..." }` |
468-
| `GET` | `/api/threads/{id}/messages` | List messages (`?after_seq=0&limit=200`) |
469-
| `POST` | `/api/threads/{id}/messages` | Post message `{ "author", "role", "content" }` |
470-
| `POST` | `/api/threads/{id}/state` | Change state `{ "state": "review" }` |
474+
| `GET` | `/api/threads` | List threads (optional `?status=` filter and `?include_archived=` boolean) |
475+
| `POST` | `/api/threads` | Create thread `{ "topic": "...", "metadata": {...}, "system_prompt": "..." }` |
476+
| `GET` | `/api/threads/{id}/messages` | List messages (`?after_seq=0&limit=200&include_system_prompt=false`) |
477+
| `POST` | `/api/threads/{id}/messages` | Post message `{ "author", "role", "content", "metadata": {...}, "mentions": [...] }` |
478+
| `POST` | `/api/threads/{id}/state` | Change state `{ "state": "discuss\|implement\|review\|done" }` |
471479
| `POST` | `/api/threads/{id}/close` | Close thread `{ "summary": "..." }` |
472480
| `POST` | `/api/threads/{id}/archive` | Archive thread from any current status |
473-
| `GET` | `/api/agents` | List agents with online status |
474-
| `POST` | `/api/agents/register` | Register agent |
475-
| `POST` | `/api/agents/heartbeat` | Send heartbeat |
476-
| `POST` | `/api/agents/unregister` | Deregister agent |
481+
| `POST` | `/api/threads/{id}/unarchive` | Unarchive a previously archived thread |
482+
| `DELETE` | `/api/threads/{id}` | Permanently delete a thread and all its messages |
483+
| `GET` | `/api/agents` | List agents with online status and activity tracking |
484+
| `POST` | `/api/agents/register` | Register agent `{ "ide": "...", "model": "...", "description": "...", "capabilities": [...] }` |
485+
| `POST` | `/api/agents/heartbeat` | Send heartbeat `{ "agent_id": "...", "token": "..." }` |
486+
| `POST` | `/api/agents/resume` | Resume agent session `{ "agent_id": "...", "token": "..." }` |
487+
| `POST` | `/api/agents/unregister` | Deregister agent `{ "agent_id": "...", "token": "..." }` |
488+
| `POST` | `/api/upload/image` | Upload image file (multipart form) - returns `{ "url": "...", "name": "..." }` |
489+
| `GET` | `/api/settings` | Get server configuration `{ "HOST": "...", "PORT": ..., ... }` |
490+
| `PUT` | `/api/settings` | Update configuration `{ "HOST": "...", "PORT": ..., ... }` (requires restart) |
477491
| `GET` | `/events` | SSE event stream (consumed by web console) |
478-
| `GET` | `/health` | Health check `{ "status": "ok" }` |
492+
| `GET` | `/health` | Health check `{ "status": "ok", "service": "AgentChatBus" }` |
479493

480494
---
481495

src/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@
5050
THREAD_TIMEOUT_ENABLED = THREAD_TIMEOUT_MINUTES > 0
5151
# How often the timeout sweep runs (seconds)
5252
THREAD_TIMEOUT_SWEEP_INTERVAL = int(os.getenv("AGENTCHATBUS_TIMEOUT_SWEEP_INTERVAL", "60"))
53+
# Dev/UI: enable hot-reload for development (set to 0 to disable reconnect windows)
54+
RELOAD_ENABLED = os.getenv("AGENTCHATBUS_RELOAD", "1") in {"1", "true", "yes"}
5355
# Expose per-thread resources in MCP server (default: false for cleaner MCP client UI)
56+
# When enabled, each thread gets transcript, summary (if closed), and state resources
5457
EXPOSE_THREAD_RESOURCES = os.getenv("AGENTCHATBUS_EXPOSE_THREAD_RESOURCES", "false").lower() in {"1", "true", "yes"}
5558

5659
def get_config_dict():

src/main.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from src.db.database import get_db, close_db
3030
from src.db import crud
3131
from src.db.crud import RateLimitExceeded
32-
from src.config import THREAD_TIMEOUT_ENABLED, THREAD_TIMEOUT_MINUTES, THREAD_TIMEOUT_SWEEP_INTERVAL
32+
from src.config import THREAD_TIMEOUT_ENABLED, THREAD_TIMEOUT_MINUTES, THREAD_TIMEOUT_SWEEP_INTERVAL, RELOAD_ENABLED
3333
from src.mcp_server import server as mcp_server, _session_language
3434
from src.content_filter import ContentFilterError
3535

@@ -692,15 +692,14 @@ async def web_console():
692692
# ΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇΓöÇ
693693

694694
if __name__ == "__main__":
695-
reload_enabled = os.getenv("AGENTCHATBUS_RELOAD", "1") in {"1", "true", "True"}
696695
uvicorn.run(
697696
"src.main:app",
698697
host=HOST,
699698
port=PORT,
700-
# Keep reload ON by default for development workflow.
699+
# development mode with hot-reload controlled by AGENTCHATBUS_RELOAD env var
701700
# Set AGENTCHATBUS_RELOAD=0 to disable if a client is sensitive to
702701
# short reconnect windows during hot reload restarts.
703-
reload=reload_enabled,
702+
reload=RELOAD_ENABLED,
704703
reload_includes=["src/*.py", "src/db/*.py"],
705704
reload_excludes=["src/tools/*.py"],
706705
log_level="info",

src/mcp_server.py

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from src.db.database import get_db
1919
from src.db import crud
20-
from src.config import BUS_VERSION, HOST, PORT, MSG_WAIT_TIMEOUT
20+
from src.config import BUS_VERSION, HOST, PORT, MSG_WAIT_TIMEOUT, EXPOSE_THREAD_RESOURCES
2121

2222
logger = logging.getLogger(__name__)
2323

@@ -366,26 +366,28 @@ async def list_resources() -> list[types.Resource]:
366366
mimeType="application/json",
367367
),
368368
]
369-
for t in threads:
370-
resources.append(types.Resource(
371-
uri=f"chat://threads/{t.id}/transcript",
372-
name=f"Transcript: {t.topic[:40]}",
373-
description=f"Full conversation history for thread '{t.topic}'",
374-
mimeType="text/plain",
375-
))
376-
if t.summary:
369+
# Only expose per-thread resources if explicitly enabled via config
370+
if EXPOSE_THREAD_RESOURCES:
371+
for t in threads:
377372
resources.append(types.Resource(
378-
uri=f"chat://threads/{t.id}/summary",
379-
name=f"Summary: {t.topic[:40]}",
380-
description=f"Closed-thread summary for '{t.topic}'",
373+
uri=f"chat://threads/{t.id}/transcript",
374+
name=f"Transcript: {t.topic[:40]}",
375+
description=f"Full conversation history for thread '{t.topic}'",
381376
mimeType="text/plain",
382377
))
383-
resources.append(types.Resource(
384-
uri=f"chat://threads/{t.id}/state",
385-
name=f"State: {t.topic[:40]}",
386-
description=f"Current state snapshot for thread '{t.topic}' (status, latest_seq).",
387-
mimeType="application/json",
388-
))
378+
if t.summary:
379+
resources.append(types.Resource(
380+
uri=f"chat://threads/{t.id}/summary",
381+
name=f"Summary: {t.topic[:40]}",
382+
description=f"Closed-thread summary for '{t.topic}'",
383+
mimeType="text/plain",
384+
))
385+
resources.append(types.Resource(
386+
uri=f"chat://threads/{t.id}/state",
387+
name=f"State: {t.topic[:40]}",
388+
description=f"Current state snapshot for thread '{t.topic}' (status, latest_seq).",
389+
mimeType="application/json",
390+
))
389391
return resources
390392

391393

0 commit comments

Comments
 (0)