Skip to main content
Developer Guide · 06

Service & Consumer Two-Tier Layer

6.1 Admin Layer

  • Login via Web UI with full permissions
  • Manage filesystem (docs/scripts/generated/soul)
  • Configure System Prompt + user profile
  • Manage Subagents + capability prompts
  • Publish Services + manage API Keys
  • Configure scheduled tasks + WeChat integration

6.2 Consumer Layer

  • Authenticate via sk-svc-... API Key (or /s/{sid}?key=... self-service link)
  • Restricted permissions: only access capabilities + allowed_docs/scripts configured in Service
  • Filesystem isolation: users/{admin}/services/{svc}/conversations/{conv}/
  • Generated file isolation: each conversation has its own generated/
  • Cannot access Admin's filesystem

6.3 Service Configuration

Each Service is a published config:

text
users/{admin_id}/services/{service_id}/
├── config.json          # Model + system_prompt + capabilities + allowed_docs/scripts + welcome_message + quick_questions + wechat_channel
├── keys.json            # API Keys (hashed)
├── wechat_sessions.json # WeChat session state
├── conversations/       # Consumer conversation directory
└── tasks/               # Service scheduled tasks

Full schema in docs/filesystem-architecture.md §4.

6.4 Service Self-Service (v2.x)

  • URL format: /s/{service_id}?key=sk-svc-xxx
  • Backend: consumer_ui.py injects template variables; frontend reads key from URLSearchParams → writes to localStoragehistory.replaceState immediately clears query
  • Frontend admin: Key Modal on success additionally shows full link with key + warning (equivalent to sharing the key)

6.4.2 Welcome Message + Quick Questions

  • Fields: welcome_message: str + quick_questions: List[str]
  • Backend template injection: _safe_json_for_inline_script prevents script breakout
  • Frontend chat: ChatGPT-style first screen (large welcome text + gradient chips), auto-hides after first message

6.4.3 Visual File/Script Selector

  • FileTreePicker.tsx: antd Tree checkable + loadData lazy loading + "All (*)" Switch
  • Folder selection = entire directory recursively (key ends with /)
  • Root constraint: allowed_docs only shows /docs, allowed_scripts only shows /scripts
  • Empty allowed_docs falls back to ["*"], empty allowed_scripts keeps empty (semantic = no scripts)

6.5 Consumer Agent Channel-Awareness

python
create_consumer_agent(..., channel: str = "web")
  • channel="web": does not inject send_message even if humanchat capability is enabled. Reason: agent output on web is already streamed to browser; calling send_message would have no delivery target and would expose tool events to consumers
  • channel="wechat": injects send_message, tool results delivered by the delivery layer
  • channel="scheduler": same as wechat
  • cache_key includes ::ch={channel} (only when non-default web)

6.6 Codex / Cursor plan-backed Services (v1.3.1)

Select an authorized connection and model in Settings → Service Management to use the existing web, Consumer API, and Service WeChat entry points. DeepAgents remains the default. The admin's personal WeChat entry point is separate and retains its existing engine path.

Configuration and resources

runtime_choice describes the selection in a create/update request. The server validates and derives runtime_binding; clients cannot supply their own binding. Creation still requires the top-level model. Replace the connection, model, and existing document directory in this minimal example:

json
{
  "name": "Team handbook",
  "model": "<authorized-model-id>",
  "runtime_choice": {
    "runtime": "codex",
    "profile_id": "<authorized-connection-id>",
    "model": "<authorized-model-id>"
  },
  "allowed_docs": ["handbook"],
  "allowed_scripts": [],
  "capabilities": [],
  "published": true
}

runtime can also be cursor. In allowed_docs and allowed_scripts, "*" grants all resources and an empty array grants none. Set them explicitly instead of relying on defaults. The Service uses its selected System Prompt and User Profile versions; review them before sharing. Admin private long-term memory is not automatically exposed.

Create a Key with {"name":"team","billing":"hosted"}, shown as the authorized-plan option in the UI. Plan Services reject BYOK, including existing BYOK Keys after switching a DeepAgents Service to a plan engine.

Execution path

text
Service web / Consumer API / Service WeChat
  → Validate Key or WeChat binding, publication state and admin model grant
  → Fixed connection and model → Runtime queue (serial per connection)
  → jellyfish_service_* tools → allowed documents, scripts and current-chat artifacts
  → Streaming events, saved chat, file previews and downloads

app/runtime/consumer.py handles sessions and execution; consumer_tools.py provides scoped resource tools. Visitors cannot use native command or file approvals or select resource paths belonging to another admin, Service, or conversation.

Changing a connection, model, resource scope, or capability starts a new native session on the next request. Saved Jellyfish history remains. Different Keys / channels do not reuse a native session. Unpublishing, deleting a Key, revoking a grant, or changing permissions cancels the corresponding queued and running tasks.

API and acceptance checks

  • GET /api/v1/models returns billing, default_model, models, and allowed_hosts. Plan Keys use hosted billing and a fixed model. An SDK's model field cannot override that model; provider, api_key, base_url, and region are rejected.
  • Native search / image generation must be enabled for the Service and supported by the client, model, and account. Plan Services do not support scheduled tasks, voice, or video; use DeepAgents for those workflows.
  • A Service Key is a shared Service-level access boundary, not an individual member identity. Valid Keys can access conversations exposed by that Service. This mode is for trusted internal members.
  • Before distribution, verify allowed-document access, rejected out-of-scope paths, continuation, stop, Key revocation, configuration changes, and artifact downloads. Verify real WeChat message and media delivery separately. Unit tests, mocked UI, and builds do not replace real provider and channel checks.

See the Service distribution implementation and acceptance scope.