Bundle
dsh-hyper-tools
Keeps Charm Hyper requests under the gateway's 10 MiB body cap: replaces the oldest images with placeholders (newest survive) before sending, and retries with a tighter projection when the gateway still rejects the body.
- Source
- samuelrubiodev
- stars
- 1 stars
- License
- MIT
- Updated
- Updated 5 hours ago
Readme
# dsh-hyper-tools
Keeps Charm Hyper model requests under the gateway's strict 10 MiB request-body cap.
Charm Hyper's HTTP gateway (Google Frontend in front of a Go backend) rejects any request body above 10 MiB with:
```json
{ "error": { "message": "invalid request body", "type": "invalid_request_error", "code": null } }
```
Long conversations accumulate images, and every image is inlined as a base64 `image_url` part. Once the serialized body crosses the cap, the whole request fails before inference — even though the images are ordinary attachments. This plugin registers one `llm/stream` middleware for the configured Charm Hyper provider routes:
1. **Before dispatch** it projects durable history so the accumulated base64 image payload fits `maxRequestImageBytes` (default 6 MiB). The **oldest** images become the harness-standard deterministic placeholders (`[image omitted to fit request image limits; …]`) and the **newest images stay**. A request that already fits is dispatched untouched through `next()` — no extra provider attempt.
2. **When the gateway still rejects the body** (the projection under-counted non-image overhead) it swallows that terminal `invalid request body` failure and re-dispatches once with the image budget multiplied by `recoveryBudgetFactor` (default `0.5`), which replaces more of the oldest images. If a tighter projection cannot remove anything further, the original failure is surfaced unchanged.
Accounting and placeholders come from the harness itself (`offloadRequestImagesWithPolicy`, `offloadedImageText`): base64 length of every image occurrence — nested tool-result images included — and the same deterministic placeholder text shipped adapters use.
## Verified behavior
Checked live against `https://hyper.charm.land/v1` (`deepseek-v4.1-flash`, six 1024×683 PNG screenshots):
| Request | Serialized body | Result |
| --- | ---: | --- |
| Accumulated images, unprojected | 16,794,575 bytes | `400 invalid request body` |
| Same history projected by this plugin | 5,599,267 bytes (4 oldest images replaced) | `200 OK` |
The gateway cap was measured at 10 MiB (10,485,760 bytes): a 10,400,000-byte body passes the gateway, a 10,490,000-byte body is rejected. `scripts/probe-hyper.py` reproduces the probe; `tests/live.test.ts` reproduces the table above.
## Install
```bash
dsh plugin --profile <profile> add dsh-hyper-tools
```
From a checkout or tarball:
```bash
dsh plugin --profile <profile> add ./dsh-hyper-tools
# or
npm pack && dsh plugin --profile <profile> add ./dsh-hyper-tools-0.1.0.tgz
```
From git (the built `lib/` is committed, so pnpm needs no build permission):
```bash
dsh plugin --profile <profile> add github:samuelrubiodev/dsh-hyper-tools#main
```
The bundle patch ([`cordis.patch.yml`](./cordis.patch.yml)) inserts one row (`hyper-tools`).
## Configuration
Every field is optional; the row `config` carries them.
| Field | Default | Meaning |
| --- | --- | --- |
| `providers` | `['charm-hyper', 'hyper']` | Provider routes to guard; matching is case-insensitive. |
| `maxRequestImageBytes` | `6291456` (6 MiB) | Aggregate base64 image payload one request may carry. |
| `maxImagesPerRequest` | absent | Optional bound on images per request. |
| `recovery` | `true` | Retry once when the gateway rejects the body. |
| `recoveryBudgetFactor` | `0.5` | Image-budget multiplier for the recovery retry. |
| `byteQuantum` | `1` | Whole-step removal quantum for byte overflow; `1` keeps the newest retainable images. |
| `countQuantum` | `1` | Whole-step removal quantum for count overflow. |
```yaml
- id: hyper-tools
name: 'dsh-hyper-tools'
config:
providers: ['charm-hyper']
maxRequestImageBytes: 6291456
```
## Notes and limits
- The budget counts **image payload only** — the platform's documented unit for request-image bounds. Text, tool schemas, and JSON structure ride outside it; the defaults leave several MiB of headroom under the 10 MiB cap, and the recovery retry covers a misestimate.
- The projection estimates each occurrence from durable attachment metadata (`attachment.bytes`); any provider-side re-encode only makes the actual payload smaller, so the estimate errs toward replacing slightly early.
- Only the routes listed in `providers` are touched; every other provider request passes through untouched.
- The plugin is adapter-agnostic: it only keys on `GenerateOptions.provider`, so it guards Charm Hyper whether it is served by `@deepseek-ai/dsh-llm-pi-ai`, a custom gateway adapter, or anything else.
## Development
```bash
npm ci
npm run typecheck
npm test # unit + integration against the real cordis + @deepseek-ai/dsh-llm runtime
npm run build
HYPER_API_KEY=... npx vitest run tests/live.test.ts # live check against Charm Hyper
```
The compiled `lib/` is committed so `github:` installs need no build step; `npm pack` / `npm publish` refresh it through `prepack`.
Compatibility: `@deepseek-ai/dsh-llm ^0.1.5-rc.1`, `@deepseek-ai/cordis ^4.0.1`.
## License
[MIT](./LICENSE)
Install
dsh plugin --profile web add github:samuelrubiodev/dsh-hyper-tools
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-hyper-tools from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.