Skip to content

Commit 8049861

Browse files
committed
Merge branch 'dev' into feat-desktop-app
# Conflicts: # pnpm-lock.yaml # vite.config.ts
2 parents 278b9b3 + 1b9a18f commit 8049861

208 files changed

Lines changed: 7217 additions & 1840 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/workflows/canary.yml‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: NPM Publish Canary
2+
3+
on:
4+
push:
5+
branches: [canary]
6+
paths-ignore:
7+
- sites/www/**
8+
9+
permissions:
10+
contents: read
11+
id-token: write
12+
13+
concurrency:
14+
group: publish-canary
15+
cancel-in-progress: false
16+
17+
jobs:
18+
publish:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v6
22+
- uses: voidzero-dev/setup-vp@v1.21.1
23+
with:
24+
node-version: 24
25+
registry-url: https://registry.npmjs.org
26+
run-install: false
27+
cache: false
28+
- run: vp install --frozen-lockfile --filter '!@codeworksh/www'
29+
# Package tsconfigs resolve aikit through its generated declarations.
30+
- run: vp run @codeworksh/aikit#build
31+
- run: vp check packages scripts .github
32+
- run: vp run --filter './packages/*' --concurrency-limit 2 typecheck
33+
- name: Publish all packages under canary
34+
run: node scripts/canary.mjs

‎AGENTS.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
## Commands
99

10-
- Don't run dev server commands (e.g `pnpm run dev`) - assume it's already running.
10+
- Don't run dev server commands (e.g `pnpm run dev`, `bun run dev`) - assume it's already running.
1111
- Don't run build commands unless specifically told to.
12-
- Focus on checking commands like `pnpm run typecheck`, `pnpm run check`, `bun run lint`, etc
12+
- Focus on checking commands like `pnpm run check`, `bun run lint` `bun run typecheck`, etc.
1313

1414
## Package Managers
1515

‎CHANGELOG.md‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,48 @@ This file is the canonical source for unreleased changes and published release n
1111

1212
## [Unreleased]
1313

14+
### Added
15+
16+
- Added automatic retry of transient provider failures in the harness loop. A turn whose request fails with a rate limit, overload, 5xx, timeout or dropped connection, including one that fails mid-stream, is retried with exponential backoff. Configure it with a top-level `retry` block in `settings.jsonc`: `{ "maxRetries": 3, "baseDelayMs": 2000, "maxDelayMs": 60000 }`, where `maxRetries: 0` turns it off. Quota errors are never retried, and a server that asks to wait longer than `maxDelayMs` fails the turn. Each failed attempt stays in the session as an aborted entry that the model never sees, and clients receive `session.retry.scheduled` and `session.retry.finished` events to show progress.
17+
18+
### Changed
19+
20+
- `model.options.maxRetries`, the retry inside the provider SDK, now defaults to `0` (was `3`). The SDK retried silently, only before the stream started, and also retried quota errors. Combined with the loop retry, one outage would have cost up to 16 requests. Set it per model if an endpoint needs it.
21+
22+
### Fixed
23+
24+
- Fixed an interrupted turn never reporting `session.turn.aborted`. The cleanup that settles the turn's open draft and publishes the event was skipped on interruption, so the draft was only cleaned up on the session's next run.
25+
26+
## [@codeworksh/aikit@0.10.0]
27+
28+
Covers every change since 0.9.2, the last release on the `latest` tag, including 0.9.3, which only shipped as dev and canary builds.
29+
30+
### Added
31+
32+
- Added the `getEnvApiKey` export, so a caller can check whether a provider has an API key in the environment using the same lookup aikit applies when it opens that provider.
33+
- Added `gpt-6-luna` to the OpenAI Codex catalog. The Codex backend serves it to ChatGPT accounts, with every reasoning level from `low` to `max` and reasoning off.
34+
35+
### Changed
36+
37+
- Updated `@ai-sdk/openai` to `^4.0.81` and `@ai-sdk/provider` to `^4.0.19`.
38+
39+
### Fixed
40+
41+
- Fixed images reaching models that cannot read them. For a model whose `input` does not include `"image"`, each image in a user message is now replaced with `(image omitted: model does not support images)` and each image in a tool result with `(tool image omitted: model does not support images)`; consecutive images collapse to one placeholder. The message and tool result are kept, so the model still knows an image was there. Previously a user image was silently dropped, which removed an image-only message entirely, and a tool-result image was sent anyway, which providers often reject. Vision models are unchanged.
42+
- Fixed `retry-after-ms` and an HTTP-date `retry-after` being ignored when normalizing a provider failure. Only a `retry-after` given in seconds was read, so `retryAfterMs` was missing and a retry could come before the server's requested wait.
43+
- Fixed OpenAI and Codex reasoning levels that the API rejects. `minimal` is no longer offered for gpt-5.4 through gpt-6 and is clamped to `low`, since these models reject it. `xhigh` and `max` are now offered on gpt-5.6 and gpt-6 models through the OpenAI API, and `max` stays off gpt-5.5 and earlier. OpenAI gpt-5.6 and gpt-6 models now turn reasoning off with `none`, as do Codex `gpt-5.5`, `gpt-5.6-luna` and `gpt-6-luna`.
44+
- Fixed `gpt-6-luna` ignoring a request to turn reasoning off. `@ai-sdk/openai` 4.0.66 dropped `reasoningEffort: "none"` for the model; aikit now requires 4.0.81.
45+
- Fixed every request to Claude Sonnet 5.5, Opus 5.5 and the Fable 5 models failing when no reasoning level was set. aikit sent `thinking: {type: "disabled"}`, which these models reject; they cannot turn thinking off, so aikit now leaves thinking to the model.
46+
- Fixed Claude thinking levels. `xhigh` and `max` are now offered on Opus 4.7 and 4.8, the Sonnet 5, Opus 5 and Fable 5 families, and `max` on Sonnet 4.6 and Opus 4.6; previously these requests were clamped down to `high`.
47+
- Fixed Claude Sonnet 4.5's context window on the Anthropic API, which is 200k tokens, not 1M (1M needs a beta header). Responses were sized against the wrong window, so long sessions failed with a context overflow instead of a shorter answer.
48+
- Fixed a prompt that already overflows the context window failing as an invalid `max_output_tokens`. The response ceiling is no longer shrunk below 16 tokens, the smallest OpenAI accepts, so the provider's context overflow error reaches the caller and `isContextOverflow` recognises it.
49+
- Fixed conversations started on OpenAI Codex failing when continued on OpenAI, Anthropic or OpenRouter. Codex tool call IDs (`call_…|fc_…`) exceed the 64-character `call_id` limit of OpenAI and of OpenRouter upstreams such as Meta, and contain characters Anthropic rejects; they are now shortened to the unique call part for those providers.
50+
- Fixed a provider error sent mid-stream, such as OpenAI's `context_length_exceeded` event, being reported as an `Unknown` failure. It is now classified by its status and code like an error returned before the stream starts, so the same overflow is an `InvalidRequest` either way.
51+
52+
### Internal
53+
54+
- The OpenAI, Codex, Anthropic and OpenRouter live e2e suites now run against a model matrix: gpt-6-luna through gpt-5.4-nano for OpenAI, gpt-6-luna, gpt-5.6-luna and gpt-5.5 for Codex, Claude Sonnet 4.6 through Fable 5.1 plus the 4.5 generation for Anthropic, and Muse Spark 1.3, GLM 5.3 Flash, DeepSeek V4.1 Flash and Gemini 3.8 Flash for OpenRouter. New suites cover every reasoning level, context overflow, cross-model and cross-provider handoff, and prompt caching.
55+
1456
## [@codeworksh/aikit@0.9.2]
1557

1658
### Added

‎CLAUDE.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
## Commands
99

10-
- Don't run dev server commands (e.g `bun run dev`, `pnpm run dev`) - assume it's already running.
10+
- Don't run dev server commands (e.g `pnpm run dev`, `bun run dev`) - assume it's already running.
1111
- Don't run build commands unless specifically told to.
12-
- Focus on checking commands like `bun run typecheck`, `pnpm run check`, `bun run lint`, etc.
12+
- Focus on checking commands like `pnpm run check`, `bun run lint` `bun run typecheck`, etc.
1313

1414
## Package Managers
1515

@@ -30,7 +30,7 @@ When uncertain, prefer: Effect, Tailwind, TypeScript, React, Clerk, TanStack, Ve
3030
## General Preferences
3131

3232
- If asked to do too much work at once, stop and state that clearly.
33-
- If computer use is helpful for completing or verifying work, shell out to gpt-5.6 with Codex for it
33+
- After you yourself have verified the work, get the work peer reviewed by another agent: `codex` for `code reviews`, `focused deep checks`, `tweaks`, `tests review` shell out to `gpt-6.1-sol` with thinking `low` or `medium` depending on complexity.
3434
- Avoid defensive future-facing design. This leads to pre-mature assumptions which are never true.
3535

3636
## Maintainability

‎README.md‎

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,70 @@
66
</a>
77
</p>
88

9-
Toolkit for building AI agents.
9+
<p align="center">
10+
<a href="https://www.npmjs.com/package/@codeworksh/cli"><img alt="npm" src="https://img.shields.io/npm/v/@codeworksh/cli?style=flat-square" /></a>
11+
<a href="https://deepwiki.com/codeworksh/codework"><img alt="Ask DeepWiki" src="https://img.shields.io/badge/Ask-DeepWiki-blue?style=flat-square" /></a>
12+
</p>
13+
14+
An open-source coding agent for your terminal: run sessions in your repo or an isolated sandbox, on any model, extended with plugins.
15+
16+
> Under active development; APIs may change.
17+
18+
## Quick start
19+
20+
```bash
21+
pnpm add -g @codeworksh/cli
22+
export ANTHROPIC_API_KEY=... # or OPENAI_API_KEY, XAI_API_KEY, ...
23+
codework run "Inspect and fix the failing tests"
24+
```
25+
26+
Continue a session, pick a model, or move into a sandbox:
27+
28+
```bash
29+
codework run --session <id> "Now add a regression test"
30+
codework run --provider openai --model gpt-5.5 --thinking high "Plan the migration"
31+
codework run --sandbox-driver daytona "Inspect repository"
32+
```
33+
34+
## Features
35+
36+
- **Any model** — OpenAI, Anthropic, Google, xAI, OpenRouter, and more via one catalog (`codework models`).
37+
- **Subscription sign-in** — `codework auth login --openai-codex` or `--github-copilot`.
38+
- **Persistent sessions** — resume any session by ID; state lives in a local database.
39+
- **Sandboxes** — run locally or in `daytona`, `vercel`, `memory`, or `sqldb` sandboxes.
40+
- **Server mode** — `codework serve` owns sessions and sandboxes; clients attach with `--server`.
41+
- **Plugins** — `codework plugin add <pkg>` adds tools, prompts, and sandbox drivers, per project or globally (`-g`).
42+
43+
See the [CLI docs](./packages/codework/README.md) for every command and flag.
44+
45+
## Packages
46+
47+
| Package | Description |
48+
| ------------------------------------------- | -------------------------------------------------------------------- |
49+
| [`@codeworksh/cli`](./packages/codework) | The `codework` coding agent CLI. |
50+
| [`@codeworksh/harness`](./packages/harness) | Effect-powered agent runtime with persistent sessions and sandboxes. |
51+
| [`@codeworksh/plugin`](./packages/plugin) | SDK for tools, prompt plugins, and sandbox drivers. |
52+
| [`@codeworksh/aikit`](./packages/aikit) | Unified multi-provider LLM API with streaming, tools, and usage. |
53+
54+
## Development
55+
56+
Requires Node.js 24.14.1+ and pnpm.
57+
58+
```bash
59+
git clone https://github.com/codeworksh/codework.git
60+
cd codework
61+
pnpm install
62+
pnpm cli -- --help # run the CLI from source
63+
pnpm exec vp check
64+
pnpm exec vp run typecheck
65+
```
1066

11-
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/codeworksh/codework)
67+
Read [AGENTS.md](./AGENTS.md) for repository conventions, and [open an issue](https://github.com/codeworksh/codework/issues) for bugs or ideas.
1268

1369
## Acknowledgements
1470

15-
The curiosity for building was inspired by by the great work of Mario Zechner on [Pi-Mono](https://github.com/badlogic/pi-mono).
71+
The curiosity to build this project was inspired by Mario Zechner’s work on [Pi-Mono](https://github.com/badlogic/pi-mono).
1672

1773
## License
1874

19-
MIT
75+
[MIT](./LICENSE)
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# @acme/codework-prompt-life
22

3-
An example third-party **prompt plugin**: it appends a short section on the meaning of life to
4-
the system prompt.
3+
An example third-party **prompt plugin**: it adds a `<meaning_of_life>` section to the system
4+
prompt.
55

66
The package uses the example `@acme` namespace to demonstrate how a third-party scoped plugin is
77
loaded and then configured by package name.
@@ -14,9 +14,7 @@ loaded and then configured by package name.
1414
}
1515
```
1616

17-
The string loads the module, the object configures it. Settings entries append after the
18-
built-ins, so this lands after `codework.prompt.default` and composes on the prompt it rendered —
19-
which is where a prompt plugin wants to be.
17+
The string loads the module, the object configures it.
2018

2119
> **Not installable as written**, for the same reason as `@acme/codework-tool-proc`: it exports
2220
> TypeScript, and Node will not strip types under `node_modules`. In this repository it is loaded
@@ -28,8 +26,6 @@ which is where a prompt plugin wants to be.
2826

2927
## Worth noting
3028

31-
- **A prompt plugin replaces the whole prompt.** `ctx.plugin.prompt.set` takes the complete
32-
string, so this plugin reads `get()` first and composes on it instead of discarding whatever
33-
`codework.prompt.default` rendered.
34-
- **It only sees earlier contributions.** Place it after the prompt plugins and tool plugins it
35-
builds on; a plugin that runs before them sees nothing they registered.
29+
- **It writes a section, not the prompt.** `Section.define("meaning_of_life")` names its block, and
30+
the harness renders it as `<meaning_of_life>` after the built-in sections. Order between plugins
31+
no longer decides where it lands.

‎extras/codework-prompt-life/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
},
1414
"devDependencies": {
1515
"@types/node": "catalog:",
16-
"effect": "4.0.0-rc.115"
16+
"effect": "4.0.1"
1717
},
1818
"peerDependencies": {
1919
"@codeworksh/plugin": "workspace:*",
20-
"effect": "4.0.0-rc.115"
20+
"effect": "4.0.1"
2121
},
2222
"engines": {
2323
"node": ">=22.0.0"
Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
/*
2-
* A third-party prompt plugin, vendored as a worked example. A prompt plugin composes on
3-
* whatever an earlier one set, so it belongs *after* the tool plugins and prompt plugins it
4-
* builds on — `ctx.plugin.prompt.get()` sees only contributions made before it ran:
2+
* A third-party prompt plugin, vendored as a worked example. It opens its own section,
3+
* `<meaning_of_life>`, which the harness renders after the built-in ones:
54
*
65
* { "plugins": ["@acme/codework-prompt-life",
76
* { "package": "@acme/codework-prompt-life", "options": { "answer": 42 } }] }
87
*/
9-
import { Plugin } from "@codeworksh/plugin";
8+
import { Plugin, Section } from "@codeworksh/plugin";
109

1110
const DEFAULT_ANSWER = 42;
12-
const HEADING = "## On the meaning of life";
11+
12+
const MeaningOfLife = Section.define("meaning_of_life");
1313

1414
/** Unvalidated by the harness, so the plugin checks its own block and falls back in place. */
1515
const readAnswer = (options: Plugin.PluginOptions): number => {
1616
const answer = options["answer"];
1717
return typeof answer === "number" && Number.isFinite(answer) ? answer : DEFAULT_ANSWER;
1818
};
1919

20-
const section = (answer: number) =>
20+
const body = (answer: number) =>
2121
[
22-
HEADING,
23-
"",
2422
"When the user asks what the meaning of life is, answer briefly and then get back to work:",
2523
"",
2624
`- The short version: ${answer}.`,
@@ -32,11 +30,6 @@ export default Plugin.define({
3230
id: "acme.prompt.life",
3331
kind: "prompt",
3432
setup(ctx, options) {
35-
const existing = ctx.plugin.prompt.get();
36-
// `set` replaces the whole prompt, so compose on what is already there rather than
37-
// discarding another plugin's work.
38-
ctx.plugin.prompt.set(
39-
existing === undefined ? section(readAnswer(options)) : `${existing}\n\n${section(readAnswer(options))}`,
40-
);
33+
ctx.plugin.prompt.sections.append(MeaningOfLife, body(readAnswer(options)));
4134
},
4235
});

‎extras/codework-sandbox-vercel/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
},
2525
"devDependencies": {
2626
"@types/node": "catalog:",
27-
"effect": "4.0.0-rc.115"
27+
"effect": "4.0.1"
2828
},
2929
"peerDependencies": {
3030
"@codeworksh/plugin": "workspace:*",
31-
"effect": "4.0.0-rc.115"
31+
"effect": "4.0.1"
3232
},
3333
"engines": {
3434
"node": ">=22.0.0"

‎extras/codework-tool-proc/package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
},
1414
"devDependencies": {
1515
"@types/node": "catalog:",
16-
"effect": "4.0.0-rc.115"
16+
"effect": "4.0.1"
1717
},
1818
"peerDependencies": {
1919
"@codeworksh/plugin": "workspace:*",
20-
"effect": "4.0.0-rc.115"
20+
"effect": "4.0.1"
2121
},
2222
"engines": {
2323
"node": ">=22.0.0"

0 commit comments

Comments
 (0)