Adapt the earliest routing repair in scroasdale PR #44268 to the current media helpers, retaining metadata in URL fallbacks and refusing successful text-only receipts for failed local uploads. Also informed by jasondschoeman-pixel issue #104357 and ericmaddox PR #104760.
Co-authored-by: scroasdale <67333169+scroasdale@users.noreply.github.com>
ClawHub's detail endpoint now answers a slug claimed by multiple owners
with 409 AMBIGUOUS_SKILL_SLUG; the bare GET in _skill_detail returned
None for every such slug, so 'skills install clawhub/@owner/slug' (and
the owner/skills/slug URL form) failed at fetch time even though the
requester already knew the owner (#104117).
- _skill_detail forwards expected_owner as the ?owner= query param on
the detail GET (params already flows through _get_json's **kwargs).
- _parse_identifier also accepts the clawhub/@owner/slug combination:
the @ surfaces only after the clawhub/ prefix is stripped, so the
had_at check now re-runs on the stripped form. GitHub-style
owner/repo/skill paths stay rejected.
_paginate_full_list wrapped the paginated list call in try/except TypeError
to detect the mcp 1.x calling convention. The same except also caught
TypeErrors raised INSIDE the modern list call — e.g. a server response
decode failure — and retried with the legacy cursor= keyword, replacing the
real error with a misleading 'unexpected keyword argument cursor' and
making genuine MCP pagination failures undiagnosable.
Probe list_method's signature instead (_list_method_accepts_params): the
legacy cursor= fallback fires only when the method genuinely doesn't accept
the mcp 2.0 params= keyword (or takes **kwargs), so a TypeError from inside
the list call propagates to the caller. Regression tests: the decode
TypeError surfaces and the legacy retry doesn't run; a genuinely 1.x-shaped
method keeps using the cursor fallback.
Three orchestrator failures traced through the Sep 7 gpt-6-astra campaign sessions:
1. delegation.independent_completions (new, default false). #104299 made every
ungrouped task its own completion message, so a 15-task call woke the
orchestrator up to 15 times; one chain received 132 notices and answered
130 of them with "already incorporated". A multi-task call now returns as
ONE consolidated message unless the flag is on; `group` is inert until then.
2. Queued units were killed before they started. Units of one call share a
pool slot but the executor was still sized by slots, so with 15 units live
a new unit queued behind a full pool; the stale monitor's clock ran from
dispatch, interrupted it at 450 s, and the child exited `interrupted 0.02s`
when its thread finally came up (13 such lanes in one session). The
executor now grows to the number of live units and the stall clock arms
when the runner actually starts.
3. The tool text said "do not wait or poll — just continue" without saying
that completions are delivered only BETWEEN turns. A model that never ends
its turn (one 203-minute turn, 717 API calls) never received 40 finished
results. Tool description, dispatch note and completion header now say to
finish independent work, give a one-line status, and end the turn.
Adapt the config-only portion of #104347; omit its environment flag and unrelated docs. Explicit update commands remain independent.
Co-authored-by: Rohith Pariki <rohithpariki@gmail.com>
Slim adaptation of #83772 to the current schema and failure-hint table.
Generated helpers are module exports on every execution path, not globals.
Correct schema, recovery hints and CLI tip rather than injecting names or
changing the execution boundary. Two registry-driven invariants reproduce
both misleading instructions on main and execute the corrected guidance.
Additional tool fix discovered during campaign #104904.
Original diagnosis and correction: @yuzilongleif-collab (#83772).
Co-authored-by: yuzilongleif-collab <235949691+yuzilongleif-collab@users.noreply.github.com>
Discover systemd targets before stopping old processes, restart even when
there are no gateway PIDs, and require successful scope listings plus active
verification. Pending launchd recovery also retains failures for inaccessible
listings and installed jobs without supervision. Keep existing PID cleanup
intact but before recovery so it cannot kill freshly verified workers.
Slim redo informed by #104274, #104283, and #104285.
Co-authored-by: fangliquanflq <fangliquan@qq.com>
Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
Preserve producer descriptions without identity wrappers and size the existing themed tooltip to the viewport. Replace skipped and structural tests with two behavioral invariants. Native Electron before/after hover, click and keyboard verification passed; campaign suite validation remains queued.
Use mktemp -d before launching the optional UI; skip UI if allocation fails. Native Chrome collision and allocation-failure probes preserve preexisting directories.
Track the path actually launched, preserving the no-UI case and unrelated profiles. Adapted the ownership approach from #104362.
Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
Apply the narrow registry fallback proposed in PR #68458 without unrelated case normalization or dead legacy flags. Preserve dedicated named profiles before using CustomProfile. This corrects existing reasoning loss only; per-model dialect configuration remains a product decision.
Co-authored-by: saotu <160758706+saotu@users.noreply.github.com>
The corrupt-cause recovery guidance hardcoded `~/.hermes/backups/` while
every other path in the same message follows the active HERMES_HOME
(`{db_path}` is already interpolated). A custom-home or named-profile
deployment was told to restore from a directory that may not exist at all,
mid data-loss incident. Both sites (turn-completion explainer and gateway
startup broadcast) now interpolate `<hermes_root>/backups` via
get_default_hermes_root(), matching hermes_cli/backup.py's real backup
location.
Fixes#104250
The memory_tool schema advertises new_text as an alias for content, and
memory_tool resolves it when content is None. But the table-driven inline
executor's arg_specs (agent/inline_tool_executors.py) did not list new_text,
so _call_tool's allowlist silently dropped it: a replace call using the
documented alias reached memory_tool with both fields None and failed with
"content is required for 'replace' action." — even though the caller
supplied the value. Forward new_text alongside content/old_text so the
documented alias fires and content still wins when both are set, matching
what the batch path (op.get("content") or op.get("new_text")) already
accepts.