Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,33 @@ All notable changes to this package are recorded here. The format follows

## Unreleased

### Added

- **`cancel_agent(run_id)` stops an agent run by its id**, with no handle needed: what `AgentRun.cancel()` does, in one request. `cancel_job(kind="agent")` in MCP uses it, so it no longer reads the run first.
- **The MCP `run_agent` tool keeps an agent given starting `urls` on their sites** unless `allowed_domains` says otherwise -- each URL's host, lower case, without `www`, the API keeping its subdomains -- as the app does, since a page the agent reads could tell it to go elsewhere. `allowed_domains=[]` lets it read any site; with no `urls` there is no limit. The client's `agent()` is unchanged: it sends what it is given.

- **The client hands a question to the agent, which searches, reads pages and answers on its own.** `agent(prompt, urls=, schema=, max_credits=, max_steps=, allowed_domains=, timeout_s=0, idempotency_key=)` returns an `AgentRun` at once; `timeout_s` asks the API to hold the request for the answer, 120 s at most. `AgentRun.wait(poll=2.0, timeout=3600)` returns the envelope once the run is `done`, `cancelled` or `credit_limit` (what it had found under `data.partial`) and raises `MeshArcError` 502 `job_failed` for `error` and for any other end it does not know, as the Node client does; `refresh()` reads it as it stands, `cancel()` stops it (`cancelled` when queued, `cancelling` when running, which stops before its next step), and `trace(after=0, follow=True)` yields what the agent does, step by step. `data` is JSON matching the schema, or `{"text": ...}` without one, and `sources` the pages it rests on. `get_agent(id)` reopens a run, and raises `MeshArcError` 410 with code `expired` once it is past its 7 days; `agent_runs(status=None, limit=25)` walks the workspace's runs, following `next`. It needs a key that can write, and spends credits: pages as they are read (a refused page is free) and the model's tokens at the model provider's price plus 20%, within `max_credits` (2,000 by default). **This needs an API that has the `/agent` route**, which is not live on mesharc.dev yet.
- **An agent run can report to a webhook and run on the workspace's own model.** `agent()` takes `webhook=` (a URL, or `{url, events, metadata}`, told about `agent.started`, `agent.action`, `agent.completed`, `agent.failed` and `agent.cancelled`) and `connection_id=` (one of the workspace's LLM connections, whose tokens then cost 1 credit per 1,000). `AgentRun.webhook_secret` is the secret the messages are signed with, returned once on the POST and kept by the handle past `refresh()`, and by the handle `continue_()` returns; `""` without a webhook. **These need an API with the agent's webhook and connection features**, which are on the API's feature branch, not yet on mesharc.dev.
- **`AgentRun.field_sources` says where each value of the answer came from**: its path (`"plans[0].price"`, `"[2].name"` for a list answer) to `{url, pageId}`, a page the run read; `{}` when the API said nothing. **This needs an API with field sources**, on the API's feature branch, not yet on mesharc.dev.
- **`AgentRun.continue_(max_credits=None, max_steps=None, timeout_s=0, idempotency_key=None)` carries on a run that stopped at `credit_limit`**, with a new budget. It returns an `AgentRun` on the new run, which resumes from where the stopped one was, keeps the pages it read (not paid for again) and its webhook, and answers in full. The API carries the webhook's secret over without repeating it, so the new handle's `webhook_secret` is the stopped handle's. `continues_run_id` and `continued_by` link the two runs. A run that did not stop at its limit, was already continued or has no saved progress raises `MeshArcError` 409 `conflict`; one past its keep date, 410 `expired`. **This needs an API that has the `/agent/{id}/continue` route**, on the API's feature branch, not yet on mesharc.dev.
- `agent_runs()` also filters by `model=` and by `since=` / `until=` (an ISO 8601 string, or a `date` / `datetime`, sent as ISO 8601), sent on every page like `status`; an empty string sends no filter. A date means its midnight UTC; a date-time without a zone is read as UTC, so a naive `datetime.now()` is local time read as UTC.
- **`web_search(news=True)` searches the engines' news results**, each hit with `publisher` and `age`; `page=` (1 to 10) reads results further in, page 2 being results 11-20. Both come last in the signature, after `idempotency_key`, so no existing call changes meaning. An equal news search comes from the cache for ten minutes, not an hour. **These need an API with news and results-page search**, on the API's feature branch, not yet on mesharc.dev.
- **Monitors: a search or an agent request, run again on a schedule and compared with the last run that answered**, under `arc.monitors` as projects are under `arc.projects`:

| Method | What it does |
|---|---|
| `monitors.create(kind, request, schedule, name=None, webhook=None, baseline_id=None, idempotency_key=None)` | Keep a search or agent request on a schedule |
| `monitors.list(kind=None)` · `monitors.get(id)` | The workspace's monitors, each with its `lastRun`; one monitor |
| `monitors.update(id, name=None, schedule=None, status=None, webhook=None)` | Sends only what is not None; `webhook=""` removes the webhook |
| `monitors.pause(id)` · `monitors.resume(id)` | Stop and restart the schedule |
| `monitors.run(id, idempotency_key=None)` | Run it now; 409 `conflict` while a run is under way |
| `monitors.runs(id, limit=25)` | Its runs, with what changed, following `next` |
| `monitors.delete(id)` | The monitor and its runs |

Each returns the API's JSON. `request` is a POST /search or POST /agent body in the API's own (camelCase) names, so a news monitor says `"sources": ["news"]` (`web_search(news=True)` maps to that; `monitors.create` does not); a monitored search reads its results page only, so `scrape` is refused; a search baseline's `limit` must be at least the monitor's. The webhook hears `search.changed` / `agent.changed`, and its secret comes back once as `webhookSecret`. Creating and running a monitor spend credits, and every call but the three reads needs a key that can write. `arc.monitor()`, the workspace's job queue, is unchanged. **This needs an API that has the `/monitors` route**, which is on the API's feature branch and not yet on mesharc.dev.
- **`run_agent`, a sixteenth MCP tool, so an assistant can hand a research question to the agent.** It needs write access; a read-only connection is answered `{"code": "read_only"}`. It returns at once with a job, hosted or local, and a retry that lands on a finished run gets its result; `get_job` and `cancel_job` take `kind="agent"` to follow and stop it, and a run past its 7 days answers `status: "expired"`. A finished answer carries `fieldSources`, where each value of `data` came from, and keeps within 60,000 characters: `fieldSources` is left out first, then its sources are cut to the first 50, then `data` to its JSON text, with a note saying where the full answer is. The model's tokens are charged at the model provider's price plus 20%. It sends its own idempotency key, made from its inputs and the ten-minute window, so a retry in the same ten minutes lands on the same run; a 409 saying that key is still being accepted (code `in_flight`, or an older API's message naming the Idempotency-Key) is answered as running, and any other 409 as an error. An output schema describes its answer. **This needs an API that has the `/agent` route**, which is not live on mesharc.dev yet.
- **`continue_agent`, a seventeenth MCP tool, carries on an agent run that stopped at its credit limit.** `continue_agent(id, max_credits=None, max_steps=None)` starts a new run on the same thread, which resumes where the stopped one was and keeps the pages it read (not paid for again); left out, the budget and steps are the stopped run's. It needs write access; a read-only connection is answered `{"code": "read_only"}`. It returns at once with the new run's job, as `run_agent` does, for `get_job` and `cancel_job` with `kind="agent"`, and sends its own idempotency key, made from its inputs and the ten-minute window. A run already carried on (a retry past that window included) is answered with the run that carried it on, and nothing new is started. A run that did not stop at its limit is answered with code `conflict`, an unknown one `not_found`, one past its 7 days `expired`. A `credit_limit` answer's note now points at `continue_agent` with the run's id, or at the run that already carried it on. **This needs an API that has the `/agent/{id}/continue` route**, which is not live on mesharc.dev yet.

## 0.6.0 - 2026-10-07

Two MCP tool names change, so **this breaks anything that calls `web_search` or `get_page` by name**; both still do what they did, under the new names below. The Python client's API is unchanged apart from two additions: `web_search()` keeps its name there.
Expand Down
Loading
Loading