Bedrock's Converse API multiplexes Claude, Llama, Titan, Mistral and
others through a single content-block protocol. None of those families
expose a per-message author identity in a unified way, so prefixing in
the text content block keeps multi-user attribution consistent
regardless of which underlying model the request lands on.
buildUserContent now passes msg through messageutil.ApplyUserNamePrefix
before constructing the text ContentBlockMemberText. Tool result paths
go through a separate code path (toolResultBlock) and are unaffected.
Image media handling is unchanged.
Tests:
- buildUserContent with Name set produces the prefixed text block
- buildUserContent without Name preserves byte-identical behavior
- existing image and base64 cases continue to pass
The Bedrock build is gated behind //go:build bedrock so this path is
only exercised in builds that opt in via that tag.
Refs #2702.
Sibling change to the anthropic_messages adapter, this time for the
SDK-based path that talks to the official Anthropic endpoint via
anthropic-sdk-go. The Messages API there is the same shape, so the
fix is identical: wrap user content with messageutil.ApplyUserNamePrefix
when the message carries Name attribution; tool result blocks pass
through unchanged.
The prefix is applied at marshal time only; the persisted message is
not mutated. Existing single-user / direct-channel flows are
unaffected because Name is empty there.
Existing provider tests continue to pass; behavior is exercised by
the messageutil unit tests (which cover ApplyUserNamePrefix
exhaustively) and the agent-level integration tests added earlier.
Refs #2702.
Anthropic's Messages API has no per-message author identity, so the
attribution from Message.Name needs to be rendered into content for
the model to see it. This adapter handles the HTTP path used by
self-hosted and custom Anthropic-compatible endpoints.
User content is wrapped via messageutil.ApplyUserNamePrefix at marshal
time, giving wire payloads like
{"role": "user", "content": "[U_alice] My name is Alice"}
The persisted Message is never mutated; the prefix exists only in the
outgoing request body.
Tool result blocks (msg.ToolCallID set) are explicitly not prefixed
because they are function outputs, not user utterances. Direct
single-user channels see no change because Name is empty there.
Tests cover the four relevant cases: prefix applied, no-name no-prefix,
tool result untouched, and a multi-user history scenario reproducing
the issue #2702 example.
Refs #2702.
SerializeMessages is the wire serializer shared by every OpenAI-style
backend in the project (openai_compat, azure, deepseek, glm, qwen,
groq, and other endpoints that accept the OpenAI Chat Completions
schema). The OpenAI spec defines an optional `name` field on each
message that disambiguates participants in multi-user conversations.
This change adds the field to the openaiMessage wire struct (with
omitempty) and the multipart map branch (only when set), so any
Message.Name produced upstream is forwarded to the model. Sanitization
upstream guarantees the wire-level constraint ^[a-zA-Z0-9_-]{1,64}$,
so backends that strictly enforce it will not reject the request.
Tests cover three properties:
- name appears on the plain-text path when set
- name appears on the multipart-with-media path when set
- both paths omit the field entirely when Name is empty (legacy
single-user channels stay byte-identical on the wire)
Refs #2702.
Two more helpers needed for end-to-end multi-user attribution:
- IsSystemSenderID filters synthetic trigger sources (cron, heartbeat,
async:* tool callbacks, system channel) so internal events do not
surface as distinct human users in the conversation. Without this,
cron-triggered messages would carry attribution like cron, producing
a confusing [cron] [System: cron] ... double prefix on adapters that
fall back to in-content rendering.
- ApplyUserNamePrefix renders msg.Name as a [name] prefix on user
content for adapters whose APIs do not support a per-message author
identity (Anthropic, Bedrock, OpenAI Responses). The persisted
message is never mutated; only the wire payload carries the prefix.
Tool result messages and non-user roles pass through unchanged.
These helpers are pure and independently testable; they will be wired
into the agent and provider adapters in subsequent commits.
Refs #2702.
OpenAI's Chat Completions name field requires ^[a-zA-Z0-9_-]{1,64}$.
Real-world sender IDs (Discord alice#1234, numeric Telegram IDs, Slack
U07AB12C3DEF, free-form CLI names) often violate this, so a sanitizer
sits between the raw inbound ID and any wire payload.
Disallowed characters collapse into a single underscore, leading and
trailing underscores are trimmed, and the result is byte-safely
truncated to 64 (output is pure ASCII).
This helper will be wired into the agent pipeline in a later commit.
Refs #2702.
Adds an optional Name field on providers.Message so per-message sender
attribution can be carried through the persistence layer and onto the
wire. The field is JSON-tagged `name,omitempty`, so:
- the OpenAI Chat Completions wire format will be able to emit the
native `name` field that disambiguates participants in multi-user
conversations;
- session stores that round-trip messages via json.Marshal preserve
the field with no extra plumbing;
- existing session files load cleanly with Name = "".
This is the schema-only change. Adapters and the agent pipeline are
updated in subsequent commits.
Refs #2702.
* refactor: support explicit model list providers
* fix(web): preserve explicit model providers
* fix(web): preserve legacy provider prefixes on model updates
fix(models): normalize explicit provider-prefixed ids
fix(api): preserve legacy model updates across providers
fix(agent): preserve config identity for explicit provider refs
* fix ci
* feat(web): download attachments in frontend
* fix: proxy pico media and force svg downloads
* feat(web): hide ephemeral media refs from persisted session history
* * completed
* * optimzie
* * fix format
* * fix pr check
* try to fix ci
* * Indicates that Windows does not support expos_paths, adding more mount paths for the Linux platform.
* fix isolation startup lifecycle and MCP transport wrapping
* fix isolation startup cleanup and optional Linux mounts
* fix isolation path handling for relative hooks
Preserve relative command and working-directory semantics when Linux isolation wraps subprocesses, and restore absolute argv path exposure to avoid startup regressions. Add hook coverage and docs updates so isolation-enabled process hooks keep working as configured.
* * fix ci
* feat(provider): add Venice AI support and update related documentation
* revert(asr): restore asr files to previous commit
* feat(config): add Venice API base URL and local LM Studio configuration
* fix(config): update Venice API base URL to correct endpoint
* feat(provider): add lmstudio vendor and local no-key behavior
* refactor(provider): consolidate protocol metadata and local tests
* fix(provider): sync lmstudio probing and model normalization
* test(web): format lmstudio model status cases for golines