anomalyco / anomalyco/opencode

[FEATURE]: `/api/experimental/generate` accepts only `{prompt, model}` while `LLM.request` already accepts `system`, `messages` and `generation`

Open
#49,549 0 comments 0 reactions 1 assignee View on GitHub

@jlongster is already working on this.

Since Sep 17, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

The stateless generate endpoint is the only way a plugin can run a model call without
creating a session. It is useful exactly as designed, but it can only send a bare prompt on
default generation settings, and the layer directly beneath it already accepts more.

packages/protocol/src/groups/generate.ts:8-16 defines the payload as:

payload: Schema.Struct({
  prompt: Schema.String,
  model: Model.Ref.pipe(Schema.optional),
}),

packages/core/src/generate.ts forwards exactly those two:

const response = yield* llm.generate(LLM.request({ model: resolved.model, prompt: input.prompt }))

But LLM.request at packages/ai/src/llm.ts:42-62 destructures system, prompt, messages,
tools, toolChoice, generation, providerOptions and http. And prompt is itself sugar
for a single user message (llm.ts:59):

messages: [...(messages?.map(Message.make) ?? []), ...(prompt === undefined ? [] : [Message.user(prompt)])],

The session path already exercises this. packages/core/src/session/model-request.ts:229-231
splits a prepared options object into generation (keys in GenerationOptions.fields) and
providerOptions, and attaches both at :252-253. So the capability is present and used; the
stateless entry simply does not offer it.

Request: widen the generate.text payload to accept messages? and generation?, forwarding
them to the LLM.request call that already accepts them. messages? rather than system?
because a real [system, user] pair is the general shape and prompt is the sugar over it.

Why it matters: a plugin that needs a system prompt today has to concatenate it into the user
turn. For anything calibrated against a fixed system/user split that is a behaviour change, not a
formatting preference. A downstream consumer building on this — the Magic Context plugin — runs a
hidden summarisation pass calibrated on a [system, user] shape at temperature 0.1 with a 32k
output cap; none of those three survive the current payload. Their wire capture against a
two-model mock provider confirms the request goes out with no instructions, no temperature and
no max_output_tokens.

I am happy to open a PR for this if the shape is agreeable.

Separately, and only if you want it answered here: is the /api/experimental/ prefix a
"may change" or a "will be removed" signal? session.import/session.export and
experimental.terminal live under it and look load-bearing, so I would rather ask than assume.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.