diff --git a/CHANGELOG.md b/CHANGELOG.md index e600aef4..fbe151ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,15 @@ opt-out. ### Changed +- **Behavior change:** the built node-server (and the Docker image) now guards `POST /channels/` and its approvals route for a channel without `verify` with `LOUSHO_API_TOKEN` / `auth.ts`, the same as `/chat`. Before, such a channel answered anyone even with a token set. Channels that verify their own requests (Slack, Discord, Telegram, GitHub, Teams, `webhookChannel` with a secret, any channel with `verify`) are unchanged, and the start-up log lists each channel route's guard (`self-verified`, `server-auth` or `open`). +- **Behavior change:** `webhookChannel` replies with `{ sessionId, text, finishReason, approval? }` (plus `approvalPrompt` on a pause), as `httpChannel` does, instead of the full `ExecutionResult`. The full result echoed the system prompt and the whole transcript to the caller. `fullResult: true` restores the old body. +- Channels answer a turn on a session that another process or replica is running (`LOUSHO_SESSION_BUSY`) with `409` and `Retry-After: 2` instead of a `500`, and report a turn that fails before the request is acknowledged to `onError` with stage `'turn'` (it said `'parse'`). +- README and [Comparison](docs/comparison.md) no longer list ACP and MCP as differentiators, and describe Agent Forge as a local visual console. + - CI is one workflow with two jobs: `ci` (type checks, lint, build, tests with coverage, docs, API and fallow gates, pack-smoke, size check, and a zod 4 type check) and `compat` (the newest peers, `ai` 7 with zod 4, plus the real-Docker sandbox tests). The separate Docker Engine, Agent Forge E2E and weekly registry-smoke workflows and the `ai` 6 / zod 3 matrix entries are gone; `npm run registry-smoke` and `npm run test:e2e:studio` still run locally. When the fallow gate fails, CI now prints its full health and duplication reports. ### Added +- `httpChannel()` created without `verify` logs one warning that the channel is unauthenticated and its `sessionKey` values are guessable. [Channels](docs/channels.md) shows `verify` in the quick start, and [Deployment](docs/deployment.md) says which routes `LOUSHO_API_TOKEN` guards. - `POST /chat` accepts an `Idempotency-Key` header: a resend with the same key replays the finished turn's reply (`Idempotent-Replayed: true`, nothing runs), resumes a turn a crash interrupted instead of appending the message again, and is a `409` (`LOUSHO_SESSION_BUSY`) while that turn still runs. The key is stored on the turn's user message (`metadata.idempotencyKey`), so it survives restarts; `session.pending()` reports it as `idempotencyKey`. See [Resending a turn](docs/deployment.md#resending-a-turn). - `fromAiSdkTools(record)` converts Vercel AI SDK tools (`tool({ ... })` or plain `{ description, inputSchema | parameters, execute, needsApproval? }` objects) into Lousho tools, keyed by name: zod and Standard Schemas are kept, `jsonSchema()` wrappers and plain JSON Schemas are converted (their own `validate` still runs), `needsApproval` (boolean or function) pauses the run for approval, and `execute` gets the call id and the run's abort signal. It imports nothing from `ai`, so tools built on `ai` 4 to 7 work with any installed version. New guide: [Migrating from the AI SDK](docs/migrating-from-ai-sdk.md). - `lousho eval` without vitest installed now says it runs `*.eval.ts` files through vitest, the directory it searched from, and the install command; [Evals](docs/evals.md) states the requirement up front. @@ -26,6 +32,7 @@ opt-out. - `lousho doctor` fails an installed `ai` 5 (AI SDK v5 is not supported) with an upgrade hint to `ai` 6 or 7 and the matching `@ai-sdk/*` majors. ### Fixed +- `lousho add` works again when `registry.lousho.com` is unreachable: the fallback now tries the release tag as the repository names it (`1.0.0-alpha.24`), then the `v`-prefixed tag, then `main`. It asked only for `v`, which 404'd. - The file tools' `deny` list (`.git` by default) is now also checked where a path really leads: a symlink or Windows junction inside the workspace pointing at `.git` or into it (`gitj -> .git`) let `edit_file gitj/config` rewrite `.git/config` (for example `core.hooksPath`, which runs code on the next git command) and `write_file gitj/PWNED` create files in `.git`. Reads, writes, edits, `list_dir`, and `glob`/`grep` given such a link as `path` are now refused. Providers with links can implement the new optional `FsProvider.realPath(path)`; `NodeWorkspace` does. See [Workspace tools](docs/workspace-tools.md#security-model). - `NodeWorkspace.writeFile` (and so `write_file` / `edit_file`) writes a temp file in the same directory and renames it into place, so a process killed mid-write no longer leaves a truncated file. A replaced file keeps its permission bits; a read-only file is still refused. - `WorkspaceCheckpoints` stores a file's backup before `write_file` / `edit_file` writes it, not after. A process killed between the write and the backup lost the original: on resume the re-run call backed up the agent's own content, so `rewind()` reported `restored` but put back the agent's version (or, for `edit_file`, recorded nothing). A re-run now keeps the turn's first backup, and rewind treats a file still holding its backed-up content as nothing to undo. `track()` also accepts a `PreparedWorkspaceWrite` (`{ prepare, write }`), which the built-in tools use. diff --git a/docs/upgrading.md b/docs/upgrading.md index ce2473f4..7df47e8d 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -220,6 +220,9 @@ there is one. A change marked "no opt-out" closed a security or data-loss bug. | Slack and Discord signature checks accept a timestamp at most a minute ahead (was five minutes either way), read in seconds. | no opt-out | | `telegramChannel` and `teamsChannel` no longer post an OAuth sign-in link in a group chat. | no opt-out | | Channels without a `store` keep their transcripts in the agent's `createAgent({ store })` when it has `sessions`. | pass the channel its own `store` | +| The built node-server (and Docker image) requires `LOUSHO_API_TOKEN` / `auth.ts` on `/channels/` for a channel without `verify` when a token or `auth.ts` is set; self-verifying channels are unchanged. | give the channel a `verify` | +| `webhookChannel` replies `{ sessionId, text, finishReason, approval? }` instead of the full `ExecutionResult`. | `webhookChannel({ fullResult: true })` | +| A channel turn on a session another process is running answers `409` (`LOUSHO_SESSION_BUSY`, `Retry-After: 2`) instead of `500`. | no opt-out (retry after the delay) | ### Sessions, approvals and durability diff --git a/llms-full.txt b/llms-full.txt index c757d70e..71aa1e36 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -19861,6 +19861,9 @@ there is one. A change marked "no opt-out" closed a security or data-loss bug. | Slack and Discord signature checks accept a timestamp at most a minute ahead (was five minutes either way), read in seconds. | no opt-out | | `telegramChannel` and `teamsChannel` no longer post an OAuth sign-in link in a group chat. | no opt-out | | Channels without a `store` keep their transcripts in the agent's `createAgent({ store })` when it has `sessions`. | pass the channel its own `store` | +| The built node-server (and Docker image) requires `LOUSHO_API_TOKEN` / `auth.ts` on `/channels/` for a channel without `verify` when a token or `auth.ts` is set; self-verifying channels are unchanged. | give the channel a `verify` | +| `webhookChannel` replies `{ sessionId, text, finishReason, approval? }` instead of the full `ExecutionResult`. | `webhookChannel({ fullResult: true })` | +| A channel turn on a session another process is running answers `409` (`LOUSHO_SESSION_BUSY`, `Retry-After: 2`) instead of `500`. | no opt-out (retry after the delay) | ### Sessions, approvals and durability