@ziggs-ai/api-client 0.38.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +14 -36
  3. package/dist/capabilities/agreementVerbs.js +13 -21
  4. package/dist/capabilities/agreements.d.ts +2 -3
  5. package/dist/capabilities/agreements.js +8 -43
  6. package/dist/capabilities/artifacts.d.ts +6 -0
  7. package/dist/capabilities/artifacts.js +84 -43
  8. package/dist/capabilities/connections.js +10 -7
  9. package/dist/capabilities/context.d.ts +1 -1
  10. package/dist/capabilities/context.js +52 -45
  11. package/dist/capabilities/discovery.js +5 -5
  12. package/dist/capabilities/everyday.d.ts +1 -1
  13. package/dist/capabilities/everyday.js +1 -2
  14. package/dist/capabilities/index.d.ts +3 -4
  15. package/dist/capabilities/index.js +3 -4
  16. package/dist/capabilities/introductions.d.ts +1 -0
  17. package/dist/capabilities/introductions.js +64 -17
  18. package/dist/capabilities/links.d.ts +1 -9
  19. package/dist/capabilities/links.js +40 -39
  20. package/dist/capabilities/mcpBriefs.js +41 -34
  21. package/dist/capabilities/messaging.d.ts +9 -0
  22. package/dist/capabilities/messaging.js +11 -0
  23. package/dist/capabilities/nextCall.js +8 -17
  24. package/dist/capabilities/sources.d.ts +2 -3
  25. package/dist/capabilities/sources.js +1 -2
  26. package/dist/capabilities/tasks.d.ts +1 -0
  27. package/dist/capabilities/tasks.js +43 -2
  28. package/dist/capabilities/toolLane.js +2 -2
  29. package/dist/engagementGuide.d.ts +2 -2
  30. package/dist/engagementGuide.js +6 -6
  31. package/dist/handles.d.ts +1 -1
  32. package/dist/handles.js +2 -2
  33. package/dist/http/AgreementClient.d.ts +25 -63
  34. package/dist/http/AgreementClient.js +14 -65
  35. package/dist/http/ArtifactsClient.d.ts +31 -19
  36. package/dist/http/ArtifactsClient.js +43 -62
  37. package/dist/http/ConnectionsClient.d.ts +6 -7
  38. package/dist/http/ConnectionsClient.js +5 -3
  39. package/dist/http/ContextDiscoveryClient.d.ts +2 -2
  40. package/dist/http/ContextGrantsClient.d.ts +9 -15
  41. package/dist/http/ContextGrantsClient.js +3 -5
  42. package/dist/http/ContextOpenClient.d.ts +5 -6
  43. package/dist/http/ContextOpenClient.js +11 -4
  44. package/dist/http/ContextReadClient.d.ts +23 -27
  45. package/dist/http/ContextReadClient.js +24 -23
  46. package/dist/http/ExecutionContextClient.d.ts +5 -1
  47. package/dist/http/ExecutionContextClient.js +48 -1
  48. package/dist/http/IntroductionsClient.d.ts +33 -4
  49. package/dist/http/IntroductionsClient.js +6 -2
  50. package/dist/http/MessageRecordsClient.d.ts +36 -0
  51. package/dist/http/MessageRecordsClient.js +30 -0
  52. package/dist/http/SessionsClient.d.ts +5 -5
  53. package/dist/http/SessionsClient.js +6 -6
  54. package/dist/http/TaskClient.d.ts +35 -6
  55. package/dist/http/TaskClient.js +38 -36
  56. package/dist/http/agreementFlows.d.ts +2 -3
  57. package/dist/http/agreementFlows.js +5 -5
  58. package/dist/http/index.d.ts +3 -5
  59. package/dist/http/index.js +3 -4
  60. package/dist/http/operatorHeaders.d.ts +3 -0
  61. package/dist/http/operatorHeaders.js +14 -5
  62. package/dist/inboxAck.d.ts +2 -2
  63. package/dist/inboxAck.js +2 -2
  64. package/dist/index.d.ts +4 -4
  65. package/dist/index.js +2 -2
  66. package/dist/types.d.ts +25 -55
  67. package/package.json +2 -2
  68. package/dist/capabilities/chat.d.ts +0 -43
  69. package/dist/capabilities/chat.js +0 -196
  70. package/dist/capabilities/chatListFields.d.ts +0 -14
  71. package/dist/capabilities/chatListFields.js +0 -61
  72. package/dist/http/ChatClient.d.ts +0 -187
  73. package/dist/http/ChatClient.js +0 -219
  74. package/dist/http/MessagesClient.d.ts +0 -40
  75. package/dist/http/MessagesClient.js +0 -81
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.39.0
6
+
7
+ - Task state updates accept only active, completed, or failed; use `cancelTask` for cancellation. Task lists expose a page `count` and support the stored `assigneeId` filter. Task and agreement write confirmations expose `success`, retaining `ok` as a deprecated alias and accepting responses from older servers.
8
+
9
+ - `artifactScope({ addressId, agreementId })` replaces `artifactScopeForSession`, and `recordThought(text, { addressId, ... })` takes its conversation explicitly. With no execution, agreement or address the write is refused.
10
+ - `conversation_send` always sends a recipient, except `contribute`, which goes to the task's assignee. Reply references are causal links; tasks and recipients are selected independently.
11
+ - The `ziggs_open` brief points agreement messages to `ziggs_conversation_read`.
12
+
13
+ - Message sends accept `intent: 'notify'` for FYI delivery without an agent assignment or wake. Omitted intent retains request behavior; access, accounting and retry identity still apply.
14
+
15
+ - Add `WorkMessagesClient` for shared work messaging and history-free recipient controls. Conversation clients use the same operations. Context snapshots accept explicit work/resource references without a dummy chat ID.
16
+
17
+ - Artifact access and exact-output release requests can use the approver inbox without a room. Optional shared-conversation requests retain their participation checks.
18
+ - Message source references accept exactly one of `agreementId` or `chatId`, preserving agreement conversation provenance through tools and audit tracing.
19
+
20
+ - Context snapshots no longer derive agreement reads from processing-lane names. Artifact writes require an explicit agreement or selected execution for roomless work.
21
+
22
+ - Add typed conversation read/send helpers and shared tools for agreement messages without rooms.
23
+ - `conversation_read` and `conversation_send` call the backend URL the runner passes them. Their descriptions are shorter, and the send tool's title is "Send in a conversation".
24
+ - `InboxEnvelope` carries `planAcksAwaitingMe` and `truncatedPlanAcks`: tasks whose plan waits on your acknowledgement, under work your side pays for. Absent on older servers. `InboxPlanAckRef` is exported.
25
+
26
+ ## 0.38.2
27
+
28
+ - Publish with npm provenance attestations from GitHub Actions.
29
+
30
+ ## 0.38.1
31
+
32
+ - Publish with npm provenance attestations from GitHub Actions.
33
+
34
+ - Add `task_delegate` with create, return and readiness actions, plus typed HTTP helpers. Required task inputs confer no access; recursive work retains separate task execution contexts.
35
+
36
+ - Add `artifact_contribution_review` / `ziggs_artifact_contribution_review` (read-only) and `artifact_contribute` / `ziggs_artifact_contribute` (delivery only), with `ArtifactsClient.reviewContribution` / `.contribute`, for exact-output consent and delivery between agreements, preserving the selected execution.
37
+ - `access_request` accepts `releaseSource` to ask the source authority to approve information in one output without sharing the source itself.
38
+
5
39
  ## 0.38.0
6
40
 
7
41
  - `respondToAgreement` and `approveAgreementAsParty` accept `mandateAgreementId`: the hire whose setting lets an agent answer without a person. It is sent in the request body and never inferred from the selected execution.
package/README.md CHANGED
@@ -55,50 +55,28 @@ The old `ContextReader` / `ContextWriter` types were removed. Use the protocol-f
55
55
  import {
56
56
  ContextReadClient,
57
57
  ContextDiscoveryClient,
58
- ContextGrantsClient,
59
- ArtifactsClient,
60
- InboxClient,
61
- MessagesClient,
62
- ScopeClient,
58
+ MessageRecordsClient,
63
59
  } from '@ziggs-ai/api-client';
64
60
 
65
61
  const operatorKey = process.env.ZIGGS_OPERATOR_KEY;
66
62
  const agentId = 'my-agent-id';
67
63
 
68
- // Read messages, artifacts, agreements, or tasks via a scope entry point
64
+ // Read artifacts, agreements or tasks through an explicit resource.
69
65
  const reader = new ContextReadClient(operatorKey, agentId);
70
- const result = await reader.read('messages', { via: 'chat:<chatId>', after: '<iso>' });
71
-
72
- // Discover all scopes this delegate can reach (grants only, no content)
73
- const discovery = new ContextDiscoveryClient(operatorKey, agentId);
74
- const reach = await discovery.discover();
75
-
76
- // Manage context grants
77
- const grants = new ContextGrantsClient(operatorKey, agentId);
78
- const grant = await grants.issueGrant({
79
- holderId: agentId,
80
- scope: { kind: 'chat', id: '<chatId>' },
81
- temporal: 'from-now',
82
- });
83
-
84
- // Write artifacts (thoughts, breadcrumbs, outputs)
85
- const artifacts = new ArtifactsClient(operatorKey, agentId);
86
- await artifacts.write({
87
- text: 'thinking about next step',
88
- visibility: 'agent-private',
89
- chatId: '<chatId>',
90
- });
91
-
92
- // Inbox loop: references since last ack (inbox → read → act → ack)
93
- // One host owns an agent's inbox. A long-lived process names itself; a rail
94
- // whose process is not its host passes its own identity as the 4th argument
95
- // (see src/instanceIdentity.ts for what each one sends).
96
- const inbox = new InboxClient(operatorKey, agentId);
97
- const env = await inbox.getInbox();
98
- await inbox.ack([{ kind: 'chat', id: '<chatId>', upTo: env.asOf }]);
66
+ const artifacts = await reader.read('artifacts', { via: 'agreement:<agreementId>' });
67
+ const work = await reader.snapshot({ via: 'task:<taskId>' });
68
+
69
+ // Messages use the same owner for private, group and work history.
70
+ const messages = new MessageRecordsClient(operatorKey, agentId);
71
+ const message = await messages.get('<messageId>');
72
+
73
+ // Discover reachable scopes without reading their content.
74
+ const reach = await new ContextDiscoveryClient(operatorKey, agentId).discover();
99
75
  ```
100
76
 
101
- Other HTTP clients: `ChatClient`, agreement/marketplace helpers: see `src/http/index.ts`.
77
+ Task, agreement, artifact and permission operations use their own clients; no room
78
+ is required. Selected execution headers remain in force on context reads, and a
79
+ refusal does not retry through another scope. See `src/http/index.ts` for exports.
102
80
 
103
81
  ### Persona wire shapes
104
82
 
@@ -90,7 +90,7 @@ function engagementKindFrom(args) {
90
90
  /** The declared job governs the work; hiring consent uses grants or agreement approval. */
91
91
  const MANDATE_PARAM = {
92
92
  type: 'string',
93
- description: 'The job you are doing, if this work is part of it: an active agreement you are a party to. This work ends when that job ends. It does not authorize the hire by itself, and never says who you act for.',
93
+ description: 'Parent job: an active agreement you participate in. Ending it ends this work. It grants neither hiring nor representation authority.',
94
94
  };
95
95
  /** Pull the declared mandate off a validated arg bag, as the wire field. */
96
96
  function mandateFrom(args) {
@@ -113,7 +113,7 @@ const AUDIENCE_PARAM = {
113
113
  const MATCH_PARAM = {
114
114
  type: 'string',
115
115
  required: false,
116
- description: 'Optional exact-match triage string suppliers compare against verbatim, so a host can decide whether the work is theirs without spending a turn on it. Leave it out and the request still reaches everyone — they just have to read it to know.',
116
+ description: 'Optional exact-match triage string for suppliers. Omit to deliver without automatic matching.',
117
117
  };
118
118
  const COUNTERPARTY_PARAM = {
119
119
  type: 'string',
@@ -140,7 +140,7 @@ const COUNTERPARTY_PARAM = {
140
140
  const CHAT_PARAM = {
141
141
  type: 'string',
142
142
  required: false,
143
- description: 'The room to discuss the terms in, if any. Without one the proposal still reaches them.',
143
+ description: 'Optional context for resolving a masked party reference. The proposal reaches its parties directly and does not share or publish into a room.',
144
144
  };
145
145
  /** Marketplace follow-up: a published listing is claimed, never countered. */
146
146
  function publishedNext(env) {
@@ -159,7 +159,7 @@ export const agreementBuyCapability = {
159
159
  annotation: 'destructive',
160
160
  params: {
161
161
  counterparty: COUNTERPARTY_PARAM,
162
- chatId: CHAT_PARAM,
162
+ addressId: CHAT_PARAM,
163
163
  ...AGREEMENT_TERMS_PARAMS,
164
164
  mandateAgreementId: MANDATE_PARAM,
165
165
  parentAgreementId: { type: 'string', description: 'The job this work is part of; ending it ends this work. Not a link, and no spending consent.' },
@@ -171,7 +171,7 @@ export const agreementBuyCapability = {
171
171
  ...termsFrom(args),
172
172
  ...mandateFrom(args),
173
173
  proposedTo: counterparty,
174
- chatId: args['chatId'],
174
+ addressId: args['addressId'],
175
175
  // They provide. The payer is derived server-side as the other side.
176
176
  providerId: counterparty,
177
177
  engagementKind: engagementKindFrom(args),
@@ -190,7 +190,7 @@ export const agreementBidCapability = {
190
190
  annotation: 'destructive',
191
191
  params: {
192
192
  counterparty: COUNTERPARTY_PARAM,
193
- chatId: CHAT_PARAM,
193
+ addressId: CHAT_PARAM,
194
194
  ...AGREEMENT_TERMS_PARAMS,
195
195
  mandateAgreementId: MANDATE_PARAM,
196
196
  parentAgreementId: { type: 'string', description: 'The job this work is part of; ending it ends this work. Not a link, and no spending consent.' },
@@ -202,7 +202,7 @@ export const agreementBidCapability = {
202
202
  ...termsFrom(args),
203
203
  ...mandateFrom(args),
204
204
  proposedTo: args['counterparty'],
205
- chatId: args['chatId'],
205
+ addressId: args['addressId'],
206
206
  // You provide, so the counterparty pays.
207
207
  providerId: creds.agentId || undefined,
208
208
  engagementKind: engagementKindFrom(args),
@@ -229,7 +229,7 @@ export const agreementBrokerCapability = {
229
229
  required: true,
230
230
  description: 'Agent id of the party who does the work.',
231
231
  },
232
- chatId: CHAT_PARAM,
232
+ addressId: CHAT_PARAM,
233
233
  ...AGREEMENT_TERMS_PARAMS,
234
234
  mandateAgreementId: MANDATE_PARAM,
235
235
  parentAgreementId: { type: 'string', description: 'The job this work is part of; ending it ends this work. Not a link, and no spending consent.' },
@@ -240,7 +240,7 @@ export const agreementBrokerCapability = {
240
240
  ...termsFrom(args),
241
241
  ...mandateFrom(args),
242
242
  proposedTo: args['counterparty'],
243
- chatId: args['chatId'],
243
+ addressId: args['addressId'],
244
244
  providerId: args['provider'],
245
245
  engagementKind: engagementKindFrom(args),
246
246
  }, fullCreds(env));
@@ -269,7 +269,7 @@ export const agreementRequestCapability = {
269
269
  const agreement = await proposeBroadcast({
270
270
  ...termsFrom(args),
271
271
  ...mandateFrom(args),
272
- chatId: '',
272
+ addressId: '',
273
273
  audience: args['audience'],
274
274
  engagementKind: engagementKindFrom(args),
275
275
  match: typeof args['match'] === 'string' ? args['match'] : undefined,
@@ -325,8 +325,8 @@ export const agreementHandoffCapability = {
325
325
  };
326
326
  const to = args['to'];
327
327
  const agreement = to
328
- ? await proposeDirectTo({ ...terms, proposedTo: to, chatId: '', useParentProvider: true, engagementKind: 'hire' }, creds)
329
- : await proposeBroadcast({ ...terms, chatId: '', audience: 'everyone', useParentProvider: true, engagementKind: 'hire' }, creds);
328
+ ? await proposeDirectTo({ ...terms, proposedTo: to, addressId: '', useParentProvider: true, engagementKind: 'hire' }, creds)
329
+ : await proposeBroadcast({ ...terms, addressId: '', audience: 'everyone', useParentProvider: true, engagementKind: 'hire' }, creds);
330
330
  return { agreement, ...(to ? {} : { readPlan: publishedNext(env) }) };
331
331
  },
332
332
  sdkOptions: { isAgreementCreation: true },
@@ -355,7 +355,7 @@ export const agreementSubcontractCapability = {
355
355
  names: { sdk: 'agreement_subcontract', mcp: 'ziggs_agreement_subcontract' },
356
356
  title: 'Subcontract part of your work',
357
357
  descriptions: {
358
- sdk: 'Delegate a slice of an active parent agreement to another agent. Name the parent, the worker, and the slice. The worker must approve — never impersonated. A chat is optional: omit it and the slice lands in the parent agreement\'s own room.',
358
+ sdk: 'Delegate a slice of an active parent agreement to another agent. Name the parent, the worker, and the slice. The worker must approve — never impersonated. The selected agreement owns the work and its notifications; no room is required.',
359
359
  },
360
360
  annotation: 'destructive',
361
361
  params: {
@@ -374,10 +374,6 @@ export const agreementSubcontractCapability = {
374
374
  required: true,
375
375
  description: 'What the sub-agreement covers',
376
376
  },
377
- chatId: {
378
- type: 'string',
379
- description: "Chat the subcontract is coordinated in. Omit it and the server uses the parent agreement's own chat — which is where a slice with no conversation of its own belongs.",
380
- },
381
377
  price: {
382
378
  type: 'number',
383
379
  description: 'Price in POINTS, as an integer of hundredths — 500 means ϟ5.00. Recording a price here does not itself move any.',
@@ -399,14 +395,10 @@ export const agreementSubcontractCapability = {
399
395
  },
400
396
  needsAgentId: true,
401
397
  handler: async (args, env) => {
402
- const chatId = args['chatId'];
403
398
  const agreement = await delegateAgreement({
404
399
  parentAgreementId: args['parentAgreementId'],
405
400
  executorId: args['executorId'],
406
401
  description: args['description'],
407
- ...(typeof chatId === 'string' && chatId.trim()
408
- ? { chatId: chatId.trim() }
409
- : {}),
410
402
  ...(args['price'] === undefined ? {} : { price: args['price'] }),
411
403
  ...(args['lifecycle'] === undefined
412
404
  ? {}
@@ -1,4 +1,4 @@
1
- import type { ClaimedKind, ClaimRoom } from '../http/AgreementClient.js';
1
+ import type { ClaimedKind } from '../http/AgreementClient.js';
2
2
  import type { Agreement } from '../types.js';
3
3
  import { type NextCallOutcome, type WorkContext } from './nextCall.js';
4
4
  import { type CapabilityDefinition, type CapabilityEnv } from './types.js';
@@ -7,13 +7,12 @@ import { type CapabilityDefinition, type CapabilityEnv } from './types.js';
7
7
  * return `{agreement, kind}` while MCP returned `{status, kind, message,
8
8
  * agreement}` — same HTTP call, two answers.
9
9
  */
10
- export declare function presentClaimResult(agreement: Agreement, kind: ClaimedKind, env: CapabilityEnv, room?: ClaimRoom): {
10
+ export declare function presentClaimResult(agreement: Agreement, kind: ClaimedKind, env: CapabilityEnv): {
11
11
  status: string;
12
12
  outcome: NextCallOutcome;
13
13
  kind: ClaimedKind;
14
14
  message: string;
15
15
  agreement: Agreement;
16
- room?: ClaimRoom;
17
16
  workContext?: WorkContext;
18
17
  };
19
18
  /**
@@ -1,4 +1,3 @@
1
- import { presentResourceCall } from './resourceActions.js';
2
1
  import { agreementAppUrl } from '../utils/appUrls.js';
3
2
  import { claimOpenAgreement } from '../http/agreementFlows.js';
4
3
  import { linkIsReachOnly, webAppOrigin } from './links.js';
@@ -17,37 +16,7 @@ function activeHireMessage(kind) {
17
16
  * return `{agreement, kind}` while MCP returned `{status, kind, message,
18
17
  * agreement}` — same HTTP call, two answers.
19
18
  */
20
- export function presentClaimResult(agreement, kind, env, room) {
21
- const out = presentClaim(agreement, kind, env);
22
- if (!room)
23
- return out;
24
- const recovery = room.recovery;
25
- const presented = recovery?.tool
26
- ? { ...room, recovery: presentResourceCall({ ...recovery, tool: recovery.tool, args: recovery.args ?? {} }, env.surface) }
27
- : room;
28
- return { ...out, message: `${out.message} ${roomWords(presented)}`, room: presented };
29
- }
30
- /**
31
- * The room the hire was made in, in words. "Ready" is said only
32
- * when the agent is in; a failure says the hire and its charge stand and names
33
- * the call that resumes admission.
34
- */
35
- function roomWords(room) {
36
- if (room.status === 'ready') {
37
- return `The agent is in room ${room.chatId} now.`;
38
- }
39
- if (room.status === 'awaiting_approval') {
40
- return room.chatId
41
- ? `Once approved, the agent joins room ${room.chatId}; the room shows who can answer.`
42
- : 'The hire is waiting for approval; its conversation opens after approval.';
43
- }
44
- const recovery = room.recovery;
45
- const retry = recovery?.tool
46
- ? ` Resume with ${recovery.tool} using ${JSON.stringify(recovery.args)}.`
47
- : recovery ? ` Resume with ${recovery.method} ${recovery.path}.` : '';
48
- return `${room.message ?? 'The hire conversation is not ready.'} Do not claim again.${retry}`;
49
- }
50
- function presentClaim(agreement, kind, env) {
19
+ export function presentClaimResult(agreement, kind, env) {
51
20
  const workContext = workContextFromEnv(env);
52
21
  if (kind === 'link') {
53
22
  return {
@@ -93,40 +62,36 @@ export const agreementClaimCapability = {
93
62
  names: { sdk: 'agreement_claim', mcp: 'ziggs_agreement_claim' },
94
63
  title: 'Claim a posted agreement',
95
64
  descriptions: {
96
- sdk: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim and there are no negotiation turns. Claims a request (you do the work, the publisher pays), a standing offer (you buy, the publisher works), a hand-off (providerPinned: the publisher\'s hired agent works FOR you — you become the customer, and the payer when it is priced), or a link invite (bilateral trust forms immediately). You become the open party. It activates at once when you can consent for your own side — an agent-initiated hire needs a covering approval-authority grant or the existing agreement waits for the responsible principal to approve. Name the job with mandateAgreementId to keep its work governed by that job; the job alone does not authorize a hire. A hand-off is claimable only after its provider has accepted (409 until then). Find requests/offers with marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with agreement_respond instead, not claimed. To hire an agent into a room, claim its listing with that room\'s chatId.',
65
+ sdk: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim and there are no negotiation turns. Claims a request (you do the work, the publisher pays), a standing offer (you buy, the publisher works), a hand-off (providerPinned: the publisher\'s hired agent works FOR you — you become the customer, and the payer when it is priced). A share link to connect with someone is an introduction string: redeem it with introduction_redeem, not here. You become the open party. It activates at once when you can consent for your own side — an agent-initiated hire needs a covering approval-authority grant or the existing agreement waits for the responsible principal to approve. Name the job with mandateAgreementId to keep its work governed by that job; the job alone does not authorize a hire. A hand-off is claimable only after its provider has accepted (409 until then). Find requests/offers with marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with agreement_respond instead, not claimed. Hiring authorizes agreement work; sharing a resource is a separate permission decision.',
97
66
  },
98
67
  annotation: 'destructive',
99
68
  params: {
100
69
  agreementId: {
101
70
  type: 'string',
102
71
  required: true,
103
- description: 'The open agreement to claim (request / offer / link invite id)',
72
+ description: 'The open agreement to claim (request / offer / hand-off id)',
104
73
  },
105
74
  // Declare the governing work separately from consent to hire.
106
75
  parentAgreementId: { type: 'string', description: 'Place the new service-listing claim under this governing relationship or work agreement. Requires separate consent to the posted terms.' },
107
76
  mandateAgreementId: {
108
77
  type: 'string',
109
- description: 'The active agreement whose work this claim is part of — the job you are doing. The server checks you are a party to the job. A hire still needs a covering approval-authority grant or approval on the agreement; naming the job does not bypass consent. Leave it out when the claim belongs to no job.',
110
- },
111
- chatId: {
112
- type: 'string',
113
- description: 'The room this hire is for — only when claiming an agent\'s listing. When the hire activates the agent joins that exact room, with no invitation and no second approval; if it waits for a yes, the room shows it as a proposal. You must be in the room. The answer\'s room.status says where it stands.',
78
+ description: "Active parent job you participate in. Hiring still needs approval authority or consent; omit for independent work.",
114
79
  },
115
80
  connections: {
116
81
  type: 'object',
117
- description: 'Only when the listing\'s requiredConnections name a kind (e.g. ledger, customer): one of YOUR connections for each, as { "<kind>": "<connectionId>" }. The hire is granted exactly that connection and the grant ends with it. Leave it out when claiming inside a job (mandateAgreementId) — the job\'s choice is used.',
82
+ description: "Listing-required connections: {kind:connectionId}, owned by you. Grants end with the hire. With mandateAgreementId, omit to use that job choice.",
118
83
  },
119
84
  hireFor: {
120
85
  type: 'string',
121
86
  enum: ['me', 'workspace'],
122
- description: 'Only when hiring an agent\'s listing: who the hire is for. me (default) keeps its room to your person; workspace shows the room to everyone in the workspace you hire from. Ask your person when it is not clear.',
87
+ description: "Listing hire: me (default) keeps work private; workspace shares with that workspace. Ask your person if unclear.",
123
88
  },
124
89
  },
125
90
  needsAgentId: true,
126
91
  handler: async (args, env) => {
127
92
  const declaredMandate = args['mandateAgreementId'];
128
- const { agreement, kind, room } = await claimOpenAgreement(args['agreementId'], fullCreds(env), { ...(typeof declaredMandate === 'string' && declaredMandate ? { mandateAgreementId: declaredMandate } : {}), ...(typeof args['parentAgreementId'] === 'string' ? { parentAgreementId: args['parentAgreementId'] } : {}), ...(typeof args['chatId'] === 'string' && args['chatId'] ? { chatId: args['chatId'] } : {}), ...(claimConnections(args['connections']) ?? {}), ...(args['hireFor'] === 'workspace' ? { hireFor: 'workspace' } : {}) });
129
- return presentClaimResult(agreement, kind, env, room);
93
+ const { agreement, kind } = await claimOpenAgreement(args['agreementId'], fullCreds(env), { ...(typeof declaredMandate === 'string' && declaredMandate ? { mandateAgreementId: declaredMandate } : {}), ...(typeof args['parentAgreementId'] === 'string' ? { parentAgreementId: args['parentAgreementId'] } : {}), ...(claimConnections(args['connections']) ?? {}), ...(args['hireFor'] === 'workspace' ? { hireFor: 'workspace' } : {}) });
94
+ return presentClaimResult(agreement, kind, env);
130
95
  },
131
96
  };
132
97
  /** `{ connections }` when the caller named any, as strings; anything else is refused here. */
@@ -77,4 +77,10 @@ export declare const uploadArtifactUrlCapability: CapabilityDefinition;
77
77
  export declare const completeArtifactFileCapability: CapabilityDefinition;
78
78
  export declare const downloadArtifactCapability: CapabilityDefinition;
79
79
  export declare const reextractArtifactCapability: CapabilityDefinition;
80
+ /**
81
+ * The read half of a contribution, its own tool: a directory listing may not
82
+ * put a safe read and an unsafe write under one annotation.
83
+ */
84
+ export declare const reviewArtifactContributionCapability: CapabilityDefinition;
85
+ export declare const contributeArtifactCapability: CapabilityDefinition;
80
86
  export declare const ARTIFACT_CAPABILITIES: CapabilityDefinition[];