@zoowork-ai/sdk 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +145 -13
- package/dist/client.d.ts +327 -64
- package/dist/client.js +71 -7
- package/dist/events.d.ts +16 -2
- package/dist/events.js +21 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/sse.d.ts +4 -8
- package/dist/sse.js +3 -7
- package/package.json +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,43 @@
|
|
|
3
3
|
All notable changes to `@zoowork-ai/sdk` (formerly `@zooclaw-agents/sdk`). Dates are the
|
|
4
4
|
day the behaviour was verified, not the day it was written.
|
|
5
5
|
|
|
6
|
+
## 0.7.0 — 2026-09-14
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **Application-executed custom tools.** Agent resources can declare `custom_tools`; event
|
|
11
|
+
helpers expose requested calls; and the client can list pending calls, resolve a call, or
|
|
12
|
+
post typed `user.custom_tool_result` content.
|
|
13
|
+
- **Filtered cursor session listing.** `listSessionPage()` adds the channel, surface,
|
|
14
|
+
runtime-mode and archive-filtered cursor lane without changing the existing numeric-page
|
|
15
|
+
behavior of `listSessions()`. Session archive and delete operations are also exposed.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **MCP configuration now covers runtime context and permissions.** Types include metadata
|
|
20
|
+
context, a server permission default, exact per-tool overrides, and trailing-prefix tool
|
|
21
|
+
policy selectors.
|
|
22
|
+
- **Channel contracts include direct DingTalk configuration and Feishu document capability
|
|
23
|
+
state.** Callers can inspect provider, sync, missing-scope and approval-state details from
|
|
24
|
+
returned capabilities.
|
|
25
|
+
|
|
26
|
+
## 0.6.0 — 2026-09-11
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **Breaking: `listAgents()` now resolves to an `AgentPage`, not an array.** Read `.data`
|
|
31
|
+
for the current page. The SDK preserves `page`, `page_size`, and `total`, and derives a
|
|
32
|
+
numeric `next_page` (`null` at the end). Existing one-page callers should replace
|
|
33
|
+
`const agents = await zc.listAgents(opts)` with `const { data: agents } = await zc.listAgents(opts)`.
|
|
34
|
+
- **Agent lists support automatic and manual pagination.** Use
|
|
35
|
+
`for await (const agent of zc.listAgents(opts))`, or `page.hasNextPage()` /
|
|
36
|
+
`page.getNextPage()`. Resolved pages are async iterable and provide `iterPages()`.
|
|
37
|
+
Later requests preserve the original label filters; early loop exit stops further fetches.
|
|
38
|
+
- Missing, invalid, or non-advancing agent pagination metadata now raises an error instead
|
|
39
|
+
of hiding a partial result. The API's fixed 100-item numeric pagination is unchanged.
|
|
40
|
+
Cross-page behavior is verified with synthetic offline HTTP tests; the live release
|
|
41
|
+
smoke covers one Agent/Session turn and cleanup, not a 101-agent pagination walk.
|
|
42
|
+
|
|
6
43
|
## 0.5.2 — 2026-09-04
|
|
7
44
|
|
|
8
45
|
### Documentation
|
package/README.md
CHANGED
|
@@ -26,9 +26,14 @@ The base URL has a working default, so you do not configure an endpoint. Overrid
|
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
28
|
// 1. Create an agent. Ownership is derived from your key, so `resource` is all you
|
|
29
|
-
// send
|
|
29
|
+
// send. Select a model returned by this deployment instead of relying on a
|
|
30
|
+
// remembered id or on a server default that can rotate.
|
|
31
|
+
const models = await zc.listModels()
|
|
32
|
+
const primary = models.find((model) => model.model === 'litellm/gpt-5.6-terra')?.model
|
|
33
|
+
if (!primary) throw new Error('Choose a model returned by listModels()')
|
|
34
|
+
|
|
30
35
|
const agent = await zc.createAgent({
|
|
31
|
-
resource: { name: 'research-agent', model: { primary
|
|
36
|
+
resource: { name: 'research-agent', model: { primary } },
|
|
32
37
|
})
|
|
33
38
|
|
|
34
39
|
// 2. Start it. Without this, createSession() returns 409 agent_not_running.
|
|
@@ -52,22 +57,65 @@ An explicit option always beats the environment variable.
|
|
|
52
57
|
|
|
53
58
|
> **Finding the agent you built in the app.** The first path segment of a ZooWork chat URL
|
|
54
59
|
> (`/chat/<32-hex>/sessions/…`) is a *workspace* id, not an `agt_…`. Resolve it with
|
|
55
|
-
> `zc.listAgents({ labels: { workspace_id: '<32-hex>' } })`;
|
|
56
|
-
>
|
|
60
|
+
> `zc.listAgents({ labels: { workspace_id: '<32-hex>' } })`; use the pagination patterns
|
|
61
|
+
> below to read one page or traverse every match. Scope is `owner_uid AND org_id` — an agent a *colleague*
|
|
57
62
|
> created in your org is fetchable by id but will not appear in your list.
|
|
58
63
|
|
|
59
64
|
> **Wait on `status.desired_state`, never on `status.actual_state`.**
|
|
60
65
|
> `actual_state` reports chat-channel connectivity. An API-only agent has no channels,
|
|
61
|
-
>
|
|
62
|
-
>
|
|
63
|
-
>
|
|
66
|
+
> but its projection depends on the channel-status capability: a GET can report `active`
|
|
67
|
+
> with zero channel counts and a `status_message` saying health was not verified when that
|
|
68
|
+
> capability is unsupported, while a transient health lookup failure remains `activating`.
|
|
69
|
+
> List and GET can therefore briefly disagree. None of these values is readiness, and
|
|
70
|
+
> `running` is not an `actual_state` value. Use `await zc.waitUntilRunning(agentId)`; it
|
|
71
|
+
> correctly polls `desired_state`.
|
|
72
|
+
|
|
73
|
+
## Listing agents and pagination
|
|
74
|
+
|
|
75
|
+
`listAgents()` returns an awaitable, async-iterable request. Use `for await` to traverse all
|
|
76
|
+
matching agents; the SDK requests each next page only as you consume the results:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
for await (const agent of zc.listAgents({ labels: { project: 'research' } })) {
|
|
80
|
+
console.log(agent.agent_id)
|
|
81
|
+
// break when you have enough; later pages will not be fetched.
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
For a single page, `await` the request and read `.data`. The page preserves `page`,
|
|
86
|
+
`page_size`, and `total`, and exposes `next_page` (`null` when there are no more results):
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const page = await zc.listAgents()
|
|
90
|
+
console.log(page.data, page.total, page.next_page)
|
|
91
|
+
|
|
92
|
+
if (page.hasNextPage()) {
|
|
93
|
+
const next = await page.getNextPage() // retains the original label filters
|
|
94
|
+
console.log(next.data)
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
You can also use `for await (const agent of page)` to iterate from an already-fetched page,
|
|
99
|
+
or `for await (const batch of page.iterPages())` to process one page at a time.
|
|
100
|
+
`getNextPage()` rejects if there is no next page; errors fetching later pages reject iteration.
|
|
101
|
+
|
|
102
|
+
The API uses **numeric pages starting at 1**, with a fixed page size of 100. The SDK derives
|
|
103
|
+
`next_page` from the returned `page`, `page_size`, and `total`; it is a number, not an opaque
|
|
104
|
+
cursor. To resume explicitly, use `zc.listAgents({ page: nextPage, labels: originalLabels })`.
|
|
105
|
+
There is no configurable `limit`. Pagination is not a snapshot: concurrent additions or
|
|
106
|
+
deletions can shift results between pages.
|
|
107
|
+
|
|
108
|
+
**Migration from the array return:** replace `const agents = await zc.listAgents(opts)` with
|
|
109
|
+
`const { data: agents } = await zc.listAgents(opts)` to keep reading one page, or switch to
|
|
110
|
+
`for await` to read every match. Missing or invalid pagination metadata now raises an error
|
|
111
|
+
instead of silently returning an empty or apparently complete array.
|
|
64
112
|
|
|
65
113
|
## Streaming a turn
|
|
66
114
|
|
|
67
115
|
`run.finished` ends a turn; assistant text arrives on `agent.assistant`.
|
|
68
116
|
|
|
69
117
|
```ts
|
|
70
|
-
import { assistantText, isRunFinished, runOutcome, toolCall } from '@zoowork-ai/sdk'
|
|
118
|
+
import { assistantText, customToolUse, isRunFinished, runOutcome, toolCall } from '@zoowork-ai/sdk'
|
|
71
119
|
|
|
72
120
|
for await (const ev of zc.streamEvents(agent.agent_id, session.session_id)) {
|
|
73
121
|
process.stdout.write(assistantText(ev)) // '' for every non-assistant event
|
|
@@ -85,8 +133,14 @@ for await (const ev of zc.streamEvents(agent.agent_id, session.session_id)) {
|
|
|
85
133
|
Three things worth knowing before you write that loop:
|
|
86
134
|
|
|
87
135
|
- **The stream is session-scoped and does not close when a turn ends.** The server closes it after an idle period. Break on `isRunFinished(ev)` yourself, or you block until that timeout.
|
|
88
|
-
- **
|
|
89
|
-
- **REST and SSE
|
|
136
|
+
- **Save the opaque cursor.** After consuming an event, retain `ev.cursor` and resume with `{ cursor }`. Do not derive it from `seq` or mix it with `after`: `after` selects the deprecated event lane, which omits user-input events. The SDK sends the cursor in the query; do not rely on a raw `Last-Event-ID` header passing through the public gateway.
|
|
137
|
+
- **The default unified REST and SSE wire formats use snake_case.** Older event formats differ; the SDK normalizes both into `SessionEvent`, where you read `eventType`. Keep the cursor unchanged.
|
|
138
|
+
|
|
139
|
+
For API sessions, `user.message` can carry `actor: { ref: 'customer-42' }`, including in
|
|
140
|
+
`initial_events`. This source-reviewed field selects per-user memory attribution. Your server
|
|
141
|
+
must authenticate the user and authorize the session; `actor.ref` does neither. It does not
|
|
142
|
+
isolate the shared agent's sandbox files or erase a session's previous context. Omit `actor`
|
|
143
|
+
to use the owner; IM sessions reject it. See the field's SDK comment for input constraints.
|
|
90
144
|
|
|
91
145
|
## Bring your own skill
|
|
92
146
|
|
|
@@ -106,6 +160,13 @@ and it is the first one nearly everyone gets. `scope` is `org` or `personal`; th
|
|
|
106
160
|
control what a skill says. `uploadSkillVersion` publishes an update, and agents that installed it
|
|
107
161
|
unpinned follow along without another `putAgentSkill`.
|
|
108
162
|
|
|
163
|
+
`uploadSkillVersion` returns a `SkillVersionRecord` with `version` and `state`, not the
|
|
164
|
+
`latest_version` and `status` of the `SkillRecord` returned by `uploadSkill`. This return
|
|
165
|
+
contract is source-reviewed, not a new live recording. On initial create, put the description
|
|
166
|
+
in the zip's frontmatter: the gateway drops the `description` option. Version uploads can
|
|
167
|
+
use that override. A successful create retried under the same name can return `409 skill_exists`;
|
|
168
|
+
read back first. Version uploads deduplicate identical content for the same skill, not HTTP keys.
|
|
169
|
+
|
|
109
170
|
## Schedules, wake and exec
|
|
110
171
|
|
|
111
172
|
```ts
|
|
@@ -125,6 +186,10 @@ const { exit_code, stdout } = await zc.exec(agent.agent_id, ['bash', '-lc', 'pwd
|
|
|
125
186
|
`listScheduleRuns`.
|
|
126
187
|
- **`updateSchedule` must omit `sessionTarget`.** It is immutable, and echoing it back from a
|
|
127
188
|
`getSchedule` result — the obvious thing to do — is a 400. The types refuse it for you.
|
|
189
|
+
- **An interval uses `{ kind: 'every', everyMs: 60_000 }`.** Optional `anchorMs` aligns it.
|
|
190
|
+
The earlier `every` type was incorrect; migrate explicitly, without guessing string units.
|
|
191
|
+
This correction and optional `ScheduleRun.session_id` are source-reviewed. Use that session
|
|
192
|
+
link only when present; it is not a run-success indicator.
|
|
128
193
|
- **`exec` resolves on a failed command.** A non-zero exit is still HTTP 200: check `exit_code`,
|
|
129
194
|
don't wait for a rejection. It runs in `/workspace` and needs an agent-scope sandbox.
|
|
130
195
|
- **A cron job can carry an outcome gate.** `payload.outcome` says what "done" looks like — a
|
|
@@ -136,13 +201,37 @@ const { exit_code, stdout } = await zc.exec(agent.agent_id, ['bash', '-lc', 'pwd
|
|
|
136
201
|
|
|
137
202
|
## Sessions, approvals, environments
|
|
138
203
|
|
|
139
|
-
`listSessions
|
|
204
|
+
`listSessions` keeps the legacy numeric-page contract. Use `listSessionPage` for the filtered
|
|
205
|
+
cursor lane: it starts with `sls1:0`, accepts channel/surface/runtime/archive filters, and returns
|
|
206
|
+
`next_cursor` plus a `list_cursor` on each row. Cursors are opaque and bound to the same filters.
|
|
207
|
+
`archiveSession` and `deleteSession` round out the session surface. There is no
|
|
140
208
|
`patchSession`: the gateway does not proxy `PATCH` at all (405), so session `metadata` is fixed at
|
|
141
209
|
creation time.
|
|
142
210
|
|
|
211
|
+
An application-executed tool is declared in `resource.custom_tools`. When
|
|
212
|
+
`customToolUse(ev)?.phase === 'requested'`, execute the named operation and call
|
|
213
|
+
`resolveCustomToolCall`; `listCustomToolCalls` recovers pending work after a restart. You may also
|
|
214
|
+
post a typed `user.custom_tool_result` event to the owning session. The run reports
|
|
215
|
+
`awaiting_approval` while paused, so use `pending_custom_tool_calls` to distinguish this wait from
|
|
216
|
+
a normal approval. These contracts are source-reviewed and need deployment verification.
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
const call = customToolUse(ev)
|
|
220
|
+
if (call?.phase === 'requested') {
|
|
221
|
+
await zc.resolveCustomToolCall(agentId, call.callId, {
|
|
222
|
+
content: [{ type: 'json', value: { price: 42 } }],
|
|
223
|
+
resolvedBy: 'pricing-service',
|
|
224
|
+
})
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
143
228
|
`listApprovals` / `resolveApproval` expose the approvals resource — `decision` is one of
|
|
144
|
-
`allow-once`, `allow-always`, `deny`.
|
|
145
|
-
|
|
229
|
+
`allow-once`, `allow-always`, `deny`. End-to-end approval and turn-budget behavior need
|
|
230
|
+
separate verification on the deployment you use.
|
|
231
|
+
|
|
232
|
+
Approval response fields are source-reviewed, not end-to-end verified: read `requested_at`,
|
|
233
|
+
`allowed_decisions` and optional timeout/resolution fields defensively. `signaled: true` means
|
|
234
|
+
the resolution was accepted; a returned `status: 'pending'` is not completed execution.
|
|
146
235
|
|
|
147
236
|
`listEnvironments`, `getEnvironment`, `createEnvironment`, `createEnvironmentVersion`,
|
|
148
237
|
`getEnvironmentVersion` and `archiveEnvironment` manage prebuilt sandbox images (apt/npm/pip
|
|
@@ -151,6 +240,14 @@ start: an agent's Environment **freezes on its first sandbox creation** — afte
|
|
|
151
240
|
is `409 environment_locked`, and stopping the agent does not clear it — and sandbox networking
|
|
152
241
|
defaults to unrestricted unless the Environment declares `networking: { type: 'limited' }`.
|
|
153
242
|
|
|
243
|
+
Build polling must have a deadline and handle `partial_ready`: some resource classes can be
|
|
244
|
+
ready while others are building or failed. `getEnvironmentVersion(id, version, { resourceClass:
|
|
245
|
+
'starter' })` selects one class; omitting the option keeps the aggregate read. Re-read the
|
|
246
|
+
aggregate before concluding the build is fully ready. These details are source-reviewed.
|
|
247
|
+
|
|
248
|
+
Channel callers must not use `allow_from` as an access-control list: the public gateway ignores
|
|
249
|
+
it. Use supported `dm_policy` settings.
|
|
250
|
+
|
|
154
251
|
## Artifacts and the system prompt
|
|
155
252
|
|
|
156
253
|
```ts
|
|
@@ -193,6 +290,41 @@ Runnable examples in [`examples/`](examples):
|
|
|
193
290
|
- [`live-smoke.ts`](examples/live-smoke.ts) — drive one agent through one turn and verify the REST and SSE reads agree.
|
|
194
291
|
- [`capability-probe.ts`](examples/capability-probe.ts) — create a throwaway agent, walk the whole lifecycle, and print a verdict per capability.
|
|
195
292
|
|
|
293
|
+
## Testing and publishing (maintainers)
|
|
294
|
+
|
|
295
|
+
Testing and publishing are independent commands. After cloning this repository on a new
|
|
296
|
+
machine, install its locked development dependencies:
|
|
297
|
+
|
|
298
|
+
```sh
|
|
299
|
+
pnpm install --frozen-lockfile
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Run staging E2E explicitly when you want to verify the SDK (Node 22.20+):
|
|
303
|
+
|
|
304
|
+
```sh
|
|
305
|
+
pnpm test:e2e
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
The command prepares an isolated test package, prints individual offline cases and timed live
|
|
309
|
+
steps, and asks for a staging API key with input hidden. Submitting the key authorizes one
|
|
310
|
+
temporary Agent/Session, one potentially billable model turn and cleanup. JSON reports remain
|
|
311
|
+
in its printed private directory. The test never publishes. Normal `pnpm test` is offline
|
|
312
|
+
and needs no key. See [E2E and recovery instructions](e2e/README.md) for scope and options.
|
|
313
|
+
|
|
314
|
+
Publishing runs through [`.github/workflows/release.yml`](.github/workflows/release.yml). Configure
|
|
315
|
+
the npm package's Trusted Publisher once with organization `SerendipityOneInc`, repository
|
|
316
|
+
`zoowork-sdk-typescript`, workflow `release.yml`, and direct publish permission. No npm token or
|
|
317
|
+
repeated `npm login` is needed after that.
|
|
318
|
+
|
|
319
|
+
For each release, merge the intended version and changelog, then publish a GitHub Release whose
|
|
320
|
+
tag is exactly `v<package version>` — for example, `v0.7.0`. The workflow verifies that match,
|
|
321
|
+
runs the offline test and build gates, and publishes the public package with npm OIDC. A mismatched
|
|
322
|
+
tag fails before publication, and an existing npm version cannot be overwritten.
|
|
323
|
+
|
|
324
|
+
The release workflow does not run live E2E or read a staging key. Run `pnpm test:e2e` separately
|
|
325
|
+
before creating the GitHub Release when live verification is required. Use
|
|
326
|
+
`npm publish --dry-run` locally to inspect the package without uploading it.
|
|
327
|
+
|
|
196
328
|
## License
|
|
197
329
|
|
|
198
330
|
MIT
|
package/dist/client.d.ts
CHANGED
|
@@ -42,6 +42,29 @@ export interface ZooworkConfig {
|
|
|
42
42
|
/** Injected fetch for edge runtimes/tests; defaults to globalThis.fetch. */
|
|
43
43
|
fetch?: (input: string, init?: RequestInit) => Promise<Response>;
|
|
44
44
|
}
|
|
45
|
+
export interface AgentListParams {
|
|
46
|
+
labels?: Record<string, string>;
|
|
47
|
+
/** Starting page, numbered from 1. The API fixes page size at 100. */
|
|
48
|
+
page?: number;
|
|
49
|
+
}
|
|
50
|
+
/** A single page. Iterating this object asynchronously continues through subsequent pages. */
|
|
51
|
+
export interface AgentPage extends AsyncIterable<AgentRecord> {
|
|
52
|
+
/** Agents in this page only. */
|
|
53
|
+
readonly data: AgentRecord[];
|
|
54
|
+
readonly page: number;
|
|
55
|
+
readonly page_size: number;
|
|
56
|
+
readonly total: number;
|
|
57
|
+
/** Next numeric page to pass to listAgents, or null at the end. */
|
|
58
|
+
readonly next_page: number | null;
|
|
59
|
+
hasNextPage(): boolean;
|
|
60
|
+
/** Fetch the next page with the same filters. Rejects when there is no next page. */
|
|
61
|
+
getNextPage(): Promise<AgentPage>;
|
|
62
|
+
/** Iterate this and subsequent pages, fetching each only when needed. */
|
|
63
|
+
iterPages(): AsyncIterableIterator<AgentPage>;
|
|
64
|
+
}
|
|
65
|
+
/** Await one page, or use for-await directly to traverse all remaining agents. */
|
|
66
|
+
export interface AgentPagePromise extends Promise<AgentPage>, AsyncIterable<AgentRecord> {
|
|
67
|
+
}
|
|
45
68
|
export declare class ZooworkError extends Error {
|
|
46
69
|
status: number;
|
|
47
70
|
/**
|
|
@@ -100,6 +123,18 @@ export interface ModelInfo {
|
|
|
100
123
|
api?: string;
|
|
101
124
|
[k: string]: unknown;
|
|
102
125
|
}
|
|
126
|
+
/** Approval behavior for one MCP server or one of its tools. */
|
|
127
|
+
export type McpToolPermission = 'always_ask' | 'always_allow';
|
|
128
|
+
/** Opt-in runtime coordinates sent only while a tool is executing, never during catalog discovery. */
|
|
129
|
+
export interface McpContextConfig {
|
|
130
|
+
/** Add the coordinates under `params._meta['ai.zooclaw/context']` on `tools/call`. */
|
|
131
|
+
meta?: boolean;
|
|
132
|
+
/** Add the coordinates as `x-zooclaw-*` headers on the tool call's HTTP requests. */
|
|
133
|
+
headers?: boolean;
|
|
134
|
+
}
|
|
135
|
+
export interface McpToolPermissionOverride {
|
|
136
|
+
permission: McpToolPermission;
|
|
137
|
+
}
|
|
103
138
|
/**
|
|
104
139
|
* One remote MCP server, declared as `resource.mcp[]` on create or update.
|
|
105
140
|
*
|
|
@@ -114,9 +149,12 @@ export interface ModelInfo {
|
|
|
114
149
|
* other way to store it, so an authenticated MCP server cannot be made to work today.
|
|
115
150
|
* Declare public servers only.
|
|
116
151
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
152
|
+
* Remote HTTP only; no stdio. Catalog failures emit `agent.error` with
|
|
153
|
+
* `kind: 'mcp_connection_failed'` or `'mcp_authentication_failed'`, a server name,
|
|
154
|
+
* an errorMessage and an optional reason. Preserve unknown reason values.
|
|
155
|
+
* Healthy catalogs remain tied to the configuration. Transient failed catalogs can expire:
|
|
156
|
+
* a later catalog resolution may probe again, not a periodic retry or recovery guarantee.
|
|
157
|
+
* These failure/recovery details are source-reviewed, not deployment-verified here.
|
|
120
158
|
*/
|
|
121
159
|
export interface McpServerDeclaration {
|
|
122
160
|
/** Server slug. Appears in every tool name as `mcp__<name>__<tool>`. No underscores. */
|
|
@@ -129,8 +167,42 @@ export interface McpServerDeclaration {
|
|
|
129
167
|
credential?: string;
|
|
130
168
|
/** Expose only these tool names from this server. Omit for all of them. */
|
|
131
169
|
toolFilter?: string[];
|
|
170
|
+
/**
|
|
171
|
+
* How tools reach the model. `deferred` (the default when omitted) keeps them behind
|
|
172
|
+
* `tool_search` / `tool_describe` until loaded; `direct` declares them on the first request.
|
|
173
|
+
* There is no `auto` value.
|
|
174
|
+
*/
|
|
175
|
+
exposure?: 'deferred' | 'direct';
|
|
176
|
+
/**
|
|
177
|
+
* Opt in to runtime coordinates for this server. Both switches default to false. The context
|
|
178
|
+
* can include agent/session/computer ids and, when available, run/turn/config/actor fields.
|
|
179
|
+
* Catalog discovery never receives it. Header delivery may be unavailable through proxies;
|
|
180
|
+
* `_meta` is the portable option.
|
|
181
|
+
*/
|
|
182
|
+
context?: McpContextConfig;
|
|
183
|
+
/** Default approval behavior for every tool on this server. Omit for the existing default-allow behavior. */
|
|
184
|
+
permission?: McpToolPermission;
|
|
185
|
+
/**
|
|
186
|
+
* Per-tool approval overrides keyed by the server's original tool name, not its
|
|
187
|
+
* `mcp__<server>__<tool>` name. Keys are exact and cannot contain `*`; at most 64 entries.
|
|
188
|
+
*/
|
|
189
|
+
tools?: Record<string, McpToolPermissionOverride>;
|
|
132
190
|
[k: string]: unknown;
|
|
133
191
|
}
|
|
192
|
+
/** One application-executed tool declared under {@link AgentResource.custom_tools}. */
|
|
193
|
+
export interface CustomToolDeclaration {
|
|
194
|
+
/** Unique within the Agent; 1–64 ASCII letters, numbers, `_` or `-`. Reserved runtime names are rejected. */
|
|
195
|
+
name: string;
|
|
196
|
+
/** Non-empty tool description, at most 4 KiB UTF-8. */
|
|
197
|
+
description: string;
|
|
198
|
+
/** JSON Schema for the input. Its top-level `type` must be `object`; at most 16 KiB serialized. */
|
|
199
|
+
input_schema: {
|
|
200
|
+
type: 'object';
|
|
201
|
+
[k: string]: unknown;
|
|
202
|
+
};
|
|
203
|
+
/** Result wait budget in milliseconds. Defaults to 600,000; maximum 86,400,000. */
|
|
204
|
+
timeoutMs?: number;
|
|
205
|
+
}
|
|
134
206
|
/**
|
|
135
207
|
* The system-prompt pin (`resource.system_prompt`).
|
|
136
208
|
*
|
|
@@ -197,7 +269,12 @@ export interface OutcomeConfig {
|
|
|
197
269
|
}
|
|
198
270
|
export interface AgentResource {
|
|
199
271
|
name: string;
|
|
200
|
-
/**
|
|
272
|
+
/**
|
|
273
|
+
* Omit this section to pin the platform's current model defaults at create time. Those
|
|
274
|
+
* defaults can rotate; call `listModels()` and set `primary` explicitly for deterministic
|
|
275
|
+
* provisioning. `max_tokens` caps output tokens per model request; omit only that field to
|
|
276
|
+
* use the platform token limit.
|
|
277
|
+
*/
|
|
201
278
|
model?: {
|
|
202
279
|
primary: string;
|
|
203
280
|
input?: string[];
|
|
@@ -215,9 +292,21 @@ export interface AgentResource {
|
|
|
215
292
|
version?: number | 'latest';
|
|
216
293
|
}[];
|
|
217
294
|
labels?: Record<string, string>;
|
|
295
|
+
/**
|
|
296
|
+
* Tool-surface and approval policy. Name selectors in `allow`, `deny`, `rules[].match.tool`,
|
|
297
|
+
* `afterRules[].match.tool`, and MCP names in `deferred.pinned` accept an exact name, `*`, or
|
|
298
|
+
* one trailing `prefix*`. Other wildcard forms match nothing. `alsoAllow` and
|
|
299
|
+
* `permissions` keys remain exact. Kept open for forward-compatible policy fields.
|
|
300
|
+
*/
|
|
218
301
|
tool_policy?: Record<string, unknown>;
|
|
219
302
|
/** Remote MCP servers. Only unauthenticated ones work today — see {@link McpServerDeclaration}. */
|
|
220
303
|
mcp?: McpServerDeclaration[];
|
|
304
|
+
/**
|
|
305
|
+
* Tools executed by your application. At most 32. A model call emits
|
|
306
|
+
* `agent.custom_tool_use`; return the result with `resolveCustomToolCall` or a
|
|
307
|
+
* `user.custom_tool_result` event. Source-reviewed; deployment availability is unverified.
|
|
308
|
+
*/
|
|
309
|
+
custom_tools?: CustomToolDeclaration[];
|
|
221
310
|
/**
|
|
222
311
|
* System-prompt pin. Omitted on create means "the platform version active right now", pinned
|
|
223
312
|
* from then on. REPLACE-ON-WRITE on PUT, like `tool_policy` — see {@link SystemPromptDeclaration}.
|
|
@@ -235,15 +324,18 @@ export interface AgentResource {
|
|
|
235
324
|
environment_version?: number;
|
|
236
325
|
}
|
|
237
326
|
/**
|
|
238
|
-
* Agent lifecycle state. Two fields, two very different meanings
|
|
239
|
-
* 2026-08-06:
|
|
327
|
+
* Agent lifecycle state. Two fields, two very different meanings:
|
|
240
328
|
*
|
|
241
329
|
* - `desired_state` is the one that gates the API. `running` is the precondition for
|
|
242
330
|
* createSession/postEvents; anything else is `409 agent_not_running`.
|
|
243
|
-
* - `actual_state` is CHANNEL
|
|
244
|
-
*
|
|
245
|
-
* `
|
|
246
|
-
*
|
|
331
|
+
* - `actual_state` is a best-effort CHANNEL-health projection, not API readiness. When
|
|
332
|
+
* route-status is unsupported, GET can report `active` with zero channel counts and a
|
|
333
|
+
* `status_message` saying health was not verified; a transient unknown remains
|
|
334
|
+
* `activating`. `listAgents` does not make the same foreground health query, so list and
|
|
335
|
+
* GET can briefly differ. Never gate on this field, and never poll it for `running` —
|
|
336
|
+
* that is not one of its values.
|
|
337
|
+
*
|
|
338
|
+
* The channel fallback behavior is source-reviewed, not deployment-verified here.
|
|
247
339
|
*/
|
|
248
340
|
export interface AgentStatus {
|
|
249
341
|
desired_state?: 'running' | 'stopped' | 'deleted' | string;
|
|
@@ -272,6 +364,27 @@ export interface AgentSkill {
|
|
|
272
364
|
}[];
|
|
273
365
|
[k: string]: unknown;
|
|
274
366
|
}
|
|
367
|
+
/** Source-reviewed asynchronous capability-configuration state for one channel feature. */
|
|
368
|
+
export interface AgentChannelCapabilitySync {
|
|
369
|
+
state: 'pending' | 'applied' | 'retry' | 'error';
|
|
370
|
+
[k: string]: unknown;
|
|
371
|
+
}
|
|
372
|
+
export interface FeishuChannelProviderStatus {
|
|
373
|
+
state: 'ready' | 'degraded';
|
|
374
|
+
missing_scopes: string[];
|
|
375
|
+
approval_state?: 'pending_admin' | null;
|
|
376
|
+
[k: string]: unknown;
|
|
377
|
+
}
|
|
378
|
+
export interface FeishuDocumentsCapability {
|
|
379
|
+
permission_admin_enabled: boolean;
|
|
380
|
+
sync: AgentChannelCapabilitySync;
|
|
381
|
+
provider: FeishuChannelProviderStatus;
|
|
382
|
+
[k: string]: unknown;
|
|
383
|
+
}
|
|
384
|
+
export interface AgentChannelCapabilities {
|
|
385
|
+
feishu_documents?: FeishuDocumentsCapability | null;
|
|
386
|
+
[k: string]: unknown;
|
|
387
|
+
}
|
|
275
388
|
/**
|
|
276
389
|
* One platform account bound to an agent, as the channel service reports it.
|
|
277
390
|
* `dm_policy` / `group_policy` are the reachability policies (`'open'` is the
|
|
@@ -288,10 +401,13 @@ export interface AgentChannel {
|
|
|
288
401
|
health?: string;
|
|
289
402
|
status?: string;
|
|
290
403
|
status_code?: string | null;
|
|
404
|
+
/** Source-reviewed capability state. Omitted when the platform reports none. */
|
|
405
|
+
capabilities?: AgentChannelCapabilities | null;
|
|
291
406
|
[k: string]: unknown;
|
|
292
407
|
}
|
|
293
408
|
/**
|
|
294
|
-
* The chat platforms you can bind, staging-verified
|
|
409
|
+
* The chat platforms you can bind. Feishu, Slack, WeCom and WeChat were staging-verified
|
|
410
|
+
* 2026-08-28. Direct DingTalk support is source-reviewed, not deployment-verified here.
|
|
295
411
|
*
|
|
296
412
|
* Three of them have a server-driven QR flow ({@link GuidedSetupPlatform}); Slack does not,
|
|
297
413
|
* and structurally cannot — a Slack app is created by a person and its tokens only ever exist
|
|
@@ -300,15 +416,15 @@ export interface AgentChannel {
|
|
|
300
416
|
*
|
|
301
417
|
* WeChat is the one platform that goes the other way: `'weixin'`/`'wechat'` on
|
|
302
418
|
* {@link ZooworkClient.addChannel} answers `400 channel.weixin_setup_required`, so the QR flow
|
|
303
|
-
* is its ONLY path.
|
|
304
|
-
*
|
|
419
|
+
* is its ONLY path. DingTalk uses `'dingtalk-connector'` and currently has a direct config path
|
|
420
|
+
* only on the public API; its product QR flow is not exposed here. See {@link AddChannelPlatform}.
|
|
305
421
|
*/
|
|
306
|
-
export type ChannelPlatform = 'feishu' | 'slack' | 'wecom' | 'weixin';
|
|
422
|
+
export type ChannelPlatform = 'feishu' | 'slack' | 'wecom' | 'weixin' | 'dingtalk-connector';
|
|
307
423
|
/**
|
|
308
424
|
* The platforms {@link ZooworkClient.addChannel} accepts — every {@link ChannelPlatform}
|
|
309
425
|
* except WeChat, which refuses explicit config and takes the QR flow only.
|
|
310
426
|
*/
|
|
311
|
-
export type AddChannelPlatform = 'feishu' | 'slack' | 'wecom';
|
|
427
|
+
export type AddChannelPlatform = 'feishu' | 'slack' | 'wecom' | 'dingtalk-connector';
|
|
312
428
|
/**
|
|
313
429
|
* The platforms with a server-driven QR flow: {@link ZooworkClient.startChannelSetup} →
|
|
314
430
|
* render the URI → poll. Slack is absent by design, not by omission.
|
|
@@ -357,11 +473,11 @@ export interface AddChannelInput {
|
|
|
357
473
|
*/
|
|
358
474
|
account?: string;
|
|
359
475
|
display_name?: string;
|
|
360
|
-
/** Server default: `'open'`. `'pairing'` is rejected
|
|
476
|
+
/** Server default: `'open'`. DingTalk accepts only `'open'`; `'pairing'` is rejected everywhere. */
|
|
361
477
|
dm_policy?: string;
|
|
362
478
|
/** Server default: `'open'`. */
|
|
363
479
|
group_policy?: string;
|
|
364
|
-
/**
|
|
480
|
+
/** Retained for compatibility; the public gateway ignores this field. It is NOT an access allowlist. Use supported dm_policy settings. */
|
|
365
481
|
allow_from?: string[];
|
|
366
482
|
/**
|
|
367
483
|
* Platform credentials for the direct (non-QR) path. Keys are platform-specific and
|
|
@@ -371,8 +487,11 @@ export interface AddChannelInput {
|
|
|
371
487
|
* needs the app-level token as well as the bot token)
|
|
372
488
|
* - `wecom` — `{ botId, secret }`, both required
|
|
373
489
|
* - `feishu` — `{ appId, appSecret, domain }`, only when skipping the QR flow
|
|
490
|
+
* - `dingtalk-connector` — `{ clientId, clientSecret }`; no public guided QR route
|
|
374
491
|
*/
|
|
375
492
|
config?: Record<string, unknown>;
|
|
493
|
+
/** Feishu only. Enable document-permission administration; defaults to false. */
|
|
494
|
+
permission_admin_enabled?: boolean;
|
|
376
495
|
}
|
|
377
496
|
export interface UpdateChannelInput {
|
|
378
497
|
/** Which binding to touch — see {@link AddChannelInput.account}. Server default: `'default'`. */
|
|
@@ -380,6 +499,8 @@ export interface UpdateChannelInput {
|
|
|
380
499
|
dm_policy?: string;
|
|
381
500
|
group_policy?: string;
|
|
382
501
|
enabled?: boolean;
|
|
502
|
+
/** Feishu only. Other platforms reject this field when it is present. */
|
|
503
|
+
permission_admin_enabled?: boolean;
|
|
383
504
|
}
|
|
384
505
|
/**
|
|
385
506
|
* Body for {@link ZooworkClient.startChannelSetup}. Every field is optional, and each platform
|
|
@@ -422,6 +543,8 @@ export interface ChannelSetupInput {
|
|
|
422
543
|
dm_policy?: string;
|
|
423
544
|
/** Server default: `'open'`. Ignored by WeChat, which forces `'disabled'`. */
|
|
424
545
|
group_policy?: string;
|
|
546
|
+
/** Feishu only. Enable document-permission administration; defaults to false. */
|
|
547
|
+
permission_admin_enabled?: boolean;
|
|
425
548
|
}
|
|
426
549
|
/** @deprecated Use {@link ChannelSetupInput}; this is the same shape under the old name. */
|
|
427
550
|
export type FeishuSetupInput = ChannelSetupInput;
|
|
@@ -548,6 +671,16 @@ export interface SkillRecord {
|
|
|
548
671
|
};
|
|
549
672
|
[k: string]: unknown;
|
|
550
673
|
}
|
|
674
|
+
/**
|
|
675
|
+
* The version row returned by uploadSkillVersion, not a SkillRecord.
|
|
676
|
+
* Source-reviewed fields; no new live recording is implied. The response stays unmodified.
|
|
677
|
+
*/
|
|
678
|
+
export interface SkillVersionRecord {
|
|
679
|
+
skill_id: string;
|
|
680
|
+
version: string | number;
|
|
681
|
+
state: 'pending' | 'ready' | 'failed' | string;
|
|
682
|
+
[k: string]: unknown;
|
|
683
|
+
}
|
|
551
684
|
/**
|
|
552
685
|
* One `session_transcripts` row, as projected by `getSession(…, { history: true })`.
|
|
553
686
|
*
|
|
@@ -571,7 +704,11 @@ export interface SessionRecord {
|
|
|
571
704
|
* `getSession` and `listSessions` carry the latest run state (`running`, `succeeded`, …) here.
|
|
572
705
|
* The `createSession` receipt does not include this field.
|
|
573
706
|
*/
|
|
574
|
-
run_status?: string;
|
|
707
|
+
run_status?: string | null;
|
|
708
|
+
/** Pending approval count on getSession; not included in every session projection. */
|
|
709
|
+
pending_approvals?: number;
|
|
710
|
+
/** Pending application-executed custom-tool count on getSession. */
|
|
711
|
+
pending_custom_tool_calls?: number;
|
|
575
712
|
/**
|
|
576
713
|
* `running` on a `createSession` receipt, nullable on `getSession`, and absent from
|
|
577
714
|
* `listSessions` rows. This is not the run outcome; read {@link SessionRecord.run_status}
|
|
@@ -580,17 +717,84 @@ export interface SessionRecord {
|
|
|
580
717
|
status?: string | null;
|
|
581
718
|
metadata?: Record<string, unknown>;
|
|
582
719
|
archived?: boolean;
|
|
720
|
+
runtime_mode?: 'active' | 'preview' | 'authoring' | 'evaluation' | string;
|
|
721
|
+
config_version?: number;
|
|
583
722
|
updated_at?: string;
|
|
723
|
+
/** Activity sort key used by filtered cursor listing. */
|
|
724
|
+
last_activity_at?: string;
|
|
725
|
+
/** Opaque per-row resume cursor returned only by {@link ZooworkClient.listSessionPage}. */
|
|
726
|
+
list_cursor?: string;
|
|
584
727
|
/** Present only when the read asked for `history: true`; the most recent `limit` rows, in order. */
|
|
585
728
|
history?: SessionHistoryEntry[];
|
|
586
729
|
[k: string]: unknown;
|
|
587
730
|
}
|
|
588
|
-
/** Write-side events
|
|
731
|
+
/** Write-side events, including `user.custom_tool_result`; unsupported types are rejected by the API. */
|
|
589
732
|
export interface OutboundEvent {
|
|
590
733
|
type: string;
|
|
591
734
|
content?: unknown;
|
|
735
|
+
/**
|
|
736
|
+
* user.message on an API session only, including createSession.initial_events.
|
|
737
|
+
* ref is 1–200 ASCII characters from [A-Za-z0-9._:@+-]. Omit actor to use the owner.
|
|
738
|
+
* Map an authenticated application user to a stable opaque ref on YOUR server.
|
|
739
|
+
* This selects memory attribution, not authentication, session authorization or file isolation.
|
|
740
|
+
* IM sessions reject actor; token and other actor keys are rejected with HTTP 400.
|
|
741
|
+
* Source-reviewed; deployment availability must be verified separately.
|
|
742
|
+
*/
|
|
743
|
+
actor?: {
|
|
744
|
+
ref: string;
|
|
745
|
+
token?: never;
|
|
746
|
+
};
|
|
592
747
|
[k: string]: unknown;
|
|
593
748
|
}
|
|
749
|
+
export type CustomToolResultImageMimeType = 'image/png' | 'image/jpeg' | 'image/gif' | 'image/webp';
|
|
750
|
+
/** One content block returned by an application-executed custom tool. */
|
|
751
|
+
export type CustomToolResultContent = {
|
|
752
|
+
type: 'text';
|
|
753
|
+
text: string;
|
|
754
|
+
} | {
|
|
755
|
+
type: 'json';
|
|
756
|
+
value: unknown;
|
|
757
|
+
} | {
|
|
758
|
+
type: 'image';
|
|
759
|
+
source: {
|
|
760
|
+
type: 'base64';
|
|
761
|
+
media_type: CustomToolResultImageMimeType;
|
|
762
|
+
data: string;
|
|
763
|
+
};
|
|
764
|
+
} | {
|
|
765
|
+
type: 'image';
|
|
766
|
+
data: string;
|
|
767
|
+
mime_type: CustomToolResultImageMimeType;
|
|
768
|
+
};
|
|
769
|
+
/** Write-side result event for {@link ZooworkClient.postEvents}. */
|
|
770
|
+
export type CustomToolResultEvent = OutboundEvent & {
|
|
771
|
+
type: 'user.custom_tool_result';
|
|
772
|
+
content: CustomToolResultContent[];
|
|
773
|
+
is_error?: boolean;
|
|
774
|
+
idempotency_key?: string;
|
|
775
|
+
} & ({
|
|
776
|
+
custom_tool_use_id: string;
|
|
777
|
+
call_id?: never;
|
|
778
|
+
} | {
|
|
779
|
+
call_id: string;
|
|
780
|
+
custom_tool_use_id?: never;
|
|
781
|
+
});
|
|
782
|
+
/** Options for the filtered cursor lane. Filters are part of the cursor scope. */
|
|
783
|
+
export interface SessionListPageOptions {
|
|
784
|
+
/** Opaque cursor returned by this same filter scope. Omit to start at `sls1:0`. */
|
|
785
|
+
cursor?: string;
|
|
786
|
+
/** 1–100; server default 50. */
|
|
787
|
+
limit?: number;
|
|
788
|
+
excludeChannels?: string[];
|
|
789
|
+
includeSurfaces?: string[];
|
|
790
|
+
runtimeModes?: Array<'active' | 'preview' | 'authoring' | 'evaluation'>;
|
|
791
|
+
includeArchived?: boolean;
|
|
792
|
+
}
|
|
793
|
+
/** One filtered session page. `next_cursor` is null at the end. */
|
|
794
|
+
export interface SessionListPage {
|
|
795
|
+
sessions: SessionRecord[];
|
|
796
|
+
next_cursor: string | null;
|
|
797
|
+
}
|
|
594
798
|
/** One `postEvents` receipt. An accepted event carries the full event object's fields too. */
|
|
595
799
|
export interface PostEventReceipt {
|
|
596
800
|
id?: string | null;
|
|
@@ -605,11 +809,10 @@ export interface SessionEventPage {
|
|
|
605
809
|
nextCursor?: string | null;
|
|
606
810
|
}
|
|
607
811
|
/**
|
|
608
|
-
* When a schedule fires
|
|
609
|
-
*
|
|
610
|
-
*
|
|
611
|
-
*
|
|
612
|
-
* than guessed at, so anything the engine accepts still type-checks.
|
|
812
|
+
* When a schedule fires: cron expression, everyMs interval in milliseconds (optional
|
|
813
|
+
* anchorMs), or an ISO instant in at. The everyMs contract is source-reviewed; it was
|
|
814
|
+
* previously misdeclared as every. Use everyMs explicitly: the SDK does not convert units
|
|
815
|
+
* or rename the obsolete every field at runtime.
|
|
613
816
|
*
|
|
614
817
|
* Cron is a five-field expression. Macros and a `CRON_TZ=` prefix are rejected; overlap is
|
|
615
818
|
* fixed to SKIP server-side, so a fire that lands on a still-running one is dropped, not queued.
|
|
@@ -621,7 +824,8 @@ export type ScheduleSpec = {
|
|
|
621
824
|
[k: string]: unknown;
|
|
622
825
|
} | {
|
|
623
826
|
kind: 'every';
|
|
624
|
-
|
|
827
|
+
everyMs: number;
|
|
828
|
+
anchorMs?: number;
|
|
625
829
|
tz?: string;
|
|
626
830
|
[k: string]: unknown;
|
|
627
831
|
} | {
|
|
@@ -782,13 +986,16 @@ export interface ScheduleRecord {
|
|
|
782
986
|
* This is the only row that carries `status` (e.g. `skipped` for a fire against a disabled
|
|
783
987
|
* schedule).
|
|
784
988
|
*
|
|
785
|
-
*
|
|
786
|
-
*
|
|
787
|
-
*
|
|
989
|
+
* Source-reviewed additions can include session_id when the fire has a known session.
|
|
990
|
+
* It is optional, not proof of success, and may be absent for command jobs or an unlinked
|
|
991
|
+
* fire. Older recordings above omit it. Without it, list the agent's sessions and match
|
|
992
|
+
* channel: 'cron' with the session_key prefix agent:{agent_id}:cron:{schedule_id}:.
|
|
788
993
|
*/
|
|
789
994
|
export interface ScheduleRun {
|
|
790
995
|
/** Which projection this row came from. Decides which of the field groups below is populated. */
|
|
791
996
|
source?: 'temporal' | 'run_projection' | string;
|
|
997
|
+
/** Present only when a session can be associated with this fire. */
|
|
998
|
+
session_id?: string;
|
|
792
999
|
/** Un-qualified `schedule_id`. */
|
|
793
1000
|
schedule_id?: string;
|
|
794
1001
|
fired_at?: string;
|
|
@@ -809,18 +1016,46 @@ export type ApprovalDecision = 'allow-once' | 'allow-always' | 'deny';
|
|
|
809
1016
|
/**
|
|
810
1017
|
* A tool call parked on a human decision.
|
|
811
1018
|
*
|
|
812
|
-
*
|
|
813
|
-
*
|
|
814
|
-
*
|
|
1019
|
+
* Fields below are source-reviewed; the existing live recordings have empty lists.
|
|
1020
|
+
* A resolve receipt can have signaled:true while status is still pending: acceptance is not
|
|
1021
|
+
* completion of the tool or run. Verify the resulting state separately.
|
|
815
1022
|
*/
|
|
816
1023
|
export interface ApprovalRecord {
|
|
817
1024
|
approval_id?: string;
|
|
818
1025
|
session_id?: string;
|
|
819
1026
|
tool_name?: string;
|
|
820
1027
|
status?: string;
|
|
1028
|
+
arguments_preview?: string;
|
|
1029
|
+
stake?: unknown;
|
|
1030
|
+
requested_at?: string;
|
|
1031
|
+
timeout_at?: string;
|
|
1032
|
+
allowed_decisions?: ApprovalDecision[];
|
|
1033
|
+
resolved_by?: string;
|
|
1034
|
+
resolved_at?: string;
|
|
1035
|
+
signaled?: boolean;
|
|
1036
|
+
decision?: ApprovalDecision;
|
|
1037
|
+
/** Legacy compatibility field; current source projects requested_at instead. */
|
|
821
1038
|
created_at?: string;
|
|
822
1039
|
[k: string]: unknown;
|
|
823
1040
|
}
|
|
1041
|
+
export type CustomToolCallStatus = 'pending' | 'completed' | 'timeout' | 'cancelled' | string;
|
|
1042
|
+
/** One application-executed custom-tool call. Unknown response fields are preserved. */
|
|
1043
|
+
export interface CustomToolCallRecord {
|
|
1044
|
+
call_id: string;
|
|
1045
|
+
session_id: string;
|
|
1046
|
+
tool_call_id: string;
|
|
1047
|
+
name: string;
|
|
1048
|
+
input: Record<string, unknown>;
|
|
1049
|
+
status: CustomToolCallStatus;
|
|
1050
|
+
requested_at: string;
|
|
1051
|
+
timeout_at?: string;
|
|
1052
|
+
resolved_by?: string;
|
|
1053
|
+
resolved_at?: string;
|
|
1054
|
+
is_error?: boolean;
|
|
1055
|
+
/** Resolve receipt: true when a pending call was signaled, false when it was already terminal. */
|
|
1056
|
+
signaled?: boolean;
|
|
1057
|
+
[k: string]: unknown;
|
|
1058
|
+
}
|
|
824
1059
|
/** Artifact lifecycle. Only a `ready` row carries a resolvable `url`. */
|
|
825
1060
|
export type ArtifactStatus = 'pending' | 'ready' | 'failed' | 'deleted' | string;
|
|
826
1061
|
/**
|
|
@@ -993,10 +1228,11 @@ export interface EnvironmentRecord {
|
|
|
993
1228
|
[k: string]: unknown;
|
|
994
1229
|
}
|
|
995
1230
|
/**
|
|
996
|
-
* One immutable Environment version. Builds
|
|
997
|
-
*
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1231
|
+
* One immutable Environment version's build state. Builds can be queued, submitting, building,
|
|
1232
|
+
* verifying, partial_ready, ready or failed. partial_ready means some resource classes are
|
|
1233
|
+
* ready; others may still be building or may have failed. It is not by itself a success/failure
|
|
1234
|
+
* verdict for your selected class. Poll with a deadline; optionally read that resourceClass
|
|
1235
|
+
* and re-read the aggregate before drawing a conclusion.
|
|
1000
1236
|
*
|
|
1001
1237
|
* THE FIELD IS `status`, NOT `state` — staging-verified 2026-08-07. A poll loop written against
|
|
1002
1238
|
* `state` compares `undefined` to `'ready'` forever and never terminates, which is precisely the
|
|
@@ -1005,8 +1241,8 @@ export interface EnvironmentRecord {
|
|
|
1005
1241
|
export interface EnvironmentVersionRecord {
|
|
1006
1242
|
environment_id?: string;
|
|
1007
1243
|
version?: number;
|
|
1008
|
-
/**
|
|
1009
|
-
status?: 'queued' | 'submitting' | 'building' | 'verifying' | 'ready' | 'failed' | string;
|
|
1244
|
+
/** Build status; partial_ready may be transient or a partial terminal result. */
|
|
1245
|
+
status?: 'queued' | 'submitting' | 'building' | 'verifying' | 'partial_ready' | 'ready' | 'failed' | string;
|
|
1010
1246
|
/** The normalized config this version was built from — not the one you posted verbatim. */
|
|
1011
1247
|
config?: EnvironmentConfig;
|
|
1012
1248
|
base_environment_id?: string;
|
|
@@ -1064,11 +1300,12 @@ export interface ZooworkClient {
|
|
|
1064
1300
|
*
|
|
1065
1301
|
* Note the scope is `owner_uid AND org_id`: an agent a colleague created in your org is
|
|
1066
1302
|
* fetchable by `getAgent` but will not appear here.
|
|
1303
|
+
*
|
|
1304
|
+
* `await listAgents()` returns one {@link AgentPage}; read `.data` for its agents and
|
|
1305
|
+
* `.next_page` / `.hasNextPage()` for continuation. `for await (const agent of listAgents())`
|
|
1306
|
+
* automatically fetches subsequent pages. Breaking the loop stops further requests.
|
|
1067
1307
|
*/
|
|
1068
|
-
listAgents(opts?:
|
|
1069
|
-
labels?: Record<string, string>;
|
|
1070
|
-
page?: number;
|
|
1071
|
-
}): Promise<AgentRecord[]>;
|
|
1308
|
+
listAgents(opts?: AgentListParams): AgentPagePromise;
|
|
1072
1309
|
getAgent(agentId: string): Promise<AgentRecord>;
|
|
1073
1310
|
/** PUT declared sections; bumps config_version on EVERY call — gate on drift, don't blind-retry. */
|
|
1074
1311
|
updateAgent(agentId: string, sections: Record<string, unknown>): Promise<AgentRecord>;
|
|
@@ -1081,13 +1318,17 @@ export interface ZooworkClient {
|
|
|
1081
1318
|
deleteAgent(agentId: string): Promise<void>;
|
|
1082
1319
|
/**
|
|
1083
1320
|
* Flip `desired_state` to `running` — the precondition for every session call.
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
* because it has no chat-channel routes to reload. Do not treat it as failure.
|
|
1321
|
+
* A successful response can contain warnings. A non-2xx response still throws ZooworkError;
|
|
1322
|
+
* warnings are not guaranteed on each start/stop and are not a substitute for error handling.
|
|
1087
1323
|
*/
|
|
1088
1324
|
startAgent(agentId: string): Promise<{
|
|
1089
1325
|
warnings: string[];
|
|
1090
1326
|
}>;
|
|
1327
|
+
/**
|
|
1328
|
+
* Request stopped state. Dependency failures can reject after desired_state changes.
|
|
1329
|
+
* Read back and reconcile; desired_state alone does not prove all runtime work is cleaned up.
|
|
1330
|
+
* A successful response's warnings and a rejected HTTP call are different outcomes.
|
|
1331
|
+
*/
|
|
1091
1332
|
stopAgent(agentId: string): Promise<{
|
|
1092
1333
|
warnings: string[];
|
|
1093
1334
|
}>;
|
|
@@ -1286,10 +1527,11 @@ export interface ZooworkClient {
|
|
|
1286
1527
|
* accepted. `SKILL.md` must be non-empty and declare both `name` and `description`.
|
|
1287
1528
|
* 50 MB expanded, zip only (store/deflate), encrypted zips rejected.
|
|
1288
1529
|
*
|
|
1289
|
-
*
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1530
|
+
* scope is org or personal. Other values are rejected by the public gateway with HTTP 400.
|
|
1531
|
+
* Ownership comes from your key. On this CREATE operation the public gateway drops the
|
|
1532
|
+
* description option: put the description in the zip's frontmatter instead.
|
|
1533
|
+
* idempotencyKey is retained as a transport option, not a replay guarantee for Skill uploads.
|
|
1534
|
+
* A retry after a successful create can return 409 skill_exists; read back before retrying.
|
|
1293
1535
|
*/
|
|
1294
1536
|
uploadSkill(zip: Blob | ArrayBuffer | Uint8Array, opts: {
|
|
1295
1537
|
scope: 'org' | 'personal';
|
|
@@ -1300,7 +1542,9 @@ export interface ZooworkClient {
|
|
|
1300
1542
|
/**
|
|
1301
1543
|
* Publish a new version of an existing skill from a zip. Same zip rules as
|
|
1302
1544
|
* {@link ZooworkClient.uploadSkill}, plus: the frontmatter `name` must match the target
|
|
1303
|
-
* skill's name.
|
|
1545
|
+
* skill's name. Unlike root create, description can override the frontmatter here.
|
|
1546
|
+
* Returns a version row (version/state), not a SkillRecord (latest_version/status).
|
|
1547
|
+
* Identical content for the same skill is deduplicated by content, not by Idempotency-Key.
|
|
1304
1548
|
*
|
|
1305
1549
|
* Agents that installed the skill unpinned follow the new version on their own — the registry
|
|
1306
1550
|
* bumps their `config_version`; you do not re-`putAgentSkill`.
|
|
@@ -1309,7 +1553,7 @@ export interface ZooworkClient {
|
|
|
1309
1553
|
fileName?: string;
|
|
1310
1554
|
description?: string;
|
|
1311
1555
|
idempotencyKey?: string;
|
|
1312
|
-
}): Promise<
|
|
1556
|
+
}): Promise<SkillVersionRecord>;
|
|
1313
1557
|
/**
|
|
1314
1558
|
* The catalog visible to your key: global skills plus your org/personal ones. `q` matches on
|
|
1315
1559
|
* name; `page` is 1-based with a fixed page size of 100. Only the `org`/`personal` rows are
|
|
@@ -1330,10 +1574,15 @@ export interface ZooworkClient {
|
|
|
1330
1574
|
history?: boolean;
|
|
1331
1575
|
limit?: number;
|
|
1332
1576
|
}): Promise<SessionRecord>;
|
|
1333
|
-
/**
|
|
1577
|
+
/** Legacy newest-first numeric page lane: 50 per page, `page` is 1-based. */
|
|
1334
1578
|
listSessions(agentId: string, opts?: {
|
|
1335
1579
|
page?: number;
|
|
1336
1580
|
}): Promise<SessionRecord[]>;
|
|
1581
|
+
/**
|
|
1582
|
+
* Filtered cursor lane. It is separate from {@link listSessions} so existing numeric-page
|
|
1583
|
+
* callers keep their contract. Cursors are opaque and valid only with the same filters.
|
|
1584
|
+
*/
|
|
1585
|
+
listSessionPage(agentId: string, opts?: SessionListPageOptions): Promise<SessionListPage>;
|
|
1337
1586
|
/**
|
|
1338
1587
|
* Stamp `archived_at`. Afterwards writes are `409 session_archived` while reads keep working.
|
|
1339
1588
|
* Interrupt an in-flight run first, or the archive races it.
|
|
@@ -1404,16 +1653,28 @@ export interface ZooworkClient {
|
|
|
1404
1653
|
cursor?: string;
|
|
1405
1654
|
signal?: AbortSignal;
|
|
1406
1655
|
}): AsyncGenerator<SessionEvent>;
|
|
1656
|
+
/** Pending calls only. Any other status is rejected by the API. */
|
|
1657
|
+
listCustomToolCalls(agentId: string, opts?: {
|
|
1658
|
+
status?: 'pending';
|
|
1659
|
+
}): Promise<CustomToolCallRecord[]>;
|
|
1660
|
+
/**
|
|
1661
|
+
* Return one call's result. A pending call answers 202/signaled:true but stays pending until
|
|
1662
|
+
* the paused run consumes it; an already-terminal call answers 200/signaled:false.
|
|
1663
|
+
*/
|
|
1664
|
+
resolveCustomToolCall(agentId: string, callId: string, input: {
|
|
1665
|
+
content: CustomToolResultContent[];
|
|
1666
|
+
isError?: boolean;
|
|
1667
|
+
resolvedBy?: string;
|
|
1668
|
+
}): Promise<CustomToolCallRecord>;
|
|
1407
1669
|
/**
|
|
1408
1670
|
* Tool calls parked on a human decision. `status` may ONLY be omitted or `'pending'` —
|
|
1409
1671
|
* staging-verified 2026-08-07; any other value is rejected, so there is no way to list
|
|
1410
1672
|
* resolved ones.
|
|
1411
1673
|
*
|
|
1412
|
-
* Approvals are a REST resource here,
|
|
1413
|
-
*
|
|
1414
|
-
*
|
|
1415
|
-
*
|
|
1416
|
-
* on an approval burns its whole turn budget waiting.
|
|
1674
|
+
* Approvals are a REST resource here, not an interchangeable user.tool_confirmation
|
|
1675
|
+
* payload. A deployment without approval support can return 501 not_configured.
|
|
1676
|
+
* The response contract is source-reviewed; end-to-end approval and turn-budget behavior
|
|
1677
|
+
* need separate verification on the deployment you use.
|
|
1417
1678
|
*/
|
|
1418
1679
|
listApprovals(agentId: string, opts?: {
|
|
1419
1680
|
status?: 'pending';
|
|
@@ -1422,7 +1683,7 @@ export interface ZooworkClient {
|
|
|
1422
1683
|
resolveApproval(agentId: string, approvalId: string, input: {
|
|
1423
1684
|
decision: ApprovalDecision;
|
|
1424
1685
|
resolvedBy?: string;
|
|
1425
|
-
}): Promise<
|
|
1686
|
+
}): Promise<ApprovalRecord>;
|
|
1426
1687
|
/**
|
|
1427
1688
|
* Artifacts this agent published, one page per call — but unlike `listEvents`, the page SAYS
|
|
1428
1689
|
* when it truncated: read `has_more`. `limit` defaults to 50, capped at 100; filter by
|
|
@@ -1540,9 +1801,9 @@ export interface ZooworkClient {
|
|
|
1540
1801
|
*
|
|
1541
1802
|
* `resource.config` takes exactly four keys — packages / files / build / networking — and
|
|
1542
1803
|
* anything else is `400 invalid_environment_config`. Building is asynchronous: poll
|
|
1543
|
-
*
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1804
|
+
* getEnvironmentVersion with a deadline before pinning it on an agent. Handle failed and
|
|
1805
|
+
* partial_ready explicitly; selected-class readiness is different from aggregate readiness.
|
|
1806
|
+
* The field is status, not state. A loop without a timeout can otherwise wait forever.
|
|
1546
1807
|
*/
|
|
1547
1808
|
createEnvironment(input: {
|
|
1548
1809
|
resource: EnvironmentResource;
|
|
@@ -1558,15 +1819,17 @@ export interface ZooworkClient {
|
|
|
1558
1819
|
*/
|
|
1559
1820
|
archiveEnvironment(environmentId: string): Promise<EnvironmentRecord>;
|
|
1560
1821
|
/**
|
|
1561
|
-
* Add
|
|
1562
|
-
*
|
|
1822
|
+
* Add a new immutable configuration version to an existing Environment. This is NOT the
|
|
1823
|
+
* separate operation that retries an existing failed version; the SDK does not wrap retry.
|
|
1563
1824
|
*
|
|
1564
1825
|
* The route is reachable, but the request body was not exercised against staging on
|
|
1565
1826
|
* 2026-08-07 — the SDK sends `{ resource: { config } }`, mirroring create.
|
|
1566
1827
|
*/
|
|
1567
1828
|
createEnvironmentVersion(environmentId: string, config: EnvironmentConfig, idempotencyKey?: string): Promise<EnvironmentVersionRecord>;
|
|
1568
|
-
/**
|
|
1569
|
-
getEnvironmentVersion(environmentId: string, version: number
|
|
1829
|
+
/** Read aggregate build state, or one resource class. Source-reviewed selector; use bounded polling. */
|
|
1830
|
+
getEnvironmentVersion(environmentId: string, version: number, opts?: {
|
|
1831
|
+
resourceClass?: 'starter' | 'pro' | 'ultra';
|
|
1832
|
+
}): Promise<EnvironmentVersionRecord>;
|
|
1570
1833
|
}
|
|
1571
1834
|
/**
|
|
1572
1835
|
* Create a client.
|
package/dist/client.js
CHANGED
|
@@ -308,12 +308,57 @@ export function createZooworkClient(cfg = {}) {
|
|
|
308
308
|
...(idempotencyKey ? { headers: { 'Idempotency-Key': idempotencyKey } } : {}),
|
|
309
309
|
});
|
|
310
310
|
},
|
|
311
|
-
listAgents:
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
311
|
+
listAgents: (opts = {}) => {
|
|
312
|
+
// Capture the filters once so caller mutations cannot change the scope mid-walk.
|
|
313
|
+
const labels = { ...opts.labels };
|
|
314
|
+
const fetchPage = async (pageNumber) => {
|
|
315
|
+
if (pageNumber !== undefined && (!Number.isSafeInteger(pageNumber) || pageNumber < 1)) {
|
|
316
|
+
throw new RangeError('Agent list page must be a positive safe integer');
|
|
317
|
+
}
|
|
318
|
+
const params = { page: pageNumber };
|
|
319
|
+
for (const [k, v] of Object.entries(labels))
|
|
320
|
+
params[`label.${k}`] = v;
|
|
321
|
+
const body = await json(`/agents${query(params)}`);
|
|
322
|
+
// Missing metadata must not silently turn a partial result into the last page.
|
|
323
|
+
// Check advancement too, so a server ignoring page cannot cause an endless walk.
|
|
324
|
+
if (!body || !Array.isArray(body.agents) || body.page !== (pageNumber ?? 1)
|
|
325
|
+
|| !Number.isSafeInteger(body.page_size) || body.page_size < 1
|
|
326
|
+
|| !Number.isSafeInteger(body.total) || body.total < 0) {
|
|
327
|
+
throw new Error('Invalid agent list pagination: expected agents, page, page_size, and total for the requested page');
|
|
328
|
+
}
|
|
329
|
+
const nextPage = body.page < Math.ceil(body.total / body.page_size) ? body.page + 1 : null;
|
|
330
|
+
const result = {
|
|
331
|
+
data: body.agents,
|
|
332
|
+
page: body.page,
|
|
333
|
+
page_size: body.page_size,
|
|
334
|
+
total: body.total,
|
|
335
|
+
next_page: nextPage,
|
|
336
|
+
hasNextPage: () => nextPage !== null,
|
|
337
|
+
getNextPage: async () => {
|
|
338
|
+
if (nextPage === null)
|
|
339
|
+
throw new Error('No next page');
|
|
340
|
+
return fetchPage(nextPage);
|
|
341
|
+
},
|
|
342
|
+
async *iterPages() {
|
|
343
|
+
let page = result;
|
|
344
|
+
while (true) {
|
|
345
|
+
yield page;
|
|
346
|
+
if (!page.hasNextPage())
|
|
347
|
+
return;
|
|
348
|
+
page = await page.getNextPage();
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
async *[Symbol.asyncIterator]() {
|
|
352
|
+
for await (const page of result.iterPages())
|
|
353
|
+
yield* page.data;
|
|
354
|
+
},
|
|
355
|
+
};
|
|
356
|
+
return result;
|
|
357
|
+
};
|
|
358
|
+
const request = fetchPage(opts.page);
|
|
359
|
+
return Object.assign(request, {
|
|
360
|
+
async *[Symbol.asyncIterator]() { yield* await request; },
|
|
361
|
+
});
|
|
317
362
|
},
|
|
318
363
|
getAgent: (agentId) => json(agents(agentId)),
|
|
319
364
|
updateAgent: (agentId, sections) => json(agents(agentId), { method: 'PUT', body: JSON.stringify(sections) }),
|
|
@@ -498,6 +543,17 @@ export function createZooworkClient(cfg = {}) {
|
|
|
498
543
|
const data = await json(`${sessions(agentId)}${query({ page: opts.page })}`);
|
|
499
544
|
return data.sessions ?? [];
|
|
500
545
|
},
|
|
546
|
+
listSessionPage: async (agentId, opts = {}) => {
|
|
547
|
+
const data = await json(`${sessions(agentId)}${query({
|
|
548
|
+
cursor: opts.cursor ?? 'sls1:0',
|
|
549
|
+
limit: opts.limit,
|
|
550
|
+
exclude_channels: opts.excludeChannels?.join(','),
|
|
551
|
+
include_surfaces: opts.includeSurfaces?.join(','),
|
|
552
|
+
runtime_modes: opts.runtimeModes?.join(','),
|
|
553
|
+
include_archived: opts.includeArchived === undefined ? undefined : String(opts.includeArchived),
|
|
554
|
+
})}`);
|
|
555
|
+
return { sessions: data.sessions ?? [], next_cursor: data.next_cursor ?? null };
|
|
556
|
+
},
|
|
501
557
|
archiveSession: async (agentId, sessionId) => {
|
|
502
558
|
const data = await json(`${sessions(agentId)}/${encodeURIComponent(sessionId)}/archive`, { method: 'POST' });
|
|
503
559
|
return { ...data, archived: data.archived ?? false };
|
|
@@ -606,6 +662,14 @@ export function createZooworkClient(cfg = {}) {
|
|
|
606
662
|
throw e;
|
|
607
663
|
}
|
|
608
664
|
},
|
|
665
|
+
listCustomToolCalls: async (agentId, opts = {}) => {
|
|
666
|
+
const data = await json(`${agents(agentId)}/custom_tool_calls${query({ status: opts.status })}`);
|
|
667
|
+
return data.custom_tool_calls ?? [];
|
|
668
|
+
},
|
|
669
|
+
resolveCustomToolCall: (agentId, callId, input) => json(`${agents(agentId)}/custom_tool_calls/${encodeURIComponent(callId)}/result`, {
|
|
670
|
+
method: 'POST',
|
|
671
|
+
body: JSON.stringify(input),
|
|
672
|
+
}),
|
|
609
673
|
listApprovals: async (agentId, opts = {}) => {
|
|
610
674
|
const data = await json(`${agents(agentId)}/approvals${query({ status: opts.status })}`);
|
|
611
675
|
return data.approvals ?? [];
|
|
@@ -700,7 +764,7 @@ export function createZooworkClient(cfg = {}) {
|
|
|
700
764
|
body: JSON.stringify({ resource: { config } }),
|
|
701
765
|
...(idempotencyKey ? { headers: { 'Idempotency-Key': idempotencyKey } } : {}),
|
|
702
766
|
}),
|
|
703
|
-
getEnvironmentVersion: (environmentId, version) => json(`${environments(environmentId)}/versions/${encodeURIComponent(String(version))}`),
|
|
767
|
+
getEnvironmentVersion: (environmentId, version, opts = {}) => json(`${environments(environmentId)}/versions/${encodeURIComponent(String(version))}${query({ resource_class: opts.resourceClass })}`),
|
|
704
768
|
};
|
|
705
769
|
return client;
|
|
706
770
|
}
|
package/dist/events.d.ts
CHANGED
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
* and may add types within a version.
|
|
18
18
|
*/
|
|
19
19
|
/** SESSION_EVENT_TYPES, mirrored from the API. */
|
|
20
|
-
export declare const SESSION_EVENT_TYPES: readonly ["run.started", "run.finished", "chat.delta", "chat.final", "chat.aborted", "chat.error", "agent.lifecycle", "agent.assistant", "agent.thinking", "agent.tool", "agent.item", "agent.plan", "agent.approval", "agent.command_output", "agent.patch", "agent.compaction", "agent.error", "attachment.created", "message.outbound"];
|
|
20
|
+
export declare const SESSION_EVENT_TYPES: readonly ["run.started", "run.finished", "chat.delta", "chat.final", "chat.aborted", "chat.error", "agent.lifecycle", "agent.assistant", "agent.thinking", "agent.tool", "agent.item", "agent.plan", "agent.approval", "agent.custom_tool_use", "agent.command_output", "agent.patch", "agent.compaction", "agent.error", "attachment.created", "message.outbound"];
|
|
21
21
|
export type SessionEventType = (typeof SESSION_EVENT_TYPES)[number];
|
|
22
22
|
/** Your own inputs, echoed back in the unified event history. */
|
|
23
|
-
export declare const PUBLIC_INPUT_EVENT_TYPES: readonly ["user.message", "user.interrupt", "user.tool_confirmation", "system.message"];
|
|
23
|
+
export declare const PUBLIC_INPUT_EVENT_TYPES: readonly ["user.message", "user.interrupt", "user.tool_confirmation", "user.custom_tool_result", "system.message"];
|
|
24
24
|
export type PublicInputEventType = (typeof PUBLIC_INPUT_EVENT_TYPES)[number];
|
|
25
25
|
/** A durable session event, normalized across the REST and SSE shapes. */
|
|
26
26
|
export interface SessionEvent {
|
|
@@ -74,6 +74,20 @@ export interface ToolCall {
|
|
|
74
74
|
isError?: boolean;
|
|
75
75
|
resultPreview?: string;
|
|
76
76
|
}
|
|
77
|
+
export interface CustomToolUse {
|
|
78
|
+
phase: 'requested' | 'resolved';
|
|
79
|
+
callId: string;
|
|
80
|
+
toolCallId?: string;
|
|
81
|
+
name?: string;
|
|
82
|
+
input?: Record<string, unknown>;
|
|
83
|
+
timeoutAt?: string;
|
|
84
|
+
outcome?: 'completed' | 'timeout' | 'cancelled';
|
|
85
|
+
isError?: boolean;
|
|
86
|
+
resolvedBy?: string;
|
|
87
|
+
resolutionChannel?: string;
|
|
88
|
+
}
|
|
89
|
+
/** Application-executed custom-tool activity; undefined for every other event type. */
|
|
90
|
+
export declare function customToolUse(e: SessionEvent): CustomToolUse | undefined;
|
|
77
91
|
/**
|
|
78
92
|
* Tool activity for an `agent.tool` event; undefined for every other type.
|
|
79
93
|
*
|
package/dist/events.js
CHANGED
|
@@ -31,6 +31,7 @@ export const SESSION_EVENT_TYPES = [
|
|
|
31
31
|
'agent.item',
|
|
32
32
|
'agent.plan',
|
|
33
33
|
'agent.approval',
|
|
34
|
+
'agent.custom_tool_use',
|
|
34
35
|
'agent.command_output',
|
|
35
36
|
'agent.patch',
|
|
36
37
|
'agent.compaction',
|
|
@@ -43,6 +44,7 @@ export const PUBLIC_INPUT_EVENT_TYPES = [
|
|
|
43
44
|
'user.message',
|
|
44
45
|
'user.interrupt',
|
|
45
46
|
'user.tool_confirmation',
|
|
47
|
+
'user.custom_tool_result',
|
|
46
48
|
'system.message',
|
|
47
49
|
];
|
|
48
50
|
const isObj = (v) => !!v && typeof v === 'object';
|
|
@@ -124,6 +126,25 @@ export function thinkingText(e) {
|
|
|
124
126
|
return '';
|
|
125
127
|
return typeof e.payload.text === 'string' ? e.payload.text : '';
|
|
126
128
|
}
|
|
129
|
+
/** Application-executed custom-tool activity; undefined for every other event type. */
|
|
130
|
+
export function customToolUse(e) {
|
|
131
|
+
if (e.eventType !== 'agent.custom_tool_use')
|
|
132
|
+
return undefined;
|
|
133
|
+
const p = e.payload;
|
|
134
|
+
const outcome = p.outcome === 'completed' || p.outcome === 'timeout' || p.outcome === 'cancelled' ? p.outcome : undefined;
|
|
135
|
+
return {
|
|
136
|
+
phase: p.phase === 'resolved' ? 'resolved' : 'requested',
|
|
137
|
+
callId: typeof p.callId === 'string' ? p.callId : '',
|
|
138
|
+
...(typeof p.toolCallId === 'string' ? { toolCallId: p.toolCallId } : {}),
|
|
139
|
+
...(typeof p.name === 'string' ? { name: p.name } : {}),
|
|
140
|
+
...(isObj(p.input) ? { input: p.input } : {}),
|
|
141
|
+
...(typeof p.timeoutAt === 'string' ? { timeoutAt: p.timeoutAt } : {}),
|
|
142
|
+
...(outcome ? { outcome } : {}),
|
|
143
|
+
...(typeof p.isError === 'boolean' ? { isError: p.isError } : {}),
|
|
144
|
+
...(typeof p.resolvedBy === 'string' ? { resolvedBy: p.resolvedBy } : {}),
|
|
145
|
+
...(typeof p.resolutionChannel === 'string' ? { resolutionChannel: p.resolutionChannel } : {}),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
127
148
|
/**
|
|
128
149
|
* Tool activity for an `agent.tool` event; undefined for every other type.
|
|
129
150
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { createZooworkClient, DEFAULT_BASE_URL, ZooworkError, type ZooworkClient, type ZooworkConfig, type ZooworkAuth, type Ownership, type ModelInfo, type AgentResource, type AgentRecord, type AgentStatus, type AgentSkill, type AgentChannel, type ChannelPlatform, type AddChannelPlatform, type GuidedSetupPlatform, type AddChannelInput, type UpdateChannelInput, type ChannelSetupInput, type ChannelSetupSession, type ChannelPollResult, type FeishuSetupInput, type FeishuSetupSession, type FeishuPollResult, type McpServerDeclaration, type SkillRecord, type SessionRecord, type SessionHistoryEntry, type SessionEvent, type SessionEventPage, type OutboundEvent, type PostEventReceipt, type ApprovalDecision, type ApprovalRecord, type ArtifactPage, type ArtifactRecord, type ArtifactStatus, type OutcomeConfig, type OutcomeEvaluator, type SystemPromptDeclaration, type SystemPromptInfo, type SystemPromptPreview, type SystemPromptPreviewInput, type SystemPromptUpgrade, type ScheduleSpec, type SchedulePayload, type ScheduleInput, type ScheduleUpdate, type ScheduleRecord, type ScheduleRun, type WakeResult, type ExecResult, type EnvironmentConfig, type EnvironmentResource, type EnvironmentRecord, type EnvironmentVersionRecord, } from './client.js';
|
|
2
|
-
export { SESSION_EVENT_TYPES, type SessionEventType, PUBLIC_INPUT_EVENT_TYPES, type PublicInputEventType, normalizeEvent, isRunFinished, runOutcome, messageText, assistantText, thinkingText, toolCall, type ToolCall, } from './events.js';
|
|
1
|
+
export { createZooworkClient, DEFAULT_BASE_URL, ZooworkError, type ZooworkClient, type ZooworkConfig, type ZooworkAuth, type Ownership, type ModelInfo, type AgentResource, type AgentRecord, type AgentListParams, type AgentPage, type AgentPagePromise, type AgentStatus, type AgentSkill, type AgentChannel, type AgentChannelCapabilitySync, type AgentChannelCapabilities, type FeishuChannelProviderStatus, type FeishuDocumentsCapability, type ChannelPlatform, type AddChannelPlatform, type GuidedSetupPlatform, type AddChannelInput, type UpdateChannelInput, type ChannelSetupInput, type ChannelSetupSession, type ChannelPollResult, type FeishuSetupInput, type FeishuSetupSession, type FeishuPollResult, type McpContextConfig, type McpServerDeclaration, type McpToolPermission, type McpToolPermissionOverride, type CustomToolDeclaration, type CustomToolResultImageMimeType, type CustomToolResultContent, type CustomToolResultEvent, type SkillRecord, type SkillVersionRecord, type SessionRecord, type SessionListPageOptions, type SessionListPage, type SessionHistoryEntry, type SessionEvent, type SessionEventPage, type OutboundEvent, type PostEventReceipt, type ApprovalDecision, type ApprovalRecord, type CustomToolCallStatus, type CustomToolCallRecord, type ArtifactPage, type ArtifactRecord, type ArtifactStatus, type OutcomeConfig, type OutcomeEvaluator, type SystemPromptDeclaration, type SystemPromptInfo, type SystemPromptPreview, type SystemPromptPreviewInput, type SystemPromptUpgrade, type ScheduleSpec, type SchedulePayload, type ScheduleInput, type ScheduleUpdate, type ScheduleRecord, type ScheduleRun, type WakeResult, type ExecResult, type EnvironmentConfig, type EnvironmentResource, type EnvironmentRecord, type EnvironmentVersionRecord, } from './client.js';
|
|
2
|
+
export { SESSION_EVENT_TYPES, type SessionEventType, PUBLIC_INPUT_EVENT_TYPES, type PublicInputEventType, normalizeEvent, isRunFinished, runOutcome, messageText, assistantText, thinkingText, customToolUse, type CustomToolUse, toolCall, type ToolCall, } from './events.js';
|
|
3
3
|
export { parseSSE, type SSEMessage } from './sse.js';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { createZooworkClient, DEFAULT_BASE_URL, ZooworkError, } from './client.js';
|
|
2
|
-
export { SESSION_EVENT_TYPES, PUBLIC_INPUT_EVENT_TYPES, normalizeEvent, isRunFinished, runOutcome, messageText, assistantText, thinkingText, toolCall, } from './events.js';
|
|
2
|
+
export { SESSION_EVENT_TYPES, PUBLIC_INPUT_EVENT_TYPES, normalizeEvent, isRunFinished, runOutcome, messageText, assistantText, thinkingText, customToolUse, toolCall, } from './events.js';
|
|
3
3
|
export { parseSSE } from './sse.js';
|
package/dist/sse.d.ts
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SSE line parser for the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* live wire and needed no changes. The `id:` field matters: The server frames each durable
|
|
6
|
-
* event as `id: <seq>` + `data: <json>`, so dropping the id line would freeze the resume
|
|
7
|
-
* cursor. Web Streams + TextDecoder only, so this runs in workers and browsers as well as
|
|
8
|
-
* Node.
|
|
2
|
+
* SSE line parser for the /events/stream endpoint.
|
|
3
|
+
* Preserve id as an opaque string: unified events use it as a resume cursor, while the
|
|
4
|
+
* legacy lane can send numeric ids. Web Streams + TextDecoder only.
|
|
9
5
|
*/
|
|
10
6
|
export interface SSEMessage {
|
|
11
7
|
event: string;
|
|
12
|
-
/** The SSE
|
|
8
|
+
/** The SSE id field, unchanged. Do not parse an opaque resume cursor as a number. */
|
|
13
9
|
id?: string;
|
|
14
10
|
data: unknown;
|
|
15
11
|
}
|
package/dist/sse.js
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* SSE line parser for the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* live wire and needed no changes. The `id:` field matters: The server frames each durable
|
|
6
|
-
* event as `id: <seq>` + `data: <json>`, so dropping the id line would freeze the resume
|
|
7
|
-
* cursor. Web Streams + TextDecoder only, so this runs in workers and browsers as well as
|
|
8
|
-
* Node.
|
|
2
|
+
* SSE line parser for the /events/stream endpoint.
|
|
3
|
+
* Preserve id as an opaque string: unified events use it as a resume cursor, while the
|
|
4
|
+
* legacy lane can send numeric ids. Web Streams + TextDecoder only.
|
|
9
5
|
*/
|
|
10
6
|
export const isObj = (v) => !!v && typeof v === 'object';
|
|
11
7
|
export async function* parseSSE(body) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoowork-ai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "TypeScript SDK for the ZooWork Managed Agents API (Developer Preview)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"zoowork",
|
|
@@ -44,9 +44,16 @@
|
|
|
44
44
|
"typecheck": "tsc --noEmit",
|
|
45
45
|
"test": "tsc --noEmit && vitest run",
|
|
46
46
|
"test:watch": "vitest",
|
|
47
|
-
"
|
|
47
|
+
"test:e2e": "node e2e/command.ts",
|
|
48
|
+
"typecheck:e2e": "tsc -p tsconfig.e2e.json",
|
|
49
|
+
"test:e2e:offline": "node --import tsx --test --test-reporter=spec e2e/*.test.ts",
|
|
50
|
+
"e2e:prepare": "node e2e/runner.ts prepare",
|
|
51
|
+
"e2e:run": "node e2e/runner.ts run",
|
|
52
|
+
"e2e:verify": "node e2e/runner.ts verify",
|
|
53
|
+
"prepack": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && npm run build"
|
|
48
54
|
},
|
|
49
55
|
"devDependencies": {
|
|
56
|
+
"@types/node": "^22.20.1",
|
|
50
57
|
"tsx": "^4.23.7",
|
|
51
58
|
"typescript": "^5.6.0",
|
|
52
59
|
"vitest": "^3.0.0"
|