@zoowork-ai/sdk 0.9.0 → 0.10.1

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 CHANGED
@@ -3,7 +3,27 @@
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
- ## Unreleased
6
+ ## 0.10.1 — 2026-10-03
7
+
8
+ - Correct production availability guidance for Files, Database viewer, Schedules and Agent configuration updates.
9
+ - Clarify approval and blocked tool events, stream cursor recovery, repeated deletion and Usage validation.
10
+ - Link to the public developer documentation.
11
+ - Documentation and comments only; no runtime or public API changes. Existing service limitations remain.
12
+
13
+ ## 0.10.0 — 2026-10-03
14
+
15
+ - Add Files, read-only Agent Database, Usage, Run Output, action paging/detail and Agent webhook management helpers.
16
+ - Add typed MCP confirmation, active Session creation and configuration concurrency metadata.
17
+ - Align onboarding and capability examples with Platform Project keys.
18
+
19
+ ### Known service and documentation limitations
20
+
21
+ Verified against production on 2026-10-03; these are not resolved by this SDK release:
22
+
23
+ - Workspace Files read/write APIs return HTTP 502 with both Platform and legacy keys ([ecap #4006](https://github.com/SerendipityOneInc/ecap-workspace/issues/4006)).
24
+ - Legacy keys cannot update or remove visible global Skill assignments on their own Agents; Platform keys succeed ([ecap #4007](https://github.com/SerendipityOneInc/ecap-workspace/issues/4007)).
25
+ - Published Authentication URLs redirect to Quickstart, including the AI Markdown entry ([docs #56](https://github.com/SerendipityOneInc/zoowork-agents-docs/issues/56)).
26
+ - Agent Database reads depend on deployment support. The production viewer was disabled, so its successful read path has not been validated.
7
27
 
8
28
  ## 0.9.0 — 2026-10-01
9
29
 
@@ -23,7 +43,7 @@ day the behaviour was verified, not the day it was written.
23
43
  - **The webhook event vocabulary.** `WEBHOOK_EVENT_TYPES` lists the sixteen types Engine
24
44
  delivers today, with a `data` shape per type behind `WebhookEventFor<T>` and
25
45
  `knownWebhookEvent()`. `WEBHOOK_SCHEDULE_CONFIG_EVENT_TYPES` declares the five schedule
26
- configuration events whose server side is not deployed yet. A type the release does not know
46
+ configuration events for schedule configuration changes. A type the release does not know
27
47
  passes through with its raw `type` and `data` instead of throwing, so a receiver stays
28
48
  forward compatible.
29
49
  - Fixed cross-language signing vectors in `src/__vectors__/webhook-vectors.json`, copied verbatim
@@ -39,9 +59,8 @@ day the behaviour was verified, not the day it was written.
39
59
 
40
60
  ### Changed
41
61
 
42
- - Local E2E checks accept Platform `zwp_live_` keys as well as legacy `zct_` keys. Production
43
- checks require an explicit URL and confirmation, and record their scope separately from
44
- staging checks. The SDK already accepts Platform keys without a client API change.
62
+ - Local E2E checks accept Platform Project keys. Production checks require an explicit URL
63
+ and confirmation, and record their scope separately from staging checks.
45
64
  - Live smoke tests select only selectable catalog models.
46
65
 
47
66
  ## 0.8.0 — 2026-09-20
@@ -220,8 +239,7 @@ No runtime change — comments only.
220
239
  - `createZooclawClient` → `createZooworkClient`; `ZooclawClient`, `ZooclawError`,
221
240
  `ZooclawAuth`, `ZooclawConfig` → `Zoowork*`.
222
241
  - `ZOOCLAW_API_KEY` / `ZOOCLAW_BASE_URL` → `ZOOWORK_API_KEY` / `ZOOWORK_BASE_URL`.
223
- - Server-side identifiers are unchanged: API keys still start with `zct_`, and skill or
224
- environment names the API returns (e.g. `zooclaw-tts`) are whatever the server says.
242
+ - Server-side identifiers and resource names remain opaque.
225
243
 
226
244
  ## 0.3.4 — 2026-08-25
227
245
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @zoowork-ai/sdk
2
2
 
3
- TypeScript SDK for the [ZooWork Managed Agents](https://github.com/SerendipityOneInc/zoowork-agents-docs) API. Developer Preview.
3
+ TypeScript SDK for the [ZooWork Managed Agents](https://zoowork.ai/docs/) API. Developer Preview.
4
4
 
5
5
  Zero runtime dependencies — it uses the platform `fetch`, which you can override for edge runtimes and tests. ESM only, Node 20+.
6
6
 
@@ -10,9 +10,7 @@ npm install @zoowork-ai/sdk
10
10
 
11
11
  ## Quickstart
12
12
 
13
- Platform Project keys (`zwp_live_...`) and existing Work tokens (`zct_...`) both work with `apiKey`. Platform scopes Agent and Session access to the key’s Project and requires initialized Org billing and bound owner credentials. Rebind the key after signing in when the API requests it.
14
-
15
- Create a Project key in Platform, or a Work token under **Settings → API Keys** in the ZooWork App. Secrets are shown once at creation. Keep them server-side: Platform keys carry Project scope, while Work tokens use the existing organization authorization contract.
13
+ Create a Project API key in [ZooWork Platform](https://platform.zoowork.ai). The secret is shown once. Save it as `ZOOWORK_API_KEY` on your server. Agent and Session access is scoped to the key's Project. Initialize Organization billing and bind owner credentials; sign in and rebind when the API requests it.
16
14
 
17
15
  ```ts
18
16
  import { createZooworkClient } from '@zoowork-ai/sdk'
@@ -68,12 +66,6 @@ separately.
68
66
 
69
67
  An explicit option always beats the environment variable.
70
68
 
71
- > **Finding the agent you built in the app.** The first path segment of a ZooWork chat URL
72
- > (`/chat/<32-hex>/sessions/…`) is a *workspace* id, not an `agt_…`. Resolve it with
73
- > `zc.listAgents({ labels: { workspace_id: '<32-hex>' } })`; use the pagination patterns
74
- > below to read one page or traverse every match. Scope is `owner_uid AND org_id` — an agent a *colleague*
75
- > created in your org is fetchable by id but will not appear in your list.
76
-
77
69
  > **Wait on `status.desired_state`, never on `status.actual_state`.**
78
70
  > `actual_state` reports chat-channel connectivity. An API-only agent has no channels,
79
71
  > but its projection depends on the channel-status capability: a GET can report `active`
@@ -155,30 +147,9 @@ must authenticate the user and authorize the session; `actor.ref` does neither.
155
147
  isolate the shared agent's sandbox files or erase a session's previous context. Omit `actor`
156
148
  to use the owner; IM sessions reject it. See the field's SDK comment for input constraints.
157
149
 
158
- ## Bring your own skill
159
-
160
- A skill is a zip. One upload creates the skill *and* its first version; `putAgentSkill` attaches it.
161
-
162
- ```ts
163
- import { readFile } from 'node:fs/promises'
164
-
165
- const skill = await zc.uploadSkill(await readFile('market-research.zip'), { scope: 'org' })
166
- await zc.putAgentSkill(agent.agent_id, skill.skill_id)
167
- ```
168
-
169
- The zip's single top-level directory must be named exactly like the `name` in its `SKILL.md`
170
- frontmatter — `market-research/SKILL.md` declaring `name: market-research`. A mismatch is a 400,
171
- and it is the first one nearly everyone gets. `scope` is `org` or `personal`; the preinstalled
172
- `global` skills are listable but not installable with an API key, so this is the only way to
173
- control what a skill says. `uploadSkillVersion` publishes an update, and agents that installed it
174
- unpinned follow along without another `putAgentSkill`.
150
+ ## Agent Skills
175
151
 
176
- `uploadSkillVersion` returns a `SkillVersionRecord` with `version` and `state`, not the
177
- `latest_version` and `status` of the `SkillRecord` returned by `uploadSkill`. This return
178
- contract is source-reviewed, not a new live recording. On initial create, put the description
179
- in the zip's frontmatter: the gateway drops the `description` option. Version uploads can
180
- use that override. A successful create retried under the same name can return `409 skill_exists`;
181
- read back first. Version uploads deduplicate identical content for the same skill, not HTTP keys.
152
+ New Agents receive global Skills by default. Use `listAgentSkills(agentId)` to inspect attached Skills. At create time, `resource.skills` accepts a catalog name or `skill_id`; `include_global_skills: false` or an explicit empty list opts out of automatic Skills. Root Skill uploads are unavailable to Project keys. Keep source changes in your application; use persona documents for standing instructions and Session messages for text task data.
182
153
 
183
154
  ## Schedules, wake and exec
184
155
 
@@ -249,20 +220,7 @@ Approval response fields are source-reviewed, not end-to-end verified: read `req
249
220
  `allowed_decisions` and optional timeout/resolution fields defensively. `signaled: true` means
250
221
  the resolution was accepted; a returned `status: 'pending'` is not completed execution.
251
222
 
252
- `listEnvironments`, `getEnvironment`, `createEnvironment`, `createEnvironmentVersion`,
253
- `getEnvironmentVersion` and `archiveEnvironment` manage prebuilt sandbox images (apt/npm/pip
254
- packages, files, a build script, and an outbound allowlist). Two facts worth having before you
255
- start: an agent's Environment **freezes on its first sandbox creation** — after that every change
256
- is `409 environment_locked`, and stopping the agent does not clear it — and sandbox networking
257
- defaults to unrestricted unless the Environment declares `networking: { type: 'limited' }`.
258
-
259
- Build polling must have a deadline and handle `partial_ready`: some resource classes can be
260
- ready while others are building or failed. `getEnvironmentVersion(id, version, { resourceClass:
261
- 'starter' })` selects one class; omitting the option keeps the aggregate read. Re-read the
262
- aggregate before concluding the build is fully ready. These details are source-reviewed.
263
-
264
- Channel callers must not use `allow_from` as an access-control list: the public gateway ignores
265
- it. Use supported `dm_policy` settings.
223
+ Platform uses its managed Environment. Root Environment administration and Channel binding return `404 service_api.not_found` for Project keys. An exported method does not expand a key's permissions.
266
224
 
267
225
  ## Artifacts and the system prompt
268
226
 
@@ -291,7 +249,9 @@ and answers the new pin plus the version bump it cost.
291
249
 
292
250
  Verification needs the **raw request bytes**. `express.json()` and most framework body parsers
293
251
  consume them, and a `JSON.parse` → `JSON.stringify` round trip does not reproduce them byte for
294
- byte, so read the body before anything else touches it:
252
+ byte, so read the body before anything else touches it. The example requires your
253
+ application to supply `acceptOnce`, an atomic durable insert plus work-item enqueue, before it
254
+ returns 204. A worker processes that item separately:
295
255
 
296
256
  ```ts
297
257
  import { createServer } from 'node:http'
@@ -315,12 +275,15 @@ createServer(async (req, res) => {
315
275
  throw error
316
276
  }
317
277
 
318
- // Acknowledge first, then do the work: the sender retries a slow or failed response, and
319
- // `event.id` is stable across retries, so it is also your deduplication key.
278
+ // Validate identity, then atomically persist the event and a durable work item.
279
+ // Implement acceptOnce with a unique webhook-id; a duplicate is successful too.
280
+ if (event.id !== req.headers['webhook-id']) { res.writeHead(400).end(); return }
281
+ try { await acceptOnce(event.id, event) } catch { res.writeHead(503).end(); return }
320
282
  res.writeHead(204).end()
321
283
 
284
+ // Dispatch this switch in the durable worker.
322
285
  const known = knownWebhookEvent(event)
323
- if (!known) return // a type this release does not know: already acknowledged, ignore it
286
+ if (!known) return // keep unknown events accepted without side effects
324
287
  switch (known.type) {
325
288
  case 'run.finished':
326
289
  console.log(known.data.run_id, known.data.status)
@@ -363,7 +326,7 @@ Four more things worth knowing:
363
326
  resolved to one of its values: choosing would be a guess about which send arrived. The Python
364
327
  SDK rejects it too.
365
328
  - **`unwrapWebhook` checks six fields and no more** — `object`, `id`, `type`, `schema_version`,
366
- `created_at`, `data` — so a field or event type a later Engine release adds is not a reason to
329
+ `created_at`, `data` — so a field or event type a later API release adds is not a reason to
367
330
  drop a delivery. `schema_version` must be a number with an **integer value**: `1` and `1.0` both
368
331
  pass, since JSON has one numeric type and they are the same number, while `1.5` is rejected with
369
332
  `invalid_payload`. The Python SDK reaches the same verdict on the same envelope.
@@ -374,7 +337,7 @@ Four more things worth knowing:
374
337
  it extends `Error`, while the Python SDK makes it a subclass of its own `ZooworkError` carrying a
375
338
  400. Match on `code`, and do not port `instanceof` checks between the two.
376
339
 
377
- You do not have to use this SDK to verify. Engine emits plain
340
+ You do not have to use this SDK to verify. ZooWork emits plain
378
341
  [Standard Webhooks](https://github.com/standard-webhooks/standard-webhooks), so the official
379
342
  library for any language works with the same `whsec_` secret and the same raw body — npm
380
343
  [`standardwebhooks`](https://www.npmjs.com/package/standardwebhooks), PyPI
@@ -394,7 +357,7 @@ and `listEvents` truncates at 500 events with nothing in the response to say it
394
357
 
395
358
  ## Documentation
396
359
 
397
- Full guides and the capability matrix: **[zoowork-agents-docs](https://github.com/SerendipityOneInc/zoowork-agents-docs)**.
360
+ Full guides and the capability matrix: **[zoowork-agents-docs](https://zoowork.ai/docs/)**.
398
361
 
399
362
  Runnable examples in [`examples/`](examples):
400
363
 
@@ -439,3 +402,60 @@ before creating the GitHub Release when live verification is required. Use
439
402
  ## License
440
403
 
441
404
  MIT
405
+
406
+ ## Developer API helpers
407
+
408
+ These helpers require an SDK release that includes them. Check the installed declarations before using an example; use the documented HTTP endpoint if the installed release lacks the method.
409
+
410
+ ```ts
411
+ const usage = await zc.getUsage({ range: '7d', view: 'both' })
412
+ const endpoint = await zc.createAgentWebhook(agentId, {
413
+ url: 'https://receiver.example/webhook', event_types: ['run.finished'],
414
+ }, 'register-hook-v1')
415
+ // Save signing_secret securely when present; an idempotent replay can return null.
416
+ const hooks = await zc.listAgentWebhooks(agentId) // hooks.webhooks
417
+ const output = await zc.getRunOutput(agentId, sessionId, runId)
418
+ const approvals = await zc.listApprovalPage(agentId, { sessionId })
419
+ ```
420
+
421
+ Direct workspace Files and the database viewer are not supported production workflows.
422
+ Supply text in Session messages, ask the Agent to create and publish Artifacts, and download
423
+ those through the Artifact API. The Agent can use `agent_db` and return query results in its
424
+ reply. Method presence is not production availability. Usage stays within the current key scope. Page helpers retain `next_cursor` and `has_more`; replay cursors
425
+ verbatim. `getApproval` and `getCustomToolCall` read terminal as well as pending actions.
426
+
427
+ Agent webhook methods include get/update/delete, `rotateAgentWebhookSecret`, `testAgentWebhook`,
428
+ `getAgentWebhookEvent`, delivery list/detail and single/batch redelivery. Pass a stable idempotency
429
+ key to create, rotation, test and redelivery. A 202 receipt confirms queuing; query delivery
430
+ records to learn the result. SDK writes do not retry automatically.
431
+
432
+ `createSession` accepts `runtime_mode: 'active'` to pin the current active configuration at
433
+ creation. Omit it to resolve active configuration on later turns. `idle_compaction` preserves
434
+ false, null and omission. MCP tool overrides accept `requireConfirmation?: boolean`.
435
+ Production `updateAgent` currently rejects `expected_config_version` with
436
+ `400 invalid_declared_key`. Omit it for ordinary last-write-wins updates; serialize competing
437
+ writes in your application. A GET followed by PUT is not atomic. Ownership-only changes do not
438
+ increment the configuration version. The separate `upgradeSystemPrompt` precondition remains supported.
439
+
440
+ ## Current production behavior
441
+
442
+ - Manual Schedule execution requires `enabled: true`, which also enables automatic firings.
443
+ A disabled Schedule can return `triggered: true` and still be skipped. The receipt is not a
444
+ run result; run rows can lack status/session linkage.
445
+ - Approval waiting is `agent.approval` / `requested`; `resolved` ends the approval wait.
446
+ `agent.tool` / `blocked` ends a call without execution, with no later `end`. Reasons include
447
+ policy denial, approval denial/timeout/cancellation, or interruption; inspect the event
448
+ payload's `deniedReason`.
449
+ - Save each processed stream cursor with its Session ID. Pass it when reading a subsequent
450
+ turn in that Session. No cursor means replay from the beginning, including old `run.finished`.
451
+ REST events and post-event receipts do not supply a cursor; the last REST page has a null
452
+ continuation token. There is no current-tail helper. Without a saved cursor, replay and
453
+ reconstruct state or deliberately start a new conversation; do not synthesize a cursor from seq.
454
+ - First Agent deletion succeeds with 204; repeated deletion returns 404 through the public API.
455
+ For cleanup retries, interpret 404 as absence only for a known Agent with unchanged key scope.
456
+ Other-tenant or inaccessible resources also return 404.
457
+ - Invalid Usage parameters can return either `400 usage.invalid_query` or 422 with no business
458
+ error type. Correct the parameters rather than retrying unchanged. Match status as well as type.
459
+
460
+ See the [public guides](https://zoowork.ai/docs/) for supported workflows. These notes do not
461
+ change SDK transport behavior or make unavailable endpoints usable.
package/dist/client.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * ZooWork Managed Agents SDK — core client. Developer Preview.
3
3
  *
4
- * Authenticate with your organization API key (`zct_…`). It carries full tenant
5
- * authority, so it is SERVER-SIDE ONLY: never ship it in a browser or mobile bundle.
4
+ * Create a Project API key at https://platform.zoowork.ai. Keep it server-side: never ship it in a browser or mobile bundle.
6
5
  *
7
6
  * IDs are opaque strings and unknown response fields must be ignored — both are
8
7
  * forward-compatibility rules, not suggestions. Errors surface an `error.type`; match on
9
8
  * that, never on the message text.
10
9
  */
10
+ import { type DeveloperApi } from './developer-api.js';
11
11
  import { type SessionEvent } from './events.js';
12
12
  /**
13
13
  * The production API base URL — the default. You should not need to set this:
@@ -22,9 +22,9 @@ export type ZooworkAuth = {
22
22
  };
23
23
  export interface ZooworkConfig {
24
24
  /**
25
- * Your API key (`zct_...`). Defaults to `ZOOWORK_API_KEY`.
25
+ * Your Platform Project API key (`zwp_live_...`). Defaults to `ZOOWORK_API_KEY`.
26
26
  *
27
- * Server-side only: it authenticates as your whole organization, not as one end user.
27
+ * Server-side only: access is scoped to the selected Project. Authorize application users separately.
28
28
  */
29
29
  apiKey?: string;
30
30
  /**
@@ -115,6 +115,8 @@ export declare class ZooworkError extends Error {
115
115
  export interface Ownership {
116
116
  owner_uid: string;
117
117
  org_id: string;
118
+ project_id?: string | null;
119
+ visibility?: 'private' | 'project';
118
120
  }
119
121
  export interface ModelInfo {
120
122
  model: string;
@@ -143,6 +145,9 @@ export interface McpContextConfig {
143
145
  }
144
146
  export interface McpToolPermissionOverride {
145
147
  permission: McpToolPermission;
148
+ /** True requires permission: 'always_ask' and a decision for each call, even with a persistent grant.
149
+ * Only allow-once or deny is offered. False/omission retains permission policy behavior. */
150
+ requireConfirmation?: boolean;
146
151
  }
147
152
  /**
148
153
  * One remote MCP server, declared as `resource.mcp[]` on create or update.
@@ -298,10 +303,15 @@ export interface AgentResource {
298
303
  seed_policy?: string;
299
304
  }[];
300
305
  };
301
- skills?: {
306
+ skills?: (({
302
307
  skill_id: string;
308
+ name?: string;
309
+ } | {
310
+ name: string;
311
+ skill_id?: string;
312
+ }) & {
303
313
  version?: number | 'latest';
304
- }[];
314
+ })[];
305
315
  /**
306
316
  * Defaults to true. False disables automatic global Skills without removing explicitly
307
317
  * listed Skills. An explicit empty `skills` array also opts out.
@@ -655,6 +665,7 @@ export interface AgentRecord {
655
665
  environment_locked_at?: string | null;
656
666
  status?: AgentStatus;
657
667
  ownership?: Ownership;
668
+ sandbox_resource_class?: string;
658
669
  [k: string]: unknown;
659
670
  }
660
671
  /**
@@ -725,6 +736,10 @@ export interface SessionRecord {
725
736
  pending_approvals?: number;
726
737
  /** Pending application-executed custom-tool count on getSession. */
727
738
  pending_custom_tool_calls?: number;
739
+ pending_approval_ids?: string[];
740
+ pending_approval_ids_complete?: boolean;
741
+ pending_custom_tool_call_ids?: string[];
742
+ pending_custom_tool_call_ids_complete?: boolean;
728
743
  /**
729
744
  * `running` on a `createSession` receipt, nullable on `getSession`, and absent from
730
745
  * `listSessions` rows. This is not the run outcome; read {@link SessionRecord.run_status}
@@ -735,6 +750,8 @@ export interface SessionRecord {
735
750
  archived?: boolean;
736
751
  /** Present on filtered pages only when `includeDeleted` was requested. */
737
752
  deleted?: boolean;
753
+ idle_compaction?: boolean | null;
754
+ pinned_config_version?: number | null;
738
755
  runtime_mode?: 'active' | 'preview' | 'authoring' | 'evaluation' | string;
739
756
  config_version?: number;
740
757
  updated_at?: string;
@@ -940,12 +957,13 @@ export interface ScheduleUpdate {
940
957
  * - `scheduleId` is the FULLY-QUALIFIED name `cron/{computer_id}/{agent_id}/{schedule_id}`, not
941
958
  * the id you chose. Your id is `name`.
942
959
  *
943
- * The three responses also disagree with each other: `POST` answers with only snake_case
944
- * `schedule_name`; `GET /schedules/{id}` answers the camelCase projection below; `GET /schedules`
960
+ * Create receipts include the public `schedule_id` and snake_case `schedule_name`; `GET /schedules/{id}` answers the camelCase projection below; `GET /schedules`
945
961
  * answers the raw Temporal describe (`spec` / `state` / `memo` / `next_action_times`) with the
946
962
  * camelCase projection merged on top. Read defensively and match on what you find.
947
963
  */
948
964
  export interface ScheduleRecord {
965
+ /** Public opaque id, also present on create receipts. */
966
+ schedule_id?: string;
949
967
  /** FULLY-QUALIFIED: `cron/{computer_id}/{agent_id}/{schedule_id}`. Not the id you passed in. */
950
968
  scheduleId?: string;
951
969
  /** The `schedule_id` you chose. This is the one you pass back to get/update/delete. */
@@ -1016,6 +1034,9 @@ export interface ScheduleRecord {
1016
1034
  export interface ScheduleRun {
1017
1035
  /** Which projection this row came from. Decides which of the field groups below is populated. */
1018
1036
  source?: 'temporal' | 'run_projection' | string;
1037
+ linked_by?: string;
1038
+ run_id?: string;
1039
+ trigger?: string;
1019
1040
  /** Present only when a session can be associated with this fire. */
1020
1041
  session_id?: string;
1021
1042
  /** Un-qualified `schedule_id`. */
@@ -1043,6 +1064,9 @@ export type ApprovalDecision = 'allow-once' | 'allow-always' | 'deny';
1043
1064
  * completion of the tool or run. Verify the resulting state separately.
1044
1065
  */
1045
1066
  export interface ApprovalRecord {
1067
+ run_id?: string;
1068
+ tool_call_id?: string;
1069
+ resolution_channel?: string;
1046
1070
  approval_id?: string;
1047
1071
  session_id?: string;
1048
1072
  tool_name?: string;
@@ -1063,6 +1087,8 @@ export interface ApprovalRecord {
1063
1087
  export type CustomToolCallStatus = 'pending' | 'completed' | 'timeout' | 'cancelled' | string;
1064
1088
  /** One application-executed custom-tool call. Unknown response fields are preserved. */
1065
1089
  export interface CustomToolCallRecord {
1090
+ run_id?: string;
1091
+ resolution_channel?: string;
1066
1092
  call_id: string;
1067
1093
  session_id: string;
1068
1094
  tool_call_id: string;
@@ -1302,26 +1328,21 @@ export interface WakeResult {
1302
1328
  triggered: boolean;
1303
1329
  }
1304
1330
  export type { SessionEvent } from './events.js';
1305
- export interface ZooworkClient {
1331
+ export interface ZooworkClient extends DeveloperApi {
1306
1332
  listModels(): Promise<ModelInfo[]>;
1307
1333
  /**
1308
1334
  * Create an agent. The gateway derives ownership from your API key and always skips the
1309
1335
  * interactive onboarding interview — the agent answers your first message directly.
1310
- * `ownership` is accepted for callers that talk to the engine without the gateway;
1311
- * through the gateway it is overwritten and can be omitted.
1336
+ * Ownership is derived from the key. Omit caller-supplied ownership.
1312
1337
  */
1313
1338
  createAgent(input: {
1314
1339
  resource: AgentResource;
1315
1340
  ownership?: Ownership;
1316
1341
  }, idempotencyKey?: string): Promise<AgentRecord>;
1317
1342
  /**
1318
- * List the agents owned by your key's bound user (engine query: `owner_uid AND org_id`,
1319
- * both injected by the gateway). `labels` filters on declared labels — e.g.
1320
- * `{ labels: { workspace_id: '…' } }` resolves an app workspace id (the first path
1321
- * segment of a ZooWork chat URL) to its agent. Page size is fixed at 100 by the engine.
1322
- *
1323
- * Note the scope is `owner_uid AND org_id`: an agent a colleague created in your org is
1324
- * fetchable by `getAgent` but will not appear here.
1343
+ * List Agents within the key's Project and applicable owner visibility. Labels filter
1344
+ * declared labels, and page size is 100. Reads by id still recheck authorization;
1345
+ * a colleague's Agent is not automatically accessible.
1325
1346
  *
1326
1347
  * `await listAgents()` returns one {@link AgentPage}; read `.data` for its agents and
1327
1348
  * `.next_page` / `.hasNextPage()` for continuation. `for await (const agent of listAgents())`
@@ -1329,10 +1350,14 @@ export interface ZooworkClient {
1329
1350
  */
1330
1351
  listAgents(opts?: AgentListParams): AgentPagePromise;
1331
1352
  getAgent(agentId: string): Promise<AgentRecord>;
1332
- /** PUT declared sections; bumps config_version on EVERY call — gate on drift, don't blind-retry. */
1353
+ /** PUT declared sections. Ownership-only changes do not bump config_version.
1354
+ * Production currently rejects expected_config_version with 400 invalid_declared_key.
1355
+ * Omit it for last-write-wins updates and serialize competing writes in the application. */
1333
1356
  updateAgent(agentId: string, sections: Record<string, unknown>): Promise<AgentRecord>;
1334
1357
  /**
1335
1358
  * Soft delete: the agent stops resolving on the API, but this is not a resource purge.
1359
+ * The first public-API deletion returns 204; repeating it returns 404. A 404 can also
1360
+ * hide an inaccessible resource, so cleanup retries must retain the original key scope.
1336
1361
  * On gateway releases that carry the channels surface, a successful delete also
1337
1362
  * best-effort disables the agent's bound channels — a failure there never turns the
1338
1363
  * delete into an error, so a chat binding can in rare cases outlive its agent.
@@ -1591,6 +1616,8 @@ export interface ZooworkClient {
1591
1616
  createSession(agentId: string, input: {
1592
1617
  initial_events?: OutboundEvent[];
1593
1618
  metadata?: Record<string, unknown>;
1619
+ runtime_mode?: 'active';
1620
+ idle_compaction?: boolean | null;
1594
1621
  }, idempotencyKey?: string): Promise<SessionRecord>;
1595
1622
  getSession(agentId: string, sessionId: string, opts?: {
1596
1623
  history?: boolean;
@@ -1678,6 +1705,7 @@ export interface ZooworkClient {
1678
1705
  /** Pending calls only. Any other status is rejected by the API. */
1679
1706
  listCustomToolCalls(agentId: string, opts?: {
1680
1707
  status?: 'pending';
1708
+ sessionId?: string;
1681
1709
  }): Promise<CustomToolCallRecord[]>;
1682
1710
  /**
1683
1711
  * Return one call's result. A pending call answers 202/signaled:true but stays pending until
@@ -1700,6 +1728,7 @@ export interface ZooworkClient {
1700
1728
  */
1701
1729
  listApprovals(agentId: string, opts?: {
1702
1730
  status?: 'pending';
1731
+ sessionId?: string;
1703
1732
  }): Promise<ApprovalRecord[]>;
1704
1733
  /** Resolve one approval. `decision` is exactly one of allow-once / allow-always / deny. */
1705
1734
  resolveApproval(agentId: string, approvalId: string, input: {
@@ -1857,7 +1886,7 @@ export interface ZooworkClient {
1857
1886
  * Create a client.
1858
1887
  *
1859
1888
  * ```ts
1860
- * const zc = createZooworkClient({ apiKey: 'zct_...' })
1889
+ * const zc = createZooworkClient({ apiKey: 'zwp_live_...' })
1861
1890
  * const zc = createZooworkClient() // reads ZOOWORK_API_KEY
1862
1891
  * ```
1863
1892
  *
package/dist/client.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * ZooWork Managed Agents SDK — core client. Developer Preview.
3
3
  *
4
- * Authenticate with your organization API key (`zct_…`). It carries full tenant
5
- * authority, so it is SERVER-SIDE ONLY: never ship it in a browser or mobile bundle.
4
+ * Create a Project API key at https://platform.zoowork.ai. Keep it server-side: never ship it in a browser or mobile bundle.
6
5
  *
7
6
  * IDs are opaque strings and unknown response fields must be ignored — both are
8
7
  * forward-compatibility rules, not suggestions. Errors surface an `error.type`; match on
9
8
  * that, never on the message text.
10
9
  */
10
+ import { createDeveloperApi } from './developer-api.js';
11
11
  import { parseSSE, isObj } from './sse.js';
12
12
  import { normalizeEvent } from './events.js';
13
13
  /**
@@ -143,7 +143,7 @@ function httpError(res, text) {
143
143
  * Create a client.
144
144
  *
145
145
  * ```ts
146
- * const zc = createZooworkClient({ apiKey: 'zct_...' })
146
+ * const zc = createZooworkClient({ apiKey: 'zwp_live_...' })
147
147
  * const zc = createZooworkClient() // reads ZOOWORK_API_KEY
148
148
  * ```
149
149
  *
@@ -165,7 +165,7 @@ export function createZooworkClient(cfg = {}) {
165
165
  })());
166
166
  if (!auth) {
167
167
  throw new Error('No ZooWork API key. Pass createZooworkClient({ apiKey }) or set ZOOWORK_API_KEY. ' +
168
- 'Keys look like zct_… and are issued by an organization administrator.');
168
+ 'Create a Project API key at https://platform.zoowork.ai.');
169
169
  }
170
170
  const bearer = 'serviceToken' in auth ? auth.serviceToken : auth.apiKey;
171
171
  /**
@@ -282,13 +282,20 @@ export function createZooworkClient(cfg = {}) {
282
282
  const own = projection.ownership;
283
283
  if (!own?.owner_uid || !own.org_id) {
284
284
  throw new ZooworkError(500, `agent ${agentId} projection carries no ownership — cannot derive the owner_uid/org_id ` +
285
- 'selectors the artifact routes require', 'ownership_unavailable');
285
+ 'selectors the file and artifact routes require', 'ownership_unavailable');
286
286
  }
287
287
  const sel = { owner_uid: own.owner_uid, org_id: own.org_id };
288
288
  ownershipByAgent.set(agentId, sel);
289
289
  return sel;
290
290
  };
291
+ const bytes = async (path) => {
292
+ const res = await doFetch(`${base}${path}`, { headers: { Authorization: `Bearer ${bearer}` } });
293
+ if (!res.ok)
294
+ throw httpError(res, await res.text());
295
+ return new Uint8Array(await res.arrayBuffer());
296
+ };
291
297
  const client = {
298
+ ...createDeveloperApi(json, bytes, artifactSelectors),
292
299
  listModels: async () => {
293
300
  const data = await json('/models');
294
301
  return Array.isArray(data) ? data : (data.models ?? []);
@@ -668,7 +675,7 @@ export function createZooworkClient(cfg = {}) {
668
675
  }
669
676
  },
670
677
  listCustomToolCalls: async (agentId, opts = {}) => {
671
- const data = await json(`${agents(agentId)}/custom_tool_calls${query({ status: opts.status })}`);
678
+ const data = await json(`${agents(agentId)}/custom_tool_calls${query({ status: opts.status, session_id: opts.sessionId })}`);
672
679
  return data.custom_tool_calls ?? [];
673
680
  },
674
681
  resolveCustomToolCall: (agentId, callId, input) => json(`${agents(agentId)}/custom_tool_calls/${encodeURIComponent(callId)}/result`, {
@@ -676,7 +683,7 @@ export function createZooworkClient(cfg = {}) {
676
683
  body: JSON.stringify(input),
677
684
  }),
678
685
  listApprovals: async (agentId, opts = {}) => {
679
- const data = await json(`${agents(agentId)}/approvals${query({ status: opts.status })}`);
686
+ const data = await json(`${agents(agentId)}/approvals${query({ status: opts.status, session_id: opts.sessionId })}`);
680
687
  return data.approvals ?? [];
681
688
  },
682
689
  resolveApproval: (agentId, approvalId, input) => json(`${agents(agentId)}/approvals/${encodeURIComponent(approvalId)}/resolve`, {
@@ -0,0 +1,200 @@
1
+ import type { ApprovalRecord, CustomToolCallRecord, Ownership } from './client.js';
2
+ import type { WebhookEventType } from './webhooks.js';
3
+ /** Response fields retain their API spelling; unknown additions are preserved. */
4
+ export type ApiObject = Record<string, unknown>;
5
+ export interface CursorOptions {
6
+ cursor?: string;
7
+ limit?: number;
8
+ }
9
+ export interface ActionListOptions extends CursorOptions {
10
+ status?: 'pending';
11
+ sessionId?: string;
12
+ }
13
+ export interface ApprovalPage extends ApiObject {
14
+ approvals: ApprovalRecord[];
15
+ has_more: boolean;
16
+ next_cursor: string | null;
17
+ }
18
+ export interface CustomToolCallPage extends ApiObject {
19
+ custom_tool_calls: CustomToolCallRecord[];
20
+ has_more: boolean;
21
+ next_cursor: string | null;
22
+ }
23
+ export interface WorkspaceFileEntry extends ApiObject {
24
+ name: string;
25
+ type: string;
26
+ size?: number;
27
+ updated_at?: string;
28
+ }
29
+ export type WorkspaceFile = (ApiObject & {
30
+ path: string;
31
+ content: string;
32
+ }) | (ApiObject & {
33
+ path: string;
34
+ entries: WorkspaceFileEntry[];
35
+ });
36
+ export interface AgentDatabase extends ApiObject {
37
+ status: 'not_provisioned' | 'ready';
38
+ tables?: {
39
+ name: unknown;
40
+ kind: unknown;
41
+ }[];
42
+ }
43
+ export interface AgentDatabaseRows extends ApiObject {
44
+ status: 'not_provisioned' | 'ready';
45
+ table?: string;
46
+ schema?: unknown[][];
47
+ columns?: string[];
48
+ rows?: unknown[][];
49
+ limit?: number;
50
+ offset?: number;
51
+ }
52
+ export interface UsageOptions {
53
+ range?: '24h' | '7d' | '30d';
54
+ timezone?: string;
55
+ groupBy?: 'session' | 'api_key';
56
+ view?: 'groups' | 'records' | 'both';
57
+ sessionId?: string;
58
+ apiKeyId?: string;
59
+ rootSessionId?: string;
60
+ attribution?: 'exact' | 'shared' | 'non_api' | 'unattributed';
61
+ page?: number;
62
+ perPage?: number;
63
+ asOf?: string;
64
+ snapshot?: string;
65
+ cursor?: string;
66
+ }
67
+ export interface UsageResult extends ApiObject {
68
+ groups?: ApiObject[];
69
+ records?: ApiObject[];
70
+ }
71
+ export interface RunOutputArtifact extends ApiObject {
72
+ artifact_id: string | null;
73
+ name: string;
74
+ content_type: string;
75
+ size: number;
76
+ }
77
+ export interface RunOutputItem extends ApiObject {
78
+ seq: number;
79
+ kind: string;
80
+ source: string;
81
+ text?: string;
82
+ artifacts: RunOutputArtifact[];
83
+ }
84
+ export interface RunOutput extends ApiObject {
85
+ run: ApiObject;
86
+ items: RunOutputItem[];
87
+ has_more: boolean;
88
+ next_cursor: string | null;
89
+ output_complete: boolean;
90
+ }
91
+ export interface AgentWebhookInput {
92
+ url: string;
93
+ event_types: Exclude<WebhookEventType, 'webhook.test'>[];
94
+ description?: string | null;
95
+ session_scope?: 'api' | 'all';
96
+ enabled?: boolean;
97
+ }
98
+ export interface AgentWebhookEndpoint extends ApiObject {
99
+ id: string;
100
+ url?: string;
101
+ event_types?: string[];
102
+ description?: string | null;
103
+ session_scope?: string;
104
+ enabled?: boolean;
105
+ }
106
+ export interface AgentWebhookPage extends ApiObject {
107
+ webhooks: AgentWebhookEndpoint[];
108
+ has_more: boolean;
109
+ next_cursor: string | null;
110
+ }
111
+ export interface AgentWebhookCreated extends ApiObject {
112
+ endpoint: AgentWebhookEndpoint;
113
+ signing_secret: string | null;
114
+ signing_secret_version: number;
115
+ signing_secret_available: boolean;
116
+ }
117
+ export interface AgentWebhookSecretRotation extends ApiObject {
118
+ endpoint_id: string;
119
+ signing_secret: string | null;
120
+ signing_secret_version: number;
121
+ signing_secret_available: boolean;
122
+ previous_versions?: unknown[];
123
+ }
124
+ export interface WebhookDeliveryOptions extends CursorOptions {
125
+ status?: 'pending' | 'in_flight' | 'succeeded' | 'dead' | 'cancelled';
126
+ eventType?: string;
127
+ eventId?: string;
128
+ sessionId?: string;
129
+ runId?: string;
130
+ scheduleId?: string;
131
+ }
132
+ export interface WebhookDeliveryPage extends ApiObject {
133
+ deliveries: ApiObject[];
134
+ has_more: boolean;
135
+ next_cursor: string | null;
136
+ }
137
+ /** These receipts acknowledge queuing, not receiver or business processing. */
138
+ export interface WebhookTestReceipt extends ApiObject {
139
+ object: 'webhook_test';
140
+ endpoint_id: string;
141
+ receipt_id: string;
142
+ }
143
+ export interface WebhookRedeliveryReceipt extends ApiObject {
144
+ object: 'webhook_redelivery';
145
+ delivery_id: string;
146
+ round: number;
147
+ deadline_at: string;
148
+ }
149
+ export interface WebhookBatchRedeliveryReceipt extends ApiObject {
150
+ object: 'webhook_redelivery_batch';
151
+ count: number;
152
+ }
153
+ export interface WebhookBatchRedeliveryInput {
154
+ status?: 'dead';
155
+ since?: string | null;
156
+ event_types?: string[] | null;
157
+ limit?: number;
158
+ }
159
+ export interface DeveloperApi {
160
+ getWorkspaceFile(agentId: string, path: string, opts?: {
161
+ showHidden?: boolean;
162
+ }): Promise<WorkspaceFile>;
163
+ writeWorkspaceFile(agentId: string, path: string, content: string): Promise<ApiObject>;
164
+ getWorkspaceFileContent(agentId: string, path: string, opts?: {
165
+ download?: boolean;
166
+ }): Promise<Uint8Array>;
167
+ getAgentDatabase(agentId: string): Promise<AgentDatabase>;
168
+ getAgentDatabaseRows(agentId: string, tableName: string, opts?: {
169
+ limit?: number;
170
+ offset?: number;
171
+ }): Promise<AgentDatabaseRows>;
172
+ getUsage(opts?: UsageOptions): Promise<UsageResult>;
173
+ getRunOutput(agentId: string, sessionId: string, runId: string, opts?: CursorOptions): Promise<RunOutput>;
174
+ getApproval(agentId: string, approvalId: string): Promise<ApprovalRecord>;
175
+ getCustomToolCall(agentId: string, callId: string): Promise<CustomToolCallRecord>;
176
+ listApprovalPage(agentId: string, opts?: ActionListOptions): Promise<ApprovalPage>;
177
+ listCustomToolCallPage(agentId: string, opts?: ActionListOptions): Promise<CustomToolCallPage>;
178
+ listAgentWebhooks(agentId: string, opts?: CursorOptions): Promise<AgentWebhookPage>;
179
+ createAgentWebhook(agentId: string, input: AgentWebhookInput, idempotencyKey: string): Promise<AgentWebhookCreated>;
180
+ getAgentWebhook(agentId: string, webhookId: string): Promise<AgentWebhookEndpoint>;
181
+ updateAgentWebhook(agentId: string, webhookId: string, input: Partial<AgentWebhookInput>): Promise<AgentWebhookEndpoint>;
182
+ deleteAgentWebhook(agentId: string, webhookId: string): Promise<void>;
183
+ rotateAgentWebhookSecret(agentId: string, webhookId: string, input: {
184
+ revoke_previous_after: 0 | 86400;
185
+ }, idempotencyKey: string): Promise<AgentWebhookSecretRotation>;
186
+ testAgentWebhook(agentId: string, webhookId: string, idempotencyKey: string): Promise<WebhookTestReceipt>;
187
+ getAgentWebhookEvent(agentId: string, eventId: string): Promise<ApiObject>;
188
+ listAgentWebhookDeliveries(agentId: string, webhookId: string, opts?: WebhookDeliveryOptions): Promise<WebhookDeliveryPage>;
189
+ getAgentWebhookDelivery(agentId: string, webhookId: string, deliveryId: string): Promise<ApiObject>;
190
+ redeliverAgentWebhookDelivery(agentId: string, webhookId: string, deliveryId: string, idempotencyKey: string): Promise<WebhookRedeliveryReceipt>;
191
+ redeliverAgentWebhookDeliveries(agentId: string, webhookId: string, input: WebhookBatchRedeliveryInput, idempotencyKey: string): Promise<WebhookBatchRedeliveryReceipt>;
192
+ }
193
+ type Request = <T>(path: string, init?: {
194
+ method?: string;
195
+ body?: string;
196
+ headers?: Record<string, string>;
197
+ }) => Promise<T>;
198
+ /** Uses the same authentication/error transport as the existing client. Never retries writes. */
199
+ export declare function createDeveloperApi(json: Request, bytes: (path: string) => Promise<Uint8Array>, selectors: (agentId: string) => Promise<Pick<Ownership, 'owner_uid' | 'org_id'>>): DeveloperApi;
200
+ export {};
@@ -0,0 +1,42 @@
1
+ const segment = encodeURIComponent;
2
+ function query(params) {
3
+ const result = new URLSearchParams();
4
+ for (const [key, value] of Object.entries(params))
5
+ if (value !== undefined)
6
+ result.set(key, String(value));
7
+ return result.size ? `?${result}` : '';
8
+ }
9
+ function post(body, idempotencyKey) {
10
+ return { method: 'POST', body: JSON.stringify(body), ...(idempotencyKey !== undefined ? { headers: { 'Idempotency-Key': idempotencyKey } } : {}) };
11
+ }
12
+ /** Uses the same authentication/error transport as the existing client. Never retries writes. */
13
+ export function createDeveloperApi(json, bytes, selectors) {
14
+ const agent = (id) => `/agents/${segment(id)}`;
15
+ const webhooks = (id) => `${agent(id)}/webhooks`;
16
+ const endpoint = (id, webhookId) => `${webhooks(id)}/${segment(webhookId)}`;
17
+ return {
18
+ getWorkspaceFile: async (id, path, opts = {}) => json(`${agent(id)}/files${query({ ...await selectors(id), path, showHidden: opts.showHidden })}`),
19
+ writeWorkspaceFile: (id, path, content) => json(`${agent(id)}/files`, post({ path, content })),
20
+ getWorkspaceFileContent: async (id, path, opts = {}) => bytes(`${agent(id)}/files/content${query({ ...await selectors(id), path, download: opts.download })}`),
21
+ getAgentDatabase: (id) => json(`${agent(id)}/database`),
22
+ getAgentDatabaseRows: (id, table, opts = {}) => json(`${agent(id)}/database/tables/${segment(table)}/rows${query({ limit: opts.limit, offset: opts.offset })}`),
23
+ getUsage: (opts = {}) => json(`/usage${query({ range: opts.range, timezone: opts.timezone, group_by: opts.groupBy, view: opts.view, session_id: opts.sessionId, api_key_id: opts.apiKeyId, root_session_id: opts.rootSessionId, attribution: opts.attribution, page: opts.page, per_page: opts.perPage, as_of: opts.asOf, snapshot: opts.snapshot, cursor: opts.cursor })}`),
24
+ getRunOutput: (id, sid, rid, opts = {}) => json(`${agent(id)}/sessions/${segment(sid)}/runs/${segment(rid)}/output${query({ cursor: opts.cursor, limit: opts.limit })}`),
25
+ getApproval: (id, aid) => json(`${agent(id)}/approvals/${segment(aid)}`),
26
+ getCustomToolCall: (id, cid) => json(`${agent(id)}/custom_tool_calls/${segment(cid)}`),
27
+ listApprovalPage: (id, opts = {}) => json(`${agent(id)}/approvals${query({ status: opts.status, session_id: opts.sessionId, cursor: opts.cursor, limit: opts.limit ?? 50 })}`),
28
+ listCustomToolCallPage: (id, opts = {}) => json(`${agent(id)}/custom_tool_calls${query({ status: opts.status, session_id: opts.sessionId, cursor: opts.cursor, limit: opts.limit ?? 50 })}`),
29
+ listAgentWebhooks: (id, opts = {}) => json(`${webhooks(id)}${query({ cursor: opts.cursor, limit: opts.limit })}`),
30
+ createAgentWebhook: (id, input, key) => json(webhooks(id), post(input, key)),
31
+ getAgentWebhook: (id, wid) => json(endpoint(id, wid)),
32
+ updateAgentWebhook: (id, wid, input) => json(`${endpoint(id, wid)}/update`, post(input)),
33
+ deleteAgentWebhook: async (id, wid) => { await json(`${endpoint(id, wid)}/delete`, post({})); },
34
+ rotateAgentWebhookSecret: (id, wid, input, key) => json(`${endpoint(id, wid)}/rotate-secret`, post(input, key)),
35
+ testAgentWebhook: (id, wid, key) => json(`${endpoint(id, wid)}/test`, post({}, key)),
36
+ getAgentWebhookEvent: (id, eid) => json(`${webhooks(id)}/events/${segment(eid)}`),
37
+ listAgentWebhookDeliveries: (id, wid, opts = {}) => json(`${endpoint(id, wid)}/deliveries${query({ cursor: opts.cursor, limit: opts.limit, status: opts.status, event_type: opts.eventType, event_id: opts.eventId, session_id: opts.sessionId, run_id: opts.runId, schedule_id: opts.scheduleId })}`),
38
+ getAgentWebhookDelivery: (id, wid, did) => json(`${endpoint(id, wid)}/deliveries/${segment(did)}`),
39
+ redeliverAgentWebhookDelivery: (id, wid, did, key) => json(`${endpoint(id, wid)}/deliveries/${segment(did)}/redeliver`, post({}, key)),
40
+ redeliverAgentWebhookDeliveries: (id, wid, input, key) => json(`${endpoint(id, wid)}/deliveries/redeliver`, post(input, key)),
41
+ };
42
+ }
package/dist/events.d.ts CHANGED
@@ -95,8 +95,9 @@ export declare function customToolUse(e: SessionEvent): CustomToolUse | undefine
95
95
  * `phase: 'end'` carries `isError` and `resultPreview`. Pair them by `toolCallId` — they are
96
96
  * NOT adjacent in the stream when calls run concurrently.
97
97
  *
98
- * `phase: 'blocked'` is a third state (see the Events reference): the call is waiting on an
99
- * approval and has NOT run. Treat it as pending, not as an end — the matching `agent.approval`
100
- * event carries the request, and an `end` still follows once it resolves.
98
+ * `phase: 'blocked'` ends the call without execution; no `end` follows. Reasons include
99
+ * policy denial, approval denial/timeout/cancellation, or interruption. Inspect
100
+ * `e.payload.deniedReason` for the reason. Approval waiting uses `agent.approval` with `phase: 'requested'`,
101
+ * followed by `phase: 'resolved'`. A resolution is not proof of successful execution.
101
102
  */
102
103
  export declare function toolCall(e: SessionEvent): ToolCall | undefined;
package/dist/events.js CHANGED
@@ -152,9 +152,10 @@ export function customToolUse(e) {
152
152
  * `phase: 'end'` carries `isError` and `resultPreview`. Pair them by `toolCallId` — they are
153
153
  * NOT adjacent in the stream when calls run concurrently.
154
154
  *
155
- * `phase: 'blocked'` is a third state (see the Events reference): the call is waiting on an
156
- * approval and has NOT run. Treat it as pending, not as an end — the matching `agent.approval`
157
- * event carries the request, and an `end` still follows once it resolves.
155
+ * `phase: 'blocked'` ends the call without execution; no `end` follows. Reasons include
156
+ * policy denial, approval denial/timeout/cancellation, or interruption. Inspect
157
+ * `e.payload.deniedReason` for the reason. Approval waiting uses `agent.approval` with `phase: 'requested'`,
158
+ * followed by `phase: 'resolved'`. A resolution is not proof of successful execution.
158
159
  */
159
160
  export function toolCall(e) {
160
161
  if (e.eventType !== 'agent.tool')
package/dist/index.d.ts CHANGED
@@ -2,3 +2,4 @@ export { createZooworkClient, DEFAULT_BASE_URL, ZooworkError, type ZooworkClient
2
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';
4
4
  export { WEBHOOK_EVENT_TYPES, WEBHOOK_SCHEDULE_CONFIG_EVENT_TYPES, type WebhookEventType, isKnownWebhookEventType, knownWebhookEvent, verifyWebhookSignature, unwrapWebhook, signWebhook, ZooworkWebhookError, type WebhookErrorCode, WEBHOOK_ID_HEADER, WEBHOOK_TIMESTAMP_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_SECRET_ENV, WEBHOOK_TOLERANCE_SECONDS, WEBHOOK_DEFAULT_MAX_BODY_BYTES, type WebhookEvent, type WebhookEventFor, type KnownWebhookEvent, type WebhookEventData, type WebhookEventDataByType, type WebhookEventAttribution, type WebhookScheduleRunRef, type WebhookWaitingOnRef, type WebhookRunEventData, type WebhookRunStartedData, type WebhookRunFinishedData, type WebhookRunYieldedData, type WebhookApprovalEventData, type WebhookApprovalRequestedData, type WebhookApprovalResolvedData, type WebhookCustomToolEventData, type WebhookCustomToolRequestedData, type WebhookCustomToolResolvedData, type WebhookOutcomeEvaluatedData, type WebhookSessionCreatedData, type WebhookSessionArchivedData, type WebhookSessionDeletedData, type WebhookScheduleFireData, type WebhookScheduleDispatchedData, type WebhookScheduleDispatchFailedData, type WebhookScheduleSkippedData, type WebhookScheduleFinishedData, type WebhookScheduleConfigData, type WebhookTestData, type WebhookHeaders, type WebhookHeaderSource, type WebhookSignatureHeaders, type VerifyWebhookInput, type VerifiedWebhook, type SignWebhookInput, } from './webhooks.js';
5
+ export type { ApiObject, CursorOptions, ActionListOptions, ApprovalPage, CustomToolCallPage, WorkspaceFileEntry, WorkspaceFile, AgentDatabase, AgentDatabaseRows, UsageOptions, UsageResult, RunOutputArtifact, RunOutputItem, RunOutput, AgentWebhookInput, AgentWebhookEndpoint, AgentWebhookPage, AgentWebhookCreated, AgentWebhookSecretRotation, WebhookDeliveryOptions, WebhookDeliveryPage, WebhookTestReceipt, WebhookRedeliveryReceipt, WebhookBatchRedeliveryReceipt, WebhookBatchRedeliveryInput, DeveloperApi, } from './developer-api.js';
@@ -0,0 +1,2 @@
1
+ /** Fixture safety only; authentication treats keys as opaque values. */
2
+ export declare function redactApiKeys(text: string, knownKey?: string): string;
@@ -0,0 +1,10 @@
1
+ /** Fixture safety only; authentication treats keys as opaque values. */
2
+ export function redactApiKeys(text, knownKey) {
3
+ let clean = text;
4
+ if (knownKey && knownKey.length >= 8)
5
+ clean = clean.split(knownKey).join('REDACTED');
6
+ return clean
7
+ .replace(/zwp_live_[A-Za-z0-9_-]{8,}/g, 'zwp_live_REDACTED')
8
+ .replace(/zct_[A-Za-z0-9_-]{8,}/g, 'zct_REDACTED')
9
+ .replace(/(Bearer )[A-Za-z0-9._~+/-]{8,}=*/g, '$1REDACTED');
10
+ }
@@ -46,10 +46,7 @@ export declare const WEBHOOK_EVENT_TYPES: readonly ["run.started", "run.finished
46
46
  /**
47
47
  * Schedule CONFIGURATION changes, as distinct from the fire events above.
48
48
  *
49
- * Declared here so a receiver can write the subscription and the handler now, but the server
50
- * side ships with Engine E5a and is NOT emitted yet — the projector currently retires such a
51
- * receipt as `unknown_source`. Do not read a delivered one of these as evidence the feature is
52
- * live; check the Engine release notes.
49
+ * Subscribe to these types for schedule configuration changes. Deliveries may be reordered.
53
50
  */
54
51
  export declare const WEBHOOK_SCHEDULE_CONFIG_EVENT_TYPES: readonly ["schedule.created", "schedule.updated", "schedule.paused", "schedule.resumed", "schedule.deleted"];
55
52
  export type WebhookEventType = (typeof WEBHOOK_EVENT_TYPES)[number] | (typeof WEBHOOK_SCHEDULE_CONFIG_EVENT_TYPES)[number];
@@ -217,7 +214,7 @@ export interface WebhookScheduleFinishedData extends WebhookScheduleFireData {
217
214
  }
218
215
  /**
219
216
  * A schedule's configuration changed. See {@link WEBHOOK_SCHEDULE_CONFIG_EVENT_TYPES}: declared,
220
- * not yet delivered.
217
+ * delivered for schedule configuration changes.
221
218
  */
222
219
  export interface WebhookScheduleConfigData extends WebhookEventAttribution {
223
220
  /**
package/dist/webhooks.js CHANGED
@@ -64,10 +64,7 @@ export const WEBHOOK_EVENT_TYPES = [
64
64
  /**
65
65
  * Schedule CONFIGURATION changes, as distinct from the fire events above.
66
66
  *
67
- * Declared here so a receiver can write the subscription and the handler now, but the server
68
- * side ships with Engine E5a and is NOT emitted yet — the projector currently retires such a
69
- * receipt as `unknown_source`. Do not read a delivered one of these as evidence the feature is
70
- * live; check the Engine release notes.
67
+ * Subscribe to these types for schedule configuration changes. Deliveries may be reordered.
71
68
  */
72
69
  export const WEBHOOK_SCHEDULE_CONFIG_EVENT_TYPES = [
73
70
  'schedule.created',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zoowork-ai/sdk",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "TypeScript SDK for the ZooWork Managed Agents API (Developer Preview)",
5
5
  "keywords": [
6
6
  "zoowork",