Skip to content

Releases: oschina/mothx

v1.3.101-pre-3

v1.3.101-pre-3 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 16 Sep 19:26

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.3.101

✨ New Features

  • Serve: Placeholder API Token Warnings

    • mothx serve init-config ships a well-known template token, which is equivalent to publishing the API key once auth is enabled — and nothing said so. The token is now a single named constant (serve.PlaceholderAuthToken) with explicit detection (IsPlaceholderAuthToken/UsesPlaceholderAuthToken), and a replacement warning is printed wherever the template is created (mothx serve init-config and the --init-serve CLI path) and again on mothx serve startup while api.auth.enabled is true and the token is still in place.
    • The startup check only fires for an enabled auth block, so the default template (auth disabled, loopback only) stays quiet and a replaced token is never flagged. serve init-config now writes through the command's own stderr, so the warning travels with the command output.
  • Members Wait for Their Lead on Interactive Surfaces

    • A session that can spawn members but is not bound to an expert team now keeps its run open for still-running members on interactive surfaces (TUI, Web UI, ACP), so a member's completion or question is handled within the same run instead of waiting for the next lead run. Headless and asynchronous sources (CLI, cron, WeChat/Feishu) still end the turn normally and deliver member notifications at their next iteration or next run; a bound expert team always waits.
  • Bound Teams Keep the Full Sub-Agent Tool Set

    • A bound expert team always exposes the complete canonical sub-agent tool set (subagent_spawn, subagent_status, subagent_send, subagent_wait, subagent_answer, subagent_destroy). Per-tool toggles that disable individual sub-agent tools apply only to non-team multi-agent sessions; the team capability is authoritative and never drops tools.
  • New Gitee/Moark Model: deepseek-v4.1-flash

    • Added deepseek-v4.1-flash to the gitee and moark providers with a 1M context window and text+image input; no default max_tokens is sent.
  • New Agnes AI Providers (International + China)

    • Added agnes (https://apihub.agnes-ai.com/v1, ${AGNES_API_KEY}) and agnes-cn (https://api.agnes-ai.cn/v1, ${AGNES_CN_API_KEY}) through a new OpenAI-compatible agnes vendor adapter. Both expose agnes-2.5-flash (200K context), agnes-2.5-pro (256K context), and agnes-3.0-flash (512K context, 65535 max output tokens).
    • Every model is declared reasoning-capable and multimodal (text,image). agnes-2.5-flash and agnes-2.5-pro send no default max_tokens of their own, so the provider default applies; agnes-3.0-flash caps output at 65535 tokens.
  • Cross-Process Notice When a Database Is Rebuilt

    • A process that backs up and rebuilds a database after a schema migration failure now announces it over the existing advisory UDP bus (database_rebuilt). Every other mothx process sharing that session directory retires its cached connection — otherwise it would keep reading and writing the replaced file through its open handle — logs the recovery, and shows the notice to the user in the TUI. The notice carries only the replaced file path; the reason and the backup stay with the recovering process.
    • The bus stays host-only: a directed broadcast on the loopback /8 network that only accepts loopback sources, so it reaches this host's other mothx processes and never leaves the machine.

🐛 Bug Fixes

  • Session Runtime Leases Now Survive Transient Database Stalls

    • Long runs could be interrupted by session runtime lease was lost even when no other process held the session. The per-directory heartbeat scheduler stopped whenever a tick observed an empty directory, even if a lease admitted moments earlier was still live: it left a registered-but-stopped entry in the scheduler registry that no later acquire could replace, so the lease was never renewed again and a later execution-path write found it expired. This was introduced when the per-lease heartbeats were coalesced into one scheduler per session directory.
    • The scheduler now exits only after it has actually unregistered itself for an idle directory, and a renewal that merely times out (a busy or unreachable session database) is retried on the next heartbeat tick instead of being reported as ownership loss. Ownership is decided by the fenced owner/epoch/token CAS, not by wall-clock expiry: taking over bumps the epoch, so a row that expired while still carrying our identity remains ours. Only a genuine fenced takeover or a released lease marks it lost. The heartbeat retry budget is derived from the shared busy_timeout (db.BusyTimeout) so a single tick can absorb a full contended begin, and lease loss is now logged with its reason.
  • Web UI: Knowledge Base Scans Keep Their Status Across Reloads

    • Starting a scan from the Web UI knowledge page blocked the HTTP request until the entire index finished and recorded nothing about the in-flight job, so the base read as merely "not indexed" and reloading the page lost the scanning state entirely.
    • The serve handler now admits the scan as a background Runtime index job through the process-wide cached service and returns a running-job projection immediately, and list/get expose the live indexing progress (phase, files done/total) using the same projection ACP already publishes. The knowledge view renders the current phase and polls while a scan is running, so a reload resumes the status instead of dropping it.
  • Content-Inspected Images No Longer Kill the Session

    • A provider content-policy refusal — for example DashScope/Qwen's InternalError.Algo.DataInspectionFailed: Input image data may contain inappropriate content — arrives as an HTTP 400, but every 4xx was treated as retryable. The same rejected image was re-sent through the provider's backoff retries plus the agent's stream-failure retries (minutes of "Retrying…"), and because a refusal is permanent the run finally failed; worse, the offending image stayed in the persisted history and was replayed on every later turn, so nothing could continue. Only starting a brand-new session recovered — not even /clear, which reloads the same history.
    • provider.IsContentRejectionError now classifies this narrow family (data inspection, content policy/moderation/filter, "inappropriate content") and IsRetryable returns false for it, so the failure surfaces immediately instead of burning the retry budget. Agent Core then recovers in place: it strips the refused images — first from the current turn, then, if the refusal persists, from the whole conversation — replacing each with a model-visible note that explains the provider's content filter blocked the image and that the pixels are unavailable, and records an append-only content_override session entry so replay (same process or after reload) never re-sends it. The run retries without the image and the session keeps working; a turn that already streamed output is healed but not re-run, so no output is duplicated.
  • Serve: Config Saves No Longer Fail with "Access is denied" on Windows

    • On Windows (including portable setups running from exFAT drives), enabling the WeChat/Feishu channel from the Web UI or saving any serve.json change failed with sync config directory: Access is denied. The atomic config writer fsynced the parent directory after the rename — a POSIX durability idiom — but FlushFileBuffers on a read-only directory handle always returns ERROR_ACCESS_DENIED on Windows, on every filesystem including exFAT. Because the failure happened after the file had already been swapped into place, the API reported an error while the new config was never applied to the runtime.
    • The post-rename directory flush is now skipped on Windows (matching etcd/bolt practice); the config file itself is still fsynced before the rename, so durability is preserved and Unix behavior is unchanged.
  • MCP: Image Tool Results Reach the Model Instead of a Placeholder

    • An MCP tool that returned image content reached the model as the literal string [image content: image/png]. The base64 payload was already present in the MCP response, but the client decoded every content block into text only, and the tool returned a text-only result, so a screenshot-style MCP server could report coordinates while the model never saw the picture. resources/read binary resources were worse: the blob field had no matching struct field, so the payload was dropped during decode and not even the placeholder appeared.
    • tools/call and resources/read now project image blocks into tools.ToolResult.Contents as real provider image content, reusing the same provider-aware preprocessing as the read and browser screenshot tools, and decode blob/uri resource fields. Results without images keep the historical text-only shape, so existing text MCP tools are unchanged. Malformed, oversized, or excess images (capped at 4 per result, matching the ACP projection limit) degrade to a text note instead of failing the call. The image capability gate in Agent Core still decides whether a non-vision model receives images at all.
  • SQLite: Transient Busy Transaction Begins Are Retried

    • Several processes opening one session directory race onto the single writer lock. The DSN begins non-read-only transactions with BEGIN IMMEDIATE, so a begin can outlast the connection's busy_timeout while other processes keep committing under synchronous(FULL), and a healthy database failed with database is locked (5).
    • The retry policy now lives in internal/db next to the DSN ownership: BeginTx (Bun), BeginSQLTx (raw *sql.DB), and RunInTx retry only SQLITE_BUSY/SQLITE_LOCKED inside a bounded budget (90 s) with exponential backoff (200 ms ...
Read more

v1.3.101-pre-2

v1.3.101-pre-2 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 15 Sep 03:51

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.3.101

✨ New Features

  • Serve: Placeholder API Token Warnings

    • mothx serve init-config ships a well-known template token, which is equivalent to publishing the API key once auth is enabled — and nothing said so. The token is now a single named constant (serve.PlaceholderAuthToken) with explicit detection (IsPlaceholderAuthToken/UsesPlaceholderAuthToken), and a replacement warning is printed wherever the template is created (mothx serve init-config and the --init-serve CLI path) and again on mothx serve startup while api.auth.enabled is true and the token is still in place.
    • The startup check only fires for an enabled auth block, so the default template (auth disabled, loopback only) stays quiet and a replaced token is never flagged. serve init-config now writes through the command's own stderr, so the warning travels with the command output.
  • Members Wait for Their Lead on Interactive Surfaces

    • A session that can spawn members but is not bound to an expert team now keeps its run open for still-running members on interactive surfaces (TUI, Web UI, ACP), so a member's completion or question is handled within the same run instead of waiting for the next lead run. Headless and asynchronous sources (CLI, cron, WeChat/Feishu) still end the turn normally and deliver member notifications at their next iteration or next run; a bound expert team always waits.
  • Bound Teams Keep the Full Sub-Agent Tool Set

    • A bound expert team always exposes the complete canonical sub-agent tool set (subagent_spawn, subagent_status, subagent_send, subagent_wait, subagent_answer, subagent_destroy). Per-tool toggles that disable individual sub-agent tools apply only to non-team multi-agent sessions; the team capability is authoritative and never drops tools.
  • New Gitee/Moark Model: deepseek-v4.1-flash

    • Added deepseek-v4.1-flash to the gitee and moark providers with a 1M context window and text+image input; no default max_tokens is sent.

🐛 Bug Fixes

  • Content-Inspected Images No Longer Kill the Session

    • A provider content-policy refusal — for example DashScope/Qwen's InternalError.Algo.DataInspectionFailed: Input image data may contain inappropriate content — arrives as an HTTP 400, but every 4xx was treated as retryable. The same rejected image was re-sent through the provider's backoff retries plus the agent's stream-failure retries (minutes of "Retrying…"), and because a refusal is permanent the run finally failed; worse, the offending image stayed in the persisted history and was replayed on every later turn, so nothing could continue. Only starting a brand-new session recovered — not even /clear, which reloads the same history.
    • provider.IsContentRejectionError now classifies this narrow family (data inspection, content policy/moderation/filter, "inappropriate content") and IsRetryable returns false for it, so the failure surfaces immediately instead of burning the retry budget. Agent Core then recovers in place: it strips the refused images — first from the current turn, then, if the refusal persists, from the whole conversation — replacing each with a model-visible note that explains the provider's content filter blocked the image and that the pixels are unavailable, and records an append-only content_override session entry so replay (same process or after reload) never re-sends it. The run retries without the image and the session keeps working; a turn that already streamed output is healed but not re-run, so no output is duplicated.
  • Serve: Config Saves No Longer Fail with "Access is denied" on Windows

    • On Windows (including portable setups running from exFAT drives), enabling the WeChat/Feishu channel from the Web UI or saving any serve.json change failed with sync config directory: Access is denied. The atomic config writer fsynced the parent directory after the rename — a POSIX durability idiom — but FlushFileBuffers on a read-only directory handle always returns ERROR_ACCESS_DENIED on Windows, on every filesystem including exFAT. Because the failure happened after the file had already been swapped into place, the API reported an error while the new config was never applied to the runtime.
    • The post-rename directory flush is now skipped on Windows (matching etcd/bolt practice); the config file itself is still fsynced before the rename, so durability is preserved and Unix behavior is unchanged.
  • MCP: Image Tool Results Reach the Model Instead of a Placeholder

    • An MCP tool that returned image content reached the model as the literal string [image content: image/png]. The base64 payload was already present in the MCP response, but the client decoded every content block into text only, and the tool returned a text-only result, so a screenshot-style MCP server could report coordinates while the model never saw the picture. resources/read binary resources were worse: the blob field had no matching struct field, so the payload was dropped during decode and not even the placeholder appeared.
    • tools/call and resources/read now project image blocks into tools.ToolResult.Contents as real provider image content, reusing the same provider-aware preprocessing as the read and browser screenshot tools, and decode blob/uri resource fields. Results without images keep the historical text-only shape, so existing text MCP tools are unchanged. Malformed, oversized, or excess images (capped at 4 per result, matching the ACP projection limit) degrade to a text note instead of failing the call. The image capability gate in Agent Core still decides whether a non-vision model receives images at all.
  • SQLite: Transient Busy Transaction Begins Are Retried

    • Several processes opening one session directory race onto the single writer lock. The DSN begins non-read-only transactions with BEGIN IMMEDIATE, so a begin can outlast the connection's busy_timeout while other processes keep committing under synchronous(FULL), and a healthy database failed with database is locked (5).
    • The retry policy now lives in internal/db next to the DSN ownership: BeginTx (Bun), BeginSQLTx (raw *sql.DB), and RunInTx retry only SQLITE_BUSY/SQLITE_LOCKED inside a bounded budget (90 s) with exponential backoff (200 ms up to a 2 s cap); non-transient errors are returned unchanged and a caller's context deadline still wins.
    • DAO Begin/BeginTx/RunInTx (including the bindings helpers), internal/db.Write, and the session schema initialization/migration boundary all use it, so concurrent startup and ordinary writes no longer turn a transient writer conflict into a hard failure.
  • Workflow: Runaway DSL Scripts Are Bounded by a Wall-Clock Budget

    • A workflow source such as while (true) {} could pin the process forever whenever its caller passed a context without a deadline. Source evaluation — which only builds the node graph, since worker agents run natively afterwards — now runs under two bounds: the caller's context and a wall-clock budget, whichever fires first interrupts the VM.
    • The budgets are 30 s for a workflow run and 5 s for the interactive workflow_lint authoring check, which must fail fast; a timeout surfaces as the sentinel ErrJSEvaluationTimeout (the lint result carries a stable, readable error), while a caller cancellation keeps returning its context error. Runner.EvalTimeout lets callers tighten the budget, and the zero value keeps the documented defaults.
  • Cancelled or Expired Decisions No Longer Block Forking

    • A session whose only decision had actually been cancelled or timed out was still treated as having a pending decision, so forking it was rejected as source session is active. Every decision-ledger reader now shares one vocabulary, so cancelled and timed-out decisions (and the legacy channel request name) clear correctly and the fork proceeds. The durable decision event name and its {"decision": …} envelope also gained a single owner each, so cross-entry decision recovery reads the same records regardless of which surface wrote them.
  • Mid-Stream Network Failures Retry Automatically Instead of Ending the Reply

    • A provider stream that died with a transient transport error (connection reset by peer, unexpected EOF, gateway 5xx, ...) after text or thinking had already been streamed failed the whole run with stream read error: ...: provider-level retries only cover streams that break before any visible output, and the agent-level retry only covered idle-stream timeouts.
    • The agent loop now performs a bounded continuation retry (up to 2 attempts) for such transient errors. Already-streamed partial output is persisted into history and a continuation instruction quoting the exact suffix is injected, so the model resumes from the interruption point instead of duplicating what the user already saw; with no visible output yet, the turn simply re-runs. Turns with an already-emitted tool call, context overflow (dedicated compaction recovery), and idle-stream timeouts (dedicated timeout retry) keep their existing behavior, and Responses remote-state turns keep their existing failover path.

🔧 Improvements

  • SQLite: Three-Phase Write-Pressure Reduction for the Session Database
    • The connection durability policy moves from synchronous(FULL) to the WAL-recommended synchronous(NORMAL): a commit no longer fsyncs while holding the single writer lock (the fsync moves to checkpoint time), so writer-lock occupancy across processes sharing one session directory shrinks from fsync scale to page-cache scale, largely eliminating the recorded "another process keeps committing until begin exceeds busy_timeout and reports database is locked" scenario. ...
Read more

v1.3.101-pre-1

v1.3.101-pre-1 Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 13 Sep 15:18

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.3.101

✨ New Features

  • Serve: Placeholder API Token Warnings
    • mothx serve init-config ships a well-known template token, which is equivalent to publishing the API key once auth is enabled — and nothing said so. The token is now a single named constant (serve.PlaceholderAuthToken) with explicit detection (IsPlaceholderAuthToken/UsesPlaceholderAuthToken), and a replacement warning is printed wherever the template is created (mothx serve init-config and the --init-serve CLI path) and again on mothx serve startup while api.auth.enabled is true and the token is still in place.
    • The startup check only fires for an enabled auth block, so the default template (auth disabled, loopback only) stays quiet and a replaced token is never flagged. serve init-config now writes through the command's own stderr, so the warning travels with the command output.

🐛 Bug Fixes

  • MCP: Image Tool Results Reach the Model Instead of a Placeholder

    • An MCP tool that returned image content reached the model as the literal string [image content: image/png]. The base64 payload was already present in the MCP response, but the client decoded every content block into text only, and the tool returned a text-only result, so a screenshot-style MCP server could report coordinates while the model never saw the picture. resources/read binary resources were worse: the blob field had no matching struct field, so the payload was dropped during decode and not even the placeholder appeared.
    • tools/call and resources/read now project image blocks into tools.ToolResult.Contents as real provider image content, reusing the same provider-aware preprocessing as the read and browser screenshot tools, and decode blob/uri resource fields. Results without images keep the historical text-only shape, so existing text MCP tools are unchanged. Malformed, oversized, or excess images (capped at 4 per result, matching the ACP projection limit) degrade to a text note instead of failing the call. The image capability gate in Agent Core still decides whether a non-vision model receives images at all.
  • SQLite: Transient Busy Transaction Begins Are Retried

    • Several processes opening one session directory race onto the single writer lock. The DSN begins non-read-only transactions with BEGIN IMMEDIATE, so a begin can outlast the connection's busy_timeout while other processes keep committing under synchronous(FULL), and a healthy database failed with database is locked (5).
    • The retry policy now lives in internal/db next to the DSN ownership: BeginTx (Bun), BeginSQLTx (raw *sql.DB), and RunInTx retry only SQLITE_BUSY/SQLITE_LOCKED inside a bounded budget (90 s) with exponential backoff (200 ms up to a 2 s cap); non-transient errors are returned unchanged and a caller's context deadline still wins.
    • DAO Begin/BeginTx/RunInTx (including the bindings helpers), internal/db.Write, and the session schema initialization/migration boundary all use it, so concurrent startup and ordinary writes no longer turn a transient writer conflict into a hard failure.
  • Workflow: Runaway DSL Scripts Are Bounded by a Wall-Clock Budget

    • A workflow source such as while (true) {} could pin the process forever whenever its caller passed a context without a deadline. Source evaluation — which only builds the node graph, since worker agents run natively afterwards — now runs under two bounds: the caller's context and a wall-clock budget, whichever fires first interrupts the VM.
    • The budgets are 30 s for a workflow run and 5 s for the interactive workflow_lint authoring check, which must fail fast; a timeout surfaces as the sentinel ErrJSEvaluationTimeout (the lint result carries a stable, readable error), while a caller cancellation keeps returning its context error. Runner.EvalTimeout lets callers tighten the budget, and the zero value keeps the documented defaults.

✅ Tests

  • Database: internal/db pins the begin-retry policy — only SQLITE_BUSY/SQLITE_LOCKED are retried, other driver errors and an expiring context are surfaced unchanged, driver codes are classified through the error's own Code() method, and RunInTx keeps commit/rollback semantics.
  • Workflow: a runaway script is interrupted by a 50 ms budget (previously that test hung), a successful evaluation behaves exactly as before, and the lint path reports an invalid result with the timeout message.
  • Serve: the generated template keeps the same constant the detection uses, a whitespace-padded placeholder is still recognized while a real or empty token is not, and the serve init-config output must contain the warning.
  • Agent loop: ten real bash echo calls run through one parallel batch (the rendezvous only closes once all ten workers are live), and ordered-start coverage pins the launch semantics — starts in the model's declared order, an in-flight call unaffected by an earlier approval wait, queued calls released when an earlier call fails, and the same ordered handle for background tool calls.
  • Runtime: the cross-process takeover test now retries the expire-then-takeover pair inside a bounded budget and gives helper startup a load-tolerant window, so a loaded machine fails setup with a clear diagnosis instead of failing the invariant under test.

v1.3.101-pre

v1.3.101-pre Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 13 Sep 07:14

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.3.101

✨ New Features

  • Serve: Placeholder API Token Warnings
    • mothx serve init-config ships a well-known template token, which is equivalent to publishing the API key once auth is enabled — and nothing said so. The token is now a single named constant (serve.PlaceholderAuthToken) with explicit detection (IsPlaceholderAuthToken/UsesPlaceholderAuthToken), and a replacement warning is printed wherever the template is created (mothx serve init-config and the --init-serve CLI path) and again on mothx serve startup while api.auth.enabled is true and the token is still in place.
    • The startup check only fires for an enabled auth block, so the default template (auth disabled, loopback only) stays quiet and a replaced token is never flagged. serve init-config now writes through the command's own stderr, so the warning travels with the command output.

🐛 Bug Fixes

  • SQLite: Transient Busy Transaction Begins Are Retried

    • Several processes opening one session directory race onto the single writer lock. The DSN begins non-read-only transactions with BEGIN IMMEDIATE, so a begin can outlast the connection's busy_timeout while other processes keep committing under synchronous(FULL), and a healthy database failed with database is locked (5).
    • The retry policy now lives in internal/db next to the DSN ownership: BeginTx (Bun), BeginSQLTx (raw *sql.DB), and RunInTx retry only SQLITE_BUSY/SQLITE_LOCKED inside a bounded budget (90 s) with exponential backoff (200 ms up to a 2 s cap); non-transient errors are returned unchanged and a caller's context deadline still wins.
    • DAO Begin/BeginTx/RunInTx (including the bindings helpers), internal/db.Write, and the session schema initialization/migration boundary all use it, so concurrent startup and ordinary writes no longer turn a transient writer conflict into a hard failure.
  • Workflow: Runaway DSL Scripts Are Bounded by a Wall-Clock Budget

    • A workflow source such as while (true) {} could pin the process forever whenever its caller passed a context without a deadline. Source evaluation — which only builds the node graph, since worker agents run natively afterwards — now runs under two bounds: the caller's context and a wall-clock budget, whichever fires first interrupts the VM.
    • The budgets are 30 s for a workflow run and 5 s for the interactive workflow_lint authoring check, which must fail fast; a timeout surfaces as the sentinel ErrJSEvaluationTimeout (the lint result carries a stable, readable error), while a caller cancellation keeps returning its context error. Runner.EvalTimeout lets callers tighten the budget, and the zero value keeps the documented defaults.

✅ Tests

  • Database: internal/db pins the begin-retry policy — only SQLITE_BUSY/SQLITE_LOCKED are retried, other driver errors and an expiring context are surfaced unchanged, driver codes are classified through the error's own Code() method, and RunInTx keeps commit/rollback semantics.
  • Workflow: a runaway script is interrupted by a 50 ms budget (previously that test hung), a successful evaluation behaves exactly as before, and the lint path reports an invalid result with the timeout message.
  • Serve: the generated template keeps the same constant the detection uses, a whitespace-padded placeholder is still recognized while a real or empty token is not, and the serve init-config output must contain the warning.
  • Agent loop: ten real bash echo calls run through one parallel batch (the rendezvous only closes once all ten workers are live), and ordered-start coverage pins the launch semantics — starts in the model's declared order, an in-flight call unaffected by an earlier approval wait, queued calls released when an earlier call fails, and the same ordered handle for background tool calls.
  • Runtime: the cross-process takeover test now retries the expire-then-takeover pair inside a bounded budget and gives helper startup a load-tolerant window, so a loaded machine fails setup with a clear diagnosis instead of failing the invariant under test.

v1.3.100

Choose a tag to compare

@github-actions github-actions released this 04 Sep 09:00

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.2.100

✨ New Features

  • WebUI: Slash Command Suggestions in the Chat Composer
    • Typing / in the chat input now shows a suggestion dropdown covering every supported slash command (/clear, /mode, /model, /defaultModel, /models, /sessions, /status, /compact, /delegate, /alloweditpath, /allowautoedit, /workflows, /skill, /skills, /rule, /esm, /help), with a dedicated subcommand filter for /esm (objective/edit/pause/resume/clear/guide).
    • Navigate with ↑/↓, complete with Tab or Enter (Enter sends the prompt when the input already matches the selection), dismiss with Esc, or click an entry; accepting a suggestion places the cursor at the end of the inserted command. The composer keeps proper combobox/listbox ARIA state (aria-expanded, aria-activedescendant, aria-selected).
    • Suggestions are suppressed while a run is active, the API is disabled, or the input spans multiple lines.

🐛 Bug Fixes

  • TUI: Prompts Submitted During an Active Run Are Queued Instead of Replacing It
    • A session allows exactly one foreground execution at a time. Previously, submitting input while a run was active replaced the in-memory run handle, orphaning the active run's terminal cleanup and its runtime lease. Such submissions are now queued in the TUI, and the next queued prompt starts only after the preceding run reaches its canonical terminal state and releases its lease — across every terminal branch (success, failure, incomplete, and cancellation).
    • Queued prompts retain their Runtime-prepared attachments (agentruntime.PreparedInput) and re-enter through the same input contract, so attachments survive the delay unchanged.

✅ Tests

  • TUI: new coverage asserting that input during an active run queues without replacing the lease owner, and that the queued prompt starts only after the cancellation path finalizes the durable run and releases its lease.

v1.2.99

Choose a tag to compare

@github-actions github-actions released this 04 Sep 02:52

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.2.99

✨ New Features

  • Unified Server-Resolved Model Catalog Across WebUI and TUI

    • A new GET /api/models/catalog endpoint resolves every selectable provider/model through providerfactory.ResolvedModels/SortProviderIDs — the same shared logic that builds the TUI's provider model lists — and returns canonical defaults plus the sorted provider list. The active provider stays selectable even when it comes from a built-in preset or a serve flag instead of the settings providers map.
    • stores.js migrates modelsmodelCatalog; the Chat new-session picker now consumes the server catalog instead of merging raw settings JSON client-side, dropping the local buildModelCatalog/settings-fallback derivation. Settings surfaces (default provider/model dropdowns, provider editor) consume the same store, and inherited built-in preset models get dedicated zh/en labels.
    • The TUI auth dialog's provider sort delegates to providerfactory.ProviderSortPriority, so TUI dialogs and the WebUI catalog share one ordering logic.
  • Enable Supervisor Mode (ESM): Slash-Command Control, Shared Guidance, and Evidence Tracking

    • WebUI ESM control moves to the same /esm slash command as the TUI (/esm <objective>, /esm status|edit|pause|resume|clear|guide) instead of dedicated graphical controls — the 500-line ESMControls component is removed, and chat input and the ESM REST API share one server-side objective path.
    • New guidance module: /esm guide <text> queues user guidance stamped with the objective's current version; the Supervisor injects pending guidance into every non-recovery role prompt and consumes it exactly once after the role result is applied — one core-owned lifecycle shared by the TUI and WebUI adapters.
    • New evidence module: a shared EvidenceTracker accumulates tool-call evidence per role run (unique tool-call IDs, per-tool counts/errors), so the "tool-backed evidence" checks in ApplyWorkerResult/ApplyReviewResult cannot diverge between adapters.
    • ESM no longer enforces token/time budgets: the budget_limited status, SetBudget/budget prompts, and the TUI /esm budget subcommand are removed; TokensUsed/TimeUsedMS remain observability-only counters. The blocked-audit threshold is centralized as BlockedAuditLimit (the objective becomes blocked after 3 consecutive runs report the same blocker).
    • Unattended derived runs resolve their execution mode through agentruntime.ResolveUnattendedMode: only os is inherited from the session mode and every other session mode falls back to yolo, so ESM role sub-agents never stop on interactive approval (hard high-risk-command protections remain mode-independent).
    • The Supervisor now runs continuations against the base Run ID (role runs use suffixed IDs derived from it), owns the terminal FinishRun call for both adapters, and clears stale streaks left by earlier continuations when a continuation ends.

🐛 Bug Fixes

  • ESM: Failed Objectives Pause Instead of Silently Re-running

    • A non-retryable role failure now pauses the objective and requires an explicit /esm resume before it can run again — queued guidance or a future trigger can no longer silently re-run a failed task. Timeouts and retryable transport errors still take the recovery path bounded by RecoveryLimit.
    • Serve startup no longer replays historically persisted "active" ESM objectives: a role may have failed just before the process exited, so Create/Edit/ResumeESM are now the only explicit execution entry points.
    • esmCoordinator gains stop/stopAll with done-channels and bounded waits; Serve shutdown cancels every ESM worker and waits for it to release session/runtime references (SessionRuntime.Shutdown remains the final resource boundary), and a closed coordinator refuses to start new workers.
  • Native Directory Picker on Headless Servers

    • The Unix native picker reports itself unavailable when DISPLAY/WAYLAND_DISPLAY is absent instead of failing silently, letting the Web UI fall back to its built-in directory browser. Launch failures that print diagnostics on stderr now surface as errors instead of being mistaken for a dialog cancel.

🔧 Improvements

  • Directory Browser: Windows Drive Roots and Path-Aware Allowed Roots

    • /api/browse allowed-root resolution now takes the requested path, and Windows drive roots are listed through a virtual browse root (drive roots share no common parent for navigation). DirBrowser gains an initialPath prop, one-shot open semantics, a server-provided selectable flag, and refresh support.
  • Tool Recovery Audit Trail

    • RequestToolExecutionRecoveryRecords records explicit user confirmation and returns only matching interrupted calls; the records are retained as audit evidence while recovery starts as a fresh execution, and a new DAO listing (ListRequestedToolRecoveries) exposes requested recoveries to Serve. Terminal Runs are never reactivated to consume these records.

✅ Tests

  • ESM: new/expanded coverage for the guidance lifecycle (version stamping, injection, one-time consumption), evidence tracking, pause-on-non-retryable-failure, base-Run-ID continuations, budget removal, /esm slash-command parity, and coordinator stop/stopAll (including closed-coordinator start refusal).
  • Serve: a process-level test asserts startup never replays historical ESM objectives; browse-root tests cover allowed-root resolution and Windows drive-root listing; native picker tests cover the headless-unavailable and stderr-diagnostic cases.
  • Provider factory: catalog resolution and provider ordering tests; settings: qwen3.8-max-0902 preset assertions.

v1.2.98

Choose a tag to compare

@github-actions github-actions released this 02 Sep 17:39

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.2.98

🔧 Improvements

  • TUI: Dead Code Cleanup and Decision Lifecycle Alignment
    • Removed unused functions (renderLiveAssistantMessage, renderPlanPanel, formatPlanForDisplay, normalizeHistoryLineEndings, resolveESMStoreDir, updateViewportContentWithFollow) and trimmed the associated plan/ESM test coverage.
    • Question requests are now registered through DecisionService, so pending questions persist and replay like approvals; duplicate question requests are rejected.
    • Terminal decision status is mapped from the actual run state instead of always marking pending decisions cancelled — only an explicit cancellation records cancelled, any other terminal outcome records timed_out.
    • The deferred print loop gained a stopPrintLoop exit path used on quit and reload so queued transcript lines are drained before teardown.
    • The external status-line refresh is deferred to actual renders, coalescing event-dense bursts into a single refresh.
    • sessionsDel now resolves the session directory through the defensive getSessionDir() helper.

✅ Tests

  • TUI: new tests cover question decision registration (pending kind, persistence, duplicate rejection) and ESM store directory resolution.

v1.2.97

Choose a tag to compare

@github-actions github-actions released this 02 Sep 10:17

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.2.97

✨ New Features

  • Online Model Discovery for Providers

    • Provider model discovery moved into internal/provider as shared helpers (ModelsEndpoint, ResolveSecretRef, DiscoverModels) that fetch and normalize a provider's /models listing into DiscoveredModels. The OpenAI-compatible /v1/provider/models and model-test endpoints now call these shared helpers instead of duplicating probe plumbing.
  • TUI: Fetch and Search Online Models in the Auth Dialog

    • A new "Fetch Online Models" entry in the provider model list and model settings views runs discovery against the draft provider's Base URL / API type on a background command and opens an "Add Model · Online List" view where fetched models can be added to or removed from the draft. Nothing is persisted until the provider is saved, and stale results after closing the dialog or switching providers are dropped, with loading/empty/error states and zh/en labels.
    • Typing in the online list filters fetched models, ranked exact > prefix > substring across model ID and display name while preserving discovery order within the same score; Esc clears the query, and a "No models match." hint shows when nothing matches.

🔧 Improvements

  • Public SDK Boundary: agent/ Stays Internal-Free

    • The provider bridge moved from the public agent/ package into bootstrap/ (which external modules already blank-import); it registers the provider resolution hook plus the concrete provider factories at init time.
    • agent.Builder no longer pre-resolves the platform session directory (the internal builder resolves the default at Build time) and reports a clear error when a hook is unregistered; the examples now blank-import bootstrap instead of internal packages.
  • Session Store Integrity Hardening

    • DeleteSession now prunes child tables without a session_id column (delivery_operations, attachment_deliveries) through their session-owned parents, so deleting a session leaves no orphaned rows.
    • Schema migrations apply in ascending version order instead of slice order; forward table references no longer depend on FK enforcement being disabled.
    • Non-terminal/terminal Run status sets are centralized in run_store.go as the single source of truth; SQL literals, partial unique indexes, fork, trajectory, and recovery paths all derive from them.
    • EndConversationTurn is idempotent for already-closed turns; conversation entry IDs grow to 64-bit; IdentityLocks delegates to a ref-counted lock registry, and the runtime lease bus closes its UDP listener once the last handler unsubscribes.

🐛 Bug Fixes

  • TUI: Instant Submit for a Lone Enter

    • A queued Enter was treated as line-break evidence, so every quick type-then-Enter send waited the full 120ms split-paste coalescing window. The extended idle window now applies only when the queue carries real paste evidence (newline-bearing rune chunks or Enter adjacent to text); a lone deferred Enter keeps the normal 16ms window and submits immediately.
  • Missing Error Reason on Abandoned Durable Runs

    • A background run abandoned after interrupted tool execution could reach a terminal status without persisting the reason. A dedicated annotation boundary (RunDAO.UpdateErrorIfEmptysession.AnnotateSessionRunErroragentruntime.AnnotateDurableRunError) now sets the error only while it is still empty — without changing run status, reviving terminal runs, or touching active runs, keeping the first recorded reason authoritative. The Responses API abandon path persists the reason through this boundary.
  • Duplicate User Entry in the Background Run Coordinator

    • The durable user entry appended during admission is already in replay state after the manager reload; the coordinator now matches the deterministic RunUserEntryID and reuses it as the continuation message instead of appending a duplicate to the transcript and the provider request. The check stays idempotent across retries, recovery, and process restarts.
  • Channel Rotation Lease Target

    • AcquireRuntimeForRotate now takes the session directory explicitly from the lifecycle owner (falling back to the dispatcher's configured directory when empty), so the mutation lease and the forced-release wait target the authoritative Session instead of whatever directory the dispatcher holds.

✅ Tests

  • Architecture: public_sdk_boundary_test fails if the public agent/ package or example/ modules import internal packages again.
  • New session tests: delete integrity (no orphaned rows), ascending migration order, Run status-set consistency, ref-counted lock registry, and lease-bus listener cleanup; widened orphan-recovery timing margins under -race.
  • Regression tests for the fast lone-Enter submit path (split-paste continuation still protected) and durable-run error annotation.

v1.2.96

Choose a tag to compare

@github-actions github-actions released this 29 Aug 15:04

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.2.96

✨ New Features

  • Runtime Workspace Input Materialization

    • A single front-end-neutral input contract now owns user files for every entry point (CLI, TUI, WebUI/API, ACP, WeChat, Feishu). Adapters submit source streams; internal/agentruntime materializes accepted files into the project workspace and the first user message declares file paths plus metadata, letting the Agent decide how and whether to read each file.
    • Images are no longer auto-converted to provider image content on ingest; input resources persist via the input_resources table with a Runtime-owned lifecycle (PrepareInput/AttachPreparedInput, discard/delete/cleanup, input_resource_events).
    • TUI /paste-image now submits a stream the Runtime writes; the Web UI gained attachment upload/preview in chat; ACP prompt content (text/image/file/audio/video) and WeChat/Feishu inbound media all normalize through this same ingress.
  • Lease-Based Execution Admission and Orphaned Run Recovery

    • The legacy TryLockRuntime/TryLockRuntimes path was replaced with explicit, purpose- and run-bound runtime leases across CLI, TUI, ACP, Serve, channels, and cron: ref-counted durable lease guards (AcquireExecutionAdmission/AcquireFork/AcquireMutations and run binding) plus recovery/reconciliation modes for stale or orphaned runs.
    • A new RecoveryCoordinator converges orphaned runs lease-first through a startup scan and periodic/wake-driven retries, backed by the session_run_recoveries table with durable state, retry accounting, and idempotent replay.
    • The session runtime snapshot surfaces admission/recovery facts (reserved, local, external, detached_remote, orphaned, recovery_failed, inconsistent); the Web UI shows matching status badges and disables delete/fork while a session is busy.
  • Durable Delivery Outbox

    • Delivery intents and ordered operations (delivery_intents/delivery_operations) with deterministic PlanDelivery sequences (caption/upload/send/fallback), a Runtime claim/fence/retry coordinator, terminal-state atomic commit of assistant message/Run/turn/event/intent, and service-start recovery.
    • WeChat (image/video/file) and Feishu (image/file) outbound media deliver natively through frozen transport contexts; published artifacts moved into a private store outside the work directory with integrity verification (size + SHA-256) on open.
  • Idempotent Run Submissions

    • New runtime_submissions table with reconcile-on-conflict handling: submit-key conflicts reuse the existing submission instead of creating duplicates, making Run admission retry-safe.

🔧 Improvements

  • DAO-Only SQL Migration

    • internal/db now owns process-wide SQLite/Bun connection lifecycle and transaction boundaries; all session, cron, stats, ESM, and delivery SQL moved into internal/dao persistence objects.
    • Removed the internal/commondb compatibility package and the delivery legacy bridge; the architecture guard enforces the DAO-only boundary with a minimal migration-owner allowlist.
  • Web UI Loading and State Stability

    • Route views (Chat/Sessions/Stats/Cron/Skills/Settings/Login) are lazy-loaded so only the active route's chunk is fetched; lucide/bits-ui/svelte dependencies are grouped into stable vendor chunks.
    • Session runtime state (load/PATCH/polling/mode switching) moved into a unit-testable manager, and loaded history snapshots merge field by field so stale or empty persisted projections never erase live assistant text.

🐛 Bug Fixes

  • Cached Input Token Double Charge

    • Usage accounting now computes uncached input tokens (UncachedInputTokens) instead of charging cache reads twice across Anthropic, OpenAI-compatible, and Google wire formats.
  • ListSessionRuns Connection Deadlock

    • ListSessionRuns queried input_resources inside the session_runs rows loop, blocking forever on the single-connection pool and hanging TUI startup for continued sessions with run records. The outer rows are now drained before a single batched query, with a regression test asserting completion.
  • Durable-Run Terminal Event Stability

    • RunExecutor.Finalize no longer publishes the terminal stream event for durable runs; FinalizeRun remains the single publisher after FinishDurable commits the assistant message, so WebUI history reloads cannot race the database write. Durable identity is recovered from the canonical Run row when the in-memory marker is gone, and already-closed conversation turns are tolerated so idempotent retries still commit the final entry and terminal event.

✅ Tests

  • Architecture: input_contract_guard_test enforces the single input contract across TUI, CLI, WebUI/API, ACP, and Channel entry points.
  • Extended admission/recovery tests for lease-first orphan convergence, execution snapshots, stop handling, idempotency, and cross-process lease behavior; delivery process integration tests for claim/fence/retry and coordinator recovery.
  • Regression tests for cached-input-token accounting and the ListSessionRuns deadlock.

v1.2.95

Choose a tag to compare

@github-actions github-actions released this 25 Aug 03:20

Changelog (Current Version)

This file contains the changes for the current version only. The full history of all versions lives in docs/en/changelog.md.

v1.2.95

✨ New Features

  • Durable CLI Runs

    • CLI runPrint now persists canonical durable runs via agentruntime.ExecutionRuntime, aligning the CLI path with WebUI, channels, and ACP lifecycle tracking.
  • UDP Runtime Lease Bus

    • Added best-effort UDP SessionLeaseBus for local-process wake-up on runtime lease and run-state changes.
    • Uses directed loopback broadcast with deduplication; SQLite leases and durable rows remain the sole authority.
  • Per-Run Provider/Model Selection (API & Web UI)

    • POST /v1/responses runs accept an optional provider field; qualified provider/model IDs are parsed and validated (with a structured mismatch error when the provider does not own the model).
    • The run executes with the requested provider's agent built through the shared SessionRuntime; run policy snapshots and request fingerprints now record the provider.
    • /v1/models now reports each model's provider.

🔧 Improvements

  • Event Broker Resync

    • Event broker now exposes SubscribeWithResync; subscriber overflow closes the WebSocket so the client reconnects and replays durable SQLite cursors.
  • Runtime Lease Heartbeat

    • Lease heartbeat now retries transient SQLite failures for a bounded interval and publishes acquired/released/lost notifications.
  • Session Capabilities (Sandbox/Browser/Web Search)

    • SessionRuntime gains CapabilitySnapshot, ConfigureCapabilities, and SetCapabilityOption; browser and web-search capabilities persist via session_capabilities and replay on load, with core tools synchronized accordingly.
    • ACP sessions restore persisted capabilities and additional directories under the runtime lease; sandbox remains process-policy-owned.
  • Web UI Provider-Aware Model Picker

    • New searchable ModelPicker component with modality icons (text/image/audio/video/file) replaces the old model menu.
    • Chat composes a provider-cascading model catalog from /v1/models plus configured providers, so selecting a provider narrows to its models and submits the provider with each run.
  • ACP Session Extension Methods

    • Added session/fork and mothx/session/setTitle handling, workspace-window negotiation (cwd/additional directories), a cascade delete across fork lineage, and an available_commands_update notification.
    • Optional editor context is injected as a bounded, untrusted context block; loading historical sessions with a released runtime lease no longer rewrites persisted bindings.

🐛 Bug Fixes

  • Background Run Optimistic Concurrency
    • Reloaded the shared session manager after durable admission so the background coordinator appends the user message to the new leaf instead of failing its optimistic concurrency check.

✅ Tests

  • Acquired the runtime lease in TestResponsesRunAPIAbandonMarksInterruptedToolsWithoutRetry before inspecting the abandoned tool record, matching the production recovery caller pattern.
  • Added ACP tests: loading a historical session with a released lease must not persist defaults, directory updates under the runtime lease, and title changes on historical sessions.
  • Added serve tests for per-run provider selection, provider/model mismatch, and qualified-model parsing.