Euler Copilot
The Copilot is Euler’s agentic control plane. It is a real tool-calling loop, not a command parser: the model reads a grounded context pack describing your current project, decides which typed tool to call, the platform executes that tool in-process, the result feeds back, and the loop continues to a bounded step limit.
It replaces two earlier half-agents, the Agent Center screen and the Ask Euler dock, neither of which could actually operate the product.
What it can do
Thirty five tools are registered, covering the lifecycle end to end. Each one is a typed capability with a JSON schema, a minimum role, and a destructive-or-spend flag.
| Area | Tools |
|---|---|
| Workspaces and projects | list_workspaces, list_use_cases, create_workspace, list_projects, open_project, create_project, set_target_profile |
| Data and runs | register_source, list_sources, trigger_run, get_run_status, cancel_run |
| Diagnosis | get_readiness_report, diagnose_failures |
| Annotation | get_annotation_layers, set_annotation_layers, run_annotation_job |
| Readiness | get_readiness_settings, set_readiness_settings |
| Search and slices | search_episodes, create_slice, list_slices, curate_subset |
| Exports | list_exports, create_export, seal_export, get_export_download, delete_export |
| Models and budget | get_models, set_model, get_budget, set_budget |
| Team | list_users, invite_user |
| Escalation | raise_support_query |
Tool implementations call the platform’s own service layer in-process rather than shelling out over HTTP, so a tool call inherits exactly the validation, audit trail and tenant isolation the REST surface already enforces.
The privacy boundary
Customer pixels never leave the platform boundary. The Copilot is a text agent. Everything it sends to the model provider is metadata: project and workspace names, readiness numbers, layer coverage, annotation text such as captions, labels and task strings, run stage summaries, error strings and schema. Frames, video bytes, base64 payloads and media file paths go to the self-hosted vision lane and the approved vision models only, never to the chat provider.
That guarantee is structural rather than a convention, enforced at three points:
- The context pack reads only named fields. It never serializes an episode, a source or a search result wholesale, so there is no field it could pick up by accident.
- Every tool implementation hand-builds its result the same way.
- A boundary assertion runs over the context pack and over every tool result before either is handed back to the model. It raises on raw bytes, on a
data:URI, on a long unbroken base64 run, and on any string that resolves to a media file path. A regression that starts leaking frames fails loudly at the boundary instead of silently shipping pixels to a vendor.
Perception models are separately governed: those surfaces run self-hosted only, and no external label API is used. See models behind the layers.
Confirmations and autopilot
Nine tools are flagged destructive or spend-incurring: trigger_run, cancel_run, run_annotation_job, curate_subset, create_export, seal_export, delete_export, set_budget and invite_user.
By default, calling one of these does not execute it. The tool returns a confirmation envelope, the stream emits a confirmation event carrying the tool name, the arguments and a prompt, and nothing has happened yet. Re-send the same message with autopilot: true to execute.
In autopilot those tools execute directly. They are audited identically either way: autopilot changes whether a human says yes, never whether the action is recorded.
Role gating is enforced twice on purpose. The endpoint requires at least viewer, and the tool registry filters the catalog the model is even shown. A viewer’s model sees read-only tools and cannot call a mutation it never received. invite_user and set_budget are admin only.
Talking to it
curl -N -X POST -H "Authorization: Bearer $EULER_TOKEN" \
-H "Content-Type: application/json" \
"$EULER_BASE_URL/v1/copilot/chat" \
-d '{
"messages": [{"role": "user", "content": "Why did my last run fail?"}],
"project_id": "acme-pilot"
}'
The response is a Server-Sent Events stream. Event names and payloads:
| Event | Payload |
|---|---|
start | provider, model, whether the provider is configured, degraded state and reason, autopilot flag, and the grounded context the turn used |
token | an incremental assistant token delta |
tool_call | step, tool, call id, arguments |
tool_result | step, tool, call id, and the result envelope |
confirmation | step, tool, call id, arguments and the confirmation prompt |
usage | model, prompt and completion tokens, cost in USD |
error | message |
done | steps used, stop reason, and the thread id |
Stop reasons are complete, cancelled, step_limit, budget_exceeded, provider_error or degraded.
The turn cancels cooperatively when the client disconnects, so closing a tab stops spending immediately.
The rest of the surface
| Endpoint | Purpose |
|---|---|
GET /v1/copilot/models | Available models, the active model, and whether a provider key is configured |
GET /v1/copilot/suggestions | Context-aware starter prompts and FAQs |
POST /v1/copilot/support | Raise a support query with the Euler team |
GET /v1/copilot/support | This tenant’s support queries |
GET /v1/copilot/threads | List threads |
GET /v1/copilot/threads/{id} | Read one thread |
DELETE /v1/copilot/threads/{id} | Delete one thread |
Threads are deliberately lightweight: JSON documents in the tenant’s object storage, not a new table. A thread is chat scrollback, not a system of record. The audit log and the action log remain the durable trail.
The safety envelope
The only deterministic behaviour around the model is the envelope that contains it:
- Bounded steps. Tool rounds are capped at eight per turn. Hitting the cap ends the turn with an honest note rather than looping.
- Budget guard. Every model call is pre-flighted against the tenant’s weekly cap, and measured usage is written to the same spend ledger every other hosted-model call site uses.
- Cancellation. A cancellation token is checked before each model call and each tool call.
- Structured transcript. Every assistant token, tool call with its arguments, tool result and error is emitted as a typed event, so the UI can render the work and the audit trail can prove what happened.
Model choice and degradation
The Copilot routes through OpenRouter against a curated allow-list of tool-calling-capable models, best default first. The live provider catalog is the source of truth for availability and price; the allow-list is the source of truth for choice, so a catalog change can never silently route a tenant onto an untested model. Operators can pin a model with EULER_COPILOT_MODEL.
Degradation is mandatory, not optional, and always disclosed in the start event:
- With no OpenRouter key configured, the turn falls back to the existing Gemini planning lane and says so.
- With neither key configured, it answers from the grounded context pack alone and says so.
It never raises into the endpoint.
Next
- What the copilot can change on your behalf: Pipeline settings and Readiness.
- Wiring your own agent to Euler instead: MCP quickstart.