docs(adr): ADR 0021, chat completions' dialects and the Responses API (D45, D46)
D45: chat completions in each known host's dialect (OpenAI, Mistral, Gemini, OpenRouter), in a common one to every other host. D46: OpenAI's Responses API as a third protocol, stateless, its encrypted reasoning sent back. D30's field at OpenAI is safety_identifier, at OpenRouter user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
115683e180
commit
e4c7259df3
1 changed files with 24 additions and 7 deletions
|
|
@ -5,7 +5,7 @@
|
|||
keeps and does, where it lives, the proposal's points 4–8 and 10, how often it warns and
|
||||
when it is built (D13–D18), who signs up and who operates (D19–D22), waiting accounts
|
||||
(D23–D26), what people are told and what never goes (D27–D30), how the first step is
|
||||
built (D31–D34) and the second (D35–D44).
|
||||
built (D31–D34) and the second (D35–D46).
|
||||
- **Builds on:** ADR 0016 (the register), ADR 0019 (private studysets), ADR 0020
|
||||
(SimpleLogin), ADR 0022 (the hand-off and the connector gone).
|
||||
- **Changes:** the rule of 10 Oct 2026 that Halkyon calls no language model with an API
|
||||
|
|
@ -172,7 +172,8 @@ including/excluding private studysets?)"):
|
|||
the person's own to send.
|
||||
- **D30 The provider learns an opaque ID per person** (recommended, over nothing): with the
|
||||
operator's key, each request carries an ID the instance derives from the account with a
|
||||
key of its own (OpenAI's `user`, Anthropic's `metadata.user_id`), never the handle, so
|
||||
key of its own (OpenAI's `safety_identifier`, OpenRouter's `user`, Anthropic's
|
||||
`metadata.user_id`; servers with no such field get none), never the handle, so
|
||||
the provider can act against one person's abuse without blocking the operator's key,
|
||||
and can't tell who it is.
|
||||
|
||||
|
|
@ -289,6 +290,22 @@ On 25 Oct, how the second step is built (the assistants, their grants and figure
|
|||
- **D44 Nobody is granted an assistant that isn't set**: a grant names the assistant by
|
||||
its ID, and stays, unused, should the operator remove that assistant from the file;
|
||||
put back, it holds again, with the person's agreement if the provider is the same.
|
||||
- **D45 Chat completions are sent in each known host's dialect, and in a common one to
|
||||
every other** (recommended, over the fields every service takes, which loses OpenAI's
|
||||
`store: false` and its reasoning models' ceiling, and over a dialect the operator
|
||||
names): OpenAI, Mistral and Gemini refuse a field they don't know, and they differ in
|
||||
the ceiling's field (`max_completion_tokens`, `max_tokens`), in usage asked for or
|
||||
always sent, and in `store`. By the base URL's host, OpenAI (api.openai.com), Mistral,
|
||||
Gemini and OpenRouter each get only their fields; any other host gets what Ollama,
|
||||
vLLM and llama.cpp all take. Replies are read leniently whatever the host, as each
|
||||
streams usage, tool calls and errors in its own way.
|
||||
- **D46 OpenAI's Responses API is a third protocol, `openai-responses`** (recommended,
|
||||
over chat completions alone): from GPT-5.4 on, OpenAI's models call tools in chat
|
||||
completions only without reasoning, and GPT-6 Astra and 6.1 Sol only through the
|
||||
Responses API. Stateless: `store: false`, so OpenAI keeps no conversation, and each
|
||||
request carries the whole of it, with the model's encrypted reasoning items as it
|
||||
streamed them, sent back in their place (as Anthropic's thinking blocks are), and the
|
||||
`phase` of its messages. Ollama, vLLM and OpenRouter speak it as well.
|
||||
|
||||
## Proposal
|
||||
|
||||
|
|
@ -306,19 +323,19 @@ On 25 Oct, how the second step is built (the assistants, their grants and figure
|
|||
the list. The operator's app shows a badge; there is no mail, as the instance keeps no
|
||||
addresses.
|
||||
4. **The assistants**, set by the operator (D4): one or more, each with an ID, the name
|
||||
people see ("Claude Sonnet"), its protocol (`anthropic`, or `openai` for every
|
||||
OpenAI-compatible service), its base URL (the provider's own unless set), model and key
|
||||
people see ("Claude Sonnet"), its protocol (`anthropic`, `openai` for every
|
||||
OpenAI-compatible service, or `openai-responses`, D46), its base URL (the provider's own unless set), model and key
|
||||
in `deploy/assistants.env` (D37: `ASSISTANTS=claude,gpt`, then `ASSISTANT_CLAUDE_NAME`,
|
||||
`_PROTOCOL`, `_BASE_URL`, `_MODEL`, `_KEY`, `_IMAGES`, and the prices of D38). There
|
||||
rather than in the app: the keys stay out of the database and its hourly backups, where
|
||||
the operator keeps the instance's other secrets. None set: no assistant on the
|
||||
instance, as today. Adding Lumo once its API is out, or switching a model, is a change
|
||||
of these and a restart; no app changes.
|
||||
5. **Two adapters of our own** behind one interface, over plain HTTP, no SDKs, in a pure
|
||||
5. **Adapters of our own, one per protocol (D46),** behind one interface, over plain HTTP, no SDKs, in a pure
|
||||
Dart package of their own, which the server uses for the operator's assistants and the
|
||||
app for personal keys (10). Features use only what both protocols share: a system prompt and messages,
|
||||
streamed text, and tool calls where a feature needs them. Tested against recorded
|
||||
replies of each. Not chosen: LiteLLM as a sidecar (a Python proxy for about 100
|
||||
streamed text, and tool calls where a feature needs them. Tested against documented
|
||||
and recorded replies of each (D36). Not chosen: LiteLLM as a sidecar (a Python proxy for about 100
|
||||
providers: one more container to run and update, for providers never used) and
|
||||
langchain_dart (a large framework for a small job).
|
||||
6. **Grants** (D2, D4): nobody has an assistant until the operator grants it to them, one
|
||||
|
|
|
|||
Loading…
Reference in a new issue