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
109 changes: 109 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,115 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

## [Unreleased]

## [2026.8.6] - 2026-08-06

### Added

- A cron job can run a script instead of a model turn. `--job-kind script`
makes the script the job: its stdout is delivered verbatim, empty stdout is a
silent tick, and a non-zero exit delivers the error and fails the job so a
broken watchdog cannot be mistaken for a quiet one. `--job-kind agent_turn
--script` runs the script first as a collector — its stdout is prepended to
the prompt as a `## Script output` block, and a tick that prints nothing (or
ends with `{"wakeAgent": false}`) skips the turn before the session is
touched, leaving no session row, transcript line, or model call behind.
Scripts resolve inside `~/.agentos/scripts/`; absolute paths, `~`, `..`, and
symlinks out of it are refused, and arguments are exec'd as argv, never handed
to a shell. Scheduling one requires an interactive CLI or Web caller — the
in-agent `cron` tool refuses it from a chat channel. (Refs #219)
- New bundled skill `cron-watchers` ships the three script jobs everyone writes
first — an RSS/Atom feed, a JSON endpoint, and a GitHub repo — each following
the contract the scheduler expects: print what is new, print nothing when
nothing is new, exit non-zero on a real failure. Deduplication state lives in
`~/.agentos/state/cron-watchers/<name>.json`, outside the scripts directory,
and the first run reports nothing by default. (Refs #219)
- `agentos cron output <job-id> [--run <run-id>]` and the `cron.runOutput` RPC
read one run's output in full; the in-agent `cron` tool gains
`action="runs"`, so "what did the watcher report?" is a question the model can
look up instead of invent.
- `senior-unilp-manager` can open the pool a position lives in.
`lp_write.py create-pool` initializes hook-less Uniswap v4 pools —
`hooks` is pinned to `address(0)` with no flag to change it, a dynamic fee is
refused, an odd fee/tick-spacing pair needs `--allow-odd-tier` because `pools`
only searches the vanilla tiers, and an already-initialized pool prints its
poolId and exits without planning. The starting price can never be corrected
afterwards, so the plan table prints tick, `sqrtPriceX96`, and the price in
both directions under a banner saying so. selftest goes 695 → 716 assertions.
- `tick --json --alert-only` lets a `senior-unilp-manager` ratchet cron stay
quiet. A tick that found nothing still prints the whole payload — the run
history keeps it — but ends on `{"wakeAgent": false}`, which
`has_actionable_output()` reads as "no news": the run succeeds and nothing is
delivered. A tick that fired, adopted a landed fire, halted, was rejected,
expired, or built a plan on a dry run is delivered as usual, and
`NEEDS_ATTENTION` deliberately alerts on every tick — it is a terminal state,
so filtering on the action alone would silence the one alarm that must never
go quiet. (Closes #234)
- `lp_read.py price --tokens` is documented (SKILL.md §6b), with the rule to use
it rather than deriving a price from a pool — a session derived a token's
price from a zero-TVL dust pool, was off by 3×, and that number would have
become the permanent starting tick of a new pool. (Refs #228)

### Fixed

- A bad cron delivery target is rejected at save time instead of failing every
run. `validate_channel_target` refuses an id beginning with a session-key
prefix (`agent:`, `cron:`, `webchat:`, `session:`) and requires an integer or
`@username` for Telegram, suggesting the id that would have worked; `cron.add`
and `cron.update` then ask the adapter itself via `TelegramChannel.probe_target`,
where only a definite "no" blocks the save. The new `channels.deliveryTargets`
RPC lists each channel's paired DMs and configured group chats, so the Web UI
renders Recipient as a dropdown with `Enter manually…` as the escape hatch.
- A cron run record now carries *why* delivery failed. `DeliveryReport.channel_detail`
turns one line of "delivery failed" into "delivery to telegram failed: Bad
Request: chat not found" in `agentos cron runs`, and an exception escaping the
channel leg reports its type instead of vanishing into `asyncio.gather`.
- `structlog` events reach `~/.agentos/logs/debug.log`. Half this codebase logs
through `logging.getLogger` and half through structlog, and only the first half
was written to the file — the missing half included every `delivery.*` warning.
- A cron run's output is stored whole. `clamp_run_output` replaces the scattered
`[:500]` slices that truncated a script job's stdout on the way into the
database; `preview_summary` is what the delivery layer and the run list get,
and the Web UI's expanded row fetches the full text lazily.
- The "→ Chat" button no longer leads to "Could not load chat history." Each run
reports `chatAvailable` and the button is hidden when it is false — script jobs
never create a session, and isolated agent sessions are reaped after 24h — while
`chat.history` answers an empty transcript for a missing cron session instead of
raising.
- The session reaper is paged. `list_sessions()` returns the 100 most recently
updated sessions — precisely the ones that are *not* expired — so expired
isolated cron sessions were never reaped on a busy store.
- A script job's output no longer vanishes. Several skips in the delivery chain
encode "the run already wrote this into the session", which holds for an agent
turn but not for a script, which has no turn: a job with `sessionTarget=current`
from webchat was reported delivered without a byte being written, and a job
bound to the chat its run *is* was skipped on `origin == session_key`. A
`cron add --script` from the CLI, which genuinely has nowhere to write, now
reports `no_session_target` rather than a bare `skipped`.
- A cron tool refusal reaches the model. Cron raises plain `ToolError` in ~30
places with field-naming messages that `envelope.py` discarded, so a call
carrying `tool_policy.elevated` on a script job came back as "received an
invalid argument" followed by seven retries that dropped the required
`schedule` field. Cron's refusals are `SafeToolError` now, and `job_kind='script'`
+ `tool_policy.elevated` is rejected up front, naming the field. (Refs #228)
- A quoted script path is unwrapped before it is stored. A model passes
`script='"watch-memory.sh"'` often enough that it is the first thing that
happens; the job saved cleanly and failed on its first tick. (Refs #219)
- `/reset` clears the visible conversation on web and CLI. `sessions.reset` keeps
the session key and only rotates `session_id`, so the transcript on screen
stayed put, which reads as "nothing happened". The Web UI clears on
`session.epoch_changed`, which covers the typed `/reset`, the slash menu, the
SessionChip button, and a reset issued by another client; the CLI gains
`ChatApplication.clear_screen()`, which drops scrollback too.
- Two `senior-unilp-manager` doc commands were unrunnable — `python3 <S>/ratchet.py`
reads as a redirect from a file named `S` in a shell — and the cron examples
cannot use `$S` at all, since a cron job runs in a fresh isolated session. Both
now spell out `{baseDir}/scripts/ratchet.py`. (Refs #228)

### Changed

- The cron surfaces say "no LLM" instead of "no model", and `agentos cron runs`
grows Delivery and Output columns.

## [2026.8.5] - 2026-08-05

### Added
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ OpenAI, Anthropic, Ollama, DeepSeek, Gemini, Qwen/DashScope, and 20+
other providers. You do not need to change your code or config to
switch providers.

AgentOS 2026.8.5 is the current release. The project website is
AgentOS 2026.8.6 is the current release. The project website is
[useagentos.dev](https://useagentos.dev). Follow
[@useAgentOS](https://x.com/useAgentOS) on X for updates.

Expand Down Expand Up @@ -224,14 +224,14 @@ agentos gateway run
> new terminal window. Or run the PATH command from step 1 again.

For an install pinned to one exact version, add `==<version>` — for
example `uv tool install --python 3.12 "use-agent-os[recommended]==2026.8.5"` —
example `uv tool install --python 3.12 "use-agent-os[recommended]==2026.8.6"` —
or use the GitHub release wheel link directly:
`https://github.com/use-agent-os/agent-os/releases/download/v2026.8.5/use_agent_os-2026.8.5-py3-none-any.whl`.
`https://github.com/use-agent-os/agent-os/releases/download/v2026.8.6/use_agent_os-2026.8.6-py3-none-any.whl`.

> [!NOTE]
> Release install commands use published GitHub release assets.
> Python wheel installs use versioned wheel filenames — for example
> `use_agent_os-2026.8.5-py3-none-any.whl` — because the installers validate the
> `use_agent_os-2026.8.6-py3-none-any.whl` — because the installers validate the
> version segment inside the wheel filename, so there is no `latest`
> wheel alias. Only the Windows portable zip has a version-independent
> `releases/latest/download/` alias.
Expand Down
1 change: 1 addition & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

| Version | Tag | Date | Notes |
|---|---|---|---|
| 2026.8.6 | v2026.8.6 | 2026-08-06 | A cron release: schedules can now run scripts, and the run history is finally readable. `--job-kind script` makes the script the job — stdout delivered verbatim, empty stdout a silent tick, non-zero exit a failed job — while `--job-kind agent_turn --script` runs the script first as a collector and skips the turn entirely when it prints nothing or ends with `{"wakeAgent": false}`, before the session is touched. Scripts resolve inside `~/.agentos/scripts/` with no escape via absolute paths, `~`, `..`, or symlinks, and are exec'd as argv. The new bundled `cron-watchers` skill ships the three watchers everyone writes first (RSS/Atom, JSON endpoint, GitHub repo). Around that, the surface that reports what a job did was rebuilt: run output is stored whole instead of clipped at 500 chars (`agentos cron output`, `cron.runOutput`, and lazy fetch in the Web UI), a script job's output no longer vanishes into delivery skips written for agent turns, the "→ Chat" button is hidden when no chat exists rather than leading to "Could not load chat history", and the session reaper stops missing expired sessions on a busy store because `list_sessions()` only returned the 100 most recent. A bad delivery target is refused at save time — a session key is not a Telegram chat id — with a dropdown of paired chats offered instead of free text, the failure reason lands on the run record, and `structlog` events (every `delivery.*` warning among them) finally reach `debug.log`. Cron's tool refusals reach the model as messages it can self-correct from instead of "received an invalid argument". `/reset` now clears the conversation on screen on both web and CLI. `senior-unilp-manager` gains `create-pool` for hook-less v4 pools — hooks pinned to `address(0)`, dynamic fees refused, odd tiers gated, and the uncorrectable starting price printed three ways before confirm — plus `tick --alert-only`, which lets a healthy ratchet cron stay quiet without silencing `NEEDS_ATTENTION`. |
| 2026.8.5 | v2026.8.5 | 2026-08-05 | A cron-reliability and web-UI release. A cron job no longer fails forever once the chat it was created from is gone: the web UI stamps `originSessionKey` onto every reminder job while forcing its target to `isolated`, and "New Chat" mints a session key client-side with no row, so a reminder created before the first message pointed at a session that never existed — the fire-time mirror then raised `KeyError: Session not found`, surfaced as `forward_failed`, and failed the run with no `best_effort` checkbox rendered for the `none` delivery mode it ran under. The mirror is opportunistic now and reports a distinct `origin_gone` status; genuine channel delivery failures still fail the run. Unknown cron tool profiles are rejected at write time instead of dying ~50 ms into every firing until the scheduler auto-paused the job — `normalize_tool_profile` raises listing the profiles that exist, the read direction stays tolerant so already-broken rows can still be listed and deleted, and the tool schema now names the valid profiles. In the web UI, cron cards stop spilling over the neighbouring column (an unbreakable session key has no break opportunity per UAX-14, and three boxes between the grid track and the text could not shrink), and a job's ID — the handle every `agentos cron …` command takes — is finally visible, shortened with a copy button. The Skills page gains `Use` / `Use in chat` buttons that pre-fill the chat composer with `use skill <name>` instead of making the operator retype it. `senior-unilp-manager` can arm an unattended take-profit ratchet on a one-sided Uniswap v4 position: at milestones measured against the original principal it exits, keeps the converted side as realized profit, and redeploys the remainder into a narrower range in a single `modifyLiquidities` (DECREASE → BURN → MINT → TAKE_PAIR, no SETTLE), authorized by an object the CLI structurally cannot construct. One live mandate per position is now enforced by scan, since `mandate_id` hashes the label and two labels armed two mandates to burn the same NFT. The combined unlock has not been rehearsed against a hooked pool; SKILL.md requires a dust rehearsal first. |
| 2026.8.3 | v2026.8.3 | 2026-08-03 | A packaging, skills, and upgrade-path release. `agentos upgrade` now installs the published release instead of delegating to `uv tool upgrade`, which re-resolved uv's *directory* receipt on checkout-backed installs and re-packaged whatever `static/dist/` was on disk — so Python moved forward while the web UI silently did not; installing a checkout stays with `scripts/install_source.sh`, the only path that rebuilds the bundle first. A `pip install use-agent-os` no longer resolves open-ended: bounds now cover the rest of the base runtime and the consumer-facing extras, each cap at the first release its upstream may break in — the next major for a `>=1.0` project, the next **minor** for a `0.x` one — recomputed from `uv.lock` by `tests/test_packaging/test_pyproject_invariants.py` so a new dependency cannot ship unbounded by accident (#153). Shipped Pilot Router tier defaults resolved against static tables with no entry for them and both tables fail open without logging, so `glm-4.7-flashx` estimated at a generic $3/$15 and seven ids — including `anthropic/claude-opus-5` — sized turns against generic limits; every tier default now carries an explicit pricing and catalog entry (#139). OpenCAP cost estimates no longer fall back to Bankr's rate sheet for the life of a process after one failed boot fetch — the price cache refreshes on a TTL, and a static-table estimate is logged once per model. Seven GMGN trading skills ship bundled under the new **Trading** category, driving the third-party `gmgn-cli` that AgentOS does not redistribute. A hub install can no longer silently shadow a bundled skill, `skill_search_community` answers with an `installed_match` block naming what a local skill is missing, and `skill_view(name="agentos", section="Skills")` resolves. Durable memory redaction moves onto the shared scanner (forced, since `AGENTOS_REDACT_SECRETS=0` is an egress-only escape hatch), which also learned the `ASIA`/`ABIA`/`ACCA` AWS prefixes and quoted `Authorization`/`x-api-key` headers. |
| 2026.8.2.post1 | v2026.8.2.post1 | 2026-08-02 | A packaging fix for the 2026.8.2 release. The wheel guard allowed markdown only at a bundled skill's `SKILL.md` plus two force-included pptx references, so `senior-unilp-manager`'s `assets/v4-reference.md` read as a forbidden entry and the tagged Windows release job failed for v2026.8.2 after the tag was already pushed — while a wheel that did build shipped `SKILL.md` links pointing at a file stripped from disk. `agentos/skills/bundled/<skill>/assets/**` is now allowed (`references/` and stray top-level markdown stay forbidden) and a real-tree test over the bundled skills fails PR CI instead of the tagged release job. Cron prompt safety no longer rejects Unicode combining marks — Vietnamese and other scripts that need them pass again, while genuinely invisible marks stay blocked. |
Expand Down
2 changes: 1 addition & 1 deletion install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ param(
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$defaultVersion = 'v2026.8.5'
$defaultVersion = 'v2026.8.6'
$repoSlug = if ($env:AGENTOS_REPOSITORY) { $env:AGENTOS_REPOSITORY } else { 'use-agent-os/agent-os' }
$pythonVersion = if ($env:AGENTOS_PYTHON_VERSION) { $env:AGENTOS_PYTHON_VERSION } else { '3.12' }
$originalPath = if ($env:Path) { $env:Path } else { '' }
Expand Down
6 changes: 3 additions & 3 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

set -euo pipefail

default_version="v2026.8.5"
default_version="v2026.8.6"
repo_slug="${AGENTOS_REPOSITORY:-use-agent-os/agent-os}"
python_version="${AGENTOS_PYTHON_VERSION:-3.12}"
original_path="${PATH:-}"
Expand All @@ -18,10 +18,10 @@ cli_extras=""

usage() {
cat <<HELP
Usage: bash install.sh [--version v2026.8.5|latest] [--profile recommended|core] [--extras name[,name]]
Usage: bash install.sh [--version v2026.8.6|latest] [--profile recommended|core] [--extras name[,name]]

Environment equivalents:
AGENTOS_VERSION=v2026.8.5
AGENTOS_VERSION=v2026.8.6
AGENTOS_INSTALL_PROFILE=recommended|core
AGENTOS_INSTALL_EXTRAS=document-extras
AGENTOS_INSTALL_DRY_RUN=1
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "use-agent-os"
version = "2026.8.5"
version = "2026.8.6"
description = "Token-Efficient AI agent with on-device Pilot Router"
license = "Apache-2.0"
license-files = ["LICENSE", "NOTICE", "THIRD_PARTY_NOTICES.md"]
Expand Down
2 changes: 1 addition & 1 deletion tests/test_install_scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
RELEASE_SH = ROOT / "install.sh"
SOURCE_PS1 = ROOT / "scripts" / "install_source.ps1"
SOURCE_SH = ROOT / "scripts" / "install_source.sh"
CURRENT_RELEASE_TAG = "v2026.8.5"
CURRENT_RELEASE_TAG = "v2026.8.6"


def test_source_install_scripts_force_refresh_local_uv_tool_package() -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_release_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import tomllib
from pathlib import Path

CURRENT_VERSION = "2026.8.5"
CURRENT_VERSION = "2026.8.6"
CURRENT_TAG = f"v{CURRENT_VERSION}"
PREVIEW_VERSION = "0.0.1rc1"
PREVIEW_TAG = f"v{PREVIEW_VERSION}"
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading