|
| 1 | +# Agent Links Runtime |
| 2 | + |
| 3 | +This document describes how `agent link` sessions run in the backend. |
| 4 | + |
| 5 | +## Scope |
| 6 | + |
| 7 | +- This runtime applies to `/agent-links/*` endpoints only. |
| 8 | +- It does not change `/profile-helper/*` behavior. |
| 9 | + |
| 10 | +## Runtime Model |
| 11 | + |
| 12 | +`agent link` chat uses Claude Agent SDK and creates an isolated workspace per session. |
| 13 | + |
| 14 | +Flow: |
| 15 | + |
| 16 | +1. Load blueprint metadata from `libs/agent_links/<slug>/agent.json`. |
| 17 | +2. Create or bind an in-memory session (`profile_helper.sessions`). |
| 18 | +3. Create a per-session working directory at: |
| 19 | + - `WORKSPACE_BASE/agent_links_sessions/<session_id>` |
| 20 | +4. Copy full blueprint content into that directory (first use only). |
| 21 | +5. Build system prompt from blueprint `rule_file_path` content. |
| 22 | +6. Run Claude Agent SDK query stream and return SSE chunks. |
| 23 | + |
| 24 | +Implementation files: |
| 25 | + |
| 26 | +- `app/api/agent_links.py` |
| 27 | +- `app/services/agent_links.py` |
| 28 | +- `app/services/agent_links_runtime.py` |
| 29 | +- `app/services/profile_helper/sessions.py` |
| 30 | + |
| 31 | +## Session Workspace |
| 32 | + |
| 33 | +- Blueprint root in metadata (`agent_workdir`) is a source template path. |
| 34 | +- Actual runtime execution path is session-specific: |
| 35 | + - `agent_session_workdir` stored in session data. |
| 36 | +- API returns runtime path in: |
| 37 | + - `POST /agent-links/{slug}/session` response `agent_workdir` |
| 38 | + - `POST /agent-links/{slug}/chat` header `X-Agent-Workdir` |
| 39 | + |
| 40 | +## Cleanup Behavior |
| 41 | + |
| 42 | +- Session cleanup is still controlled by in-memory session TTL and max-count: |
| 43 | + - `PROFILE_HELPER_SESSION_TTL_SECONDS` |
| 44 | + - `PROFILE_HELPER_SESSION_MAX_COUNT` |
| 45 | +- `agent_links_runtime.ensure_session_workspace(...)` performs best-effort orphan directory cleanup: |
| 46 | + - any directory under `WORKSPACE_BASE/agent_links_sessions/` whose name is not in active session IDs is removed. |
| 47 | + |
| 48 | +## Prompt and Model |
| 49 | + |
| 50 | +- Prompt source: |
| 51 | + - runtime prefers loading rule content from the copied session workspace path. |
| 52 | + - fallback reads blueprint `rule_file_path` when session path cannot be resolved. |
| 53 | + - if missing/unreadable, runtime falls back to `META_SYSTEM_PROMPT`. |
| 54 | +- Runtime always appends a workspace boundary system suffix: |
| 55 | + - only paths inside current session workspace are allowed |
| 56 | + - prefer relative paths from workspace root |
| 57 | + - reject absolute/outside paths and `..` traversal |
| 58 | +- Model priority: |
| 59 | + 1. request body `model` |
| 60 | + 2. blueprint `default_model` |
| 61 | + 3. agent config default (`ANTHROPIC_MODEL`/configured model) |
| 62 | + |
| 63 | +## Tools and Permissions |
| 64 | + |
| 65 | +- Allowed tools are set from `DEFAULT_ALLOWED_TOOLS`. |
| 66 | +- Permission mode is `bypassPermissions` for agent link runtime. |
| 67 | +- Runtime passes `cwd` and `add_dirs` as the session workspace. |
| 68 | + |
| 69 | +## Blueprint Import Limits |
| 70 | + |
| 71 | +`POST /agent-links/import` and `/agent-links/import/preview`: |
| 72 | + |
| 73 | +- only `.zip` uploads are accepted |
| 74 | +- max upload size is `5MB` |
| 75 | +- zip path traversal is blocked (`Invalid zip structure`) |
| 76 | +- preview returns up to 300 file paths plus total file count |
| 77 | + |
| 78 | +## Session Workspace File Upload |
| 79 | + |
| 80 | +`POST /agent-links/{slug}/files/upload`: |
| 81 | + |
| 82 | +- uploads a file into current session workspace |
| 83 | +- supports `target_path` (relative subdirectory; default `uploads`) |
| 84 | +- blocks path escape outside workspace |
| 85 | +- max file size is `30MB` |
| 86 | + |
| 87 | +## SSE Format |
| 88 | + |
| 89 | +`POST /agent-links/{slug}/chat` returns `text/event-stream`. |
| 90 | + |
| 91 | +- structured events: |
| 92 | + - `data: {"type":"assistant_delta","content":"..."}` |
| 93 | + - `data: {"type":"thinking","content":"..."}` |
| 94 | + - `data: {"type":"tool_call", ...}` |
| 95 | + - `data: {"type":"tool_result", ...}` |
| 96 | + - `data: {"type":"plan", ...}` |
| 97 | + - `data: {"type":"system", ...}` |
| 98 | + - `data: {"type":"result", ...}` |
| 99 | +- error event: |
| 100 | + - `data: {"error":"..."}` |
| 101 | +- end marker: |
| 102 | + - `data: [DONE]` |
| 103 | + |
| 104 | +## Agent Link Chat UI Defaults |
| 105 | + |
| 106 | +Current `agent link` chat page is intentionally simplified for end users: |
| 107 | + |
| 108 | +- auto-sends a hidden first user message `"你好"` after session init, so the first assistant reply acts as welcome text |
| 109 | +- by default only renders normal dialogue and `plan` blocks |
| 110 | +- hides low-level runtime events (`thinking`, `tool_call`, `tool_result`, `system`) in this page |
| 111 | +- Enter sends message, but IME composing Enter (Chinese input method candidate selection) does not send |
0 commit comments