Commit Graph
475 Commits
Author SHA1 Message Date
MelekiandClaude Opus 4.8 4d29b09488 MCP-Server: URL optional – URL-lose Einträge als reine Allowlist-Freigabe
Entkoppelt "Server erzeugen" von "Server erlauben": Ein MCP-Eintrag ohne
URL erzeugt keinen eigenen (kollidierenden) HTTP-Server mehr, steuert aber
weiterhin die Allowlist-Freigabe mcp__<name>__* bei. Gedacht für extern
(z.B. stdio via ~/.claude.json) laufende Server, die gott nur erlauben,
aber nicht selbst starten soll – sonst kollidiert gotts URL-Server mit dem
gleichnamigen externen und der Server verschwindet ganz.

- ParseMcpServers: Url optional (null erlaubt), nur Name+leer wird verworfen
- Frontend: Name genügt, URL-Placeholder + Hinweistext angepasst

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 19:11:34 +02:00
MelekiandClaude Opus 4.8 9d21138e62 Fix MCP-Allowlist: exakte Server-Form mcp__<name>__* statt nie-matchendem Glob
Die Claude-CLI-Permission-Engine parst eine Allowlist-Regel via split("__")
zu {serverName, toolName} und vergleicht den Servernamen per strenger
Gleichheit (===); ein '*' wirkt ausschliesslich im Tool-Teil, nie im
Server-Teil. Die generalisierte Form "mcp__*<name>*" parste damit zu einem
Server namens "*<name>*" und matchte NIE -> jeder ueber die MCP-Liste
eingetragene Server wurde headless still abgelehnt (Regression aus 5f7dec6).

- ClaudeCliService.cs: Allowlist-Glob mcp__*<name>* -> mcp__<name>__*
  (exakter Server + Tool-Wildcard, dieselbe Form wie mcp__web-search-prime__*);
  Kommentar erklaert die strenge Server-Gleichheit.
- index.html: UI-Hinweis korrigiert - Name muss exakt dem Tool-Praefix
  entsprechen (z.B. UnityMCP, nicht Unity); Freigabe als mcp__<name>__*.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 10:33:17 +02:00
MelekiandClaude Opus 4.8 3ae94fb697 Workflow-Totalverlust beheben: inkrementelle Persistenz + Token-Fix + Resume
Bisher wurden Workflow-Subagent-Outputs nur beim sauberen FinalizeChain in
die DB gerettet - bei Abbruch (529/Timeout/Stop/Hard-Kill) war alles weg,
Tokens standen auf 0.

- A) Inkrementelle Persistenz: MaybeFlushWorkflowProgress() (throttled 6s)
  schreibt workflow_info + Token + runId waehrend des Laufs -> ueberlebt
  Hard-Kill (OOM/Redeploy), wo kein catch/finally laeuft.
- B) Output-Rettung: ReadLive liest jetzt vollstaendige Subagent-Outputs aus
  journal.jsonl (nicht nur Counts), inkl. State.
- C) Token-Fix: neuer assistant-Branch -> CliEventType.Usage; EffectiveUsage()
  rettet Orchestrator-Token bei Abbruch statt 0.
- D) Resume: Feld/Migration workflow_run_id; FinalizeChain persistiert die
  runId; naechster Chat injiziert einen resumeFromRunId-Hinweis.
- UI: Workflow-Status-Modal zeigt geretteten Output + runId/"fortsetzbar"-Banner.

Build 0/0, ReadLive gegen echtes journal.jsonl verifiziert, adversarial 2x geprueft.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 16:14:47 +02:00
MelekiandClaude Opus 4.8 5f7dec6448 Generalize MCP servers, add model refresh button, add sonnet-5
- MCP: replace fixed single Unity field with a generic list of servers
  ({name, url, token?}); dynamic mcp-config + allowlist glob mcp__*<name>*
  per entry; new mcp-servers-ui.js editor (no data migration)
- Models: frontend refresh button wired to existing POST /api/models/refresh,
  reloads optgroups and restores selection
- Model: add sonnet-5 alias + dropdown option (bare "sonnet" stays 4.6)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 08:51:20 +02:00
MelekiandClaude Opus 4.8 1032cd5c63 Unity-MCP: extern benannten Server in headless-Allowlist zulassen
Ergänzt mcp__UnityMCP__* neben mcp__unity__* in der --allowed-tools-Liste
(innerhalb von hasUnityMcp), damit ein unter dem Namen "UnityMCP" statt
"unity" laufender MCP-Server im headless -p-Pfad nicht still abgelehnt wird.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 05:45:09 +02:00
MelekiandClaude Opus 4.8 418a22d18d docs: Kommentar-Schreibweise wf_<runId>.json zu <runId>.json vereinheitlicht
Die runId ist bereits mit "wf_" praefixiert; der Code erzeugt
<proj>/workflows/<runId>.json. Die Kurz-Referenzen in den Code-Kommentaren
(WorkflowProgressTracker, ClaudeCliService, AnthropicService, SessionEndpoint)
nutzten faelschlich das doppelte "wf_"-Praefix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:18:49 +02:00
MelekiandClaude Opus 4.8 2b95161596 Read workflow-status telemetry from CLI transcript files
Dynamic ultracode workflows run as a detached background task with their
own transcript dir, so their subagent events never flow through the main
-p stream. The previous parent_tool_use_id tap therefore captured nothing
for real workflows and the status stayed "none" the whole run.

Replace the tap with a file-based reader:
- TapWorkflowLaunch parses the "Transcript dir:" line from the Workflow
  tool_result and registers the run.
- WorkflowProgressTracker becomes a per-session registry of transcript
  paths (no longer a stream accumulator).
- WorkflowTelemetryReader reads journal.jsonl for live counts (running)
  and <runId>.json for rich per-agent telemetry (completed); FinalizeChain
  persists the rich JSON into chains.workflow_info.
- Modal renders phases + a per-agent list (label/phase/state/tokens/
  tool-calls/duration) instead of the obsolete tool breakdown.

Sync ARCHITECTURE.md, ARCHITECTURE_QUICK.md and README.md to the new
mechanism.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 18:14:42 +02:00
MelekiandClaude Opus 4.8 b6e546f618 Add workflow-status telemetry view and make panel modes on-demand
Workflow-status: a new WorkflowProgressTracker singleton taps the
suppressed dynamic-workflow subagent events (those carrying
parent_tool_use_id) into per-session telemetry without altering the
existing guard; the snapshot is serialized into the new chains.workflow_info
column on FinalizeChain (ChainId-matched so a panel member of the same
session cannot clear it) and exposed via GET /api/sessions/{id}/workflow-status
(live -> persisted -> none). The header menu gains a 'Workflow-Status' entry
with a modal that live-polls every 2s while running and self-stops on close.

Panel on-demand: Fusion/MoA is now a transient per-request multiModelMode
flag (like plan/ultracode) instead of a persisted session column. Session
settings keep only the panel members + moa_layers; the mode <select> was
removed and the composer dropdown drives the mode per request.

Docs: ARCHITECTURE.md, ARCHITECTURE_QUICK.md and README.md updated for both
features plus the already-shipped z.ai/GLM provider, GLM 5.2+ effort
passthrough, web-search-prime MCP and the ultracode toggle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 17:27:46 +02:00
MelekiandClaude Opus 4.8 5b1802efee Replace mode toggle cycle with a dropdown menu
The composite mode control (#planModeBtn) now opens a dropdown menu
instead of cycling, following the emoji-picker pattern: each mode is an
entry with icon + label + description, the active one marked with a
check. Direct jumps between modes are now possible, so selecting
plan/ultracode resets the persisted panel mode to avoid running both the
panel and the CLI worker. Unified the active button states.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 15:57:34 +02:00
MelekiandClaude Opus 4.8 d5854a3f4b Add ultracode toggle that runs a request as a native dynamic workflow
A new transient per-request toggle state (off→plan→ultracode→fusion→moa)
that whitelists the CLI's Workflow + Task tools so Anthropic's native
dynamic-workflow orchestration runs in gott's headless -p mode without a
permission gate (the engine silently denies Workflow otherwise). Effort is
raised to xhigh (the real ultracode equivalent; "ultracode" itself is not a
valid effort value) without downgrading an explicit max. Only enabled for
Claude models (z.ai/GLM has no workflow runtime) and not in plan mode. The
frontend injects a "use a workflow" hint, like plan mode injects its own.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 15:35:38 +02:00
MelekiandClaude Opus 4.8 5418dc9225 Enable GLM web search and 5.2+ effort over the z.ai CLI path
GLM models cannot run Anthropic's server-side WebSearch/WebFetch, so when a
GLM model has web search enabled and ZaiApiKey is set, GenerateMcpConfig
registers z.ai's web_search_prime HTTP MCP server and CreateCliStartInfo
allows mcp__web-search-prime__* while disallowing the native WebSearch/WebFetch
tools — otherwise the model tries the (headless-ungranted) native tool first
and only falls back to the MCP search on the second attempt.

Effort is now passed through for GLM-5.2 and newer (version compare, not a
prefix match, so 5.3/6 are picked up automatically and glm-5.2[1m]/glm-5-turbo
parse correctly); older GLM models still drop CLAUDE_CODE_EFFORT_LEVEL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 14:30:59 +02:00
MelekiandClaude Opus 4.8 0f3d658fd3 Add z.ai/GLM provider via per-process Claude CLI env injection
Route glm:-prefixed models through the CLI/Anthropic path: ResolveModelId
strips the glm: prefix, and CreateCliStartInfo activates the z.ai
Anthropic-compatible endpoint (ANTHROPIC_BASE_URL/AUTH_TOKEN) only for that
process when IsZaiModel matches, leaving every other request's OAuth login
untouched. GLM model list is loaded through the existing model cache and
exposed via /api/models/glm with a "GLM (z.ai)" optgroup in the agent form.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 14:01:43 +02:00
MelekiandClaude Opus 4.8 e6770bb5f8 Fix shared-bot Telegram agent resolution and add effort badge
- TelegramService: build the chat context with the session owner instead
  of the bot owner, so a public/shared bot resolves the agent for foreign
  sessions; credentials/CLI permission stay with the bot owner.
- Agent cards: render an effort badge next to the model badge when an
  agent has an explicit reasoning effort set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 12:56:42 +02:00
MelekiandClaude Opus 4.8 e395927a67 Send cronjob result and notify-agent reaction to Telegram
The cronjob notification ran the notify-agent on the result summary and
sent only its reaction to Telegram. When the agent merely acknowledged the
summary (e.g. "👍"), the actual cronjob result never reached Telegram —
the user got a header plus an emoji and no information.

Send the real result as the guaranteed first Telegram message, then run
the notify-agent best-effort and send its reaction as a separate second
message. The agent run is wrapped in try/catch with a canRunNotifyAgent
guard instead of the old return-aborts, so a missing key / OpenAI without
key / unavailable CLI only skips the reaction — the result is already
delivered. The notify-agent still persists its reaction to the web history
automatically (ChatNonStreaming / ChatNonStreamingViaCli).

TelegramService.SendNotification now uses SendLongMessage so long results
are chunked into 4096-char messages instead of being rejected whole.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:45:00 +02:00
MelekiandClaude Opus 4.8 6e301b7498 Document panel subagent filtering, token badges, and CLI fallback reach
Bring the docs in line with the recently shipped features:

- Multi-model panel: all MoA rounds are now persisted (F5-safe) with a
  per-member JSON transcript (layer/totalLayers/segments); member tokens
  are folded into the worker usage via seedUsage (live badge + DB).
- CLI parser filters subagent internals centrally via the
  parent_tool_use_id guard → no nameless tool boxes in stream or history.
- Per-member token badges: panel_member_done and the persisted JSON carry
  the token fields, rendered by the shared buildPanelMemberMeta helper.
- Composer toggle: _modePersist serializes mode PATCHes and sendMessage
  awaits them, preventing the MoA single-round race.
- CLI fallback now also covers cronjobs and Telegram; keyless providers
  (nvidia/gemini/minimax/pollinations) resolve server keys instead of
  hard-failing on a missing user key.
- Krea: one request per image (batchSize no longer sent to the API).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:24:08 +02:00
MelekiandClaude Opus 4.8 8e5a961e94 Show per-member token usage badges on panel bubbles
memberUsage was already populated for CLI members (from the result event)
and Anthropic-API members (via the tool loop), but it was never written to
the panel_member_done SSE event or the persisted content JSON, so the
frontend had no token data to render.

Add the token fields (input/output/cacheRead/cacheCreation) to both the
SSE event and the persisted JSON, and render them via a shared
buildPanelMemberMeta helper used by both the live stream and history, so
the badge survives F5. OpenAI members (no per-turn tokens), error members,
and pre-existing history without token fields fall through to no badge.

The badge is display-only; aggregation into the worker/chain total via
seedUsage is unchanged, so there is no double counting and no DB migration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 17:47:49 +02:00
MelekiandClaude Opus 4.8 17ba4840dd Hide subagent stream events in the CLI parser
When a panel member spawned a subagent via the Agent tool, the Claude CLI
emitted the subagent's internal steps as separate top-level messages
carrying parent_tool_use_id: tool_use blocks arrived as type:"assistant"
(no handler → dropped) and the matching tool_result as type:"user", which
created a nameless, label-less collapsible box in the frontend — both in
the live stream and in the persisted history (same segment source).

Skip any top-level event with a non-empty parent_tool_use_id at the single
stream JSON parser, so subagent internals never become CliStreamEvents.
This covers worker and panel-member paths at once. The Agent tool call
itself (parent_tool_use_id=null) stays visible, and the final result event
— which aggregates subagent tokens — carries no parent_tool_use_id, so the
token balance is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 17:47:41 +02:00
MelekiandClaude Opus 4.8 2501096e19 Fix MoA single-round and writable read-only panel members
Two bugs surfaced when driving the composite toggle (off→plan→fusion→moa)
in an all-CLI setup (no API keys):

1. MoA ran only 1 round instead of the configured 2. cycleCompositeMode
   fired the multiModelMode PATCH un-serialized and sendMessage did not
   await it, so a message sent right after toggling loaded the session
   before 'moa' was committed → the backend read the prior 'fusion' value
   → 1 round. Persisted totalLayers in the DB confirmed fusion (1) for all
   post-toggle chains. Serialize mode PATCHes into a promise chain (last
   click wins, in order) and await it in sendMessage/sendMessageDirect.

2. A read-only panel member could still write files. ClaudeCliService
   hard-coded --permission-mode acceptEdits, which auto-accepts Write/Edit
   regardless of --allowed-tools, so a member running with planMode=true
   (tools limited to Read/Glob/Grep) could still call write_file. Use
   'plan' when planMode is set; this also closes the same latent hole for
   regular plan-mode users on the shared CLI path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:55:25 +02:00
MelekiandClaude Opus 4.8 e3f89043c1 Fix cronjob/telegram fallback for keyless server-key providers
Cronjobs and Telegram bots threw a hard error when an agent had no
assigned user API key, even for providers (nvidia/gemini/minimax/
pollinations) whose server-side key ChatEndpoint resolves automatically
via ResolveProviderConfig. The guard blocked every non-empty provider
instead of only "openai", so e.g. the nvidia agent failed on "Jetzt
ausführen" although the normal chat worked.

Mirror ChatEndpoint's three-way handling at all three sites
(ExecuteCronjob, SendCronjobNotification, TelegramService.HandleMessage):
- Anthropic (empty provider): Claude CLI fallback when permitted/available
- "openai": hard error (no server key, no CLI equivalent)
- other providers: pass through with empty token; server key resolved later

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:25:05 +02:00
MelekiandClaude Opus 4.8 f99c3c1db9 Drop flex container from panel agents card chips
The panel agents card wrapped its agent chips in a display:flex container;
render them in a plain div so they flow naturally with the surrounding
layout instead of being forced onto one flex row.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 08:44:42 +02:00
MelekiandClaude Opus 4.8 5c89adb6df Persist panel member token costs to DB via usage seed
Replace the separate panel_usage SSE event + frontend accumulator with
server-side seeding of the worker's usage object. Both the done-event and
FinalizeChain read from the same usage, so panel (Fusion/MoA) member tokens
now flow into the live badge AND the DB as a single source of truth — the
badge no longer drops to the worker-only value after F5.

- RunPanel takes a TokenUsage usageSink; accumulates member costs after the
  Task.WhenAll barrier (single-threaded, no lock)
- ChatEndpoint passes panelUsage as seedUsage to all three worker paths
- StreamChat / StreamChatViaCli / OpenAI StreamChat fold seedUsage into usage
  at creation time, so every exit path persists it
- OpenAI done-events extended with cacheCreation/cacheRead fields for live
  consistency when seeded by Anthropic members
- chat.js: remove redundant _panelUsage / _addPanelUsage / panel_usage
- TODO.md: mark the live-only v1 boundary closed, note the new mechanism

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 08:44:36 +02:00
MelekiandClaude Opus 4.8 1b203707ec Merge plan and panel toggles into one composer button
The composer had two separate mode buttons (plan + panel). Fold them into a
single #planModeBtn that cycles through every operating mode in one place:
Off -> Plan -> Fusion -> MoA -> Off. Cleaner UI, one affordance instead of two.

Plan stays transient (reset on session switch, never persisted) while
Fusion/MoA persist to the session via apiUpdateSession({multiModelMode}) and
are read server-side from ctx.MultiModelMode. The compat var _planModeActive
is kept in sync (true iff mode === 'plan') so sendMessage and modals.js read
it unchanged. No text label — icon + tint only.

- index.html: drop the separate panel button, reuse #planModeBtn
- chat.css: unified states (plan/fusion/moa tints) on #planModeBtn
- chat.js: cycleCompositeMode / initCompositeMode / _renderCompositeBtn
  replace the split plan/panel functions
- chat-page.js: single wiring block, init from session.multiModelMode
- ARCHITECTURE_QUICK.md: document the unified toggle

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 08:11:13 +02:00
MelekiandClaude Opus 4.8 47557c9724 Include panel member tokens in the chain cost badge
Panel member token usage was tracked but discarded, so the cost badge only
ever showed the worker's tokens — misleading for MoA where the real cost is
roughly rounds x agents. Collect each member's usage and add it to the badge.

Each member fills its own TokenUsage in parallel (Anthropic loop via the
existing memberUsage, CLI via the now-captured CliChatResult return value;
OpenAI members stay null, nachruestbar). RunPanel sums them after the
Task.WhenAll barrier — single-threaded, so no lock or Interlocked needed —
across all MoA rounds and emits a panel_usage SSE event before panel_done.
The frontend adds those tokens onto the worker totals in the done handler so
the badge reflects the full chain cost.

- SseHelper: add TokenUsage.Add()
- AnthropicService.Panel.cs: PanelMemberResult.Usage, accumulate per round
  after the barrier, emit panel_usage; RunPanelMemberViaCli returns usage
- chat.js: _panelUsage state, panel_usage case, add to worker tokens on done,
  reset on stream start
- TODO.md: check off the member-token item

v1 limit: live badge only — FinalizeChain still persists worker tokens, so a
reload shows worker-only cost.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 18:08:55 +02:00
MelekiandClaude Opus 4.8 0f87ccdcab Persist MoA intermediate layers so they survive reload
Previously only the final proposer layer was persisted, so after a reload
the intermediate MoA rounds and their "Runde k/N" dividers were gone — the
history showed only the last refined round, not the full live view. Persist
every proposer round instead, tagging each member's JSON transcript with
its layer index, and rebuild the round structure on reload.

- AnthropicService.Panel.cs: persist every round unconditionally; drop the
  now-dead persist parameter and isFinalLayer local; write layer/totalLayers
  into the transcript; iteration = layer*100+index+1 so DB rows are
  layer-aware (no UNIQUE constraint on chain_id/iteration, id-based ordering)
- history.js: group panel bubbles by layer on reload and insert the
  "Runde k / N" divider on round change for MoA (totalLayers > 1), matching
  the live startPanelLayer view; back-compat for old format (default layer 1)
- TODO.md: check off the MoA persistence item

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 18:03:37 +02:00
MelekiandClaude Opus 4.8 1641bf11b6 Fix Krea image generation by removing unsupported batchSize
Krea removed the batchSize parameter ("Generation batch size is no longer
supported, submit one request per output"), so every image request failed
with HTTP 422 — breaking session/agent avatar generation. Drop batchSize
from the payload and instead send one request per requested image in a
loop, collecting all returned jobs. Endpoint paths, Bearer auth and base
URL are unchanged.

- KreaService: remove batchSize from payload
- KreaService: loop record.BatchSize times, one POST per image, aggregate
  jobs (handles both array and single-object responses)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 17:14:30 +02:00
MelekiandClaude Opus 4.8 c32d1e004f Fix panel member streaming and persist full transcript with images
Three related panel-member improvements:

Tool-box streaming fix: correlate tool boxes by tool ID instead of a
single pointer (fixes orphaned spinners and empty boxes when a member
calls multiple tools in one message), forward CLI ToolEnd to capture the
tool input (command/path), normalize tool names, clean up orphaned
spinners on finalize, and add a blinking cursor during text streaming.

Image/screenshot support: CLI panel members now extract image refs from
the last user message (like the worker) and drop them as temp files
readable via the Read tool, so members can see screenshots and file
attachments instead of being blind on image-based questions.

Reload persistence: each member persists a structured JSON transcript
({name, model, segments:[text|tool]}) instead of plain text, so a reload
restores text AND tool boxes interleaved exactly like live. history.js
renders the transcript and keeps back-compat for the old [Panel: Name]
plaintext format.

- AnthropicService.Agents.cs: NonStreamingLoopCallbacks.TranscriptSink,
  loop collects text/tool segments, tool input added to combined event
- AnthropicService.Panel.cs: CLI member ID-correlation + ToolEnd input +
  image refs + transcript; RunPanelMember persists one JSON transcript
- stream-ui.js: tool boxes keyed by ID, name normalization, cursor,
  orphaned-spinner cleanup
- history.js: render JSON transcript with tool boxes, plaintext fallback

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 16:51:40 +02:00
MelekiandClaude Opus 4.8 aa0b8ee493 Add proposer role prompt to panel members
Panel members run read-only (PlanMode / tool-less) but kept their normal
agent prompt, so they repeatedly attempted write/execute/git actions that
the read-only filter blocks — getting stuck in failing tool loops and
wasting tokens. Append an explicit proposer role clarification to each
member's system prompt so they go straight to analysis + text proposal
and leave the actual writing/committing to the synthesizer agent.

- ChatService: PanelMemberRolePrompt constant (read-only, propose-only)
- PrepareContext: append the role prompt to each panel member's SystemPrompt
- Covers all three provider paths (Anthropic direct, CLI/OpenAI via
  ExtractSystemPromptText)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 14:52:40 +02:00
MelekiandClaude Opus 4.8 b7ff928340 Add Mixture-of-Agents (MoA) mode on top of Fusion
Extend the panel engine with a layer loop: Fusion is one proposer round,
MoA runs N rounds where each round after the first sees the previous
round's responses via <previous_layer_responses> and refines its answer.
Only the final round is persisted; intermediate rounds are live-only.
Rounds are clamped to 1-5.

- SessionRecord + migration: moa_layers column (default 2)
- RunPanel: layer loop with per-member cloned message injection
- CloneForMember / BuildPreviousLayerBlock helpers for member isolation
- SSE: panel_layer_start / panel_layer_done events
- Frontend: layer_index composite keying, round dividers, MoA option
- Docs: ARCHITECTURE + ARCHITECTURE_QUICK updated

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:46:28 +02:00
MelekiandClaude Opus 4.8 f21ed9ff9f Stream panel member responses live with a parallel SSE write-lock
Panel members now stream token-by-token and show tool uses in real time
(like the session agent) instead of delivering text only at completion.
The key constraint is byte-level safety: N members flushing SSE frames
concurrently on the shared HttpResponse would interleave and corrupt the
stream, so a SemaphoreSlim gate serializes the writes (not the model work).

- SseHelper.TryWriteSse takes an optional write-lock (default null, backward
  compatible)
- NonStreamingLoopCallbacks carries SseGate + MemberIndex; _text/_tool/_error
  events are tagged with the member index (review/finalizer stay at -1, no gate)
- CLI members forward TextDelta/ToolStart/ToolResult live instead of
  discarding everything but the final text
- Anthropic-API members stream per tool-round via the loop callbacks; OpenAI
  members fall back to collected text at panel_member_done
- Frontend demuxes by member index into per-bubble interleaved text/tool
  rendering

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:18:13 +02:00
MelekiandClaude Opus 4.8 268f11fa6d Add multi-model panel with Fusion mode
Panel agents answer the user prompt in parallel (read-only, non-streaming);
their responses are merged into the worker's last user message as a
<panel_responses> block, and the session agent synthesizes one final
streamed answer. The RunPanel engine is built layer-ready for future MoA.

- New session fields: multi_model_mode (off/fusion), panel_agent_ids (CSV)
  with idempotent column migration
- New partial Services/AnthropicService.Panel.cs holding the RunPanel engine
- Provider-agnostic members: Anthropic RunNonStreamingToolLoop / OpenAI
  CompleteText / CLI plan-mode; all forced read-only, persisted with Tag=panel
- SSE events: panel_start, panel_member_start, panel_member_done, panel_done
- Frontend: multi-agent picker, live panel bubbles, history rendering
- Graceful degradation: panel errors fall back to worker-only

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 12:55:06 +02:00
MelekiandClaude Opus 4.8 b23eba32b4 Let session owners reassign their session to another user
Previously a session could only be reassigned to another user via a
manual DB UPDATE. This adds it to the session edit UI for every owner of
a session (not just admins) - the ownership check in HandleUpdate
(existing.UserId == userId) already guarantees the caller owns the
session, so handing over one's own session is safe.

Backend:
- ProfileEndpoint: new GET /api/users returning a minimal user directory
  (userId/username/displayName only) for any logged-in user. The
  admin-gated /api/admin/users stays the source for sensitive fields
  (defaultPath/canUseCli/isAdmin).
- SessionEndpoint.HandleUpdate: validate the target user exists (400 if
  not) and pass allowUserReassign: true to UpdateSession.
- DatabaseService.UpdateSession: new allowUserReassign flag; only then is
  a non-empty userId applied as user_id (empty/null is ignored - a
  session must always have an owner).

Frontend:
- index.html: hidden #sessionOwnerRow with a user picker card in the
  session edit form (existing sessions only).
- cards.js: buildUserCard helper for the picker.
- session-page.js: initSessionUserPicker loads users via apiGetUsers(),
  preselects the current owner, and on an actual owner change asks for
  confirmation (irreversible - the session leaves the user's own list).
- api.js: apiGetUsers() -> /api/users.
- ARCHITECTURE.md: document /api/users.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 11:52:53 +02:00
MelekiandClaude Fable 5 483aa471a1 Fix duplicate image display when sending multiple same-named images
Pasted screenshots all share the same filename (e.g. "image.png"), so the
placeholder substitution in _renderUserTextContent resolved every
placeholder to the FIRST matching inline image via find() - showing the
first image N times. Data itself was always correct (DB/agent received
all images; a refresh rendered them properly).

Match images consumingly (findIndex + splice on a copy) instead: labels
and inlineImages are built in the same order, so same-named images now
map one-to-one. Also fix the same latent issue in the legacy attachment
path in history.js (_autoLoadImageAttachments), keeping the shift()
fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 17:14:21 +02:00
MelekiandClaude Fable 5 4e41401f23 Add Claude Fable 5 model option
Adds the new claude-fable-5 model (released 2026-06-09) as a selectable
model alongside the existing Claude models:

- ChatService.ResolveModelId: map "fable" and "fable-5" to claude-fable-5
- index.html: fable-5 option in the model dropdown (after opus-4-8)
- ARCHITECTURE.md: model list + resolution table updated

Default stays opus-4-8. The invite-only sibling Mythos 5 is intentionally
not included.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 06:53:42 +02:00
MelekiandClaude Opus 4.8 1e37f078e0 Resume CLI steering after an ask_user_choice answer
The ask_user_choice MCP tool blocks the CLI process (short-polling
ChoiceAnswers) until the user answers, after which the same
ChatStreamingAsync invocation continues. isUserChoice was set true when
the choice was raised but never reset, so both steering gates (the
tool-boundary kill and the turn-end check, each guarded by
!isUserChoice) stayed blocked for the rest of the run. A message thrown
in after answering was not drained at the next boundary; it lingered in
the queue and only arrived at chain end as a Close() leftover — the user
saw it "come in only at the very end" instead of in between.

Reset isUserChoice (and choiceToolCallId) as soon as the choice tool's
result comes back, before the steering check, so a message injected
during the choice pause takes effect at the next boundary just like
without a preceding choice. As a side effect the stop reason and error
handling after an answered choice are now correct (end_turn / real
errors surfaced) instead of staying awaiting_user_choice. CLI-specific:
the API path finalizes the chain on awaiting_user_choice, so it is
unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 17:46:22 +02:00
MelekiandClaude Opus 4.8 de07b49b67 Persist steering messages that arrive during chain finalization
A steering message confirmed to the user as injected:true could still be
lost: after the loop's last HasPending check it runs out and the chain
finalizes (done event + final messages still streaming — the "few extra
messages" the user sees), then the finally block called Clear() and threw
the queue away. A message arriving in that window was accepted
(IsStreaming still true, Stop runs only in finally) but never drained and
never persisted, so it vanished after F5. Platform-independent; Windows
only widened the window via slower CLI teardown.

Replace the queue with a per-session gated state: Open() at chain start,
Close() at chain end. TryEnqueue() and Close() are mutually exclusive via
a per-session lock, so a confirmed injection can no longer be lost — the
loop either drains it or Close() returns it as leftover. The endpoint now
opens the gate at chain start, uses TryEnqueue as the authoritative check
(false → client resends as a normal message), and in finally closes the
gate and persists any leftover as Type="steer" instead of discarding it,
so it survives F5 and the model sees it on the next message.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 14:50:31 +02:00
MelekiandClaude Opus 4.8 59e25f421c Tell the model to actively resume after a CLI steering restart
After a steering kill-and-restart the new claude child read the
<work_in_progress> transcript, merely acknowledged the injected message,
and ended the turn waiting passively for a background task that no longer
existed (the kill also killed its child background processes). Add an
explicit instruction to the work_in_progress block: actively continue and
finish the task this run instead of just acknowledging, and treat any
previously started background/async operations as gone (restart them if
needed) rather than waiting on them.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 08:07:40 +02:00
MelekiandClaude Opus 4.8 fe18fc324e Set CLI child working directory to the workspace
The Claude CLI child process inherited the gott server's CWD because
CreateCliStartInfo never set WorkingDirectory. On Linux systemd usually
sets WorkingDirectory= to the workspace, so it worked by accident; on
Windows the service starts from its install directory, so the CLI's own
built-in tools resolved relative patterns (e.g. Glob "Sources/**")
against the wrong directory and returned "No files found", while
absolute paths still worked. --add-dir only grants access, it does not
set the CWD.

Thread the workspace through ChatStreamingAsync -> RunCliStreamingAsync
-> CreateCliStartInfo and set psi.WorkingDirectory (guarded by
Directory.Exists). GetStatusAsync stays without a CWD.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 08:07:31 +02:00
MelekiandClaude Opus 4.8 9acf57b032 Simplify steering input placeholder text
Shorten the streaming-mode input placeholder from
"💬 Einwurf an die laufende Arbeit… (Enter)" to a terse "Einwurf...".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:34:14 +02:00
MelekiandClaude Opus 4.8 cf4238859e Fix duplicate messages after entering a running chain
When the chat is opened while a chain is already streaming, the recovery
poll (_streamingPollInterval) is started. Its forced pollHistory(true)
renders the DB messages while the live SSE bubbles render them too — the
live bubbles never advance lastKnownMessageId, so the poll re-fetches the
same assistant message and renders a second bubble.

Make live SSE and the recovery poll mutually exclusive:
- Stop a lingering recovery poll at the start of a real live stream so the
  SSE renders alone.
- Re-ensure the regular (isStreaming-guarded) history polling idempotently
  in the finally block, so it is not left off after entering a running chain.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 08:32:51 +02:00
MelekiandClaude Opus 4.8 f2fd493e5f Add live steering injection into running chains
Let the user inject a message into a running chain instead of only being
able to abort it. While a chain streams, typing + Enter sends the text to
a new /api/chat/steer endpoint; it is drained at the next iteration
boundary, wrapped with a hint so the model actively classifies it
("complements the task -> keep working" vs. "changes course -> adjust"),
and stored as a Type="steer" user message so it survives reload.

Shared infrastructure (provider-agnostic):
- SteeringQueue: out-of-band queue keyed by sessionId, mirrored from
  StreamingTracker (Enqueue/Drain/Clear).
- Program.cs registers it as a singleton and passes it to AnthropicService.
- ChatEndpoint: POST /api/chat/steer enqueues only while IsStreaming,
  Clear() in the finally.
- ChatService.BuildHistoryFromDb groups Type="steer" so no two
  consecutive user turns are produced on re-chat.
- Frontend api.js/chat.js/bubbles.js/history.js + chat.css render the
  optimistic steer bubble and the steer_injected SSE event; Enter during
  a stream sends a steer instead of being blocked.

Anthropic API path:
- Drain point B (tool boundary, merged into the tool_result user turn)
  and C (turn end -> inject + continue instead of finalize).

Claude CLI path (kill-and-restart):
- The agentic loop runs inside the claude child, so true mid-turn inject
  is impossible. On a pending steer the child is killed at the next tool
  boundary, progress is rebuilt from the DB as a <work_in_progress>
  transcript, and the CLI is restarted with the steer appended.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 06:49:58 +02:00
MelekiandClaude Opus 4.8 a58f279eaa Add effort badge to chain summary
Snapshot the agent's effort onto the chain (like model) so it survives
reload, archive and shared chains, then show it in the chain-end meta line.

- ChainRecord.Effort + chains.effort column (TryAddColumn migration).
- CreateChain INSERT carries the value.
- ChatService snapshots agent.Effort at chain creation, but only for Claude
  models – OpenAI providers store '' so there is no misleading badge.
- Anthropic streaming + CLI done-events include effort for the live path.
- chat.js buildMetaBadges renders "Effort: <level>" after the model badge,
  only when a value is set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:08:44 +02:00
MelekiandClaude Opus 4.8 381530dbfe Show reasoning-effort dropdown directly below model selector
Move the effort dropdown out of the collapsed "Weitere Einstellungen"
section to sit right under the model selector, so it is always visible
when configuring an agent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 22:08:37 +02:00
MelekiandClaude Opus 4.7 3f913f14b5 Add per-agent reasoning effort
Opus 4.5+ and Sonnet 4.6+ support a new "effort" knob that controls how
much budget the model spends on thinking and tool calls. Plumb it through
end to end so each agent can pick its own level.

Storage & shape:
- New TEXT column agents.effort (default '') added via TryAddColumn.
- AgentRecord.Effort + INSERT/UPDATE in DatabaseService.Agents.cs.
- ChatContext.Effort + SubAgentContext.Effort so the value travels with the
  request alongside model and tool settings.

Agent editor:
- Effort dropdown above git-commit behavior in the agent form (low/medium/
  high/xhigh/max plus empty = "use default"). Always visible; on OpenAI
  providers the value is sent but silently ignored.
- agent-page.js load/save and AgentEndpoint create/update wired up.

Anthropic API path:
- StreamChat and RunNonStreamingToolLoop add output_config: { effort } when
  effort is set and not "high" – empty/null/"high" means "omit and let the
  API pick its default".
- Sub-agents (preparer/review/finalizer) get the parameter through
  RunAgentChat so each step uses its own agent's effort.

Anthropic CLI path:
- ClaudeCliService.ChatStreamingAsync takes an effort parameter and exports
  CLAUDE_CODE_EFFORT_LEVEL on the spawned process. Env-var beats the
  --effort flag because it also covers "max" and "ultracode".
- StreamChatViaCli, ChatNonStreamingViaCli, RunSubAgentViaCli, and the
  ChatEndpoint anthropic branches all hand the value through.

ARCHITECTURE.md / ARCHITECTURE_QUICK.md updated with the new field.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 21:33:32 +02:00
MelekiandClaude Opus 4.7 88fb3c9867 Add Opus 4.8 model
New Anthropic flagship released 30 May 2026. Adds the dropdown entry as
the new default for fresh agents, maps "opus-4-8" -> "claude-opus-4-8" in
ResolveModelId, and bumps the "opus" alias from 4.7 to 4.8 so the family
shortcut tracks the latest release.

ARCHITECTURE.md updated to list opus-4-8 in both the field reference and the
model-resolution block.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 21:26:13 +02:00
MelekiandClaude Opus 4.7 112fd70f3b Remove obsolete [1m] model variants
Since March 2026 the 1M-token context window is the default for Opus 4.6/4.7
and Sonnet 4.6 – no separate variant or beta header needed. The "[1m]" suffix
on model IDs is dead code now and would even produce HTTP 400 against the
current API.

Cleanup:
- Drop 3 [1m] options from the agent model dropdown; default selection moves
  from opus-4-7[1m] to opus-4-7.
- Drop 5 [1m] mappings from ResolveModelId and add a defensive Replace as a
  safety net for any agent record still holding an old value.
- One-shot startup migration on agents.model + chains.model strips the suffix
  so existing chains can be re-chatted without errors.
- ARCHITECTURE.md reflects the slimmed list and explains why 1M is now default.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 21:25:35 +02:00
MelekiandClaude Opus 4.7 271902f32d feat(telegram): CLI-Fallback bei fehlendem API-Key (analog Web-UI)
Wenn ein Telegram-Bot eine Nachricht empfängt und für den Agent kein
API-Key zugewiesen ist, fiel der Bot bisher hart aus ("Kein API-Key
für diesen Agent zugewiesen"). Im Web-UI wird in dem Fall bereits auf
Claude-CLI zurückgefallen – das macht der Telegram-Pfad jetzt analog.

- AnthropicService.Cli: Neue Methode ChatNonStreamingViaCli(...) für
  Non-SSE-Caller (Telegram). Macht dasselbe wie StreamChatViaCli aber
  ohne SSE: System-Prompt + Auto-Context, History-Kontext-Block, letzte
  User-Message (inkl. Image/PDF-Refs), Text + tool_use + tool_result in
  DB persistieren, finalen Text zurückgeben + FinalizeChain mit echten
  Token-Counts vom CLI-Result.
- TelegramService: Bei userApiKey == null jetzt CanUseCli, IsAdmin und
  IsCliAvailable prüfen. Bei OpenAI-Providern bleibt der Hard-Fail
  (kein CLI-Äquivalent). Spezifische Fehlermeldungen pro Szenario.
  Zusätzlich Schutz gegen leere Antwort.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 20:44:36 +02:00
Meleki 205dbab6a0 fix(anthropic-cli): PDF-Anhänge (type:'document') für CLI-Pfad akzeptieren
Frontend sendet PDFs als type:'document'-Block (chat.js), aber
ExtractLastUserImageRefs filterte nur 'image' und 'file' → PDFs landeten
nie als Temp-Datei im CLI-Workspace und Claude konnte sie nicht per
Read-Tool öffnen.
2026-05-22 21:42:40 +02:00
Meleki 1c9b6e3e63 change message system info font-size 2026-05-14 12:43:31 +02:00
MelekiandClaude Opus 4.6 358d9328be fix(openai): Tool-Calling-Reliability verbessern (maxIterations, forced tool_choice, Thinking-Strip)
- maxIterations aus Server-Settings an OpenAI-StreamChat durchreichen (war hardcoded 10)
- Auto-Continue: tool_choice="required" erzwingt Tool-Call statt erneuter Ankündigung,
  wird nach erfolgreichem Tool-Call wieder auf "auto" zurückgesetzt
- Direktive Continuation-Message statt einfaches "Continue."
- StripOldThinking: <think>-Blöcke aus älteren Assistant-Messages entfernen (nur letzte 4 behalten),
  reduziert Kontext-Inflation die ab ~20k Tokens zu Tool-Call-Degradation führt
- reasoning_split=true entfernt (wird von MiniMax-API ignoriert)
- parallel_tool_calls=false für MiniMax (Streaming, Non-Streaming, Payload-Preview)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-14 12:16:55 +02:00
MelekiandClaude Opus 4.6 0f2f026baa feat(openai): Auto-Continue bei abgebrochenen Action-Ankündigungen + MiniMax-Sampling
MiniMax-M2.7 stoppt häufig nach Action-Ankündigung ohne Tool-Call (z.B. "Lass mich X machen:" → stop).
Auto-Continue erkennt das per Heuristik und injiziert automatisch "Continue." als User-Message (max 3×).
MiniMax-Sampling: temperature=1.0, top_p=0.95 (offizielle Empfehlung für agentic Performance).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-14 11:48:33 +02:00