@ziggs-ai/api-client 0.13.0 → 0.14.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.
@@ -0,0 +1,71 @@
1
+ /** What became of one hello. `expired` is derived by the server, not stored. */
2
+ export type IntroductionStatus = 'open' | 'redeemed' | 'declined' | 'revoked' | 'expired';
3
+ export type IntroductionOutcome = 'link_pending' | 'already_teammates' | 'already_linked';
4
+ export interface IntroductionFrom {
5
+ orgId: string;
6
+ agentId: string | null;
7
+ agentCreatedAt?: string | null;
8
+ claimedLabel?: {
9
+ text: string;
10
+ selfChosen: boolean;
11
+ verified: boolean;
12
+ };
13
+ /**
14
+ * Same text as claimedLabel.text. Not identity — anyone can pick it.
15
+ */
16
+ label: string;
17
+ }
18
+ export interface IntroductionView {
19
+ token: string;
20
+ status: IntroductionStatus;
21
+ outcome: IntroductionOutcome | null;
22
+ notice?: string;
23
+ from: IntroductionFrom;
24
+ venue: string | null;
25
+ venueRef: string | null;
26
+ note: string | null;
27
+ agreementId: string | null;
28
+ redeemedBy: {
29
+ agentId: string | null;
30
+ orgId: string | null;
31
+ } | null;
32
+ expiresAt: string;
33
+ /** The public page the string points at. This is what you hand over. */
34
+ url: string;
35
+ /**
36
+ * Returned to a redeemer only: the two ids the meeting is now worth, and what
37
+ * each is for. `agentId` is where messages go; `principal` is who can be a
38
+ * party to an agreement. Passing one where the other belongs is refused as if
39
+ * the agent did not exist, which is the wall this field exists to remove.
40
+ */
41
+ counterparty?: {
42
+ principal: string;
43
+ agentId: string | null;
44
+ label: string;
45
+ nextStep: string;
46
+ };
47
+ }
48
+ export interface MintIntroductionInput {
49
+ venue?: string;
50
+ venueRef?: string;
51
+ note?: string;
52
+ }
53
+ /**
54
+ * Introduction tokens — the one object to exchange when you meet an
55
+ * agent somewhere Ziggs does not own.
56
+ *
57
+ * The token carries no authority, which is why minting one is free: it widens
58
+ * nobody's reach. Redeeming one stages a link proposal the two humans sign.
59
+ */
60
+ export declare class IntroductionsClient {
61
+ private readonly operatorKey;
62
+ private readonly agentId?;
63
+ private readonly baseUrl;
64
+ constructor(operatorKey: string, agentId?: string, baseUrl?: string);
65
+ mint(input?: MintIntroductionInput): Promise<IntroductionView>;
66
+ redeem(token: string): Promise<IntroductionView>;
67
+ decline(token: string): Promise<IntroductionView>;
68
+ revoke(token: string): Promise<IntroductionView>;
69
+ listMine(limit?: number): Promise<IntroductionView[]>;
70
+ private call;
71
+ }
@@ -0,0 +1,54 @@
1
+ import { getBackendUrl } from '../utils/urlUtils.js';
2
+ import { throwApiError } from '../shared/apiError.js';
3
+ import { buildOperatorHeaders } from './operatorHeaders.js';
4
+ /**
5
+ * Introduction tokens — the one object to exchange when you meet an
6
+ * agent somewhere Ziggs does not own.
7
+ *
8
+ * The token carries no authority, which is why minting one is free: it widens
9
+ * nobody's reach. Redeeming one stages a link proposal the two humans sign.
10
+ */
11
+ export class IntroductionsClient {
12
+ operatorKey;
13
+ agentId;
14
+ baseUrl;
15
+ constructor(operatorKey, agentId, baseUrl) {
16
+ if (!operatorKey) {
17
+ throw new Error('IntroductionsClient: operatorKey is required');
18
+ }
19
+ this.operatorKey = operatorKey;
20
+ this.agentId = agentId;
21
+ this.baseUrl = baseUrl || getBackendUrl();
22
+ }
23
+ async mint(input = {}) {
24
+ return this.call('POST', '/introductions', input, 'mint');
25
+ }
26
+ async redeem(token) {
27
+ return this.call('POST', `/introductions/${encodeURIComponent(token)}/redeem`, {}, 'redeem');
28
+ }
29
+ async decline(token) {
30
+ return this.call('POST', `/introductions/${encodeURIComponent(token)}/decline`, {}, 'decline');
31
+ }
32
+ async revoke(token) {
33
+ return this.call('DELETE', `/introductions/${encodeURIComponent(token)}`, undefined, 'revoke');
34
+ }
35
+ async listMine(limit) {
36
+ const query = limit != null ? `?limit=${encodeURIComponent(String(limit))}` : '';
37
+ return this.call('GET', `/introductions${query}`, undefined, 'listMine');
38
+ }
39
+ async call(method, path, body, label) {
40
+ const res = await fetch(`${this.baseUrl}${path}`, {
41
+ method,
42
+ headers: {
43
+ ...buildOperatorHeaders(this.operatorKey, this.agentId),
44
+ ...(body === undefined ? {} : { 'Content-Type': 'application/json' }),
45
+ },
46
+ ...(body === undefined ? {} : { body: JSON.stringify(body) }),
47
+ });
48
+ const text = await res.text().catch(() => '');
49
+ if (!res.ok) {
50
+ throwApiError(res, text, `IntroductionsClient.${label} failed: ${res.status}`);
51
+ }
52
+ return JSON.parse(text);
53
+ }
54
+ }
@@ -13,6 +13,7 @@ export interface TaskWriteConfirm {
13
13
  structureChanged?: boolean;
14
14
  stepId?: string;
15
15
  stepStatus?: string;
16
+ patchedCount?: number;
16
17
  resultRecorded?: boolean;
17
18
  terminalState?: string;
18
19
  [key: string]: unknown;
@@ -23,6 +24,20 @@ export interface TaskWriteConfirm {
23
24
  * subcontract inputs rather than teaching those routes to keep one.
24
25
  */
25
26
  export type PlanReviewTiming = 'with_proposal' | 'before_execution';
27
+ export interface CreateTaskGraphNodeData {
28
+ nodeId: string;
29
+ agreementId: string;
30
+ description: string;
31
+ title?: string;
32
+ assigneeId?: string;
33
+ waitsOn?: string[];
34
+ joinKind?: 'all' | 'any';
35
+ }
36
+ export interface CreateTaskGraphData {
37
+ nodes: CreateTaskGraphNodeData[];
38
+ inputArtifactIds?: string[];
39
+ review?: 'before_execution';
40
+ }
26
41
  export interface CreateTaskData {
27
42
  description: string;
28
43
  /**
@@ -55,6 +70,8 @@ export interface CreateTaskData {
55
70
  * the shape in its own control flow where nothing else can see it.
56
71
  */
57
72
  waitsOn?: string[];
73
+ /** Atomically declare a native work graph beneath the returned root task. */
74
+ graph?: CreateTaskGraphData;
58
75
  }
59
76
  export declare function createTask(taskData: CreateTaskData, creds: Creds): Promise<Task>;
60
77
  export declare function getTask(taskId: string, creds: Creds): Promise<Task>;
@@ -91,6 +108,13 @@ export interface PlanReplaceStep {
91
108
  result?: unknown;
92
109
  }
93
110
  export declare function replaceTaskPlan(taskId: string, steps: PlanReplaceStep[], creds: Creds): Promise<TaskWriteConfirm>;
111
+ /** Named-step progress — only the listed steps change. */
112
+ export type PlanStepPatch = {
113
+ stepId: string;
114
+ status: 'pending' | 'in_progress' | 'completed' | 'skipped';
115
+ result?: unknown;
116
+ };
117
+ export declare function updateTaskPlanSteps(taskId: string, patches: PlanStepPatch[], creds: Creds): Promise<TaskWriteConfirm>;
94
118
  export declare function updateTaskPlanStep(taskId: string, stepId: string, status: string, result: unknown, creds: Creds): Promise<TaskWriteConfirm>;
95
119
  export declare function reportTask(taskId: string, message: string | undefined, creds: Creds): Promise<TaskWriteConfirm>;
96
120
  export declare function setTaskSatisfaction(taskId: string, satisfaction: 'positive' | 'negative', creds: Creds): Promise<TaskWriteConfirm>;
@@ -135,6 +159,7 @@ export declare class TaskClient {
135
159
  getSubtasks(parentTaskId: string): Promise<Task[]>;
136
160
  replaceTaskPlan(taskId: string, steps: PlanReplaceStep[]): Promise<TaskWriteConfirm>;
137
161
  updateTaskPlanStep(taskId: string, stepId: string, status: string, result?: unknown): Promise<TaskWriteConfirm>;
162
+ updateTaskPlanSteps(taskId: string, patches: PlanStepPatch[]): Promise<TaskWriteConfirm>;
138
163
  reportTask(taskId: string, message?: string): Promise<TaskWriteConfirm>;
139
164
  setTaskSatisfaction(taskId: string, satisfaction: 'positive' | 'negative'): Promise<TaskWriteConfirm>;
140
165
  listTasks(options?: ListTasksOptions): Promise<ListTasksResult>;
@@ -55,6 +55,7 @@ function extractWriteConfirm(data) {
55
55
  : {}),
56
56
  ...(typeof d['stepId'] === 'string' ? { stepId: d['stepId'] } : {}),
57
57
  ...(typeof d['stepStatus'] === 'string' ? { stepStatus: d['stepStatus'] } : {}),
58
+ ...(typeof d['patchedCount'] === 'number' ? { patchedCount: d['patchedCount'] } : {}),
58
59
  ...(d['resultRecorded'] === true ? { resultRecorded: true } : {}),
59
60
  ...(typeof d['terminalState'] === 'string'
60
61
  ? { terminalState: d['terminalState'] }
@@ -152,10 +153,29 @@ export async function getActiveTasksForAgent(agentId, creds) {
152
153
  const data = await res.json().catch(() => null);
153
154
  const fromAgent = Array.isArray(data?.['tasks']) ? data['tasks'] : [];
154
155
  if (fromAgent.length > 0)
155
- return fromAgent;
156
+ return workable(fromAgent);
156
157
  // Fallback when /agents/:id/tasks is empty but party-agreement tasks exist.
157
158
  return getActiveTasksForAgentViaPartyAgreements(agentId, creds);
158
159
  }
160
+ /**
161
+ * Drop the tasks the platform created but deliberately did not deliver.
162
+ *
163
+ * `heldByDeps` is a DELIVERY condition, not a task state: a task waiting on its
164
+ * `waitsOn` edges is genuinely `active`, so `?state=active` returns it and the
165
+ * assignee's own work list hands over a task nobody woke it for. Every caller of
166
+ * this function is asking "what can I act on now", and for a withheld row the
167
+ * answer is nothing — `updateTaskState` refuses it with `dependencies_unmet`.
168
+ * Two of AgentHost's three callers do worse than waste a wake: the needs gate
169
+ * and the unmet-access sweep both FAIL the tasks they find, so a withheld node
170
+ * was one missing grant away from being failed before its turn came.
171
+ *
172
+ * Filtered here rather than at `/agents/:id/tasks`, which is also the route the
173
+ * UI lists an agent's work with — a person looking at the graph should see the
174
+ * withheld node sitting there waiting, which is the whole point of a join.
175
+ */
176
+ function workable(tasks) {
177
+ return tasks.filter((t) => t.heldByDeps !== true);
178
+ }
159
179
  async function getActiveTasksForAgentViaPartyAgreements(agentId, creds) {
160
180
  const { listAgreements } = await import('./AgreementClient.js');
161
181
  const agreements = await listAgreements({ status: 'active' }, creds);
@@ -175,7 +195,7 @@ async function getActiveTasksForAgentViaPartyAgreements(agentId, creds) {
175
195
  return Array.isArray(data?.['tasks']) ? data['tasks'] : [];
176
196
  }));
177
197
  const merged = lists.flat();
178
- return merged.filter((t) => !t.assigneeId || t.assigneeId === agentId);
198
+ return workable(merged.filter((t) => !t.assigneeId || t.assigneeId === agentId));
179
199
  }
180
200
  // Backend deliberately has no `/chats/:id/tasks` route — it's composable
181
201
  // from links → per-agreement tasks. We do the composition here so callers
@@ -263,6 +283,34 @@ export async function replaceTaskPlan(taskId, steps, creds) {
263
283
  throw new Error('Invalid response: task write confirm not found');
264
284
  return confirm;
265
285
  }
286
+ export async function updateTaskPlanSteps(taskId, patches, creds) {
287
+ if (!taskId)
288
+ throw new Error('updateTaskPlanSteps: taskId is required');
289
+ if (!patches || !Array.isArray(patches) || patches.length === 0) {
290
+ throw new Error('updateTaskPlanSteps: patches must name at least one step');
291
+ }
292
+ for (const patch of patches) {
293
+ if (!patch?.stepId)
294
+ throw new Error('updateTaskPlanSteps: each patch needs a stepId');
295
+ if (!patch?.status)
296
+ throw new Error('updateTaskPlanSteps: each patch needs a status');
297
+ }
298
+ assertCreds(creds, 'plan step patch');
299
+ const res = await fetch(`${getTaskBaseUrl()}/${taskId}/plan`, {
300
+ method: 'PATCH',
301
+ headers: buildHeaders(creds),
302
+ body: JSON.stringify({ patches }),
303
+ });
304
+ if (!res.ok) {
305
+ const responseBody = await res.text().catch(() => '');
306
+ throwApiError(res, responseBody, `Plan step patch failed: ${res.status} ${res.statusText}`);
307
+ }
308
+ const data = await res.json().catch(() => null);
309
+ const confirm = extractWriteConfirm(data);
310
+ if (!confirm)
311
+ throw new Error('Invalid response: task write confirm not found');
312
+ return confirm;
313
+ }
266
314
  export async function updateTaskPlanStep(taskId, stepId, status, result, creds) {
267
315
  if (!taskId)
268
316
  throw new Error('updateTaskPlanStep: taskId is required');
@@ -406,6 +454,7 @@ export class TaskClient {
406
454
  getSubtasks(parentTaskId) { return getSubtasks(parentTaskId, this.creds); }
407
455
  replaceTaskPlan(taskId, steps) { return replaceTaskPlan(taskId, steps, this.creds); }
408
456
  updateTaskPlanStep(taskId, stepId, status, result) { return updateTaskPlanStep(taskId, stepId, status, result, this.creds); }
457
+ updateTaskPlanSteps(taskId, patches) { return updateTaskPlanSteps(taskId, patches, this.creds); }
409
458
  reportTask(taskId, message) { return reportTask(taskId, message, this.creds); }
410
459
  setTaskSatisfaction(taskId, satisfaction) { return setTaskSatisfaction(taskId, satisfaction, this.creds); }
411
460
  listTasks(options) { return listTasks(options ?? {}, this.creds); }
@@ -11,6 +11,8 @@ export { ContextReadClient, CONTEXT_READ_TYPES, CONTEXT_READ_VIA, VIA_KINDS, par
11
11
  export type { ContextReadType, ContextReadQuery, ContextReadEnvelope, ContextSnapshotResult, ContextSnapshotParticipant, ViaKind, } from './ContextReadClient.js';
12
12
  export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
13
13
  export type { DiscoverableItem } from './ContextDiscoveryClient.js';
14
+ export { IntroductionsClient } from './IntroductionsClient.js';
15
+ export type { IntroductionView, IntroductionFrom, IntroductionStatus, IntroductionOutcome, MintIntroductionInput, } from './IntroductionsClient.js';
14
16
  export { GrantsClient } from './GrantsClient.js';
15
17
  export type { ListGrantsQuery, ListGrantsResult, UnreadableRail } from './GrantsClient.js';
16
18
  export { ContextGrantsClient } from './ContextGrantsClient.js';
@@ -9,6 +9,7 @@ export { ArtifactsClient,
9
9
  artifactScopeForSession, AGREEMENT_LANE_PREFIX, ARTIFACT_INLINE_TEXT_MAX_CHARS, ARTIFACT_INLINE_TEXT_OVER_LIMIT_HINT, } from './ArtifactsClient.js';
10
10
  export { ContextReadClient, CONTEXT_READ_TYPES, CONTEXT_READ_VIA, VIA_KINDS, parseVia, viaHint, } from './ContextReadClient.js';
11
11
  export { ContextDiscoveryClient } from './ContextDiscoveryClient.js';
12
+ export { IntroductionsClient } from './IntroductionsClient.js';
12
13
  export { GrantsClient } from './GrantsClient.js';
13
14
  export { ContextGrantsClient } from './ContextGrantsClient.js';
14
15
  export { grantCaveat, CONTEXT_GRANT_SCOPE_KINDS, GRANT_SCOPE_KINDS, } from './grants.js';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from './http/index.js';
2
2
  export * from './capabilities/index.js';
3
- export * from './relay/provisionRelayWorkers.js';
4
3
  export { ConnectionManager } from './ConnectionManager.js';
5
4
  export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, isPersonaRef, isRoomPresentationRef, isOpaquePresentationRef, AGREEMENT_ENGAGEMENT_KIND, isValidContentType, partySideIds, partyActorIds, } from './types.js';
6
5
  export type { PrincipalPresentation } from './types.js';
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from './http/index.js';
2
2
  export * from './capabilities/index.js';
3
- export * from './relay/provisionRelayWorkers.js';
4
3
  export { ConnectionManager } from './ConnectionManager.js';
5
4
  export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, isPersonaRef, isRoomPresentationRef, isOpaquePresentationRef, AGREEMENT_ENGAGEMENT_KIND, isValidContentType, partySideIds, partyActorIds, } from './types.js';
6
5
  export { getBackendUrl } from './utils/urlUtils.js';
package/dist/types.d.ts CHANGED
@@ -79,6 +79,16 @@ export interface Task {
79
79
  * from "nobody has picked it up" — this one is waiting on purpose.
80
80
  */
81
81
  heldByDeps?: boolean;
82
+ joinKind?: 'all' | 'any';
83
+ graph?: {
84
+ nodes: Array<{
85
+ nodeId: string;
86
+ taskId: string;
87
+ }>;
88
+ review?: 'before_execution';
89
+ } | null;
90
+ graphNodeId?: string | null;
91
+ heldByGraphReview?: boolean;
82
92
  plan?: {
83
93
  steps?: PlanStep[];
84
94
  };
@@ -148,6 +158,8 @@ export interface AgreementApprovalEntry {
148
158
  role?: string;
149
159
  status?: string;
150
160
  respondedAt?: string | null;
161
+ /** Why a pending slot is held (e.g. 'formation-gate', 'contact-basis'), when the server said. */
162
+ heldReason?: string | null;
151
163
  }
152
164
  export interface Agreement {
153
165
  agreementId: string;
@@ -163,6 +175,17 @@ export interface Agreement {
163
175
  money?: {
164
176
  price?: number | null;
165
177
  paymentStatus?: string;
178
+ transactionId?: string | null;
179
+ /**
180
+ * Ledger hold for this agreement, or null if paymentStatus says held but
181
+ * no hold row exists. Amount is cents. Never includes a wallet id.
182
+ */
183
+ held?: {
184
+ amount: number;
185
+ currency: string;
186
+ state: 'held' | 'released' | 'refunded';
187
+ agreementId: string;
188
+ } | null;
166
189
  };
167
190
  lifecycle?: string;
168
191
  expiresAt?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,119 +0,0 @@
1
- import type { Agreement, Creds } from '../types.js';
2
- import { claimOpenAgreement, delegateAgreement, getMyAgreements, pullOffers, type DelegateContextGrantResult, type GrantView } from '../http/index.js';
3
- /** Minimal relay step shape — keep field names aligned with agents/coordinators/relayTypes.ts */
4
- export interface RelayStepInput {
5
- stepId: string;
6
- order: number;
7
- assigneeId: string;
8
- description: string;
9
- /** Standing offer agreementId to claim for this worker (optional). */
10
- offerAgreementId?: string;
11
- }
12
- export interface RelayPayloadShape {
13
- inputArtifactIds?: string[];
14
- steps: Array<{
15
- stepId: string;
16
- order: number;
17
- agreementId: string;
18
- assigneeId: string;
19
- description: string;
20
- }>;
21
- }
22
- export type ProvisionMethod = 'existing' | 'claim' | 'delegate';
23
- export type StepProvisionStatus = 'active' | 'pending_approval';
24
- /**
25
- * What happened to the coordinator's pass on this worker contract.
26
- *
27
- * - `granted` — the coordinator may create work citing this contract.
28
- * - `reused` — it already held one; nothing was minted.
29
- * - `pending_approval` — the pass needs a person. An agent cannot MINT a root
30
- * agreement grant at all: `POST /context/grants` requires the `context:grant`
31
- * operator scope, which a delegate never holds ("no re-mint or grant will
32
- * satisfy this"). So an initiator agent's only route is delegating the
33
- * participation grant it holds — and handing a slice to a third party in
34
- * another org opens a card that owner must approve.
35
- * - `deferred` — the contract itself is not active yet, so there is no
36
- * participation grant to delegate from. Provision again after it activates.
37
- * - `failed` — named so the caller stops rather than kicking off a run whose
38
- * branches will each be refused one at a time.
39
- */
40
- export type GrantProvisionStatus = 'granted' | 'reused' | 'pending_approval' | 'deferred' | 'failed';
41
- export interface StepGrantProvision {
42
- status: GrantProvisionStatus;
43
- grantId?: string;
44
- /** The approval card's agreement id, when a person has to say yes. */
45
- approvalAgreementId?: string;
46
- error?: string;
47
- }
48
- export type ProvisionedRelayStep = RelayPayloadShape['steps'][number] & {
49
- provisionMethod: ProvisionMethod;
50
- status: StepProvisionStatus;
51
- /**
52
- * The coordinator's pass on this step's contract. Handing over an agreement
53
- * id is not enough: membership in work is a grant, and the coordinator is not
54
- * a party to this contract, so nothing about it reaches the coordinator
55
- * otherwise.
56
- */
57
- grant: StepGrantProvision;
58
- };
59
- export interface RelayProvisionDeps {
60
- getMyAgreements: typeof getMyAgreements;
61
- pullOffers: typeof pullOffers;
62
- claimOpenAgreement: typeof claimOpenAgreement;
63
- delegateAgreement: typeof delegateAgreement;
64
- /**
65
- * Grants on one agreement scope. `role` picks which side: `holder` is what
66
- * this initiator holds (the participation grant to delegate FROM), `issuer` is
67
- * what it has already caused (so a re-provision reuses rather than re-mints).
68
- */
69
- listAgreementGrants: (args: {
70
- agreementId: string;
71
- role: 'holder' | 'issuer';
72
- }, creds: Creds) => Promise<GrantView[]>;
73
- delegateAgreementGrant: (args: {
74
- parentGrantId: string;
75
- holderId: string;
76
- agreementId: string;
77
- }, creds: Creds) => Promise<DelegateContextGrantResult>;
78
- }
79
- export interface ProvisionRelayWorkersInput {
80
- creds: Creds;
81
- hireAgreementId: string;
82
- /**
83
- * The coordinator that will create the work. Required, because provisioning a
84
- * worker FOR a coordinator is two acts and this names who the second one is
85
- * for: without an `agreement`-scope grant on each worker contract, the
86
- * coordinator's very first `task_create` is refused with "holds no grant on
87
- * agreement …" and every branch of the run fails the same way.
88
- */
89
- coordinatorId: string;
90
- chatId?: string;
91
- steps: RelayStepInput[];
92
- inputArtifactIds?: string[];
93
- }
94
- export interface ProvisionRelayWorkersResult {
95
- payload: RelayPayloadShape;
96
- steps: ProvisionedRelayStep[];
97
- /**
98
- * Everything a person still has to approve before kickoff — agreement
99
- * activations AND grant hand-overs, in one list. They gate the run
100
- * identically, so splitting them would just make a caller check two.
101
- */
102
- pendingApprovals: string[];
103
- readyForKickoff: boolean;
104
- }
105
- type AgreementWithParent = Agreement & {
106
- parentAgreementId?: string;
107
- };
108
- export declare function findExistingWorkerDelegation(hireAgreementId: string, assigneeId: string, agreements: AgreementWithParent[]): AgreementWithParent | null;
109
- export declare function findOpenOfferForAgent(assigneeId: string, offers: Agreement[]): Agreement | null;
110
- /**
111
- * The default grant plumbing, built on the two clients that own these routes.
112
- *
113
- * A thin function seam rather than the clients themselves, so a test can drive
114
- * provisioning without a backend — the same reason the agreement calls are
115
- * injected.
116
- */
117
- export declare function defaultRelayProvisionDeps(): RelayProvisionDeps;
118
- export declare function provisionRelayWorkers(input: ProvisionRelayWorkersInput, deps?: RelayProvisionDeps): Promise<ProvisionRelayWorkersResult>;
119
- export {};