Files
odysseus/specs/model-quirks.md
T
RaresKeYandStressTestor 7026cf40b5 docs: bootstrap specs ground truth (#5794)
* docs(specs): restore bootstrap after dev rewrite

* docs(specs): remove runtime inventory snapshot

* docs(specs): reconcile current dev truth

* docs(specs): document scheduled task actions as an owner-attribution source

Owner Attribution covered cookie, bearer-token and internal-loopback
requests. Scheduled task actions are a fourth source and behave
differently: _execute_action passes owner=task.owner off the stored
ScheduledTask row, so no request and no resolved principal are in
flight, and route-level require_user() never runs.

Webhook triggers are the sharp case. They are unauthenticated by
design with the token as the only credential and execute under the
stored task.owner.

Paths cite routes/task/task_routes.py, the canonical location after
the task subpackage move (#6081); routes/task_routes.py on current dev
is the backward-compat shim.

* docs(specs): add chained tasks to the trigger list, refresh dev stamp

Review feedback from RaresKeY on the previous commit.

"Every trigger path" was too broad: success-chained tasks are another
path into _execute_action. Added them with their own citation, and
noted that chaining additionally requires the target task to share
task.owner and rejects cycles, which is stricter than the trigger-side
checks. Softened the lead-in to "these trigger paths".

Line 56 still pointed at routes/task_routes.py for webhook credential
validation. That path is the backward-compat shim on current dev after
the task subpackage move (#6081); repointed to the canonical
routes/task/task_routes.py.

Stamp moved to dev@2a6b09b. Inspection backing that bump was scoped:
every file path cited in this spec was mechanically checked to resolve
on 2a6b09b, and every file:line in the Owner Attribution additions was
read against it. Behavioral claims elsewhere in the file were not
re-audited.

* docs(specs): correct SECURE_COOKIES description to match current behavior

Third of the stale details RaresKeY enumerated. The cookie section
described SECURE_COOKIES as purely opt-in, which stopped being true.

_secure_cookie() (routes/auth_routes.py:89) treats an explicit true or
false as authoritative and derives the Secure attribute from the
request otherwise, including when the variable is unset and when
docker-compose injects it present-but-empty. Either the connection
scheme or the first X-Forwarded-Proto hop being https is enough.

* docs(specs): refresh current dev truth

---------

Co-authored-by: StressTestor <212606152+StressTestor@users.noreply.github.com>
2026-08-25 14:18:44 +02:00

5.7 KiB

Model Behavior Observations

Last updated: dev@2e2bb52 | 2026-08-16

Scope

This file records model- or provider+model-specific behavior observed in Odysseus code, tests, Issues, PRs, commits, and provider documentation. It is a compact evidence map, not a runtime matcher. General canonical rules belong in model-capability-canonical.md; provider-wide transport belongs in the provider map.

The canonical capability layer intentionally has no src/model_behavior_quirks.py. Adding a registry before runtime call sites carry structured provider, model, version, and dialect identity would create another model-name matching layer.

General Observation Template

Record only the fields supported by the evidence:

  • provider and endpoint/dialect scope;
  • exact provider-returned model ID or family;
  • structured model/provider version when available;
  • capability or request/response behavior observed;
  • exact native request field/value and response field when relevant;
  • source, confidence, status, and reproduction date;
  • whether the behavior is already implemented in runtime code.

If exact structured identity is unavailable, keep the observation here and in its current tested runtime location. Do not promote it through substring, regex, prose, or serialized-prompt parsing in the canonical layer.

Model-Specific Observation Map

Observation Scope Behavior Evidence/status
Moonshot Kimi K2.5/K2.6 fixed temperature official Moonshot, K2.5/K2.6, OpenAI Chat omit temperature; thinking mode owns its fixed value #3960, f5d3e509; implemented in current runtime
Moonshot reasoning tool history same provider/models/dialect preserve assistant reasoning_content across tool continuation #3118, 2e6fff22; implemented
Claude Opus 4.7+ sampling omission Anthropic Messages, Opus 4.7+ and major-only later IDs such as claude-opus-5 omit temperature, top_p, and top_k where the runtime rule applies #3117, 4f48cfa9, #5761; implemented through current runtime identity logic
Mistral structured reasoning reasoning-capable Mistral model through native/compatible response shape use graded effort where accepted; keep typed thinking separate from text #4698, bd9149f7, provider docs; partly implemented
Ollama native reasoning control selected reasoning model/deployment native think; reasoning in message.thinking/thinking #3031 and provider docs; deployment scoped
Ollama native gpt-oss reasoning level gpt-oss served through Ollama native think accepts low/medium/high and does not represent off provider docs; deployment scoped
Ollama compatibility disable observation Ollama 0.20.6+, observed Qwen3.5 compatibility path reasoning_effort: none was reported to disable reasoning #5503; unmerged/low confidence until reproduced

Issue and commit references are evidence identifiers, not runtime dependencies. Open or unmerged observations remain provisional until reproduced or supported by current provider documentation.

Other Model-Level Observations

  • Kimi K2.5/K2.6 multimodality differs from older K2 variants (#2522). Promote only from an exact provider card or scoped registry, never the kimi token.
  • Google product names suggest media tasks to humans, but its Models resource does not publish complete modalities. Keep those modalities unknown without stronger model-scoped evidence.
  • Ollama /api/tags names can omit vision markers (#3743, #4487). Use selected model /api/show.capabilities, not its name.
  • Local reasoning controls vary by serving template/config: message/system directives, chat_template_kwargs.enable_thinking, native booleans, structured objects, budgets, and effort levels were all observed (#3031). These are endpoint/deployment facts, not universal checkpoint properties.
  • DeepSeek, vLLM/NIM, Mistral, Moonshot, Ollama, and harmony-style servers use different structured reasoning channels. Provider/dialect evidence chooses the channel; generic response-text scanning is not capability discovery.
  • Current runtime recognizes DeepSeek V4 identifiers in its thinking-model patterns; that is request/response handling evidence, not proof that every V4-named endpoint exposes identical capabilities.
  • GPT-OSS deployments can reserve native tool names. Runtime aliases colliding Odysseus tool names at the provider boundary and reverses the alias before local execution; this is dialect compatibility, not extra tool authorization.
  • Cohere native and compatibility transports expose different thinking controls/channels. The Cohere model list does not itself prove reasoning.
  • MiniMax M2.7 exposes different thinking channels through Anthropic and OpenAI-compatible transports. Its current model list is identity-only.
  • Gemma/Phi/Qwen vision behavior has changed across serving engines (#1430, #1704, #1478). Native engine metadata or a verified endpoint probe outranks a model-family name list.

Promotion Gate

Before an observation becomes canonical runtime behavior, a consumer must already have the necessary structured identity and tests must cover both its positive scope and a neighboring negative scope. Request control and response visibility remain separate: hiding reasoning text is not the same as disabling reasoning at the provider (#2905).

Current Gaps

  • Runtime still contains model-name helpers for several implemented behaviors; this spec records them but the canonical catalog does not duplicate them.
  • Hosted aliases and provider behavior can change; there is no durable observation expiry/revalidation layer yet.
  • Detail/probe-only model facts cannot safely be populated from list discovery.