Skip to content

Feat/web search agent - #13

Merged
Siddharth-DWT merged 5 commits into
mainfrom
feat/web-search-agent
Oct 12, 2026
Merged

Siddharth-DWT merged 5 commits into
mainfrom
feat/web-search-agent

Conversation

@Siddharth-DWT

@Siddharth-DWT Siddharth-DWT commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Title: The agent and monitors: agent(), AgentRun with continue_, arc.monitors, and the run_agent and continue_agent MCP tools

Branch: feat/web-search-agent → main. Three commits on top of main (27f1332, Release 0.6.0):

  • 41a14f2 Merge origin/main (0.6.0) into feat/web-search-agent. This brings the branch onto 0.6.0 with no file changes of its own: its tree is exactly 0.6.0's.
  • 0ffa768 the agent and monitors.
  • 91bf33a review fixes (below).

The branch's two older commits (3b07879, ce8a7a6) were released as 0.5.0 and add nothing to the diff.

Up to date with main (checked 12 Oct): main (27f1332) has no commits the branch lacks, and the branch merges into it cleanly. Against main the diff is 9 files, +1,926 −73.

Review fixes (91bf33a)

From a code review of this branch:

  1. run_agent stays on its starting sites. Given urls and no allowed_domains, the MCP tool holds the agent to the URLs' sites: each host, lower case, without www (the API keeps its subdomains). The app does the same, because a page the agent reads could tell it to go elsewhere.
    • allowed_domains given wins, and [] means no limit;
    • with no urls there is nothing to hold it to;
    • the client's agent() is unchanged, and sends what it is given, as the API documents.
  2. cancel_agent(run_id) stops an agent run by its id in one request. MCP cancel_job(kind="agent") uses it instead of reading the run first, and AgentRun.cancel() shares it.
  3. One cursor pager (_paged) serves searches(), agent_runs() and monitors.runs(), instead of three copies of the loop.
  4. AgentRun.wait() returns only a done, cancelled or credit_limit run. Any other end raises MeshArcError 502 job_failed, as the Node client does.

What

Client (mesharc/__init__.py)

  • agent(prompt, urls=, schema=, max_credits=, max_steps=, allowed_domains=, webhook=, connection_id=, timeout_s=0, idempotency_key=) returns an AgentRun at once.
    • wait() returns once the run is done, cancelled or credit_limit, and raises MeshArcError for error.
    • It also has refresh(), cancel(), and trace(after=0, follow=True), which yields the steps.
    • It holds data, sources and field_sources (each value's path → {url, pageId}).
    • webhook_secret is returned once and kept by the handle across refresh() and continue_().
  • AgentRun.continue_(max_credits=, max_steps=, timeout_s=, idempotency_key=) carries on a run stopped at credit_limit.
    • The new run keeps the pages already read (not paid for again) and the webhook.
    • continues_run_id and continued_by link the two runs.
    • Errors: 409 conflict for a run that cannot be continued; 410 expired past 7 days.
  • cancel_agent(id) stops a run by its id, with no handle needed.
  • get_agent(id) reopens a run; agent_runs(status=, model=, since=, until=, limit=) walks the workspace's runs, following next. since and until take ISO strings, dates or datetimes.
  • web_search(news=True, page=) reads news results (with publisher and age) and results pages 2–10. Both come last in the signature, so no existing call changes meaning.
  • arc.monitors: create(kind, request, schedule, name=, webhook=, baseline_id=, idempotency_key=), list(kind=), get, update, pause, resume, run, runs (following next) and delete. A search or agent request is kept on a schedule. arc.monitor(), the job queue, is unchanged.

MCP server (mesharc/mcp.py): 17 tools on 0.6.0's names (search_web, list_pages(url=))

  • run_agent hands a question to the agent and returns at once with a job.
  • continue_agent(id, max_credits=, max_steps=) carries on a run stopped at its limit:
    • a run already carried on is answered with the run that continued it;
    • a run that cannot be continued is conflict, an unknown one not_found, one past its 7 days expired.
  • Both: need write access ({"code": "read_only"} otherwise); send their own idempotency key, made from their inputs and a ten-minute window; answer a 409 in_flight as running.
  • run_agent with urls and no allowed_domains stays on those URLs' sites; [] means no limit.
  • get_job and cancel_job take kind="agent"; cancel_job stops a run in one request. A finished answer keeps within 60,000 characters: fieldSources is dropped first, then the sources are cut, then data. The answer never includes the webhook secret.
  • Eleven of the seventeen tools need write access.

Docs: README (the agent, continue, monitors, the MCP tool list, idempotency, timeouts) and CHANGELOG (under Unreleased).

Testing

  • Checks on the branch head (12 Oct): ruff clean, mypy no issues, pytest 247 passed (4 of them new, for the review fixes), scripts/check_release.py passes (version 0.6.0).

  • The review fixes, live against the local API (6/6):

    • run_agent with https://www.Books.toscrape.com/ and no allowed_domains made a run held to books.toscrape.com;
    • allowed_domains=[] gave a run with no limit, and no urls gave none;
    • MCP cancel_job and the client's cancel_agent each stopped a run;
    • wait() returned the cancelled run as an answer.
  • Live, against the local API in production mode: 17/17. Covered:

    • news search and page 2;
    • creating a monitor with a search as its baseline, listing, update (schedule, webhook set and removed), pause and resume;
    • run now, with a second run refused with 409, settled and compared; then delete;
    • an agent run on a tiny budget stopping at credit_limit, then continue_() to a full answer with field sources and the thread links;
    • continuing twice refused with 409;
    • agent_runs(model=, since=date);
    • MCP get_job(kind="agent") without the webhook secret, and continue_agent on a finished run refused with conflict.

    The MCP server lists exactly the 17 expected tools, and search_web answered live.

Notes

  • Needs the API's feature branch (Seam-be feat/search-agent-groundwork, PR #26): /agent, /agent/{id}/continue, /monitors, and search news and page. Release only after it is live on mesharc.dev.

  • Not in this PR: the API branch has more that the client and MCP do not cover yet:

    • follow-ups and conversations (/agent/{id}/follow-up, /agent/conversations);
    • an agent monitor's records;
    • agent batches;
    • triggers;
    • proposals;
    • /estimate.

    They come in a follow-up PR. Proposals will only be listable over MCP, so an AI client cannot approve its own agent's proposals.

  • Version: stays 0.6.0 here; the release PR bumps it.

Siddharth-DWT added 5 commits October 7, 2026 16:44
…CP tool

- Client: web_search(query, ...) runs POST /search and waits; get_search(id); searches(q=None, limit=25) pages the history.
- MCP: web_search, a sixteenth tool with an output schema, within the 60,000-character budget; hosted hands back a job. get_job takes kind search.
- MCP errors carry the API's code and request_id; the read-only answer names 'Also allow changes'.
- The settings guide gives json_schema, llm_extract and formats in shapes the API accepts.
# Conflicts:
#	CHANGELOG.md
#	mesharc/mcp.py
…itors, run_agent and continue_agent

Client:
- agent(prompt, urls=, schema=, max_credits=, max_steps=, allowed_domains=,
  webhook=, connection_id=, timeout_s=, idempotency_key=) returns an
  AgentRun: wait(), refresh(), cancel(), trace(), data, sources,
  field_sources, webhook_secret (kept across refresh and continue_), and
  continue_() for a run stopped at credit_limit. get_agent(id),
  agent_runs(status=, model=, since=, until=).
- web_search(news=True, page=) for news results and later pages.
- arc.monitors: create, list, get, update, pause, resume, run, runs,
  delete -- a search or agent request kept on a schedule.

MCP (17 tools on 0.6.0's names):
- run_agent and continue_agent, both needing write access, answering at
  once with a job; get_job and cancel_job take kind="agent". A finished
  answer keeps within 60,000 characters (fieldSources dropped first).
  Their own idempotency keys; a 409 in_flight is answered as running.
…e pager, a stricter wait

- MCP run_agent given urls and no allowed_domains is held to the URLs'
  sites (host, lower case, without www), as the app does: a page the
  agent reads could tell it to go elsewhere. allowed_domains given wins,
  [] is no limit, and with no urls there is none. The client's agent()
  is unchanged.
- MeshArc.cancel_agent(run_id) stops an agent run by its id in one
  request; MCP cancel_job(kind="agent") uses it instead of reading the
  run first, and AgentRun.cancel() shares it.
- One cursor pager (_paged) for searches(), agent_runs() and
  monitors.runs(), instead of three copies of the loop.
- AgentRun.wait() returns only a done, cancelled or credit_limit run;
  any other end raises MeshArcError 502 job_failed, as the Node client.
- pytest 247 pass (4 new); ruff and mypy clean. README and CHANGELOG.
@Siddharth-DWT
Siddharth-DWT merged commit 04c385c into main Oct 12, 2026
6 checks passed
@Siddharth-DWT
Siddharth-DWT deleted the feat/web-search-agent branch October 12, 2026 10:29
Siddharth-DWT added a commit that referenced this pull request Oct 15, 2026
#17)

**Title:** Follow-ups, tables, monitors in full, triggers, proposals,
sub-accounts, and four monitor MCP tools

**Branch:** `feat/web-search-agent` → `main`. Two commits: `466280c`,
this work, made from `main` after #13's squash merge; and `149f7c1`,
`main` merged in (the security policy, #16; no conflict). Against `main`
the diff is 8 files, +1,371 −71, and it merges cleanly (checked with
`git merge-tree` on 15 Oct).

**Not to be released yet.** Every call added here needs API routes that
are on Seam-be's `feat/search-agent-groundwork` and not yet on
mesharc.dev. Release it (0.7.0) once that is deployed, as
`CONTRIBUTING.md` asks.

## Why

The API gained follow-ups, tables, monitor caps and records, triggers,
proposals, the estimate, sub-accounts, saved logins and data providers.
The client and the MCP server should reach them.

## What

**Client** (`mesharc/__init__.py`)

- **The agent:**
- `agent()` takes `login_id`, `data_connections` and `proposals`, each
sent only when given;
- `AgentRun.follow_up(prompt, ...)` asks the next question in the run's
conversation;
- `conversations(q=)` and `conversation(id)` list and read
conversations;
  - `trace()` knows the `lookup` step.
- **Monitors:**
- `create` and `update` take `budget`, `alerts`, `add_to_project`,
`rows`, `destination` and `sentiment`. `{}`, `""` and `False` are sent,
so they clear a setting; only `None` is left out.
- New: `overview()`, `rows()`, `rows_page()`, `row()`, `row_events()`
and `export_rows()`.
- **`arc.agent_batches`:** `preview`, `start`, `get`, `rows`, `wait`,
`list`, `cancel` and `export`, for the agent over every row of a table.
- **Also new:** `arc.triggers`, `arc.proposals` and `estimate(kind,
schedule, ...)`.
- **Sub-accounts:**
  - `arc.sub_accounts` makes and manages them;
- `MeshArc(tenant=...)` and `as_sub_account(id)` send `X-MeshArc-Tenant`
on every request;
  - `TENANT_HEADER` names the header.
- **`arc.connections` and `arc.logins`:** the workspace's connections
(data providers among them) and its saved logins.
- **Internals:** small shared helpers (`_some`, `_agent_body`,
`_offset_rows`, `_download`); `export()` now uses `_download`.

**MCP server** (`mesharc/mcp.py`): 21 tools.

- **`create_monitor`** keeps a web search (news too) or an agent
question on a schedule:
- an agent monitor stays on its starting sites unless told otherwise, as
`run_agent` does;
  - optional monthly cap, and record-by-record following;
- its own idempotency key, made from its inputs and the ten-minute
window.
- **`list_monitors`** lists the workspace's monitors, or one with its
latest runs. Read-only.
- **`pause_monitor`** pauses or resumes one.
- **`get_monitor_rows`** reads an agent monitor's records and what
moved, within 60,000 characters. Read-only.
- **`create_project`** takes `max_credits_per_run` and
`max_credits_per_month`. On a kept crawl they are set on the project it
becomes.
- Output schemas for the new answers; the server instructions name the
new tools.

**Docs:** README (follow-ups; logins, data providers and proposals;
monitors in full; tables; triggers, proposals and the estimate;
sub-accounts; connections and logins; the MCP tool list and the
read-only split; idempotency) and CHANGELOG, under Unreleased.

## Testing

- **Checks:** `ruff` clean, `mypy` clean, `pytest` 277 passed.
- `tests/test_client_workspace.py` (20 tests) and
`tests/test_monitor_tools.py` (10 tests) are new.
- The tool lists in `test_definitions.py` and `test_mcp_http.py` now
hold 21 tools, 8 of them read-only.
- **Live, against the local API from the feature branch**, in a
throwaway Scale workspace deleted afterwards:
- an agent run and its follow-up on one thread, the conversation listed,
and a 409 for a follow-up of a message that is not the latest;
  - a two-row table: preview, run, rows and export;
- an agent monitor with caps and records: 19 records with their sources,
and the overview;
  - a trigger made, listed, previewed, paused and deleted;
- sub-accounts: made; `as_sub_account` acts inside one, its own key
works and is revoked, and a suspended one refuses the header;
  - a data-provider connection whose real test refuses a made-up key;
  - the four MCP tools and `create_project`'s caps.
- **Field names** in the docs and the MCP descriptions checked against
Seam-be: a monitor record's columns are `attrs`; a table row's are
`values`.

## Notes

- `mesharc-mcp` pins the published 0.6.0 and is unchanged. It follows
the release.
- The MCP idempotency key is per process when run locally, as for
`run_agent`.

Co-authored-by: Siddharth-DWT <smishara9120@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant