@ziggs-ai/api-client 0.37.7 → 0.37.9

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.
@@ -6,7 +6,7 @@
6
6
  * keeps the people who actually receive (`participantSummary`) and drops the
7
7
  * other two unless `fields` asks for them.
8
8
  */
9
- export declare const CHAT_LIST_DEFAULT_FIELDS: readonly ["chatId", "name", "updatedAt", "lastMessage", "unreadCount", "participantSummary"];
9
+ export declare const CHAT_LIST_DEFAULT_FIELDS: readonly ["chatId", "name", "updatedAt", "lastMessage", "unreadCount", "participantSummary", "readable", "requestAccess"];
10
10
  /** Apply `fields`, or the MCP default when the caller omitted it. */
11
11
  export declare function projectChatListRows(chats: unknown[], fieldsRaw?: unknown): unknown[];
12
12
  export declare function utf8Bytes(value: unknown): number;
@@ -14,6 +14,9 @@ export const CHAT_LIST_DEFAULT_FIELDS = [
14
14
  'lastMessage',
15
15
  'unreadCount',
16
16
  'participantSummary',
17
+ // A room you may only list says so, with the read request ready to file.
18
+ 'readable',
19
+ 'requestAccess',
17
20
  ];
18
21
  function slimParticipant(row) {
19
22
  if (!row || typeof row !== 'object' || Array.isArray(row))
@@ -425,14 +425,14 @@ export const accessRequestCapability = {
425
425
  title: 'Request access for yourself or named readers',
426
426
  annotation: 'destructive', needsAgentId: true,
427
427
  descriptions: {
428
- sdk: 'Request optional bounded access to one artifact, chat, agreement context or task. Creates only a pending approval; never grants access or approves. Name who to ask in recipientId: your work brief offers them for this wake — workBrief.actingFor.customer.id (the customer of the hire you are working in, for their own accounts and resources) or workBrief.actingFor.operator.id (your operator, for tools you bring). Anyone else is refused, and the refusal lists who you can ask. Artifact requests also need chatId, the conversation they approve in. To create work under an agreement you can read but not work on (a task create refused with WORK_ACCESS_REQUIRED), request permission=work on it; only someone who can work on it may approve, and it lasts until the agreement ends. Use scopeId for a known artifact; or scopeKind=artifact with agreementId of your active hire to request its system-maintained workspace summary (workspace name/type and agents, including future updates, not private conversations or document bodies). Send the returned appUrl, wait for human approval, then open the returned scope. To arrange reading of one artifact for others, name them in holders (agents by id, people or workspaces by id or the participant reference this room shows you); include yourself only if you need to read it too. The owner approves that exact list once and each reader gets its own grant; readers who can already read it come back as already_readable. Hiring alone grants no source access. Revocation and expiry are checked by the system.',
428
+ sdk: 'Request optional bounded access to one artifact, chat, agreement context or task. Creates only a pending approval; never grants access or approves. Name who to ask in recipientId: your work brief offers them for this wake — workBrief.actingFor.customer.id (the customer of the hire you are working in, for their own accounts and resources) or workBrief.actingFor.operator.id (your operator, for tools you bring). Anyone else is refused, and the refusal lists who you can ask. Artifact requests also need chatId, the conversation they approve in. To create work under an agreement you can read but not work on (a task create refused with WORK_ACCESS_REQUIRED), request permission=work on it; only someone who can work on it may approve, and it lasts until the agreement ends. Use scopeId for a known artifact; or scopeKind=artifact with agreementId of your active hire to request its system-maintained workspace summary (workspace name/type and agents, including future updates, not private conversations or document bodies). Send the returned appUrl, wait for human approval, then open the returned scope. To arrange reading of one artifact for others, name them in holders (agents by id, people or workspaces by id or the participant reference this room shows you); include yourself only if you need to read it too. The owner approves that exact list once and each reader gets its own grant; readers who can already read it come back as already_readable. To see which rooms a person is in (to find the room they mean), request scopeKind=person, scopeId=their person id, permission=list, from that person; once they approve, your chat list shows their rooms, each marked readable or not, and reading one still needs its own request. Hiring alone grants no source access. Revocation and expiry are checked by the system.',
429
429
  },
430
430
  params: {
431
- scopeKind: { type: 'string', required: true, enum: ['artifact', 'chat', 'agreement', 'task'] },
431
+ scopeKind: { type: 'string', required: true, enum: ['artifact', 'chat', 'agreement', 'task', 'person'] },
432
432
  scopeId: { type: 'string', description: 'Original resource id. Omit when using a hire agreementId to request its workspace summary.' },
433
433
  agreementId: { type: 'string', description: 'Artifact scope only: current hire id, used instead of scopeId to request the system-maintained workspace summary.' },
434
434
  reason: { type: 'string', required: true, description: 'Why access is needed and who will receive the reply or summary' },
435
- permission: { type: 'string', enum: ['read', 'reply', 'work'], description: 'read by default; reply is read and reply and is only valid for a chat; work lets you create work under an agreement you can read but not work on, and lasts until it ends' },
435
+ permission: { type: 'string', enum: ['read', 'reply', 'work', 'list'], description: 'read by default; reply is read and reply and is only valid for a chat; work lets you create work under an agreement you can read but not work on, and lasts until it ends; list is required for a person scope and shows which rooms they are in, never their messages' },
436
436
  temporal: { type: 'string', enum: ['from-now', 'from-start'], description: 'Chat history requested; default from-now. Earlier messages need from-start. Other resources use from-start.' },
437
437
  durationHours: { type: 'number', description: 'Integer 1–168 hours after approval; default 24' },
438
438
  chatId: { type: 'string', description: 'Artifact or workspace requests only: existing conversation with the owner' },
@@ -462,14 +462,16 @@ export const accessRequestCapability = {
462
462
  throw new Error(`${key} is required`);
463
463
  }
464
464
  const scopeKind = args.scopeKind;
465
- if (!['artifact', 'chat', 'agreement', 'task'].includes(scopeKind))
465
+ if (!['artifact', 'chat', 'agreement', 'task', 'person'].includes(scopeKind))
466
466
  throw new Error('Unsupported scopeKind');
467
467
  const agreementId = typeof args.agreementId === 'string' ? args.agreementId.trim() : undefined;
468
468
  const scopeId = typeof args.scopeId === 'string' ? args.scopeId.trim() : undefined;
469
469
  if (Boolean(agreementId) === Boolean(scopeId) || (agreementId && scopeKind !== 'artifact'))
470
470
  throw new Error('Provide scopeId, or agreementId for its workspace summary artifact');
471
- const permission = args.permission ?? 'read';
472
- if (!['read', 'reply', 'work'].includes(String(permission)) || (permission === 'reply' && scopeKind !== 'chat'))
471
+ const permission = args.permission ?? (scopeKind === 'person' ? 'list' : 'read');
472
+ if ((permission === 'list') !== (scopeKind === 'person'))
473
+ throw new Error('A person scope is requested with permission=list, and list only for a person');
474
+ if (!['read', 'reply', 'work', 'list'].includes(String(permission)) || (permission === 'reply' && scopeKind !== 'chat'))
473
475
  throw new Error('Only chat access may request reply permission');
474
476
  if (permission === 'work' && scopeKind !== 'agreement')
475
477
  throw new Error('Only agreement access may request work permission');
@@ -503,7 +505,10 @@ export const accessRequestCapability = {
503
505
  ...(actingAgentId ? { actingAgentId } : {}),
504
506
  scope: result.scope ?? { kind: scopeKind, id: scopeId },
505
507
  appUrl: `${(env.webUrl ?? 'https://ziggsai.com').replace(/\/$/, '')}/app/agreements/${encodeURIComponent(result.agreementId)}`,
506
- resumeAfterApproval: { tool: env.surface === 'mcp' ? 'ziggs_open' : 'open', args: result.scope ? { [`${result.scope.kind}Id`]: result.scope.id } : { [`${scopeKind}Id`]: scopeId } },
508
+ // A person scope opens nothing: the yes shows up in the chat list.
509
+ ...(scopeKind === 'person'
510
+ ? env.surface === 'mcp' ? { resumeAfterApproval: { tool: 'ziggs_chat_list', args: {} } } : {}
511
+ : { resumeAfterApproval: { tool: env.surface === 'mcp' ? 'ziggs_open' : 'open', args: result.scope ? { [`${result.scope.kind}Id`]: result.scope.id } : { [`${scopeKind}Id`]: scopeId } } }),
507
512
  note: `${result.message ?? 'A request card is open.'} No access granted until they approve; then open the original resource using the same agent identity.`,
508
513
  };
509
514
  },
@@ -100,7 +100,7 @@ const BRIEFS = {
100
100
  },
101
101
  // Rooms
102
102
  ziggs_chat_list: {
103
- does: 'Lists rooms you hold a grant on, with last message and unread count. fields adds members or rosterSummary.',
103
+ does: 'Lists rooms you hold a grant on, with last message and unread count, plus the rooms a person let you list, marked readable: false with no message and the read request to file. fields adds members or rosterSummary.',
104
104
  },
105
105
  ziggs_chat_open: {
106
106
  does: 'Opens or reuses a conversation with a person or agent (participantId), starts a group (participantIds), or invites people into a room (chatId).',
@@ -178,7 +178,7 @@ const BRIEFS = {
178
178
  },
179
179
  // Tasks
180
180
  ziggs_task_create: {
181
- does: 'Creates a task under an active agreement, or a work graph under a root task. plan sets its checklist.',
181
+ does: 'Creates a task under an active agreement, or a job with its children in one call. plan sets its checklist.',
182
182
  changes: 'creates the tasks and notifies their assignees',
183
183
  },
184
184
  ziggs_task_get: {
@@ -200,7 +200,7 @@ const BRIEFS = {
200
200
  changes: 'closes the task, proving nobody read or paid; the same idempotencyKey is a no-op',
201
201
  },
202
202
  ziggs_task_cancel: {
203
- does: 'Cancels one task. Cancelling a held graph’s root withdraws the graph.',
203
+ does: 'Cancels one task. Cancelling a job cancels its live children.',
204
204
  changes: 'the task is cancelled',
205
205
  },
206
206
  ziggs_task_acknowledge_control: {
@@ -72,14 +72,14 @@ export const cancelTaskCapability = {
72
72
  names: { sdk: 'task_cancel', mcp: 'ziggs_task_cancel' },
73
73
  title: 'Cancel a task',
74
74
  descriptions: {
75
- sdk: 'Cancel one task (PATCH /tasks/:id/cancel). A held graph withdraws by cancelling its root — that is one act, not a blocked state. Cancel ends this task; it does not amend a live hire.',
75
+ sdk: 'Cancel one task (PATCH /tasks/:id/cancel). Cancelling a job cancels its live children — that is one act, not a blocked state. Cancel ends this task; it does not amend a live hire.',
76
76
  },
77
77
  annotation: 'destructive',
78
78
  params: {
79
79
  taskId: {
80
80
  type: 'string',
81
81
  required: true,
82
- description: 'The task to cancel. For a held graph, pass the root.',
82
+ description: 'The task to cancel. To withdraw a whole job, pass the job.',
83
83
  },
84
84
  },
85
85
  needsAgentId: true,
@@ -153,7 +153,10 @@ export declare function addChatMember(input: AddChatMemberInput, creds: Creds):
153
153
  * an existing participant and `chatId` is omitted.
154
154
  */
155
155
  export declare function sendChatMessage(input: SendChatMessageInput, creds: Creds): Promise<SendChatMessageResult>;
156
- export declare function listMyChats(creds: Creds): Promise<ChatSummary[]>;
156
+ export declare function listMyChats(creds: Creds, filters?: {
157
+ participantId?: string;
158
+ readable?: boolean;
159
+ }): Promise<ChatSummary[]>;
157
160
  export declare class ChatClient {
158
161
  private creds;
159
162
  /**
@@ -154,14 +154,20 @@ export async function sendChatMessage(input, creds) {
154
154
  ...(coverage ? { coverage } : {}),
155
155
  };
156
156
  }
157
- export async function listMyChats(creds) {
157
+ export async function listMyChats(creds, filters = {}) {
158
158
  assertCreds(creds, 'list my chats');
159
+ const query = new URLSearchParams();
160
+ if (filters.participantId)
161
+ query.set('participantId', filters.participantId);
162
+ if (filters.readable !== undefined)
163
+ query.set('readable', String(filters.readable));
164
+ const qs = query.toString();
159
165
  // empty array only for a genuine empty 200; any failure (non-2xx /
160
166
  // network) throws so ziggs_chat_list reports a real error instead of "you
161
167
  // have no chats". HTTP failures are ApiError (status/body/code).
162
168
  let res;
163
169
  try {
164
- res = await fetch(`${getBackendUrl()}/chats/mine`, {
170
+ res = await fetch(`${getBackendUrl()}/chats/mine${qs ? `?${qs}` : ''}`, {
165
171
  method: 'GET',
166
172
  headers: buildHeaders(creds),
167
173
  });
@@ -98,11 +98,11 @@ export declare class ContextGrantsClient {
98
98
  issueGrant(input: IssueContextGrantInput): Promise<GrantView>;
99
99
  /** Request-only endpoint: a successful call must still have granted no access. */
100
100
  requestAccess(input: {
101
- scopeKind: 'artifact' | 'chat' | 'agreement' | 'task';
101
+ scopeKind: 'artifact' | 'chat' | 'agreement' | 'task' | 'person';
102
102
  scopeId?: string;
103
103
  agreementId?: string;
104
104
  reason: string;
105
- permission?: 'read' | 'reply' | 'work';
105
+ permission?: 'read' | 'reply' | 'work' | 'list';
106
106
  temporal?: 'from-now' | 'from-start';
107
107
  durationHours?: number;
108
108
  chatId?: string;
@@ -41,21 +41,28 @@ export declare function acknowledgeTaskControl(taskId: string, requestId: string
41
41
  * subcontract inputs rather than teaching those routes to keep one.
42
42
  */
43
43
  export type PlanReviewTiming = 'with_proposal' | 'before_execution';
44
- export interface CreateTaskGraphNodeData {
45
- nodeId: string;
44
+ /**
45
+ * One child created with its parent, all or none. `name` only lets siblings
46
+ * name each other in `waitsOn`; it is not stored, and the create answers with
47
+ * the task id each name became.
48
+ */
49
+ export interface CreateTaskChildData {
50
+ name: string;
46
51
  agreementId: string;
47
52
  description: string;
48
53
  title?: string;
49
54
  assigneeId?: string;
55
+ /** Names of sibling children in the same create that must finish first. */
50
56
  waitsOn?: string[];
51
57
  joinKind?: 'all' | 'any';
52
- /** A yes/no question over the steps this one waits on; it runs only on yes. */
58
+ /** A yes/no question over the children this one waits on; it runs only on yes. */
53
59
  runIf?: string;
54
- }
55
- export interface CreateTaskGraphData {
56
- nodes: CreateTaskGraphNodeData[];
57
60
  inputArtifactIds?: string[];
58
- review?: 'before_execution';
61
+ }
62
+ /** What a create with children answers for each one. */
63
+ export interface CreatedTaskChild {
64
+ name: string;
65
+ taskId: string;
59
66
  }
60
67
  export interface CreateTaskData {
61
68
  description: string;
@@ -89,8 +96,20 @@ export interface CreateTaskData {
89
96
  * the shape in its own control flow where nothing else can see it.
90
97
  */
91
98
  waitsOn?: string[];
92
- /** Atomically declare a native work graph beneath the returned root task. */
93
- graph?: CreateTaskGraphData;
99
+ /**
100
+ * How the task closes, fixed at create. `children` (the default when
101
+ * `children` is given) makes it a job that closes when its children close:
102
+ * completed when every child no sibling waits on completed or was skipped.
103
+ * `result` (the default otherwise) closes by its own result.
104
+ */
105
+ closesBy?: 'result' | 'children';
106
+ /**
107
+ * Children created with this task in one call, all or none. The job's
108
+ * `inputArtifactIds` go to the children that wait on nothing, and
109
+ * `planReviewTiming: before_execution` holds every child until this task's
110
+ * plan is acknowledged.
111
+ */
112
+ children?: CreateTaskChildData[];
94
113
  /**
95
114
  * When the answer stops being useful, ISO 8601. At the deadline
96
115
  * the holder posts what it has and where it is stuck, and stops. A deadline
@@ -115,7 +134,9 @@ export interface CreateTaskCheckBackData {
115
134
  /** Total reminders allowed per person asked, after the first ask. */
116
135
  maxReminders: number;
117
136
  }
118
- export declare function createTask(taskData: CreateTaskData, creds: Creds): Promise<Task>;
137
+ export declare function createTask(taskData: CreateTaskData, creds: Creds): Promise<Task & {
138
+ children?: CreatedTaskChild[];
139
+ }>;
119
140
  export declare function getTask(taskId: string, creds: Creds): Promise<Task>;
120
141
  export interface UpdateTaskStateData {
121
142
  result?: unknown;
@@ -212,7 +233,9 @@ export declare class TaskClient {
212
233
  constructor(operatorKey: string, agentId?: string);
213
234
  requestControl(taskId: string, request: Parameters<typeof requestTaskControl>[1]): Promise<TaskWriteConfirm>;
214
235
  acknowledgeControl(taskId: string, requestId: string, supported?: boolean): Promise<TaskWriteConfirm>;
215
- createTask(data: CreateTaskData): Promise<Task>;
236
+ createTask(data: CreateTaskData): Promise<Task & {
237
+ children?: CreatedTaskChild[];
238
+ }>;
216
239
  getTask(taskId: string): Promise<Task>;
217
240
  updateTaskState(taskId: string, state: TaskState, data?: UpdateTaskStateData): Promise<TaskWriteConfirm>;
218
241
  getActiveTasksForAgent(agentId: string): Promise<Task[]>;
@@ -112,7 +112,10 @@ export async function createTask(taskData, creds) {
112
112
  const task = extractTask(data);
113
113
  if (!task)
114
114
  throw new Error('Invalid response: task data not found');
115
- return task;
115
+ const children = data?.children;
116
+ return Array.isArray(children)
117
+ ? { ...task, children: children }
118
+ : task;
116
119
  }
117
120
  export async function getTask(taskId, creds) {
118
121
  if (!taskId)
package/dist/types.d.ts CHANGED
@@ -103,17 +103,16 @@ export interface Task {
103
103
  */
104
104
  heldByDeps?: boolean;
105
105
  joinKind?: 'all' | 'any';
106
- graph?: {
107
- nodes: Array<{
108
- nodeId: string;
109
- taskId: string;
110
- }>;
111
- review?: 'before_execution';
112
- } | null;
113
- graphNodeId?: string | null;
114
- heldByGraphReview?: boolean;
115
106
  /**
116
- * A graph step that runs only if a yes/no question holds over the steps it
107
+ * How the task closes, fixed at create. `children` makes it a job: never
108
+ * handed out, it closes when its children (the tasks naming it as their
109
+ * parent) close.
110
+ */
111
+ closesBy?: 'result' | 'children';
112
+ /** True while the task waits for its parent's plan to be acknowledged. */
113
+ heldByParentReview?: boolean;
114
+ /**
115
+ * A child that runs only if a yes/no question holds over the steps it
117
116
  * waits on. Once asked: `run`, `skipped` (closed cancelled without running),
118
117
  * `held` (waiting for the buyer to acknowledge its plan) or `buyer_run`.
119
118
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.37.7",
3
+ "version": "0.37.9",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",