Staging (Week of 26-06-22) - #213
Merged
Merged
Conversation
Adds a transport-agnostic SelectionElicitor strategy plus a select_path tool the model calls ONLY when a path is genuinely ambiguous. The tool resolves candidates confined to the project root (path-traversal guarded, .anton hidden), auto-resolves a single match, reports no-match for zero, and prompts only when >=2 candidates remain. The chosen path returns as the tool result so the agent continues with no separate user message. CLI gets a terminal picker; embedding hosts inject their own elicitor.
When the user references a file/folder without a resolvable path, the tool now opens a navigable picker (browse mode) instead of forcing the model to ask for a typed path. A ToolDef.prompt rule steers the model to the picker over asking. Browse-mode picks are validated as any existing path of the requested kind; pick mode (candidate disambiguation) is unchanged.
…gainst root Lets the host pass a SelectionElicitor through ChatSessionConfig instead of setting it on the session after construction, so cowork-server can wire its streaming picker in one place. Browse-mode picks that come back relative are now resolved against the request root, and the escape watcher resumes in a finally so a tool error cannot leave it paused.
- add a _status() helper and route every select_path result through it,
dropping the repeated json.dumps({"status": ...}) blocks
- hoist json and Path to module top, remove the per-function local imports
in the select_path code
- drop the unused session arg from _collect_selection_candidates
- drop @runtime_checkable from SelectionElicitor (nothing isinstance-checks
it); keep it a Protocol so hosts satisfy it by shape
`AntonSettings.model_post_init` derived `openai_base_url` from `minds_url` with a hardcoded `/api/v1` suffix. That's correct only for the legacy `mdb.ai` host; `api.mindshub.ai` serves the OpenAI-compatible API at `/v1`, so the derivation produced a wrong endpoint (`https://api.mindshub.ai/api/v1`) for the current product. A leftover from the mdb.ai era — the rest of the stack (cowork-server `minds_chat_base_url`, cowork `index.ts`) already branches on host. Make it host-aware: `/v1` for mindshub, `/api/v1` for `mdb.ai`, and preserve an already-suffixed URL. Mirrors cowork-server's `minds_chat_base_url`. Tests: tests/test_settings.py::TestMindsOpenAIBaseUrlDerivation — mindshub→/v1, mdb.ai→/api/v1, already-suffixed preserved, and no derivation when an openai key is already set. Verified against real pydantic loading the edited source. Refs ENG-436. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…G-436)
Second instance of the hardcoded /api/v1 (the first was config/settings.py
model_post_init). LocalScratchpadRuntime's subprocess-env setup built
OPENAI_BASE_URL as `{ANTON_MINDS_URL}/api/v1` unconditionally for
openai-compatible — correct for mdb.ai, wrong for api.mindshub.ai (/v1).
In the cowork-server flow this is overridden by the explicit
coding_base_url, but it's a latent footgun for any openai-compatible +
minds invocation that doesn't pass one. Make it host-aware to match
settings.py and cowork-server's minds_chat_base_url.
Refs ENG-436.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
read_image resolved relative paths against Path.cwd(). Under the desktop app the agent's cwd is NOT the project, so a project-relative image path (a rendered deck, chart, screenshot in the artifacts folder) resolved to the wrong directory and came back 'file not found' — forcing the agent to copy a contact sheet into a cwd-reachable dir to see anything. Resolve relative paths against the session workspace base (where artifacts live), mirroring publish_or_preview; fall back to cwd for the CLI, where cwd already is the project. Absolute paths are unchanged. With this + the inference-router image-block fix (mindshub_inference#302), Anton can read project/artifact images by absolute OR project-relative path — no workaround. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(settings): host-aware minds→openai base URL derivation (ENG-436)
Consolidated global config home. The .env chain now appends ~/.cowork/.env last (so it wins), keeping ~/.anton/.env as a fallback for installs that haven't migrated. Workspace-relative .anton/ is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add ~/.cowork/.env to the env-loading chain
Docs and README download links updated to the new canonical domain. ENG-437 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat(select_path): inline file/folder picker for ambiguous paths
read_image: resolve relative paths against the workspace, not cwd
_fetch_url accepted any http(s) URL with no destination check, allowing full-read SSRF — cloud metadata (169.254.169.254), RFC1918 hosts, and loopback were all reachable and their full response bodies returned in the SSE stream. Changes: - Add _check_url_ssrf(): resolves the hostname to all A/AAAA records and rejects any that fall in loopback / link-local / RFC1918 / cloud-metadata / carrier-grade-NAT ranges. - Switch _fetch_url to follow_redirects=False and manually step through each redirect, running _check_url_ssrf on every Location target before following — prevents a public URL redirecting to an internal one. - ANTON_ALLOW_PRIVATE_FETCH=1 disables the guard for self-hosted / LAN deployments that legitimately need to reach private addresses. Normal public web fetching (Wikipedia, GitHub, any public API) is completely unaffected — all public IPs pass the check. Reported class: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
fix(security): guard web_fetch against SSRF — CWE-918
…dshub-ai ENG-437: Update download URLs to downloads.mindshub.ai
…host, not "openai-compatible") The scratchpad LLM forced vision_format="anthropic" for ANY openai-compatible provider. That's only right for Minds/MindsHub/MDB.AI (which proxy Anthropic over the OpenAI envelope). Gemini is presented to the scratchpad as openai-compatible (it speaks OpenAI's protocol at Google's endpoint), so it was getting Anthropic-shaped image blocks — malformed for Google, which expects standard OpenAI image_url blocks. Image/vision input through the Gemini scratchpad was broken. Gate the anthropic override on the existing _anthropic_proxy host check (mdb.ai / mindshub.ai) only. OpenAIProvider already defaults to supports_vision=True / vision_format="openai", so Gemini and any generic OpenAI-compatible endpoint now correctly use OpenAI image_url, while Minds/MindsHub keep the Anthropic format. Text-only was already fine; this fixes vision. Surfaced in the ENG-466 review of cowork-server #111 (presenting gemini as openai-compatible exposed this pre-existing scratchpad_boot assumption). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…gs too Same bug #216 fixed in scratchpad_boot, on the main-agent path: LLMClient.from_settings's "openai-compatible" factory hardcoded vision_format="anthropic" unconditionally. A standalone anton instance with openai-compatible pointed at a non-Anthropic endpoint (Gemini, a generic proxy) gets Anthropic-shaped image blocks → mangled images. (Does not affect the cowork product: cowork-server's build_llm_client constructs OpenAIProvider directly with the default vision_format="openai", bypassing from_settings. So this is the anton-standalone path only.) Gate on the base-URL host (mdb.ai / mindshub.ai) like the scratchpad_boot fix: Minds/MindsHub keep anthropic image blocks; Gemini + generic compatible endpoints use OpenAI image_url. Tests: from_settings vision_format is anthropic for mindshub/mdb hosts, openai for Gemini and generic hosts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stamp an env-derived is_ci flag on send_event so CI/automation traffic can be filtered out of the product funnel. Detection is env-only to keep this path anonymous (no PII) — no email/staff signal is available here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…385) Address PR review: - Drop CI/automation traffic entirely instead of stamping is_ci, matching the cowork side and avoiding a per-query exclusion filter. - Drive detection from an explicit ANTON_IS_CI signal with known CI-provider markers as a fallback, using a real truthiness check. The bare CI var is no longer consulted, so CI=false (or a leaked CI) no longer misclassifies as CI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, not openai-compatible) (#216) * fix(scratchpad): correct vision format for Gemini (gate anthropic on host, not "openai-compatible") The scratchpad LLM forced vision_format="anthropic" for ANY openai-compatible provider. That's only right for Minds/MindsHub/MDB.AI (which proxy Anthropic over the OpenAI envelope). Gemini is presented to the scratchpad as openai-compatible (it speaks OpenAI's protocol at Google's endpoint), so it was getting Anthropic-shaped image blocks — malformed for Google, which expects standard OpenAI image_url blocks. Image/vision input through the Gemini scratchpad was broken. Gate the anthropic override on the existing _anthropic_proxy host check (mdb.ai / mindshub.ai) only. OpenAIProvider already defaults to supports_vision=True / vision_format="openai", so Gemini and any generic OpenAI-compatible endpoint now correctly use OpenAI image_url, while Minds/MindsHub keep the Anthropic format. Text-only was already fine; this fixes vision. Surfaced in the ENG-466 review of cowork-server #111 (presenting gemini as openai-compatible exposed this pre-existing scratchpad_boot assumption). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(llm): gate openai-compatible vision format on host in from_settings too Same bug #216 fixed in scratchpad_boot, on the main-agent path: LLMClient.from_settings's "openai-compatible" factory hardcoded vision_format="anthropic" unconditionally. A standalone anton instance with openai-compatible pointed at a non-Anthropic endpoint (Gemini, a generic proxy) gets Anthropic-shaped image blocks → mangled images. (Does not affect the cowork product: cowork-server's build_llm_client constructs OpenAIProvider directly with the default vision_format="openai", bypassing from_settings. So this is the anton-standalone path only.) Gate on the base-URL host (mdb.ai / mindshub.ai) like the scratchpad_boot fix: Minds/MindsHub keep anthropic image blocks; Gemini + generic compatible endpoints use OpenAI image_url. Tests: from_settings vision_format is anthropic for mindshub/mdb hosts, openai for Gemini and generic hosts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-instrumentation-in-app-events ENG-385: tag CI traffic with is_ci
[Feat] Desktop app publish url
deterministic zip bundle so md5 is time-independent
…es the LLM (ENG-463) scrub_credentials only redacted DS_* datasource secrets, so a provider key (mdb_/sk-/AIza) appearing in a tool result, scratchpad traceback, or settings echo passed straight into model context — and the agent was caught writing a raw mdb_ key into generated code. A model can only emit a secret it can see. It's already applied to every tool result before it's appended to history (session.py:1472/1464); extend it to also redact: - the values of provider env vars (OPENAI/ANTHROPIC/GEMINI/ANTON_*_API_KEY + ANTON_MINDS_API_KEY) with an informative [VAR] label, then - anything matching a well-known key shape (mdb_…, sk-/sk-proj-/sk-ant-…, AIza…) so a key that didn't originate from one of our env vars is still caught. Base URLs and short sk-/mdb_ fragments are left readable to avoid over-redaction. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Caller tags reach `Langfuse-Tags` via `",".join(...)` and the MindsHub router splits on commas, so an embedded comma silently split one tag into two and a CR/LF would make httpx reject the outbound request. Strip commas and control chars and trim each tag, dropping any that become empty. Adds a unit test for `_build_trace_headers` locking in tag ordering (harness first, then caller tags), the sanitization, and the load-bearing "identity wins" merge for `turn_id`/`harness` metadata. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Triggers the auto-release workflow (fires on changes to anton/__init__.py on main) so the trace_tags / trace_metadata kwargs from this branch reach PyPI as a new anton-agent release. cowork-server #125 pins anton-agent>=2.26.6.30.1 against it, so this must land on main before that PR merges. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
send trace data
Before refusing a task based on a training-data fact (e.g. "that company isn't public"), Anton now treats the user's question as evidence the fact may have changed, verifies online first, and only blocks after confirming the assumption is still current. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…t prompt (ENG-508) (#227) * feat(datasources): surface connection identity/label in the agent prompt (ENG-508) build_datasource_context listed only DS_* var names, so the agent could see a connection existed but not which account — breaking multi-account selection. It now shows a short, non-secret label per connection: the human label ("Support") if set, else the account email / account_email (OAuth), else the DB host (+ name). Scoped to those identity fields — never a dump of client_id / config, never a secret, and respects the record's secure_keys. Works for pre-existing random-slug connections too (reads the stored fields). Adds tests covering identity selection, secret/secure_keys safety, account_email, and label preference. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(datasources): omit `_`-prefixed bookkeeping from the env-var list (ENG-508 review) The Connected Data Sources prompt listed `_connector_id`/`_method`/`_label` as DS_* env vars — noise the agent shouldn't reference. Skip `_`-prefixed keys. Adds a test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…le-training-data-assumptions-online-before ENG-513: validate stale training-data assumptions before blocking tasks
…eys-from-context fix(scrub): redact provider API keys from tool output before it reaches the LLM (ENG-463)
Updates the README to reflect that Anton is the open-source agentic harness behind MindsHub Cowork, swaps in the Cowork app downloads, and cleans up stale references. - **Reposition**: Anton is "the open-source agentic harness that powers MindsHub Cowork" — the default agent inside Cowork, and standalone via the CLI. Dropped the "alternative to Claude-Cowork" framing (collides with the *Cowork* product name). - **Downloads → Cowork**: removed the standalone Anton `.pkg`/`.exe` links; the desktop/web path now points to `console.mindshub.ai` (web) and the `mindshub-cowork` macOS/Windows builds. Kept the Anton CLI install (curl/PowerShell). - **Community**: added Discord (`mindshub.ai/discord`) in the badges/nav and a new **Help & community** section; added **Contributing** (PRs target `dev`) and a **Security** pointer. - **License**: footer previously claimed **AGPL-3.0**, but the repo's `LICENSE` file is **MIT**. Removed the hardcoded mention to avoid future drift — the README now relies on GitHub's license display + a dynamic badge.⚠️ If Anton is meant to be AGPL, the `LICENSE` file needs updating (separate change). - **Cleanups**: fixed typos (`Calendarss`, "was was", "connect an interact", "unsubscribable"); "at MindsDB" → "at MindsHub" in the naming section. - **UTMs** on `mindshub.ai` links (`utm_campaign=anton-readme`); downloads and Discord left bare. - **Preserved** all technical/maintainer content (web search table, workspace layout, firewall, analytics, trace headers, Dev guidelines, Versioning, Releasing) with heading anchors intact, plus the promo image, gifs, and DeepWiki badge.
…ompt - datasources.md: registers hasdata engine (api_key + base_url fields, test snippet, full endpoint reference table) - prompts.py: adds HasData section to PUBLIC DATA so Anton knows when/how to reach for each of the 25+ APIs without manual instruction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…datasources.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The API does not return results directly. Step 1 returns a CDN URL in requestMetadata.resultUrl; step 2 fetches that URL after a 2-3s wait. - Fix test_snippet to use the async two-step flow - Document the pattern prominently with a canonical code example - Add sitelinks dict/list guard (field type varies by result) - Remove incorrect root-probe from test (/ returns 404) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n-25-web-data-apis-via-single-connector ENG-520: add HasData datasource + endpoint docs in system prompt
Publisher: add list_versions / activate_version
Confidence Score: 5/5 - Safe to MergeSafe to merge — this staging PR for the week of 26-06-22 shows no identified issues across the automated heuristic analysis or manual review pass. No logic bugs, security concerns, missing validations, or performance regressions were detected in any of the changed files. The PR appears clean and ready for production. Key Findings:
|
Main to staging
hamishfagg
approved these changes
Jul 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.