Skip to content
dsh.fish
Bundle

@canary-builds/dsh-web-search-zai

Z.AI (GLM) web search provider for the DeepSeek Harness web seam — native web_search_20250305 through Z.AI's Anthropic-compatible Messages API. Dependency-free.

Source
Canary-Builds
License
MIT
Updated
Updated 8 days ago

Readme

# DSH Web Search Z.AI

Native-feeling `web_search` for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) installs whose model route is Z.AI / GLM, delivered as one dependency-free Cordis plugin for the host `web` seam (`ctx.web`).

The shipped harness selects `deepseek-official` as its search provider, which requires a real DeepSeek API key. On an install that runs GLM through the `zai` provider, only `ZAI_API_KEY` exists — so every `web_search` fails with HTTP 401. This package registers a `zai-official` search provider that performs searches through Z.AI's Anthropic-compatible Messages API using the native `web_search_20250305` server tool (`glm-5.3`), authenticating with the `ZAI_API_KEY` credential you already have, and flips the `web` seam's selection to it. The Profile Bundle patch carries both rows; a fresh install needs no manual composition editing.

## How it works

- Sends one Messages request per search: model `glm-5.3`, the `web_search_20250305` server tool (`max_uses: 3`), `max_tokens: 512` — sources come from the tool-result blocks, so the completion budget stays small and inside the web tool's 60s timeout.
- Z.AI's Anthropic dialect returns tool results as `tool_result` blocks whose content is a **stringified Python-repr/JSON hybrid** rather than standard `web_search_tool_result` blocks (which is exactly why the shipped `web-search-deepseek` provider cannot simply be repointed at Z.AI). A quote-aware scanner extracts `title` / `link` / `content` records from either shape, standard blocks included for forward compatibility.
- Transient upstream failures (`Internal Network Failure`, 5xx, timeouts) are retried up to 3 times; permanent errors surface verbatim with the HTTP status.
- Each request is appended to the initiating session log as `web/zai-search-llm-request` for observability, mirroring the shipped provider.
- Registration goes through `web.registerSearchProvider`, whose disposer is fiber-owned — removing the plugin row cleanly unregisters the provider and (on a fresh apply of the base config) restores the previous selection.

## Requirements

- DeepSeek Harness with the `web` seam (the standard `web` profile; any base-backed profile works).
- A Z.AI API key stored as the `ZAI_API_KEY` credential — the web Models page writes it, or use your credentials store directly. No other credentials, environment variables, or npm dependencies.

> **Cost note:** every search is a GLM model turn with server-side search. It bills like a small model call, not like a free search-API hit.

## Install

Install into your web profile (the package carries its own Profile Bundle patch — no manual composition row is needed):

```sh
dsh plugin --profile web add @canary-builds/dsh-web-search-zai
```

Restart DSH. To update, run the same command again and restart.

If your profile's `cordis.patch.yml` already overrides the `web` row (any manual `searchProvider` selection), remove that override — profile patches apply after bundle patches and would win. Likewise, remove any manually inserted `web-search-zai` row before switching to the bundle install; two rows with the same id will collide.

### Install from a git checkout (pre-release)

Until the first npm release, install from a clone:

```sh
git clone https://github.com/Canary-Builds/dsh-web-search-zai \
  ~/.dsh/profiles/web/plugins/dsh-web-search-zai
ln -sfn ../plugins/dsh-web-search-zai \
  ~/.dsh/profiles/web/node_modules/dsh-web-search-zai
```

Then add the rows to `~/.dsh/profiles/web/cordis.patch.yml` (the same content as this package's `cordis.patch.yml`, with the row name `dsh-web-search-zai` matching the unscoped symlink):

```yaml
- insert:
    - id: web-search-zai
      name: dsh-web-search-zai

- id: web
  name: '@deepseek-ai/dsh-web'
  config:
    searchProvider: zai-official
    fetchProvider: http
```

Profiles with `patchReload: live` pick the change up without a restart; otherwise restart DSH.

### Switching back to DeepSeek

Store a real DeepSeek key as `DEEPSEEK_API_KEY`, remove this package (`dsh plugin --profile web remove @canary-builds/dsh-web-search-zai`), and restore `searchProvider: deepseek-official` in the `web` row. The shipped provider row is never touched by this bundle's patch while it is installed — but removing the bundle restores the base config on the next start.

## Configuration

There is no settings card and no schema dependency — deliberately, to keep the package installable with zero npm dependencies. The knobs are the constants at the top of [`index.js`](index.js):

| Constant | Default | Meaning |
| --- | --- | --- |
| `MODEL` | `glm-5.3` | Model that performs the search turn |
| `MAX_USES` | `3` | Server-tool search passes per request |
| `MAX_TOKENS` | `512` | Completion budget (sources arrive in tool blocks) |
| `MAX_ATTEMPTS` / `RETRY_DELAY_MS` | `3` / `700` | Transient-failure retry policy |
| `REQUEST_TIMEOUT_MS` | `45000` | Per-attempt timeout, inside the web tool's budget |
| `API_KEY_REF` | `ZAI_API_KEY` | Credentials-store reference |

## Compatibility

- Targets the DSH `web` seam contract (`registerSearchProvider` / `WebSearchProvider`) as shipped in `0.1.x`; the seam is stable, but a future DSH that changes the provider contract will need a re-test.
- The Z.AI tool-result dialect is parsed tolerantly (Python-repr and JSON shapes, nested or flat). If Z.AI changes the shape entirely, searches fail with a descriptive `WEB_PROVIDER_ERROR` naming the endpoint — file an issue.

## Behavior notes

- The provider reports `available()` only when the credentials service is present; searches throw `WEB_PROVIDER_CREDENTIAL_MISSING` with setup instructions when `ZAI_API_KEY` is unset.
- URLs are deduped across multiple search passes within one request; snippets are capped at 400 characters; the seam's `maxResults` truncation applies downstream.
- Cancellation is honored end-to-end (`WEB_ABORTED`), including mid-fetch.

## License

MIT

## Development

Single-file ESM plugin, no build step, no dependencies: edit `index.js`, restart DSH (or rely on a live profile patch reload after touching `cordis.patch.yml`). Functional smoke test: import `apply`, mount it on a mock `ctx` exposing `web.registerSearchProvider` and the credentials seam, and call `provider.search({ query })`. [Report an issue](https://github.com/Canary-Builds/dsh-web-search-zai/issues) · [Canary Builds](https://canarybuilds.com)

Install

dsh plugin --profile web add github:Canary-Builds/dsh-web-search-zai

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source