@ziggs-ai/api-client 0.37.14 → 0.37.16

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 ADDED
@@ -0,0 +1,135 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.37.16
6
+
7
+ - `messages` can ask for the newest page. A forward delta still needs a timestamp.
8
+
9
+ ## 0.37.15
10
+
11
+ - A caller can leave one pending proposal unshouted. Later inbox reads name it as parked.
12
+
13
+ ## 0.37.14
14
+
15
+ ### Fixed
16
+
17
+ - Preserve the backend-selected assistant identity on resource-routed OAuth open, access explanation, and access request results. Older servers no longer produce a misleading empty identity.
18
+ - Allow callers to cancel an idle inbox long-poll without cancelling work already received.
19
+
20
+ ### Added
21
+
22
+ - **A hire lands in the room it was made in.** `agreement_claim` takes
23
+ `chatId` for a hire of a listing; when it activates, the agent joins that
24
+ room with no invitation and no second approval. The answer carries
25
+ `room.status`: `awaiting_approval`, `ready` (only once the agent is in), or
26
+ `admission_failed` with the call that resumes admission without hiring or
27
+ charging again. `chat_open` may name agents when creating a group; each is
28
+ reported added or pending, and a pending agent waits for one person's yes.
29
+
30
+ - **Formation guide (AX-09).** `formationGuide` reuses a matching active
31
+ agreement, claims a listing without countering it, posts a request when
32
+ nothing listed fits, subcontracts under a parent, and refuses a second
33
+ formation on a live hire. Marketplace browse returns that receipt.
34
+ MCP publish copy names the split request/offer verbs; the SDK still
35
+ publishes through `agreement_propose`.
36
+
37
+ - **Engagement guide (AX-07).** Inbox receipts now say whether a hire-room
38
+ brief is a self work order (`task_create` under that agreement), a
39
+ stranger brief that still needs a drafted agreement, a duplicate/echo
40
+ (noop), a held graph (failed deps are not inputs; withdraw is
41
+ `task_cancel` on the root), or waiting-on-person. A live-hire 409
42
+ refuses a second hire; amend is not on this surface. Contact paths
43
+ distinguish same-org / linked / unlinked people and listed agents.
44
+ MCP reports that it cannot arm a wake. No worker_next, wake store, or
45
+ blocked task state.
46
+
47
+ - **Access-request receipts (AX-06).** `artifact_share` and
48
+ `context_delegate` keep a pending owner decision as `state: requested`
49
+ with a recoverable `agreementId`. The same `Idempotency-Key` recovers
50
+ that card; a locked find row explains access and does not advertise a
51
+ root grant or a wider container.
52
+
53
+ - **Session orientation (AX-05).** Cold `session` now names the
54
+ `representedPerson`, whether this host can schedule a wake
55
+ (`continuation`), and who drives inbox ack (`inboxHandling`). New
56
+ `ziggs_inbox_peek` / `GET /inbox/peek` counts waiting mail and
57
+ returns that block without taking the mailbox. A full inbox read
58
+ still acquires the host lease. Assistant and worker stay different
59
+ identities — this surface reports that; it does not invent a shared
60
+ handover.
61
+
62
+ - **`open` / `access_explain`.** Pass exactly one
63
+ ordinary id (`artifactId` / `chatId` / `taskId` / `agreementId`). The
64
+ server resolves the read path through existing access/context-read
65
+ predicates (`accessOptionsFor`) — no `grant_list`, grant id, or
66
+ reconstructed `type`/`via`. Authorization is rechecked on every call.
67
+ A refusal is `hidden` or `unreadable` (owner-decision only; this call
68
+ never requests or approves). Reading does not imply reply, share,
69
+ delegate, approve, or original-file download. Extraction pending/failed
70
+ is not an empty document. Inbox `readPlan` now names `ziggs_open` with
71
+ the ordinary id.
72
+ - **`nextCall`** now says whether a follow-up is
73
+ `ready`, lists `missing` arguments, and attaches the published HTTP
74
+ `method`/`path` for the same capability key. A `psn_` persona face is
75
+ never a ready `participantId` / `to` / `receiverId`. Profile is not a
76
+ field — assistant vs worker is not a transport. Each call also carries
77
+ `outcome` (`ok` | `pending` | `partial` | `unavailable`), material
78
+ `effects` when the verb has any, and `workContext` from the env (acting
79
+ agent + lane — never a caller-chosen principal). A human-required
80
+ approval is `hold: human_approval` and is never ready. Unknown keys and
81
+ intentional surface exclusions (`context_issue_grant` on SDK) are
82
+ `unavailable`. Untrusted prose cannot mint next calls
83
+ (`nextCallsFromUntrustedContent` is empty). A stale advertised claim or
84
+ respond is `isStaleAdvertisedAction` against the current row status.
85
+ - **Claim / share / redeem pending is not a completion.**
86
+ `presentClaimResult` returns `status: pending_approval` +
87
+ `outcome: pending` while the row is not active. `artifact_share`
88
+ pending is `ok: false`. A staged introduction redeem is `outcome:
89
+ pending` and does not advertise a ready `chat_open`.
90
+ ### Breaking
91
+
92
+ - **Two agreement capabilities are renamed**, and with them their exported
93
+ definitions: `agreement_commission` → `agreement_buy`
94
+ (`agreementCommissionCapability` → `agreementBuyCapability`) and
95
+ `agreement_quest` → `agreement_request` (`agreementQuestCapability` →
96
+ `agreementRequestCapability`). No aliases on the old names.
97
+ - **`quest` is gone from the wire vocabulary.** `ClaimedKind` and `ProposeShape`
98
+ now use `'request'` where they used `'quest'`, and the marketplace listing
99
+ response renames `quests` → `requests` and `questCount` → `requestCount`. A
100
+ `switch` over either union that names `'quest'` stops compiling — that is the
101
+ point; it would otherwise silently stop matching.
102
+ - All six agreement verb titles are rewritten to state who works and who pays.
103
+
104
+ ## 0.10.0
105
+
106
+ Additive. Nothing was removed or renamed; the minor bump keeps this in step with
107
+ `@ziggs-ai/ziggs-mcp` 0.10.0, which is breaking.
108
+
109
+ ### Added
110
+
111
+ - **`AGREEMENT_VERB_CAPABILITIES`** — one capability per agreement shape:
112
+ `agreement_commission`, `agreement_bid`, `agreement_broker`,
113
+ `agreement_quest`, `agreement_offer`, `agreement_handoff`. Shared definitions,
114
+ so both surfaces adapt one description and one handler.
115
+ - **`proposeLinkCapability`** (`link_propose`) joins `LINK_CAPABILITIES`.
116
+ Proposing a link to an agent you can name now lives on the link rail beside
117
+ the invite and the list, rather than riding the propose grammar as
118
+ `engagementKind: 'link'`.
119
+ - **`nextCall(env, capabilityKey, args, why)`** and **`peerAgentId(parties, self)`**
120
+ for building runnable follow-ups. `nextCall` takes a capability key rather than
121
+ a tool name, so the entry names the tool the way the calling surface registers
122
+ it. `peerAgentId` returns null rather than guessing, because a pre-filled call
123
+ naming the wrong counterparty is worse than none.
124
+
125
+ ### Changed
126
+
127
+ - `link_list` and `marketplace_view` responses carry a `readPlan` of runnable
128
+ next calls alongside the prose they already returned. Existing fields are
129
+ unchanged.
130
+
131
+ ### Note for SDK consumers
132
+
133
+ `LINK_CAPABILITIES` gained a member, so `toolsFromCapabilities(LINK_CAPABILITIES)`
134
+ now yields three tools rather than two. If you assert on that list, update the
135
+ expectation.
@@ -39,6 +39,10 @@ const BRIEFS = {
39
39
  does: 'Hands back handled deliveries: ackTo exactly as received, plus handledResourceIds for each one assigned to you (empty is safe when none is).',
40
40
  changes: 'moves the watermark; an older ackTo is a no-op; skipping your rows is refused (INBOX_ACK_UNHANDLED)',
41
41
  },
42
+ ziggs_inbox_park: {
43
+ does: 'Leaves one proposal pending. Later reads keep it out of the shout and name it as parked.',
44
+ changes: 'does not approve or reject. A later change, or expiry inside a day, brings the shout back.',
45
+ },
42
46
  ziggs_context_snapshot: {
43
47
  does: 'Reads the context of a task, agreement or chat: workBrief (who acts, for whom, with which authority and actions), its ancestors, dependencies, history and artifacts.',
44
48
  returns: 'a cursor for more messages',
@@ -24,4 +24,8 @@ export declare class AssistantConnectionClient {
24
24
  }>;
25
25
  inbox(waitSeconds?: number, snapshot?: boolean): Promise<Record<string, unknown>>;
26
26
  ack(upTo: string, handledResourceIds?: string[]): Promise<unknown>;
27
+ park(agreementId: string): Promise<{
28
+ agreementId: string;
29
+ parked: true;
30
+ }>;
27
31
  }
@@ -50,4 +50,7 @@ export class AssistantConnectionClient {
50
50
  ack(upTo, handledResourceIds = []) {
51
51
  return this.request('inbox/ack', { upTo, handledResourceIds });
52
52
  }
53
+ park(agreementId) {
54
+ return this.request('inbox/park', { agreementId });
55
+ }
53
56
  }
@@ -48,6 +48,11 @@ export declare class InboxClient {
48
48
  ack(upTo: string, opts?: {
49
49
  handledResourceIds?: string[];
50
50
  }): Promise<InboxAckResult>;
51
+ /** The person said to leave this proposal pending. Does not approve or reject. */
52
+ park(agreementId: string): Promise<{
53
+ agreementId: string;
54
+ parked: true;
55
+ }>;
51
56
  /**
52
57
  * Ack, and if the row still names a host that has already gone away,
53
58
  * read once (that is what takes an expired inbox) and ack again.
@@ -118,6 +118,21 @@ export class InboxClient {
118
118
  }
119
119
  return JSON.parse(body);
120
120
  }
121
+ /** The person said to leave this proposal pending. Does not approve or reject. */
122
+ async park(agreementId) {
123
+ if (!agreementId)
124
+ throw new Error('InboxClient.park: agreementId is required');
125
+ const res = await fetch(`${this.baseUrl}/inbox/park`, {
126
+ method: 'POST',
127
+ headers: this.headers(),
128
+ body: JSON.stringify({ agreementId }),
129
+ });
130
+ const body = await res.text().catch(() => '');
131
+ if (!res.ok) {
132
+ throw pollSurfaceError('InboxClient.park', res, body);
133
+ }
134
+ return JSON.parse(body);
135
+ }
121
136
  /**
122
137
  * Ack, and if the row still names a host that has already gone away,
123
138
  * read once (that is what takes an expired inbox) and ack again.
@@ -4,6 +4,14 @@ export interface ListMessagesOptions {
4
4
  /** Page size, default 100, hard cap 1000. */
5
5
  limit?: number;
6
6
  }
7
+ /**
8
+ * The chat message URL.
9
+ *
10
+ * `after` is a forward delta: the server returns that page only when both
11
+ * `after` and `direction=forward` are set. Omitting both is the newest page,
12
+ * which is how a person asks what just happened without already knowing a time.
13
+ */
14
+ export declare function messagesListUrl(base: string, chatId: string, opts?: ListMessagesOptions): string;
7
15
  export interface ListMessagesResult {
8
16
  messages: unknown[];
9
17
  latestSequence: string | null;
@@ -21,5 +29,12 @@ export declare class MessagesClient {
21
29
  private readonly agentId;
22
30
  constructor(operatorKey: string, agentId: string);
23
31
  list(chatId: string, opts?: ListMessagesOptions): Promise<ListMessagesResult>;
32
+ /**
33
+ * Newest page. No `after`, so the server walks backward from now.
34
+ * `list` is the forward delta and cannot answer "what just happened".
35
+ */
36
+ listLatest(chatId: string, opts?: {
37
+ limit?: number;
38
+ }): Promise<ListMessagesResult>;
24
39
  private _headers;
25
40
  }
@@ -2,6 +2,23 @@ import { decodeOperatorKeyClaims } from '../shared/operatorKey.js';
2
2
  import { buildOperatorHeaders } from './operatorHeaders.js';
3
3
  import { getBackendUrl } from '../utils/urlUtils.js';
4
4
  import { throwApiError } from '../shared/apiError.js';
5
+ /**
6
+ * The chat message URL.
7
+ *
8
+ * `after` is a forward delta: the server returns that page only when both
9
+ * `after` and `direction=forward` are set. Omitting both is the newest page,
10
+ * which is how a person asks what just happened without already knowing a time.
11
+ */
12
+ export function messagesListUrl(base, chatId, opts = {}) {
13
+ const url = new URL(`${base}/chats/${encodeURIComponent(chatId)}/messages`);
14
+ if (opts.after) {
15
+ url.searchParams.set('direction', 'forward');
16
+ url.searchParams.set('after', opts.after);
17
+ }
18
+ if (opts.limit != null)
19
+ url.searchParams.set('limit', String(opts.limit));
20
+ return url.toString();
21
+ }
5
22
  /**
6
23
  * Read-side client for forward-delta message reads.
7
24
  *
@@ -24,17 +41,16 @@ export class MessagesClient {
24
41
  async list(chatId, opts = {}) {
25
42
  if (!chatId)
26
43
  return { messages: [], latestSequence: null };
27
- const url = new URL(`${getBackendUrl()}/chats/${encodeURIComponent(chatId)}/messages`);
28
44
  // Forward-delta read mode. Backend routes to `listMessagesForward`
29
45
  // only when BOTH `after` and `direction=forward` are present; without
30
46
  // `after` the same handler falls into backward pagination and returns
31
47
  // a different envelope. Default `after` to the unix epoch so the
32
48
  // forward branch always wins when callers want "from the beginning".
33
- url.searchParams.set('direction', 'forward');
34
- url.searchParams.set('after', opts.after || '1970-01-01T00:00:00.000Z');
35
- if (opts.limit != null)
36
- url.searchParams.set('limit', String(opts.limit));
37
- const res = await fetch(url.toString(), { headers: this._headers() });
49
+ const url = messagesListUrl(getBackendUrl(), chatId, {
50
+ after: opts.after || '1970-01-01T00:00:00.000Z',
51
+ limit: opts.limit,
52
+ });
53
+ const res = await fetch(url, { headers: this._headers() });
38
54
  if (!res.ok) {
39
55
  const body = await res.text().catch(() => '');
40
56
  // Callers branch on ApiError.status (404 = chat deleted/not visible).
@@ -42,6 +58,20 @@ export class MessagesClient {
42
58
  }
43
59
  return (await res.json());
44
60
  }
61
+ /**
62
+ * Newest page. No `after`, so the server walks backward from now.
63
+ * `list` is the forward delta and cannot answer "what just happened".
64
+ */
65
+ async listLatest(chatId, opts = {}) {
66
+ if (!chatId)
67
+ return { messages: [], latestSequence: null };
68
+ const res = await fetch(messagesListUrl(getBackendUrl(), chatId, { limit: opts.limit }), { headers: this._headers() });
69
+ if (!res.ok) {
70
+ const body = await res.text().catch(() => '');
71
+ throwApiError(res, body, `MessagesClient.listLatest failed: ${res.status}`);
72
+ }
73
+ return (await res.json());
74
+ }
45
75
  _headers() {
46
76
  return {
47
77
  'content-type': 'application/json',
@@ -3,7 +3,7 @@ export * from './AgreementClient.js';
3
3
  export * from './MarketplaceClient.js';
4
4
  export * from './agreementFlows.js';
5
5
  export * from './ChatClient.js';
6
- export { MessagesClient } from './MessagesClient.js';
6
+ export { MessagesClient, messagesListUrl } from './MessagesClient.js';
7
7
  export type { ListMessagesOptions, ListMessagesResult } from './MessagesClient.js';
8
8
  export { ArtifactsClient, artifactScopeForSession, AGREEMENT_LANE_PREFIX, ARTIFACT_INLINE_TEXT_MAX_CHARS, ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT, } from './ArtifactsClient.js';
9
9
  export type { ArtifactVisibility, ListArtifactsOptions, ListArtifactsQuery, ListArtifactsResult, WriteArtifactInput, } from './ArtifactsClient.js';
@@ -3,7 +3,7 @@ export * from './AgreementClient.js';
3
3
  export * from './MarketplaceClient.js';
4
4
  export * from './agreementFlows.js';
5
5
  export * from './ChatClient.js';
6
- export { MessagesClient } from './MessagesClient.js';
6
+ export { MessagesClient, messagesListUrl } from './MessagesClient.js';
7
7
  export { ArtifactsClient,
8
8
  // agreement lanes are not chats — callers scope artifact writes with this.
9
9
  artifactScopeForSession, AGREEMENT_LANE_PREFIX, ARTIFACT_INLINE_TEXT_MAX_CHARS, ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT, } from './ArtifactsClient.js';
package/dist/types.d.ts CHANGED
@@ -501,6 +501,8 @@ export interface InboxEnvelope extends InboxRequestChannel {
501
501
  truncatedTasks: number;
502
502
  proposalsAwaitingMe: InboxProposalRef[];
503
503
  truncatedProposals: number;
504
+ /** Left pending on purpose. Not part of the shout. */
505
+ parkedProposals?: InboxProposalRef[];
504
506
  connectionRequestsAwaitingMe: InboxConnectionRequestRef[];
505
507
  truncatedConnectionRequests: number;
506
508
  humanAttention?: InboxHumanAttention;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.37.14",
3
+ "version": "0.37.16",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "homepage": "https://ziggsai.com/docs",
6
6
  "bugs": {
@@ -43,7 +43,8 @@
43
43
  "license": "Apache-2.0",
44
44
  "files": [
45
45
  "dist",
46
- "README.md"
46
+ "README.md",
47
+ "CHANGELOG.md"
47
48
  ],
48
49
  "publishConfig": {
49
50
  "access": "public",