@polyweave/zhipu (1.0.7)
Installation
@polyweave:registry=https://hub.kl1.tenere.ai/api/packages/Polyweave/npm/npm install @polyweave/zhipu@1.0.7"@polyweave/zhipu": "1.0.7"About this package
@polyweave/zhipu
Zhipu AI / GLM adapter for Polyweave — chat, embeddings, function calling, 1M context, AllTools agent capability.
Synopsis
import { createZhipuAdapter } from '@polyweave/zhipu';
import { createTextFrame, createParamFrame, createFrameSink, FrameType } from '@polyweave/core';
var adapter = createZhipuAdapter({ apiKey: process.env.ZHIPU_API_KEY, model: 'glm-4-plus' });
adapter.source.pipe(createFrameSink(function(frame) {
if (frame.type === FrameType.TEXT) console.log('Text:', frame.content.text);
if (frame.type === FrameType.TOOL_CALL) console.log('Tool:', frame.content.name, frame.content.arguments);
if (frame.type === FrameType.EMBEDDING) console.log('Embedding dims:', frame.content.dimensions);
}));
adapter.sink.write(createTextFrame('Write a short story about AI'));
// Embeddings
adapter.sink.write(createParamFrame('embedding_model', 'embedding-3'));
adapter.sink.write({ type: FrameType.EMBEDDING, id: 'emb1', timestamp: Date.now(), content: { text: 'Zhipu AI embeddings' } });
Install
npm install @polyweave/zhipu
Why
Zhipu AI's GLM series provides AllTools agent capability (function calling, web search, code interpreter, knowledge base retrieval in a single model), 1M token context, vision (GLM-4V), and embeddings. The adapter exposes these through standard Polyweave frame protocol with budget tracking and cost estimation, enabling zero-special-case integration into multi-provider routing pipelines.
API
createZhipuAdapter(config)
Creates a frame duplex adapter for Zhipu AI / GLM. Returns an IFrameDuplex with source, sink, setReady, and name.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
config.apiKey |
string |
No | process.env.ZHIPU_API_KEY |
Zhipu API bearer token |
config.baseURL |
string |
No | https://open.bigmodel.cn/api/paas/v4 |
API base URL override |
config.model |
string |
No | glm-4-plus |
Default chat model (overridable via PARAM) |
config.budget |
number |
No | 0 |
Hard cap in USD. When cumulative spend reaches this, incoming TEXT/IMAGE/EMBEDDING frames are rejected with ERROR(BUDGET_EXCEEDED) + END |
config.name |
string |
No | null |
Logical name for the node, exposed on the duplex |
config.timeout |
number |
No | 120000 |
HTTP request timeout in milliseconds |
Return value: IFrameDuplex — a bidirectional frame stream.
Properties on the returned duplex:
.source— readable frame source (output frames from the adapter).sink— writable frame sink (input frames into the adapter).setReady(key)— provide the API key after construction; flushes buffered frames.name— logical name (config.name)
Frame Protocol
| Input frame | Action |
|---|---|
TEXT |
Appends {role:'user', content:frame.content.text} to conversation, sends POST /v4/chat/completions (streaming by default) |
IMAGE |
Vision mode — converts to image_url content block with optional text prompt, appended to conversation as a user message with multimodal content. Requires url or data/b64_json content |
EMBEDDING |
Sends POST /v4/embeddings with frame.content.text and params.embedding_model |
TOOL_RESULT |
Appends {role:'tool', tool_call_id, content} to conversation |
PARAM |
Accumulates into adapter config. key=apiKey triggers setReady; key=budget sets the budget cap |
COST_CHECK |
Enters dry-run mode. Buffers subsequent content frames, calls costEstimator.estimate(), emits a COST frame then END. If maxBudget exceeded, emits ERROR(BUDGET_EXCEEDED) + END |
START |
Ignored |
END |
Ignored |
TOPOLOGY_SCAN |
Emits TOPOLOGY_REPORT describing the adapter node, then forwards the scan frame |
| Output frame | Trigger |
|---|---|
TEXT |
Chat content deltas (streaming) or full completion body (batch) |
TOOL_CALL |
Tool call chunks from stream or complete calls from batch response |
EMBEDDING |
One per embedding request; contains vector, dimensions, and model in content |
RECEIPT |
Cost receipt. Progressive receipts every 50 output tokens during streaming; final receipt from usage data at end. Embedding receipts use char-count estimation (text.length / 4) |
COST |
Estimated cost from COST_CHECK dry-run, containing bounds, accuracy, estimateSource, forwardEstimate, inputBounds, maxOutputTokens |
ERROR |
Errors (see Error Conditions) followed by END |
END |
Always emitted after each request completes (including errors) |
PARAM Keys
| Key | Type | Default | Description |
|---|---|---|---|
model |
string |
glm-4-plus |
Chat model ID |
embedding_model |
string |
embedding-3 |
Embedding model for EMBEDDING frames |
max_tokens |
number |
1024 |
Max completion tokens |
temperature |
number |
undefined | Sampling temperature |
top_p |
number |
undefined | Nucleus sampling parameter |
stream |
boolean |
true |
Enable SSE streaming |
system |
string |
undefined | System prompt (sent as messages[0] with role=system) |
tools |
object[] |
undefined | Tool definitions for function calling |
tool_choice |
string |
undefined | Tool choice constraint |
response_format |
object |
undefined | Response format (e.g. {type: 'json_object'}) |
budget |
number |
0 |
Set or override budget cap at runtime |
apiKey |
string |
undefined | Set or override API key at runtime (triggers setReady) |
Error Conditions
Every error emits an ERROR frame immediately followed by an END frame with metadata.error: true.
| Condition | Error Message | Error Code | When |
|---|---|---|---|
| Budget exhausted | 'Budget exceeded' |
BUDGET_EXCEEDED |
budgetTotal > 0 && totalSpent >= budgetTotal — rejected at frame entry before any API call |
| COST_CHECK estimate exceeds maxBudget | 'Est cost exceeds budget' |
BUDGET_EXCEEDED |
Dry-run estimate > costCheckOptions.maxBudget via costEstimator.checkBudget() |
| IMAGE frame missing url/data | 'IMAGE frame requires url/data' |
ADAPTER_ERROR |
IMAGE with no url, data, or b64_json content |
| HTTP 4xx/5xx from chat API | API error message (from response.error.message) or 'HTTP ' + statusCode |
ADAPTER_ERROR |
Response statusCode >= 400 |
| HTTP 4xx/5xx from embeddings API | API error message (from response.error.message) or 'HTTP ' + statusCode |
ADAPTER_ERROR |
Response statusCode >= 400 |
| Network error (chat or embedding) | err.message (e.g. ECONNREFUSED) |
ADAPTER_ERROR |
req.on('error', ...) fires |
| Request timeout | 'Timeout' |
ADAPTER_ERROR |
req.on('timeout', ...) fires |
| JSON parse failure (chat) | 'Parse: ' + err.message |
ADAPTER_ERROR |
Chat response body is not valid JSON |
| JSON parse failure (embedding) | 'Parse: ' + err.message |
ADAPTER_ERROR |
Embedding response body is not valid JSON |
| Stream error | 'Stream error' or API error from SSE chunk |
ADAPTER_ERROR |
Streaming SSE event.error is present |
| Sink paused or ended | None (frame dropped) | — | duplex.sink.paused || duplex.sink.ended — frame is silently ignored |
| Missing API key | Frames buffered | — | Frames enqueue in frameBuffer until setReady(key) is called |
Cost Tracking
The adapter maintains a totalSpent cumulative counter. Costs are derived from ZHIPU_COSTS in src/costs.js:
| Model | Input (per 1M tokens) | Output (per 1M tokens) |
|---|---|---|
glm-4-plus |
$0.05 | $0.10 |
glm-4-flash |
$0.01 | $0.01 |
glm-4-air |
$0.01 | $0.01 |
glm-4-alltools |
$0.05 | $0.10 |
glm-4-long |
$0.05 | $0.10 |
glm-4v |
$0.05 | $0.10 |
glm-4 |
$0.05 | $0.10 |
glm-4-flashx |
$0.01 | $0.01 |
embedding-3 |
$0.001 | $0.00 |
Model matching is case-insensitive substring lookup (model.toLowerCase().indexOf(key) >= 0). Unknown models return zero cost.
Embedding Endpoint
EMBEDDING frames call POST /v4/embeddings with:
{ model: params.embedding_model, input: frame.content.text }
The response data[0].embedding is emitted as an EMBEDDING frame with { vector, dimensions, model } in content. Token count is estimated as Math.ceil(text.length / 4). A RECEIPT is emitted with the estimated input cost, followed by END.
Tests
npm test
Runs rigor.test.js (property-based cost verification: pricing table oracle, non-negative costs, zero-cost at zero tokens, monotonicity) and smoke.test.js (construction with defaults/config, setReady presence, PARAM accumulation).
Requirements
- Node.js 22 or later (as per
enginesfield inpackage.json) - ESM only (
"type": "module") - Peer dependencies:
@polyweave/core,@polyweave/costs
Dependencies
Development Dependencies
| ID | Version |
|---|---|
| @polyweave/core | * |
| @polyweave/costs | * |
| @rigor/core | * |
Peer Dependencies
| ID | Version |
|---|---|
| @polyweave/core | * |
| @polyweave/costs | * |
| @polyweave/errors | * |