bots-garden/mini-mepublic Fork
⑂ 5e919b3
Commits
⬇ Clone ▾
git clone https://git.rickub.com/bots-garden/mini-me.git
git clone ssh://git@rickub.com/bots-garden/mini-me.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

🛟 Updated.

k33g committed 2026-10-21T09:02:43+02:00 Browse files
5e919b3 parent: 53ad5d2
modified .tickets/epics.yaml +3 -0
@@ -45,3 +45,6 @@ epics:
4545 - title: Loop
4646 state: open
4747 color: "#1d76db"
48+ - title: Mini Me as a service
49+ state: open
50+ color: "#006b75"
@@ -45,3 +45,6 @@ epics:
45 - title: Loop45 - title: Loop
46 state: open46 state: open
47 color: "#1d76db"47 color: "#1d76db"
48+ - title: Mini Me as a service
49+ state: open
50+ color: "#006b75"
added .tickets/issues/0113-mini-me-as-a-service-ideas.yaml +175 -0
new file mode 100644
@@ -0,0 +1,175 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 113
3+title: "Mini Me as a service: turn mm into a dedicated app, or expose it as services — ideas"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-21T13:00:00.000Z
9+updatedAt: 2026-10-21T13:00:00.000Z
10+labels: []
11+milestone: v1.0.0
12+epic: Mini Me as a service
13+related:
14+ - 71
15+ - 105
16+ - 46
17+ - 89
18+ - 66
19+body: |
20+ Starting point for the epic "Mini Me as a service". Ideas only — nothing
21+ decided, nothing implemented.
22+
23+ ## The wish (user's words, 2026-10-21)
24+ Make it possible — through plugins, scripts, a UI… — to turn mini-me into
25+ an application dedicated to one particular task, OR to have mini-me expose
26+ services that other applications call. The ideas are still vague: this
27+ ticket collects directions to choose from.
28+
29+ ## What mm already has that points this way (checked in the repo)
30+ - A dedicated app is already "just YAML" for many demos: demos/translator,
31+ little-coder, guards, docs-search, memory-search, plans… — a system
32+ prompt, a model, skills, declared tools (`tools:`), hooks, AGENTS.md.
33+ What is missing is packaging and a UI of their own.
34+ - mm is already callable from a program, three ways: `mm -p "…"` (one
35+ answer on stdout; with `structuredOutput`, JSON shaped by Go types),
36+ `mm --ask <agent>` (context on stdin), and ACP — a JSON-RPC protocol on
37+ stdio with sessions, tool calls, permissions and forms. The `sidekick`
38+ web client already drives mm over ACP.
39+ - Agents already call agents (`mmConfigs`, `/ask-<name>`, `ask_agent`):
40+ a first "service" model, process to process.
41+ - Extension points: hooks (any language, JSON on stdin/stdout), declared
42+ tools, MCP servers, skills; WASM plugins studied in ticket 46.
43+ - Packaging: the Docker Sandbox kits (sbx), release binaries.
44+ - Ticket 71 (SDK) already proposes the Go-library road: remove the global
45+ state (config.Cfg, the active sink, the plan store), a public package,
46+ and a headless `mm -p --output-format stream-json`. Ticket 105 asks for a
47+ package that exposes the methods.
48+
49+ ## Direction A — mini-me as a dedicated application
50+ 1. An "app bundle": one folder = agent.yaml + skills + tools + hooks +
51+ prompts + an optional UI description; `mm run ./translator` (or
52+ `mm app add <url>`). Versioned, shareable, installable.
53+ 2. Commands defined in the YAML: `/translate-pro <text>` = a prompt
54+ template + chosen tools, shown in /help and the editor menu — a task app
55+ without writing Go.
56+ 3. A start-up form: the app asks what it needs (the ask_user forms already
57+ exist) before the first question — a wizard (demos/project-wizard does
58+ it through the model today).
59+ 4. A window layout per app: header text, which panes, which keys, a result
60+ pane (e.g. "translation" beside "original").
61+ 5. Output contracts per app: structuredOutput, files written with
62+ save_answer, a "result" event a script can wait for.
63+ 6. A small web UI served by mm itself for one app (a form + the answer),
64+ on top of the service below.
65+
66+ ## Direction B — mini-me exposes services
67+ 1. **mm as an MCP server** (`mm -mcp`): each configured agent becomes one
68+ MCP tool (`ask_translator`, `ask_expert`). Any MCP client — Claude
69+ Desktop, Zed, other agents, mm itself — can call a mini-me agent with
70+ its model, skills and tools. Reuses the ask machinery. Likely the
71+ cheapest first step.
72+ 2. **An OpenAI-compatible HTTP façade** (`mm -serve :8080`, POST
73+ /v1/chat/completions): any OpenAI client (Open WebUI, scripts, IDE
74+ plugins) talks to an mm AGENT — tools, skills, hooks run server-side —
75+ instead of a bare model.
76+ 3. **A small REST API of mm's own**: POST /agents/{name}/ask, sessions
77+ (GET /sessions, resume), /docs and /memory searches as endpoints,
78+ streaming as SSE.
79+ 4. **ACP over a network transport** (WebSocket) instead of stdio, so a web
80+ page or a remote editor drives mm like sidekick does locally.
81+ 5. **A worker mode**: mm reads jobs from a folder, a queue or a webhook and
82+ writes results — no human in the loop (see ticket 89).
83+ 6. **Headless stream-json** (from ticket 71): one JSON event per line, the
84+ simplest contract for Python/Node/shell callers.
85+
86+ ## Direction C — plugins
87+ 1. A plugin = a package of tools + hooks + skills (+ maybe a UI piece),
88+ installed with `mm plugin add`, declared in agent.yaml.
89+ 2. WASM for sandboxed plugins (ticket 46); plain processes for the rest.
90+ 3. A plugin can also be a "front end": the window, ACP and the REPL are
91+ already three clients of one loop; a fourth could be a plugin.
92+
93+ ## What every direction needs (prerequisites to weigh)
94+ - No more process-wide state (ticket 71 phase 1): one process serving many
95+ callers needs per-session config, sink, plans (ticket 108 did plans for
96+ ACP; the active-sink global and config.Cfg remain).
97+ - Concurrency: ACP turns are serialised today; a service needs parallel
98+ sessions — and local models usually serve one request at a time.
99+ - Permissions without a human: yolo on/off is per agent; a service needs a
100+ policy (allow-lists, a separate approval channel, ticket 89).
101+ - Authentication and limits for anything on the network.
102+ - A versioned contract: once other apps call mm, its API cannot break
103+ freely.
104+ - Observability: trace (exists), per-request logs, errors as data.
105+
106+ ## Suggested first experiments (small, measurable)
107+ 1. `mm -mcp`: expose the agents of `mmConfigs` as MCP tools; call them
108+ from Zed or Claude Desktop.
109+ 2. An app-bundle convention on one existing demo (translator): `mm run
110+ demos/translator`, with YAML-defined commands.
111+ 3. The OpenAI-compatible façade on one agent, driven by Open WebUI.
112+
113+ ## Open questions
114+ - Who is the first "application" you have in mind (a team tool, a
115+ personal assistant, a CI step, a web page)? It decides A vs B.
116+ - Local only (one machine, one user) or networked (several users)?
117+ - Go library (ticket 71) first, or a protocol (MCP / HTTP) first?
118+tasks:
119+ - id: 1
120+ title: "Pick the first target application and the direction (A dedicated app, B services, C plugins)"
121+ state: open
122+ priority: none
123+ author:
124+ name: k33g
125+ email: ph.charriere@gmail.com
126+ createdAt: 2026-10-21T13:00:00.000Z
127+ updatedAt: 2026-10-21T13:00:00.000Z
128+ - id: 2
129+ title: "Experiment: mm as an MCP server exposing the mmConfigs agents as tools"
130+ state: open
131+ priority: none
132+ author:
133+ name: k33g
134+ email: ph.charriere@gmail.com
135+ createdAt: 2026-10-21T13:00:00.000Z
136+ updatedAt: 2026-10-21T13:00:00.000Z
137+ - id: 3
138+ title: "Experiment: an app-bundle convention (one folder, `mm run <dir>`, YAML-defined commands) on demos/translator"
139+ state: open
140+ priority: none
141+ author:
142+ name: k33g
143+ email: ph.charriere@gmail.com
144+ createdAt: 2026-10-21T13:00:00.000Z
145+ updatedAt: 2026-10-21T13:00:00.000Z
146+ - id: 4
147+ title: "Experiment: an OpenAI-compatible HTTP façade in front of one agent"
148+ state: open
149+ priority: none
150+ author:
151+ name: k33g
152+ email: ph.charriere@gmail.com
153+ createdAt: 2026-10-21T13:00:00.000Z
154+ updatedAt: 2026-10-21T13:00:00.000Z
155+ - id: 5
156+ title: "List the prerequisites to lift (global state, concurrency, permissions without a human, auth) and link them to tickets 71, 89, 108"
157+ state: open
158+ priority: none
159+ author:
160+ name: k33g
161+ email: ph.charriere@gmail.com
162+ createdAt: 2026-10-21T13:00:00.000Z
163+ updatedAt: 2026-10-21T13:00:00.000Z
164+comments:
165+ - id: 1
166+ author:
167+ name: k33g
168+ email: ph.charriere@gmail.com
169+ createdAt: 2026-10-21T14:00:00.000Z
170+ body: |
171+ User's direction (2026-10-21): local use; each mm instance exposes a
172+ web service on its own port; the service is the equivalent of the
173+ user's prompt (like mm -p); structured output; streaming and
174+ non-streaming; a cancel API. The OpenAI-compatible HTTP façade
175+ (direction B.2) is the candidate: specified in ticket 114.
new file mode 100644
@@ -0,0 +1,175 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 113
3+title: "Mini Me as a service: turn mm into a dedicated app, or expose it as services — ideas"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-21T13:00:00.000Z
9+updatedAt: 2026-10-21T13:00:00.000Z
10+labels: []
11+milestone: v1.0.0
12+epic: Mini Me as a service
13+related:
14+ - 71
15+ - 105
16+ - 46
17+ - 89
18+ - 66
19+body: |
20+ Starting point for the epic "Mini Me as a service". Ideas only — nothing
21+ decided, nothing implemented.
22+
23+ ## The wish (user's words, 2026-10-21)
24+ Make it possible — through plugins, scripts, a UI… — to turn mini-me into
25+ an application dedicated to one particular task, OR to have mini-me expose
26+ services that other applications call. The ideas are still vague: this
27+ ticket collects directions to choose from.
28+
29+ ## What mm already has that points this way (checked in the repo)
30+ - A dedicated app is already "just YAML" for many demos: demos/translator,
31+ little-coder, guards, docs-search, memory-search, plans… — a system
32+ prompt, a model, skills, declared tools (`tools:`), hooks, AGENTS.md.
33+ What is missing is packaging and a UI of their own.
34+ - mm is already callable from a program, three ways: `mm -p "…"` (one
35+ answer on stdout; with `structuredOutput`, JSON shaped by Go types),
36+ `mm --ask <agent>` (context on stdin), and ACP — a JSON-RPC protocol on
37+ stdio with sessions, tool calls, permissions and forms. The `sidekick`
38+ web client already drives mm over ACP.
39+ - Agents already call agents (`mmConfigs`, `/ask-<name>`, `ask_agent`):
40+ a first "service" model, process to process.
41+ - Extension points: hooks (any language, JSON on stdin/stdout), declared
42+ tools, MCP servers, skills; WASM plugins studied in ticket 46.
43+ - Packaging: the Docker Sandbox kits (sbx), release binaries.
44+ - Ticket 71 (SDK) already proposes the Go-library road: remove the global
45+ state (config.Cfg, the active sink, the plan store), a public package,
46+ and a headless `mm -p --output-format stream-json`. Ticket 105 asks for a
47+ package that exposes the methods.
48+
49+ ## Direction A — mini-me as a dedicated application
50+ 1. An "app bundle": one folder = agent.yaml + skills + tools + hooks +
51+ prompts + an optional UI description; `mm run ./translator` (or
52+ `mm app add <url>`). Versioned, shareable, installable.
53+ 2. Commands defined in the YAML: `/translate-pro <text>` = a prompt
54+ template + chosen tools, shown in /help and the editor menu — a task app
55+ without writing Go.
56+ 3. A start-up form: the app asks what it needs (the ask_user forms already
57+ exist) before the first question — a wizard (demos/project-wizard does
58+ it through the model today).
59+ 4. A window layout per app: header text, which panes, which keys, a result
60+ pane (e.g. "translation" beside "original").
61+ 5. Output contracts per app: structuredOutput, files written with
62+ save_answer, a "result" event a script can wait for.
63+ 6. A small web UI served by mm itself for one app (a form + the answer),
64+ on top of the service below.
65+
66+ ## Direction B — mini-me exposes services
67+ 1. **mm as an MCP server** (`mm -mcp`): each configured agent becomes one
68+ MCP tool (`ask_translator`, `ask_expert`). Any MCP client — Claude
69+ Desktop, Zed, other agents, mm itself — can call a mini-me agent with
70+ its model, skills and tools. Reuses the ask machinery. Likely the
71+ cheapest first step.
72+ 2. **An OpenAI-compatible HTTP façade** (`mm -serve :8080`, POST
73+ /v1/chat/completions): any OpenAI client (Open WebUI, scripts, IDE
74+ plugins) talks to an mm AGENT — tools, skills, hooks run server-side —
75+ instead of a bare model.
76+ 3. **A small REST API of mm's own**: POST /agents/{name}/ask, sessions
77+ (GET /sessions, resume), /docs and /memory searches as endpoints,
78+ streaming as SSE.
79+ 4. **ACP over a network transport** (WebSocket) instead of stdio, so a web
80+ page or a remote editor drives mm like sidekick does locally.
81+ 5. **A worker mode**: mm reads jobs from a folder, a queue or a webhook and
82+ writes results — no human in the loop (see ticket 89).
83+ 6. **Headless stream-json** (from ticket 71): one JSON event per line, the
84+ simplest contract for Python/Node/shell callers.
85+
86+ ## Direction C — plugins
87+ 1. A plugin = a package of tools + hooks + skills (+ maybe a UI piece),
88+ installed with `mm plugin add`, declared in agent.yaml.
89+ 2. WASM for sandboxed plugins (ticket 46); plain processes for the rest.
90+ 3. A plugin can also be a "front end": the window, ACP and the REPL are
91+ already three clients of one loop; a fourth could be a plugin.
92+
93+ ## What every direction needs (prerequisites to weigh)
94+ - No more process-wide state (ticket 71 phase 1): one process serving many
95+ callers needs per-session config, sink, plans (ticket 108 did plans for
96+ ACP; the active-sink global and config.Cfg remain).
97+ - Concurrency: ACP turns are serialised today; a service needs parallel
98+ sessions — and local models usually serve one request at a time.
99+ - Permissions without a human: yolo on/off is per agent; a service needs a
100+ policy (allow-lists, a separate approval channel, ticket 89).
101+ - Authentication and limits for anything on the network.
102+ - A versioned contract: once other apps call mm, its API cannot break
103+ freely.
104+ - Observability: trace (exists), per-request logs, errors as data.
105+
106+ ## Suggested first experiments (small, measurable)
107+ 1. `mm -mcp`: expose the agents of `mmConfigs` as MCP tools; call them
108+ from Zed or Claude Desktop.
109+ 2. An app-bundle convention on one existing demo (translator): `mm run
110+ demos/translator`, with YAML-defined commands.
111+ 3. The OpenAI-compatible façade on one agent, driven by Open WebUI.
112+
113+ ## Open questions
114+ - Who is the first "application" you have in mind (a team tool, a
115+ personal assistant, a CI step, a web page)? It decides A vs B.
116+ - Local only (one machine, one user) or networked (several users)?
117+ - Go library (ticket 71) first, or a protocol (MCP / HTTP) first?
118+tasks:
119+ - id: 1
120+ title: "Pick the first target application and the direction (A dedicated app, B services, C plugins)"
121+ state: open
122+ priority: none
123+ author:
124+ name: k33g
125+ email: ph.charriere@gmail.com
126+ createdAt: 2026-10-21T13:00:00.000Z
127+ updatedAt: 2026-10-21T13:00:00.000Z
128+ - id: 2
129+ title: "Experiment: mm as an MCP server exposing the mmConfigs agents as tools"
130+ state: open
131+ priority: none
132+ author:
133+ name: k33g
134+ email: ph.charriere@gmail.com
135+ createdAt: 2026-10-21T13:00:00.000Z
136+ updatedAt: 2026-10-21T13:00:00.000Z
137+ - id: 3
138+ title: "Experiment: an app-bundle convention (one folder, `mm run <dir>`, YAML-defined commands) on demos/translator"
139+ state: open
140+ priority: none
141+ author:
142+ name: k33g
143+ email: ph.charriere@gmail.com
144+ createdAt: 2026-10-21T13:00:00.000Z
145+ updatedAt: 2026-10-21T13:00:00.000Z
146+ - id: 4
147+ title: "Experiment: an OpenAI-compatible HTTP façade in front of one agent"
148+ state: open
149+ priority: none
150+ author:
151+ name: k33g
152+ email: ph.charriere@gmail.com
153+ createdAt: 2026-10-21T13:00:00.000Z
154+ updatedAt: 2026-10-21T13:00:00.000Z
155+ - id: 5
156+ title: "List the prerequisites to lift (global state, concurrency, permissions without a human, auth) and link them to tickets 71, 89, 108"
157+ state: open
158+ priority: none
159+ author:
160+ name: k33g
161+ email: ph.charriere@gmail.com
162+ createdAt: 2026-10-21T13:00:00.000Z
163+ updatedAt: 2026-10-21T13:00:00.000Z
164+comments:
165+ - id: 1
166+ author:
167+ name: k33g
168+ email: ph.charriere@gmail.com
169+ createdAt: 2026-10-21T14:00:00.000Z
170+ body: |
171+ User's direction (2026-10-21): local use; each mm instance exposes a
172+ web service on its own port; the service is the equivalent of the
173+ user's prompt (like mm -p); structured output; streaming and
174+ non-streaming; a cancel API. The OpenAI-compatible HTTP façade
175+ (direction B.2) is the candidate: specified in ticket 114.
added .tickets/issues/0114-openai-compatible-http-service.yaml +204 -0
new file mode 100644
@@ -0,0 +1,204 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 114
3+title: "OpenAI-compatible HTTP service: each mm instance answers prompts on its own port (stream, non-stream, structured output, cancel)"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-21T14:00:00.000Z
9+updatedAt: 2026-10-21T14:00:00.000Z
10+labels:
11+ - kind::feature
12+milestone: v1.0.0
13+epic: Mini Me as a service
14+related:
15+ - 113
16+ - 71
17+ - 89
18+body: |
19+ An OpenAI-compatible HTTP service in front of ONE mini-me agent: what
20+ `mm -p` does — one prompt in, the agent's turn (its tools, skills, hooks
21+ run inside mm), the answer out — but over HTTP, so any program, or any
22+ OpenAI client, can use the agent. Epic "Mini Me as a service"; the first
23+ concrete step of ticket 113.
24+
25+ ## The user's requirements (2026-10-21)
26+ - local use;
27+ - each mini-me instance exposes a web service on its own port;
28+ - the service is the equivalent of the user's prompt — like `mm -p`;
29+ - structured output must be possible;
30+ - answers in streaming AND non-streaming mode;
31+ - a cancel API.
32+
33+ ## Proposal (to confirm)
34+
35+ ### Start
36+ - `mm -serve 8080 agent.yaml` (flag) or a `serve:` block in the YAML
37+ (`port`, `host`). Default host 127.0.0.1: local only; another host must
38+ be asked for explicitly. One agent per instance, one port per instance —
39+ several agents = several `mm -serve` on several ports.
40+ - Optional `serve.apiKey`: when set, requests must carry
41+ `Authorization: Bearer <key>` (OpenAI clients already send one); 401
42+ otherwise. Even on 127.0.0.1, other local processes can reach the port.
43+
44+ ### Endpoints
45+ - `POST /v1/chat/completions` — the prompt. From the request:
46+ - `messages`: the LAST user message is the prompt; earlier user/assistant
47+ messages are the conversation so far (stateless, as OpenAI clients
48+ expect: they resend the history each time). The agent's own system
49+ prompt stays first; a client `system` message is appended after it
50+ (or refused — to decide).
51+ - `stream`: false → one `chat.completion` JSON; true → Server-Sent
52+ Events, `chat.completion.chunk` deltas, then `data: [DONE]`.
53+ `stream_options.include_usage` adds the usage chunk.
54+ - `model`: accepted if it names this agent (see /v1/models), refused
55+ otherwise — or ignored (to decide).
56+ - `response_format`: see "Structured output" below.
57+ - `tools` / `tool_choice` from the client: refused (400) — the agent's
58+ tools are its own and run inside mm; the client never sees a tool call.
59+ - `temperature`, `max_tokens`…: passed over the agent's sampling, or
60+ ignored (to decide).
61+ - `GET /v1/models` — one model: this agent (id = `acp.name`, e.g. `bob`),
62+ so clients that list models (Open WebUI) can select it.
63+ - **Cancel**:
64+ - closing the connection (the client stops reading a stream, or gives up
65+ on a request) cancels the turn — the standard behaviour of OpenAI
66+ clients;
67+ - `POST /v1/mm/cancel/{id}` (mm's own extension) cancels a request by id
68+ from elsewhere — another process, a "Stop" button. The id is the
69+ response's `id` (`chatcmpl-…`), also sent at once as an
70+ `X-MM-Request-Id` header, so a non-streaming caller knows it before the
71+ answer;
72+ - a cancelled request ends with `finish_reason: "cancelled"` (stream) or
73+ HTTP 499 / an error body (non-stream) — to decide.
74+ - `GET /v1/mm/health` — up, the agent's name, the model, busy or idle.
75+
76+ ### Structured output
77+ Today `structuredOutput` (Go types in the YAML) turns an agent into a JSON
78+ answerer and FORBIDS tools (config.StructuredOutputConflict). Two levels:
79+ 1. v1: an agent with `structuredOutput` serves JSON answers — the
80+ `content` is the JSON, `response_format` may be omitted; a request
81+ asking `{"type":"json_object"}` or `json_schema` from an agent without
82+ structuredOutput is refused (400) with the reason.
83+ 2. v2: `response_format: {"type":"json_schema", …}` per request, on an
84+ agent WITH tools: the turn runs with its tools, then a last formatting
85+ call turns the answer into the schema. To design.
86+
87+ ### What streams
88+ - The answer's text, as deltas.
89+ - Thinking models: `reasoning_content` deltas (as llama.cpp and DMR send
90+ them), shown only if the client asks — or never (to decide).
91+ - What the agent does meanwhile (tool calls, hooks) is NOT part of the
92+ OpenAI format. Options: nothing (default); mm extension events
93+ (`event: mm.tool` SSE events that OpenAI clients ignore); or short
94+ progress lines in the text — to decide.
95+
96+ ### One turn at a time
97+ mm runs one turn at a time (process-wide active sink, engine not designed
98+ for concurrent turns — the same reason ACP serialises with turnMu), and a
99+ local model usually serves one request at a time anyway. A second request
100+ waits in a short queue, or gets 429 + Retry-After when the queue is full
101+ (size to decide, e.g. 4).
102+
103+ ### No human in the loop
104+ Same rules as `mm -p`: tools that would ask for permission run only with
105+ `yolo: true`, otherwise they are refused (the model reads the refusal);
106+ `ask_user` is not available. Hooks run as usual.
107+
108+ ### Sessions
109+ Stateless by default (the client sends the history). With
110+ `sessions.enabled: true`, each request could be saved as a session file —
111+ or an `X-MM-Session` header could continue a stored session on the server
112+ side (to decide; not needed by OpenAI clients).
113+
114+ ### Errors
115+ OpenAI's error shape: `{"error": {"message", "type", "code"}}` with 400
116+ (bad request), 401, 404, 429, 500, 503 (model server down — engine.Explain's
117+ line as the message).
118+
119+ ## How to check it
120+ curl (streaming and not), the official `openai` Python client
121+ (`base_url="http://127.0.0.1:8080/v1"`), Open WebUI pointed at it, a cancel
122+ from a second terminal; a structured agent answered by `jq`. A demo in
123+ demos/ with a small model, measured.
124+
125+ ## Open questions for the user
126+ - A client `system` message: append after the agent's prompt, or refuse?
127+ - Client sampling (`temperature`, `max_tokens`): honour or ignore?
128+ - Show tool activity while streaming (mm extension events), or nothing?
129+ - Cancelled non-streaming request: which HTTP answer?
130+ - Sessions: stateless only, or save / continue sessions server-side?
131+tasks:
132+ - id: 1
133+ title: "Agree on the open questions (system message, sampling, tool activity in the stream, cancelled status, sessions)"
134+ state: open
135+ priority: none
136+ author:
137+ name: k33g
138+ email: ph.charriere@gmail.com
139+ createdAt: 2026-10-21T14:00:00.000Z
140+ updatedAt: 2026-10-21T14:00:00.000Z
141+ - id: 2
142+ title: "mm -serve / serve: block (port, host 127.0.0.1, optional apiKey); GET /v1/models and /v1/mm/health — with tests"
143+ state: open
144+ priority: none
145+ author:
146+ name: k33g
147+ email: ph.charriere@gmail.com
148+ createdAt: 2026-10-21T14:00:00.000Z
149+ updatedAt: 2026-10-21T14:00:00.000Z
150+ - id: 3
151+ title: "POST /v1/chat/completions non-streaming: last user message = prompt, history from messages, the agent's turn as in mm -p, OpenAI response and errors — with tests"
152+ state: open
153+ priority: none
154+ author:
155+ name: k33g
156+ email: ph.charriere@gmail.com
157+ createdAt: 2026-10-21T14:00:00.000Z
158+ updatedAt: 2026-10-21T14:00:00.000Z
159+ - id: 4
160+ title: "Streaming: SSE chat.completion.chunk deltas, [DONE], include_usage — a ui.Sink writing the stream — with tests"
161+ state: open
162+ priority: none
163+ author:
164+ name: k33g
165+ email: ph.charriere@gmail.com
166+ createdAt: 2026-10-21T14:00:00.000Z
167+ updatedAt: 2026-10-21T14:00:00.000Z
168+ - id: 5
169+ title: "Cancel: client disconnect cancels the turn; POST /v1/mm/cancel/{id} + X-MM-Request-Id; one turn at a time with a short queue / 429 — with tests"
170+ state: open
171+ priority: none
172+ author:
173+ name: k33g
174+ email: ph.charriere@gmail.com
175+ createdAt: 2026-10-21T14:00:00.000Z
176+ updatedAt: 2026-10-21T14:00:00.000Z
177+ - id: 6
178+ title: "Structured output v1: an agent with structuredOutput answers JSON; json response_format refused on an agent without it — with tests"
179+ state: open
180+ priority: none
181+ author:
182+ name: k33g
183+ email: ph.charriere@gmail.com
184+ createdAt: 2026-10-21T14:00:00.000Z
185+ updatedAt: 2026-10-21T14:00:00.000Z
186+ - id: 7
187+ title: "Check with curl, the openai Python client, Open WebUI; a measured demo; docs EN+FR (how-to, reference, explanation)"
188+ state: open
189+ priority: none
190+ author:
191+ name: k33g
192+ email: ph.charriere@gmail.com
193+ createdAt: 2026-10-21T14:00:00.000Z
194+ updatedAt: 2026-10-21T14:00:00.000Z
195+ - id: 8
196+ title: "Later (v2): per-request response_format json_schema on an agent with tools (a formatting call after the turn)"
197+ state: open
198+ priority: none
199+ author:
200+ name: k33g
201+ email: ph.charriere@gmail.com
202+ createdAt: 2026-10-21T14:00:00.000Z
203+ updatedAt: 2026-10-21T14:00:00.000Z
204+comments: []
new file mode 100644
@@ -0,0 +1,204 @@
1+# Managed by IssueSpec. Hand edits are welcome; keep the schema valid.
2+id: 114
3+title: "OpenAI-compatible HTTP service: each mm instance answers prompts on its own port (stream, non-stream, structured output, cancel)"
4+state: open
5+author:
6+ name: k33g
7+ email: ph.charriere@gmail.com
8+createdAt: 2026-10-21T14:00:00.000Z
9+updatedAt: 2026-10-21T14:00:00.000Z
10+labels:
11+ - kind::feature
12+milestone: v1.0.0
13+epic: Mini Me as a service
14+related:
15+ - 113
16+ - 71
17+ - 89
18+body: |
19+ An OpenAI-compatible HTTP service in front of ONE mini-me agent: what
20+ `mm -p` does — one prompt in, the agent's turn (its tools, skills, hooks
21+ run inside mm), the answer out — but over HTTP, so any program, or any
22+ OpenAI client, can use the agent. Epic "Mini Me as a service"; the first
23+ concrete step of ticket 113.
24+
25+ ## The user's requirements (2026-10-21)
26+ - local use;
27+ - each mini-me instance exposes a web service on its own port;
28+ - the service is the equivalent of the user's prompt — like `mm -p`;
29+ - structured output must be possible;
30+ - answers in streaming AND non-streaming mode;
31+ - a cancel API.
32+
33+ ## Proposal (to confirm)
34+
35+ ### Start
36+ - `mm -serve 8080 agent.yaml` (flag) or a `serve:` block in the YAML
37+ (`port`, `host`). Default host 127.0.0.1: local only; another host must
38+ be asked for explicitly. One agent per instance, one port per instance —
39+ several agents = several `mm -serve` on several ports.
40+ - Optional `serve.apiKey`: when set, requests must carry
41+ `Authorization: Bearer <key>` (OpenAI clients already send one); 401
42+ otherwise. Even on 127.0.0.1, other local processes can reach the port.
43+
44+ ### Endpoints
45+ - `POST /v1/chat/completions` — the prompt. From the request:
46+ - `messages`: the LAST user message is the prompt; earlier user/assistant
47+ messages are the conversation so far (stateless, as OpenAI clients
48+ expect: they resend the history each time). The agent's own system
49+ prompt stays first; a client `system` message is appended after it
50+ (or refused — to decide).
51+ - `stream`: false → one `chat.completion` JSON; true → Server-Sent
52+ Events, `chat.completion.chunk` deltas, then `data: [DONE]`.
53+ `stream_options.include_usage` adds the usage chunk.
54+ - `model`: accepted if it names this agent (see /v1/models), refused
55+ otherwise — or ignored (to decide).
56+ - `response_format`: see "Structured output" below.
57+ - `tools` / `tool_choice` from the client: refused (400) — the agent's
58+ tools are its own and run inside mm; the client never sees a tool call.
59+ - `temperature`, `max_tokens`…: passed over the agent's sampling, or
60+ ignored (to decide).
61+ - `GET /v1/models` — one model: this agent (id = `acp.name`, e.g. `bob`),
62+ so clients that list models (Open WebUI) can select it.
63+ - **Cancel**:
64+ - closing the connection (the client stops reading a stream, or gives up
65+ on a request) cancels the turn — the standard behaviour of OpenAI
66+ clients;
67+ - `POST /v1/mm/cancel/{id}` (mm's own extension) cancels a request by id
68+ from elsewhere — another process, a "Stop" button. The id is the
69+ response's `id` (`chatcmpl-…`), also sent at once as an
70+ `X-MM-Request-Id` header, so a non-streaming caller knows it before the
71+ answer;
72+ - a cancelled request ends with `finish_reason: "cancelled"` (stream) or
73+ HTTP 499 / an error body (non-stream) — to decide.
74+ - `GET /v1/mm/health` — up, the agent's name, the model, busy or idle.
75+
76+ ### Structured output
77+ Today `structuredOutput` (Go types in the YAML) turns an agent into a JSON
78+ answerer and FORBIDS tools (config.StructuredOutputConflict). Two levels:
79+ 1. v1: an agent with `structuredOutput` serves JSON answers — the
80+ `content` is the JSON, `response_format` may be omitted; a request
81+ asking `{"type":"json_object"}` or `json_schema` from an agent without
82+ structuredOutput is refused (400) with the reason.
83+ 2. v2: `response_format: {"type":"json_schema", …}` per request, on an
84+ agent WITH tools: the turn runs with its tools, then a last formatting
85+ call turns the answer into the schema. To design.
86+
87+ ### What streams
88+ - The answer's text, as deltas.
89+ - Thinking models: `reasoning_content` deltas (as llama.cpp and DMR send
90+ them), shown only if the client asks — or never (to decide).
91+ - What the agent does meanwhile (tool calls, hooks) is NOT part of the
92+ OpenAI format. Options: nothing (default); mm extension events
93+ (`event: mm.tool` SSE events that OpenAI clients ignore); or short
94+ progress lines in the text — to decide.
95+
96+ ### One turn at a time
97+ mm runs one turn at a time (process-wide active sink, engine not designed
98+ for concurrent turns — the same reason ACP serialises with turnMu), and a
99+ local model usually serves one request at a time anyway. A second request
100+ waits in a short queue, or gets 429 + Retry-After when the queue is full
101+ (size to decide, e.g. 4).
102+
103+ ### No human in the loop
104+ Same rules as `mm -p`: tools that would ask for permission run only with
105+ `yolo: true`, otherwise they are refused (the model reads the refusal);
106+ `ask_user` is not available. Hooks run as usual.
107+
108+ ### Sessions
109+ Stateless by default (the client sends the history). With
110+ `sessions.enabled: true`, each request could be saved as a session file —
111+ or an `X-MM-Session` header could continue a stored session on the server
112+ side (to decide; not needed by OpenAI clients).
113+
114+ ### Errors
115+ OpenAI's error shape: `{"error": {"message", "type", "code"}}` with 400
116+ (bad request), 401, 404, 429, 500, 503 (model server down — engine.Explain's
117+ line as the message).
118+
119+ ## How to check it
120+ curl (streaming and not), the official `openai` Python client
121+ (`base_url="http://127.0.0.1:8080/v1"`), Open WebUI pointed at it, a cancel
122+ from a second terminal; a structured agent answered by `jq`. A demo in
123+ demos/ with a small model, measured.
124+
125+ ## Open questions for the user
126+ - A client `system` message: append after the agent's prompt, or refuse?
127+ - Client sampling (`temperature`, `max_tokens`): honour or ignore?
128+ - Show tool activity while streaming (mm extension events), or nothing?
129+ - Cancelled non-streaming request: which HTTP answer?
130+ - Sessions: stateless only, or save / continue sessions server-side?
131+tasks:
132+ - id: 1
133+ title: "Agree on the open questions (system message, sampling, tool activity in the stream, cancelled status, sessions)"
134+ state: open
135+ priority: none
136+ author:
137+ name: k33g
138+ email: ph.charriere@gmail.com
139+ createdAt: 2026-10-21T14:00:00.000Z
140+ updatedAt: 2026-10-21T14:00:00.000Z
141+ - id: 2
142+ title: "mm -serve / serve: block (port, host 127.0.0.1, optional apiKey); GET /v1/models and /v1/mm/health — with tests"
143+ state: open
144+ priority: none
145+ author:
146+ name: k33g
147+ email: ph.charriere@gmail.com
148+ createdAt: 2026-10-21T14:00:00.000Z
149+ updatedAt: 2026-10-21T14:00:00.000Z
150+ - id: 3
151+ title: "POST /v1/chat/completions non-streaming: last user message = prompt, history from messages, the agent's turn as in mm -p, OpenAI response and errors — with tests"
152+ state: open
153+ priority: none
154+ author:
155+ name: k33g
156+ email: ph.charriere@gmail.com
157+ createdAt: 2026-10-21T14:00:00.000Z
158+ updatedAt: 2026-10-21T14:00:00.000Z
159+ - id: 4
160+ title: "Streaming: SSE chat.completion.chunk deltas, [DONE], include_usage — a ui.Sink writing the stream — with tests"
161+ state: open
162+ priority: none
163+ author:
164+ name: k33g
165+ email: ph.charriere@gmail.com
166+ createdAt: 2026-10-21T14:00:00.000Z
167+ updatedAt: 2026-10-21T14:00:00.000Z
168+ - id: 5
169+ title: "Cancel: client disconnect cancels the turn; POST /v1/mm/cancel/{id} + X-MM-Request-Id; one turn at a time with a short queue / 429 — with tests"
170+ state: open
171+ priority: none
172+ author:
173+ name: k33g
174+ email: ph.charriere@gmail.com
175+ createdAt: 2026-10-21T14:00:00.000Z
176+ updatedAt: 2026-10-21T14:00:00.000Z
177+ - id: 6
178+ title: "Structured output v1: an agent with structuredOutput answers JSON; json response_format refused on an agent without it — with tests"
179+ state: open
180+ priority: none
181+ author:
182+ name: k33g
183+ email: ph.charriere@gmail.com
184+ createdAt: 2026-10-21T14:00:00.000Z
185+ updatedAt: 2026-10-21T14:00:00.000Z
186+ - id: 7
187+ title: "Check with curl, the openai Python client, Open WebUI; a measured demo; docs EN+FR (how-to, reference, explanation)"
188+ state: open
189+ priority: none
190+ author:
191+ name: k33g
192+ email: ph.charriere@gmail.com
193+ createdAt: 2026-10-21T14:00:00.000Z
194+ updatedAt: 2026-10-21T14:00:00.000Z
195+ - id: 8
196+ title: "Later (v2): per-request response_format json_schema on an agent with tools (a formatting call after the turn)"
197+ state: open
198+ priority: none
199+ author:
200+ name: k33g
201+ email: ph.charriere@gmail.com
202+ createdAt: 2026-10-21T14:00:00.000Z
203+ updatedAt: 2026-10-21T14:00:00.000Z
204+comments: []