# dsh-glm-web-search
Use your Z.AI (GLM) subscription as DeepSeek Harness's search, fetch and vision backend.
Sign in with the Z.AI account you already have — no API key, no separate billing.
npm ·
GitHub ·
中文文档
```bash
dsh plugin --profile desktop add dsh-glm-web-search
```
## Why this exists
DeepSeek Harness ships its own `web_search` / `web_fetch` backends, which means another API key
and another bill. But plenty of people already pay for a Z.AI plan — and that quota can already
run `web_search_prime` and `webReader` server-side. Nobody had wired it up.
This plugin does exactly that. **One email login turns your existing subscription into the
harness's search and fetch capability.** Installing it is enough; the tool names and arguments
the model sees do not change, only the service behind them.
## Features
| Capability | What it does |
|---|---|
| **Web search** | Replaces the official `web_search` backend with `web_search_prime` |
| **Web reader** | Replaces the official `web_fetch` backend with `webReader` |
| **Vision** | Adds a `zai_vision` tool for image description, OCR and visual Q&A |
| **Zero dependencies** | No `node_modules`, no `dependencies`, no `peerDependencies` |
| **Status line** | `/dsh-glm-status` shows token age, plan expiry and remaining quota |
## Install
### From the Plugin Manager
Open **Plugins → Add plugin**, type the package name, and press **Install**:
```text
dsh-glm-web-search
```
Leave the install source on **npm** — or switch it to **Mainland China mirror** (npmmirror) if the
official registry is slow; both serve the same tarball. Restart the harness afterwards: plugin code
is loaded at startup, so a freshly installed plugin is not active until then.
### From the command line
```bash
dsh plugin --profile desktop add dsh-glm-web-search
```
### From this repository
For a local checkout, or to pin an exact commit:
```bash
dsh plugin --profile desktop add github:czpGhost/dsh-glm-web-search
dsh plugin --profile desktop add /absolute/path/to/dsh-glm-web-search
```
Nothing here runs a build script, so pnpm never asks you to allowlist one.
### Then sign in once
```text
/dsh-glm-web-search login
```
Your browser opens the authorization page; the token is stored automatically on approval.
From then on `web_search` and `web_fetch` resolve to Z.AI.
## Usage
```text
/dsh-glm-web-search login # sign in (opens your browser)
/dsh-glm-web-search logout # sign out, forget the local credential
/dsh-glm-web-search status # token, plan and quota
/dsh-glm-login /dsh-glm-logout /dsh-glm-status # equivalent aliases
```
Each subcommand is also a standalone command because the menu matches on a command's **name**:
typing `/dsh-glm-log` is what surfaces both `login` and `logout`.
### Upgrading
The Plugin Manager does not auto-update installed plugins. Remove the old version first, then add
the new one:
```bash
dsh plugin --profile desktop remove dsh-glm-web-search
dsh plugin --profile desktop add dsh-glm-web-search
```
Then restart. Your credential lives outside the package, so it survives an upgrade.
## Screenshot
`/dsh-glm-status`:
```text
▸ token 30m · Start Plan · GLM-5.3 2.95M left · resets 2h 57m
account you@example.com
token valid 30m
plan ZCode Start Plan [active] · ends 10-12 23:59 (3d 2h)
quota GLM-5.3 ██████████ 98% 2.95M/3M resets 2h 57m
quota GLM-5.3-Flash ██████████ full resets 2h 57m
cycle daily grant, refills at 00:00 Asia/Shanghai
```
The quota bar draws **remaining**, not used. Drawn as used, a brand-new account would render as
an empty bar — which reads as "exhausted", exactly backwards.
## Configuration
| Field | Default | Purpose |
|---|---|---|
| `origin` | `https://zcode.z.ai` | Gateway origin |
| `model` | unset (resolved live) | Model that runs search and fetch |
| `appVersion` | probed | Client version advertised to the gateway |
| `jwtEnv` | `ZAI_JWT` | Credential reference |
| `tokenPath` | `$DSH_HOME/dsh-glm-web-search/token.json` | Local token file |
| `vision` | `true` | Register the `zai_vision` tool |
| `timeoutMs` | `90000` | Per-request deadline |
Credential order: managed record → `$ZAI_JWT` → the local token file.
On a headless host, set `ZAI_BROWSER_OPEN=0`; the URL is still printed so you can open it yourself.
## Two things worth knowing
**Search results are capped.** Upstream returns at most 10 sources per `web_search` call, and the
harness's `dsh-tool-web` then truncates `sources[]` to **8** (setting `truncated: true`). One call
may carry up to 4 queries, run concurrently; the merged result still hits the 8-source cap.
**It has no dependency tree at all.** `src/` reaches the harness only through injected services
(`ctx.web`, `ctx.tools`, `ctx.commands`), and imports nothing outside its own tree except Node
builtins — so there is no `node_modules`, no `dependencies`, and no `peerDependencies`. That matters
beyond tidiness: declaring a `@deepseek-ai/dsh-*` peer makes the harness's install preflight compare
your range against the runtime version and **reject the whole installation** when they disagree.
The subtler hazard is a second copy of a stateful harness package. Same version, byte-identical
files, and it still breaks: two files mean two *module instances*, and a module-local
`Symbol()` differs between them. `@deepseek-ai/dsh-tools` keys its internal scheduler on exactly
that (`const TOOL_RUNTIME_SCHEDULER = Symbol("@deepseek-ai/dsh-tools.scheduler")`), so
`@deepseek-ai/dsh-agent-loop` reaching through `ctx.tools[TOOL_RUNTIME_SCHEDULER]` finds
`undefined` and the turn dies with `Cannot read properties of undefined (reading 'prepare')`.
`Symbol.for()` keys live in a global registry and survive duplication — `schemastery` uses one,
which is why it is safe to appear twice and `dsh-tools` is not.
## Roadmap
- [x] Search, fetch and vision
- [x] Email OAuth login, no API key
- [x] Status line with quota
- [x] Published on [npm](https://www.npmjs.com/package/dsh-glm-web-search)
- [ ] Real screenshots and a demo GIF
- [ ] Documentation polish (PRs welcome)
## FAQ
**Do I need a paid Z.AI plan?**
No. A free account gets an experience plan that already covers search and fetch. Vision needs the
Flash model, which the same plan includes.
**Where is my credential stored?**
`$DSH_HOME/dsh-glm-web-search/token.json` — one file, no environment variables required. Delete it
or run `logout` to revoke locally.
**Why do I only get 8 results?**
That is the harness's own cap, not Z.AI's. Upstream returns 10; `dsh-tool-web` trims to
`searchMaxResults` (default 8). Raise it in that plugin's config if you need more.
**Does this work headless?**
Yes. Set `ZAI_BROWSER_OPEN=0` and `login` prints the URL instead of opening a browser.
**Will it break when Z.AI ships a new client?**
Possibly — the gateway fingerprints the client, so a new ZCode build can invalidate the identity
constants. That is a one-line fix here, not a redesign.
## Star History
[](https://www.star-history.com/?repos=czpGhost%2Fdsh-glm-web-search&type=timeline&legend=top-left)
## Disclaimer
This project is for technical sharing and learning purposes only. Please comply with the relevant
terms of service and applicable laws, and use it at your own risk.
## License
[MIT](LICENSE)