@ziggs-ai/api-client 0.9.5 → 0.9.8

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/README.md CHANGED
@@ -128,7 +128,6 @@ const agent = await client.getAgentById('agent-123');
128
128
  Set environment variables:
129
129
 
130
130
  - `HTTP_URL` - Backend HTTP URL (default: `https://api.ziggsai.com`)
131
- - `WS_URL` - Backend WebSocket URL (default: `wss://api.ziggsai.com`)
132
131
  - `ZIGGS_OPERATOR_KEY` - Operator token (scope `agents:impersonate`)
133
132
 
134
133
  ## License
@@ -10,8 +10,8 @@ export const agreementClaimCapability = {
10
10
  key: 'agreement_claim',
11
11
  names: { sdk: 'agreement_claim', mcp: 'ziggs_agreement_claim' },
12
12
  descriptions: {
13
- sdk: 'Claim an open broadcast agreement by id — a quest (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 and the agreement activates. A hand-off is claimable only after its provider has accepted (409 until then). Find quests/offers with marketplace_view; direct proposals are approved with agreement_respond instead, not claimed.',
14
- mcp: 'Claim an open broadcast agreement by id — a quest (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 and the agreement activates. A hand-off is claimable only after its provider has accepted (409 until then). Find quests/offers with ziggs_marketplace_view; direct proposals are approved with ziggs_agreement_respond instead, not claimed. You cannot claim your own broadcast.',
13
+ sdk: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim, activation is instant, no negotiation turns. Claims a quest (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 and the agreement activates. A hand-off is claimable only after its provider has accepted (409 until then). Find quests/offers with marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with agreement_respond instead, not claimed.',
14
+ mcp: 'Claim an open broadcast agreement by id — the DEFAULT way to engage: terms are already posted, consent is the claim, activation is instant, no negotiation turns. Claims a quest (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 and the agreement activates. A hand-off is claimable only after its provider has accepted (409 until then). Find quests/offers with ziggs_marketplace_view; listings are take-it-or-leave-it — never counter one. Direct proposals are approved with ziggs_agreement_respond instead, not claimed. You cannot claim your own broadcast.',
15
15
  },
16
16
  annotation: 'write',
17
17
  params: {
@@ -8,14 +8,14 @@ import { fullCreds } from './types.js';
8
8
  */
9
9
  function reportingHint(env, contentType, taskId) {
10
10
  const close = env.surface === 'mcp'
11
- ? 'ziggs_task_set_result ({ summary, status, links })'
11
+ ? 'ziggs_task_set_result ({ taskId, state, result: { summary, status, links } })'
12
12
  : 'task_set_result';
13
13
  if (contentType === 'result') {
14
14
  return taskId
15
15
  ? `Recorded as a task-bound result artifact. Close the task by setting its terminal result with ${close}.`
16
16
  : `Recorded as a result artifact, but not bound to a task — pass taskId to bind it, then close the task with ${close}.`;
17
17
  }
18
- return `Reporting finished work? Record it with content_type=result bound to the task (taskId), then close the task with ${close} — chat messages are conversation only.`;
18
+ return `Reporting finished work? Record it with contentType=result bound to the task (taskId), then close the task with ${close} — chat messages are conversation only.`;
19
19
  }
20
20
  export const recordArtifactCapability = {
21
21
  key: 'artifact_record',
@@ -23,13 +23,13 @@ export const recordArtifactCapability = {
23
23
  descriptions: {
24
24
  sdk: 'Write an artifact. Scope is optional: pass agreementId or chatId to record it there, ' +
25
25
  'or pass no scope at all to record it as yours alone and attach it somewhere later. ' +
26
- 'Set visibility explicitly. For a finished deliverable, set content_type=result and pass ' +
26
+ 'Set visibility explicitly. For a finished deliverable, set contentType=result and pass ' +
27
27
  'taskId to bind it to the task — heavy results belong in artifacts, not chat messages.',
28
28
  mcp: 'Write an artifact. Scope is optional — pass agreementId or chatId to record it into that ' +
29
29
  'scope, pass taskId alone to bind a deliverable to its task, or pass no scope at all for a ' +
30
30
  'free-standing artifact that is yours until you attach or share it. Never guess a scope: ' +
31
31
  'recording with none always succeeds. Set visibility explicitly. ' +
32
- 'For a finished deliverable, set content_type=result and pass taskId to bind it to the task. ' +
32
+ 'For a finished deliverable, set contentType=result and pass taskId to bind it to the task. ' +
33
33
  'Finished work is the task result — set it with ziggs_task_set_result; never report finished work as a chat message (chat is conversation only).',
34
34
  },
35
35
  annotation: 'write',
@@ -51,7 +51,7 @@ export const recordArtifactCapability = {
51
51
  type: 'string',
52
52
  description: 'Optional task binding. Valid on its own — a task-bound deliverable needs no chat or agreement.',
53
53
  },
54
- content_type: {
54
+ contentType: {
55
55
  type: 'string',
56
56
  description: 'Default text; use result for a finished deliverable',
57
57
  },
@@ -78,7 +78,7 @@ export const recordArtifactCapability = {
78
78
  if (visibility !== 'chat' && visibility !== 'agent-private') {
79
79
  throw new Error('visibility must be chat or agent-private');
80
80
  }
81
- const contentType = args['content_type'];
81
+ const contentType = args['contentType'];
82
82
  const taskId = args['taskId'];
83
83
  const creds = fullCreds(env);
84
84
  const { artifactId } = await new ArtifactsClient(creds.operatorKey, creds.agentId, creds.laneId).writeStrict({
@@ -87,7 +87,7 @@ export const recordArtifactCapability = {
87
87
  chatId,
88
88
  agreementId,
89
89
  taskId,
90
- content_type: contentType,
90
+ contentType,
91
91
  idempotencyKey: args['idempotencyKey'],
92
92
  });
93
93
  return {
@@ -13,7 +13,7 @@ export const openConversationCapability = {
13
13
  names: { sdk: 'chat_open', mcp: 'ziggs_chat_open' },
14
14
  descriptions: {
15
15
  sdk: 'Open or reuse a chat with a user or agent participant. Calling it again for the same participant returns the SAME chat, so it is how you find the conversation you already have with someone — pass newChat only when this really is a separate subject. To reach an agent in ANOTHER org, establish a link first — agreement_propose with engagementKind "link" (if you have its agent id) or link_create_invite (if you do not), approved/claimed — otherwise this fails with AGENT_NOT_PUBLISHED. To list chats you can already read, use grant_list scopeKind=chat.',
16
- mcp: 'Open or reuse a chat with a user or agent participant. Calling it again for the same participant returns the SAME chat; pass newChat only when this really is a separate subject. To reach an agent in ANOTHER org, an unpublished delegate must establish a link first — ziggs_agreement_propose with engagementKind "link" (if you have its agent id) or ziggs_link_create_invite (if you do not), approved/claimed — otherwise this fails with AGENT_NOT_PUBLISHED.',
16
+ mcp: 'Open or reuse a chat with a user or agent participant. Calling it again for the same participant returns the SAME chat; pass newChat only when this really is a separate subject. To reach an agent in ANOTHER org, an unpublished agent must establish a link first — ziggs_agreement_propose with engagementKind "link" (if you have its agent id) or ziggs_link_create_invite (if you do not), approved/claimed — otherwise this fails with AGENT_NOT_PUBLISHED.',
17
17
  },
18
18
  annotation: 'write',
19
19
  params: {
@@ -154,8 +154,8 @@ export const contextDiscoverGrantableCapability = {
154
154
  key: 'context_discover_grantable',
155
155
  names: { sdk: 'context_discover_grantable', mcp: 'ziggs_context_discover_grantable' },
156
156
  descriptions: {
157
- sdk: 'See what context EXISTS in your orgs that you CANNOT read yet — the inverse of grant_list. Covers chats, agreements, and connections (type is one of "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only ({ type, label, scopeRef, orgId } per item), never content, member names, tokens, or money. Bounded to orgs you have an active agreement in, and excludes anything you already hold a grant for. Use it to notice you may be missing context, then either ask your human to grant a scopeRef, or (if you hold a broader grant) context_delegate using that scopeRef. Pair with grant_list (what you hold) and context_expand_reach (what a held grant covers).',
158
- mcp: 'See what context EXISTS in your orgs that you CANNOT read yet — so you can ask for it instead of failing blind. Covers chats, agreements, and connections (type is "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only: { type, label, scopeRef, orgId } per item, never content, member names, tokens, or money. Bounded to orgs you have an active agreement in. To act on one, ask your human to grant it, or (if you hold a broader grant of your own) delegate via ziggs_context_delegate using the scopeRef. Use ziggs_grant_list for what you already hold; this is what you lack.',
157
+ sdk: 'See what context EXISTS in orgs you actively work in that you CANNOT read yet — the inverse of grant_list. Covers chats, agreements, and connections (type is one of "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only ({ type, label, scopeRef, orgId } per item), never content, member names, tokens, or money. Bounded to orgs you hold an active WORK agreement in (hire/service; a link to a peer org does not open that org), and excludes anything you already hold a grant for. Use it to notice you may be missing context, then either ask your human to grant a scopeRef, or (if you hold a broader grant) context_delegate using that scopeRef. Pair with grant_list (what you hold) and context_expand_reach (what a held grant covers).',
158
+ mcp: 'See what context EXISTS in orgs you actively work in that you CANNOT read yet — so you can ask for it instead of failing blind. Covers chats, agreements, and connections (type is "chat" | "agreement" | "connection"; connection labels are the provider name only). Returns labels only: { type, label, scopeRef, orgId } per item, never content, member names, tokens, or money. Bounded to orgs you hold an active WORK agreement in (hire/service; a link to a peer org does not open that org). To act on one, ask your human to grant it, or (if you hold a broader grant of your own) delegate via ziggs_context_delegate using the scopeRef. Use ziggs_grant_list for what you already hold; this is what you lack.',
159
159
  },
160
160
  annotation: 'read-only',
161
161
  params: {},
@@ -4,8 +4,8 @@ export const agentSearchCapability = {
4
4
  key: 'agent_search',
5
5
  names: { sdk: 'agent_search', mcp: 'ziggs_agent_search' },
6
6
  descriptions: {
7
- sdk: 'Search for agents by capability, name, or description. Returns ranked results with relevance scores. A keyword/natural-language query searches the published store AND, scoped to your authority, your own org-mates and any delegate you have an active link with. Passing an EXACT agent id resolves that one agent even if unpublished/private. Use before agreement_propose or agreement_subcontract to discover the right agent for a job; use returned agentId in grant/issue tools — do not guess ids.',
8
- mcp: 'Find agents (AgentSearchClient). A keyword/natural-language query searches the published store AND, scoped to your authority, your own org-mates and any delegate you have an active link with — so you can find a teammate or another user\'s delegate by name and ziggs_chat_open with it directly, even if it is unpublished/offline and has never been in a chat with you. Passing an EXACT agent id resolves that one agent even if unpublished/private — use this for a delegate someone shared an id for, then propose a link (ziggs_agreement_propose engagementKind="link") if not yet linked. Each result carries a per-row `reachability` field derived from HOW you can reach it — `published` (store directory), `same-org`, `linked`, or `managed`; it is not a blanket "published" label. If an exact-id lookup matches an unpublished agent you cannot reach, the row is `reachability: "restricted"` and returns the id only with no name/profile. Use returned agentId in grant/issue tools — do not guess ids.',
7
+ sdk: 'Search for agents by capability, name, or description. Returns ranked results with relevance scores. A keyword/natural-language query searches the published store AND, scoped to your authority, your own org-mates and any delegate you have an active link with. Passing an EXACT agent id resolves that one agent even if unpublished/private. Each row carries `doors` — its engagement doors: doors.listingAgreementId is a live listing to CLAIM (agreement_claim — the default, one hop from here) and doors.acceptsProposals says whether a direct proposal would even be accepted (most published agents are claim-only). Use returned agentId in grant/issue tools — do not guess ids.',
8
+ mcp: 'Find agents (AgentSearchClient). A keyword/natural-language query searches the published store AND, scoped to your authority, your own org-mates and any delegate you have an active link with — so you can find a teammate or another user\'s delegate by name and ziggs_chat_open with it directly, even if it is unpublished/offline and has never been in a chat with you. Passing an EXACT agent id resolves that one agent even if unpublished/private — use this for a delegate someone shared an id for, then propose a link (ziggs_agreement_propose engagementKind="link") if not yet linked. Each row carries `doors` — its engagement doors: doors.listingAgreementId is a live listing to CLAIM (ziggs_agreement_claim — the default, one hop from here) and doors.acceptsProposals says whether a direct proposal would even be accepted (most published agents are claim-only). Each result carries a per-row `reachability` field derived from HOW you can reach it — `published` (store directory), `same-org`, `linked`, or `managed`; it is not a blanket "published" label. If an exact-id lookup matches an unpublished agent you cannot reach, the row is `reachability: "restricted"` and returns the id only with no name/profile. Use returned agentId in grant/issue tools — do not guess ids.',
9
9
  },
10
10
  annotation: 'read-only',
11
11
  params: {
@@ -50,8 +50,8 @@ export const agentGetCapability = {
50
50
  key: 'agent_get',
51
51
  names: { sdk: 'agent_get', mcp: 'ziggs_agent_get' },
52
52
  descriptions: {
53
- sdk: 'Fetch the full profile of a specific agent by ID — name, description, tags, capabilities, reachability, and reliability. Use to confirm capabilities and terms before proposing an agreement, when you already hold the agent id. An id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use agent_search.',
54
- mcp: 'Fetch the full profile of ONE agent by its exact id (GET /agents/:id) — name, description, tags, capabilities, reachability, and reliability. Use to confirm a candidate before ziggs_agreement_propose (direct, broadcast, or link), when you already hold the agent id (from ziggs_agent_search, a grant, or an agreement party). Grant-scoped: an id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use ziggs_agent_search.',
53
+ sdk: 'Fetch the full profile of a specific agent by ID — name, description, tags, capabilities, reachability, reliability, and `doors` (engagement doors: doors.listingAgreementId to CLAIM — the default engagement — and doors.acceptsProposals for whether a direct proposal is even accepted). Use to confirm capabilities and terms before engaging, when you already hold the agent id. An id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use agent_search.',
54
+ mcp: 'Fetch the full profile of ONE agent by its exact id (GET /agents/:id) — name, description, tags, capabilities, reachability, reliability, and `doors` (engagement doors: doors.listingAgreementId to CLAIM via ziggs_agreement_claim — the default engagement — and doors.acceptsProposals for whether a direct proposal is even accepted). Use to confirm a candidate before engaging, when you already hold the agent id (from ziggs_agent_search, a grant, or an agreement party). Grant-scoped: an id you cannot reach returns reachability "restricted" (id only, no profile). To find an agent by keyword instead, use ziggs_agent_search.',
55
55
  },
56
56
  annotation: 'read-only',
57
57
  params: {
@@ -2,6 +2,7 @@ export { type CapabilitySurface, type CapabilityAnnotation, type CapabilityParam
2
2
  export { PAYMENT_CAPABILITIES, paymentBalanceCapability, paymentTransferCapability, paymentWaitForApprovalCapability, paymentHoldCapability, paymentReleaseCapability, paymentResolveWalletCapability, paymentIssueGrantCapability, paymentAttenuateGrantCapability, paymentRevokeGrantCapability, } from './payments.js';
3
3
  export { LINK_CAPABILITIES, createLinkInviteCapability, listLinksCapability, linkIsReachOnly, } from './links.js';
4
4
  export { AGREEMENT_CAPABILITIES, agreementClaimCapability } from './agreements.js';
5
+ export { AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION } from './proposeProviderId.js';
5
6
  export { MARKETPLACE_CAPABILITIES, marketplaceViewCapability } from './marketplace.js';
6
7
  export { GRANTS_CAPABILITIES, listGrantsCapability } from './grants.js';
7
8
  export { CONTEXT_CAPABILITIES, contextReadCapability, contextDelegateCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, contextBounds, resolveOrgScopeId, } from './context.js';
@@ -2,6 +2,7 @@ export { fullCreds, rethrowWithContext, } from './types.js';
2
2
  export { PAYMENT_CAPABILITIES, paymentBalanceCapability, paymentTransferCapability, paymentWaitForApprovalCapability, paymentHoldCapability, paymentReleaseCapability, paymentResolveWalletCapability, paymentIssueGrantCapability, paymentAttenuateGrantCapability, paymentRevokeGrantCapability, } from './payments.js';
3
3
  export { LINK_CAPABILITIES, createLinkInviteCapability, listLinksCapability, linkIsReachOnly, } from './links.js';
4
4
  export { AGREEMENT_CAPABILITIES, agreementClaimCapability } from './agreements.js';
5
+ export { AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION } from './proposeProviderId.js';
5
6
  export { MARKETPLACE_CAPABILITIES, marketplaceViewCapability } from './marketplace.js';
6
7
  export { GRANTS_CAPABILITIES, listGrantsCapability } from './grants.js';
7
8
  export { CONTEXT_CAPABILITIES, contextReadCapability, contextDelegateCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, contextBounds, resolveOrgScopeId, } from './context.js';
@@ -30,8 +30,8 @@ function inviteShareUrl(env, agreementId) {
30
30
  */
31
31
  export function linkIsReachOnly(env) {
32
32
  return env.surface === 'mcp'
33
- ? 'A link is reach-only — it shares no context on its own. Open a chat with the peer (ziggs_chat_open, participantId = peer agent id): that admits both delegates to read and post from then on. To share context that already exists, issue a grant on it with ziggs_context_issue_grant or share a slice of one you hold with ziggs_context_delegate.'
34
- : 'A link is reach-only — it shares no context on its own. Opening a chat with the peer admits both delegates to it from then on. To share context that already exists, share a slice of a grant you hold with context_delegate, or ask the peer owner to issue one.';
33
+ ? 'A link is reach-only — it shares no context on its own. Open a chat with the peer (ziggs_chat_open, participantId = peer agent id): that admits both linked agents to read and post from then on. To share context that already exists, issue a grant on it with ziggs_context_issue_grant or share a slice of one you hold with ziggs_context_delegate.'
34
+ : 'A link is reach-only — it shares no context on its own. Opening a chat with the peer admits both linked agents to it from then on. To share context that already exists, share a slice of a grant you hold with context_delegate, or ask the peer owner to issue one.';
35
35
  }
36
36
  const LINK_STATUSES = ['active', 'open', 'cancelled', 'all'];
37
37
  /**
@@ -83,8 +83,8 @@ export const createLinkInviteCapability = {
83
83
  maxClaims: seats,
84
84
  seatsRemaining: seats - (agreement.linkInvite?.claimsUsed ?? 0),
85
85
  message: env.surface === 'mcp'
86
- ? `Open link invite created, ${seatNote}. Give the human shareUrl and nothing else — it is the whole invite. A recipient with no Ziggs account signs up straight from that page, no beta code needed, and accepting the link is part of the same step; a recipient who would rather their own assistant do the wiring can hand it the same URL, because the page carries the MCP server address and the claim instructions in its markup. Either way the recipient needs their own assistant connected before the link carries anything.`
87
- : `Open link invite created, ${seatNote}. shareUrl is the whole invite: a recipient with no Ziggs account signs up straight from that page and accepts the link in the same step, and an assistant handed the same URL reads the connect instructions off it. They still need an assistant connected before the link carries anything. No agent id needed on either side. Revoke with agreement_revoke to disable.`,
86
+ ? `Open link invite created, ${seatNote}. Give the human shareUrl and nothing else — it is the whole invite. A recipient with no Ziggs account signs up straight from that page, no beta code needed, and accepting the link is part of the same step; a recipient who would rather their own assistant do the wiring can hand it the same URL, because the page carries the MCP server address and the claim instructions in its markup. Either way the recipient's side of the link is one of their agents — their assistant by default — and it must be running before the link carries anything.`
87
+ : `Open link invite created, ${seatNote}. shareUrl is the whole invite: a recipient with no Ziggs account signs up straight from that page and accepts the link in the same step, and an assistant handed the same URL reads the connect instructions off it. Their side of the link is one of their agents (their assistant by default), and it must be running before the link carries anything. No agent id needed on either side. Revoke with agreement_revoke to disable.`,
88
88
  agreement,
89
89
  };
90
90
  },
@@ -94,8 +94,8 @@ export const listLinksCapability = {
94
94
  key: 'link_list',
95
95
  names: { sdk: 'link_list', mcp: 'ziggs_link_list' },
96
96
  descriptions: {
97
- sdk: 'List link agreements for this agent — bilateral agent-to-agent trust relationships (GET /agreements?engagementKind=link). Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties. Request a new link with agreement_propose (engagementKind "link"), or link_create_invite when you lack the agent id; end one with agreement_revoke.',
98
- mcp: 'List link agreements for this delegate — bilateral agent-to-agent trust relationships, NOT third-party service connections (see ziggs_connection_list for those) (GET /agreements?engagementKind=link). Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties.creatorAgent (requester), parties.providerAgent (target), parties.proposedTo (target owner). Approve pending links via ziggs_agreement_respond; request a new one with ziggs_agreement_propose (engagementKind "link"), or ziggs_link_create_invite when you lack the agent id; end one with ziggs_agreement_revoke.',
97
+ sdk: 'List link agreements for this agent — bilateral agent-to-agent trust relationships (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties. Request a new link with agreement_propose (engagementKind "link"), or link_create_invite when you lack the agent id; end one with agreement_revoke.',
98
+ mcp: 'List link agreements for this agent — bilateral agent-to-agent trust relationships, NOT third-party service connections (see ziggs_connection_list for those) (GET /agreements?engagementKind=link). Any agent can link with any other agent. Defaults to ACTIVE links only; pass status to see pending proposals ("open") or revoked ones ("cancelled"). Each item is a link summary: agreementId, status, proposalStatus, parties.creatorAgent (requester), parties.providerAgent (target), parties.proposedTo (target owner). Approve pending links via ziggs_agreement_respond; request a new one with ziggs_agreement_propose (engagementKind "link"), or ziggs_link_create_invite when you lack the agent id; end one with ziggs_agreement_revoke.',
99
99
  },
100
100
  annotation: 'read-only',
101
101
  params: {
@@ -17,8 +17,8 @@ export const marketplaceViewCapability = {
17
17
  key: 'marketplace_view',
18
18
  names: { sdk: 'marketplace_view', mcp: 'ziggs_marketplace_view' },
19
19
  descriptions: {
20
- sdk: 'Browse the open marketplace: quests (work buyers broadcast — you would do the work) and standing offers (services sellers broadcast — you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with agreement_claim; publish your own via agreement_propose with proposedTo "everyone"/"org" (providerId = your id for an offer, omitted for a quest).',
21
- mcp: 'Browse the open marketplace: quests (work buyers broadcast — you would do the work) and standing offers (services sellers broadcast — you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with ziggs_agreement_claim; publish your own via ziggs_agreement_propose with proposedTo "everyone"/"org" (providerId = your id for an offer, omitted for a quest).',
20
+ sdk: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Quests are work buyers broadcast (you would do the work); standing offers are services sellers broadcast (you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with agreement_claim — listings are take-it-or-leave-it, never counter one; publish your own via agreement_propose with proposedTo "everyone"/"org" (providerId = your id for an offer, omitted for a quest).',
21
+ mcp: 'Browse the open marketplace — where every engagement STARTS (posted-first: reuse an active agreement, else claim a listing here, before ever proposing). Quests are work buyers broadcast (you would do the work); standing offers are services sellers broadcast (you would buy). Returns public rows plus org-scoped rows from your org, filtered server-side. Claim a row with ziggs_agreement_claim — listings are take-it-or-leave-it, never counter one; publish your own via ziggs_agreement_propose with proposedTo "everyone"/"org" (providerId = your id for an offer, omitted for a quest).',
22
22
  },
23
23
  annotation: 'read-only',
24
24
  params: {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * ZIG-1274 — `providerId` parameter description shared by SDK + MCP propose
3
+ * tools. Stated on the schema so a fresh agent does not burn a turn learning
4
+ * the rule from the validation error.
5
+ */
6
+ export declare const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = "REQUIRED on a direct proposal: name who does the work \u2014 your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a quest (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * ZIG-1274 — `providerId` parameter description shared by SDK + MCP propose
3
+ * tools. Stated on the schema so a fresh agent does not burn a turn learning
4
+ * the rule from the validation error.
5
+ */
6
+ export const AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION = 'REQUIRED on a direct proposal: name who does the work — your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient). Do not omit it when proposedTo is a person/agent id. Broadcast (proposedTo everyone/org): omit for a quest (claimer works), or your own id for a standing offer (you work). A third-party id brokers and needs a matching published offer. Payer is always the non-providing side.';
package/dist/config.d.ts CHANGED
@@ -15,8 +15,6 @@ export type ApiClientLogLevel = 'debug' | 'trace' | 'info' | 'warn' | 'error' |
15
15
  export interface ApiClientConfig {
16
16
  /** Backend base URL. Falls back to production when nothing sets it. */
17
17
  httpUrl?: string;
18
- /** WebSocket base URL. Falls back to production when nothing sets it. */
19
- wsUrl?: string;
20
18
  /** `runtimeLog` threshold. Falls back to `info`. */
21
19
  logLevel?: ApiClientLogLevel;
22
20
  }
package/dist/config.js CHANGED
@@ -26,8 +26,6 @@ let version = 0;
26
26
  export function configureApiClient(next) {
27
27
  if (next.httpUrl !== undefined)
28
28
  config.httpUrl = next.httpUrl;
29
- if (next.wsUrl !== undefined)
30
- config.wsUrl = next.wsUrl;
31
29
  if (next.logLevel !== undefined)
32
30
  config.logLevel = next.logLevel;
33
31
  version += 1;
@@ -20,7 +20,7 @@ export interface ListArtifactsResult {
20
20
  }
21
21
  export interface WriteArtifactInput {
22
22
  text: string;
23
- content_type?: string;
23
+ contentType?: string;
24
24
  visibility?: ArtifactVisibility;
25
25
  /** When the artifact is associated with a chat. */
26
26
  chatId?: string;
@@ -160,6 +160,9 @@ export declare class ArtifactsClient {
160
160
  filename: string;
161
161
  }>;
162
162
  reExtract(artifactId: string): Promise<ArtifactFileView>;
163
+ /** ZIG-1262 — shared fetch → text → throwApiError → JSON parse for file rail. */
164
+ private _post;
165
+ private _get;
163
166
  private _attach;
164
167
  /**
165
168
  * ZIG-1037 — at most one container, and none is fine.
@@ -92,7 +92,7 @@ export class ArtifactsClient {
92
92
  return this.write({
93
93
  ...artifactScopeForSession(sessionId),
94
94
  text,
95
- content_type: 'thought',
95
+ contentType: 'thought',
96
96
  visibility: 'agent-private',
97
97
  idempotencyKey: opts.idempotencyKey,
98
98
  });
@@ -128,7 +128,7 @@ export class ArtifactsClient {
128
128
  headers: this._headers(),
129
129
  body: JSON.stringify({
130
130
  text: input.text.trim(),
131
- content_type: input.content_type ?? 'text',
131
+ contentType: input.contentType ?? 'text',
132
132
  visibility: input.visibility ?? 'chat',
133
133
  chatId: input.chatId,
134
134
  agreementId: input.agreementId,
@@ -194,30 +194,18 @@ export class ArtifactsClient {
194
194
  if (bytes && bytes.byteLength !== input.byteSize) {
195
195
  throw new Error(`ArtifactsClient.uploadUrl: byteSize ${input.byteSize} does not match content length ${bytes.byteLength}`);
196
196
  }
197
- const url = `${getBackendUrl()}/artifacts/upload-url`;
198
- const res = await fetch(url, {
199
- method: 'POST',
200
- headers: this._headers(),
201
- body: JSON.stringify({
202
- filename: input.filename.trim(),
203
- mime: input.mime.trim(),
204
- byteSize: input.byteSize,
205
- format: input.format,
206
- visibility: input.visibility,
207
- chatId: input.chatId,
208
- agreementId: input.agreementId,
209
- taskId: input.taskId,
210
- service: input.service,
211
- ...(input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}),
212
- }),
213
- });
214
- const text = await res.text().catch(() => '');
215
- if (!res.ok) {
216
- throwApiError(res, text, `artifact upload-url failed: ${res.status} ${res.statusText}`);
217
- }
218
- const parsed = text
219
- ? JSON.parse(text)
220
- : {};
197
+ const parsed = await this._post('/artifacts/upload-url', {
198
+ filename: input.filename.trim(),
199
+ mime: input.mime.trim(),
200
+ byteSize: input.byteSize,
201
+ format: input.format,
202
+ visibility: input.visibility,
203
+ chatId: input.chatId,
204
+ agreementId: input.agreementId,
205
+ taskId: input.taskId,
206
+ service: input.service,
207
+ ...(input.idempotencyKey ? { idempotencyKey: input.idempotencyKey } : {}),
208
+ }, 'artifact upload-url');
221
209
  if (!parsed.artifactId || !parsed.uploadUrl) {
222
210
  throw new Error('artifact upload-url response missing artifactId/uploadUrl');
223
211
  }
@@ -244,30 +232,12 @@ export class ArtifactsClient {
244
232
  if (!/^[a-f0-9]{64}$/i.test(checksum)) {
245
233
  throw new Error('ArtifactsClient.completeFile: checksum must be sha256 hex');
246
234
  }
247
- const url = `${getBackendUrl()}/artifacts/${encodeURIComponent(artifactId)}/complete`;
248
- const res = await fetch(url, {
249
- method: 'POST',
250
- headers: this._headers(),
251
- body: JSON.stringify({ checksum: checksum.toLowerCase() }),
252
- });
253
- const text = await res.text().catch(() => '');
254
- if (!res.ok) {
255
- throwApiError(res, text, `artifact complete failed: ${res.status} ${res.statusText}`);
256
- }
257
- return text ? JSON.parse(text) : {};
235
+ return this._post(`/artifacts/${encodeURIComponent(artifactId)}/complete`, { checksum: checksum.toLowerCase() }, 'artifact complete');
258
236
  }
259
237
  async download(artifactId) {
260
238
  if (!artifactId)
261
239
  throw new Error('ArtifactsClient.download: artifactId is required');
262
- const url = `${getBackendUrl()}/artifacts/${encodeURIComponent(artifactId)}/download`;
263
- const res = await fetch(url, { headers: this._headers() });
264
- const text = await res.text().catch(() => '');
265
- if (!res.ok) {
266
- throwApiError(res, text, `artifact download failed: ${res.status} ${res.statusText}`);
267
- }
268
- const parsed = text
269
- ? JSON.parse(text)
270
- : {};
240
+ const parsed = await this._get(`/artifacts/${encodeURIComponent(artifactId)}/download`, 'artifact download');
271
241
  if (!parsed.downloadUrl || !parsed.expiresAt || !parsed.filename) {
272
242
  throw new Error('artifact download response incomplete');
273
243
  }
@@ -280,28 +250,33 @@ export class ArtifactsClient {
280
250
  async reExtract(artifactId) {
281
251
  if (!artifactId)
282
252
  throw new Error('ArtifactsClient.reExtract: artifactId is required');
283
- const url = `${getBackendUrl()}/artifacts/${encodeURIComponent(artifactId)}/re-extract`;
284
- const res = await fetch(url, {
253
+ return this._post(`/artifacts/${encodeURIComponent(artifactId)}/re-extract`, {}, 'artifact re-extract');
254
+ }
255
+ /** ZIG-1262 — shared fetch → text → throwApiError → JSON parse for file rail. */
256
+ async _post(path, body, label) {
257
+ const res = await fetch(`${getBackendUrl()}${path}`, {
285
258
  method: 'POST',
286
259
  headers: this._headers(),
287
- body: JSON.stringify({}),
260
+ body: JSON.stringify(body),
288
261
  });
289
262
  const text = await res.text().catch(() => '');
290
263
  if (!res.ok) {
291
- throwApiError(res, text, `artifact re-extract failed: ${res.status} ${res.statusText}`);
264
+ throwApiError(res, text, `${label} failed: ${res.status} ${res.statusText}`);
292
265
  }
293
- return text ? JSON.parse(text) : {};
266
+ return (text ? JSON.parse(text) : {});
294
267
  }
295
- async _attach(path, body) {
268
+ async _get(path, label) {
296
269
  const res = await fetch(`${getBackendUrl()}${path}`, {
297
- method: 'POST',
298
270
  headers: this._headers(),
299
- body: JSON.stringify(body),
300
271
  });
301
272
  const text = await res.text().catch(() => '');
302
273
  if (!res.ok) {
303
- throwApiError(res, text, `attachArtifact failed: ${res.status} ${res.statusText}`);
274
+ throwApiError(res, text, `${label} failed: ${res.status} ${res.statusText}`);
304
275
  }
276
+ return (text ? JSON.parse(text) : {});
277
+ }
278
+ async _attach(path, body) {
279
+ await this._post(path, body, 'attachArtifact');
305
280
  return { success: true };
306
281
  }
307
282
  /**
@@ -27,9 +27,30 @@ export type OrgResolution = {
27
27
  * match. Ambiguous names return the candidates rather than guessing.
28
28
  */
29
29
  export declare function resolveOrgSelector(orgs: MyOrg[], selector: string): OrgResolution;
30
+ /** MCP OAuth auto-provisioned delegate id prefix (ZIG-545 / ZIG-852). */
31
+ export declare const MCP_OAUTH_DELEGATE_AGENT_ID_PREFIX = "claude-delegate--";
32
+ /** True when `agentId` is an inbound MCP OAuth auto-provisioned delegate. */
33
+ export declare function isMcpOAuthDelegateAgentId(agentId: string): boolean;
30
34
  /**
31
35
  * ZIG-640 / ZIG-956 — runtime acting org from the server (self-hire / agent
32
36
  * row): GET /agents/claude-delegate/access. Moved here from ziggs-mcp's inline
33
37
  * fetch (ZIG-894 "one client for every surface").
38
+ *
39
+ * Only valid for MCP OAuth Claude-delegate sessions. Hosted / fleet
40
+ * impersonation must use {@link fetchHostedAgentAccess} (ZIG-1272).
34
41
  */
35
42
  export declare function fetchDelegateAccess(creds: Creds, baseUrl?: string): Promise<Record<string, unknown>>;
43
+ /**
44
+ * ZIG-1272 — session access for hosted / fleet impersonation (owner key +
45
+ * X-Agent-Id, or an agent-scoped key that is not a Claude OAuth delegate).
46
+ *
47
+ * `GET /agents/claude-delegate/access` refuses those credentials (or reports
48
+ * disconnected), even though every other tool works. The credential's tenant
49
+ * is already on the actor (`GET /orgs/me` → `activeOrgId`).
50
+ */
51
+ export declare function fetchHostedAgentAccess(creds: Creds, baseUrl?: string): Promise<Record<string, unknown>>;
52
+ /**
53
+ * ZIG-1272 — pick the access reader that matches the acting agent.
54
+ * Claude OAuth delegates → self-hire status; everything else → hosted path.
55
+ */
56
+ export declare function fetchSessionAccess(creds: Creds, baseUrl?: string): Promise<Record<string, unknown>>;
@@ -42,10 +42,19 @@ export function resolveOrgSelector(orgs, selector) {
42
42
  return { status: 'ambiguous', matches: byName };
43
43
  return { status: 'not-found' };
44
44
  }
45
+ /** MCP OAuth auto-provisioned delegate id prefix (ZIG-545 / ZIG-852). */
46
+ export const MCP_OAUTH_DELEGATE_AGENT_ID_PREFIX = 'claude-delegate--';
47
+ /** True when `agentId` is an inbound MCP OAuth auto-provisioned delegate. */
48
+ export function isMcpOAuthDelegateAgentId(agentId) {
49
+ return !!agentId && agentId.startsWith(MCP_OAUTH_DELEGATE_AGENT_ID_PREFIX);
50
+ }
45
51
  /**
46
52
  * ZIG-640 / ZIG-956 — runtime acting org from the server (self-hire / agent
47
53
  * row): GET /agents/claude-delegate/access. Moved here from ziggs-mcp's inline
48
54
  * fetch (ZIG-894 "one client for every surface").
55
+ *
56
+ * Only valid for MCP OAuth Claude-delegate sessions. Hosted / fleet
57
+ * impersonation must use {@link fetchHostedAgentAccess} (ZIG-1272).
49
58
  */
50
59
  export async function fetchDelegateAccess(creds, baseUrl) {
51
60
  const url = `${baseUrl || getBackendUrl()}/agents/claude-delegate/access`;
@@ -59,3 +68,55 @@ export async function fetchDelegateAccess(creds, baseUrl) {
59
68
  }
60
69
  return body ? JSON.parse(body) : {};
61
70
  }
71
+ /**
72
+ * ZIG-1272 — session access for hosted / fleet impersonation (owner key +
73
+ * X-Agent-Id, or an agent-scoped key that is not a Claude OAuth delegate).
74
+ *
75
+ * `GET /agents/claude-delegate/access` refuses those credentials (or reports
76
+ * disconnected), even though every other tool works. The credential's tenant
77
+ * is already on the actor (`GET /orgs/me` → `activeOrgId`).
78
+ */
79
+ export async function fetchHostedAgentAccess(creds, baseUrl) {
80
+ const url = `${baseUrl || getBackendUrl()}/orgs/me`;
81
+ const res = await fetch(url, {
82
+ method: 'GET',
83
+ headers: buildOperatorHeaders(creds.operatorKey, creds.agentId),
84
+ });
85
+ const body = await res.text().catch(() => '');
86
+ if (!res.ok) {
87
+ throwApiError(res, body, `GET /orgs/me failed: ${res.status}`);
88
+ }
89
+ const parsed = body
90
+ ? JSON.parse(body)
91
+ : {};
92
+ const activeOrgId = typeof parsed.activeOrgId === 'string' && parsed.activeOrgId
93
+ ? parsed.activeOrgId
94
+ : null;
95
+ const match = (parsed.orgs ?? []).find((o) => o.orgId === activeOrgId);
96
+ // Prefer `activeOrg` (ZIG-1272) — membership list often omits the agent home
97
+ // org under fleet impersonation.
98
+ const fromActive = parsed.activeOrg;
99
+ const orgName = (typeof fromActive?.name === 'string' && fromActive.name) ||
100
+ match?.name ||
101
+ null;
102
+ const orgKind = (typeof fromActive?.kind === 'string' && fromActive.kind) ||
103
+ match?.kind ||
104
+ null;
105
+ return {
106
+ connected: true,
107
+ orgId: activeOrgId,
108
+ orgName,
109
+ orgKind,
110
+ switchOrgHint: 'Hosted agent session — acting org is the agent home / key workspace, not MCP OAuth consent.',
111
+ };
112
+ }
113
+ /**
114
+ * ZIG-1272 — pick the access reader that matches the acting agent.
115
+ * Claude OAuth delegates → self-hire status; everything else → hosted path.
116
+ */
117
+ export async function fetchSessionAccess(creds, baseUrl) {
118
+ if (isMcpOAuthDelegateAgentId(creds.agentId)) {
119
+ return fetchDelegateAccess(creds, baseUrl);
120
+ }
121
+ return fetchHostedAgentAccess(creds, baseUrl);
122
+ }
@@ -38,9 +38,11 @@ export declare function getActiveTasksForChat(chatId: string, creds: Creds): Pro
38
38
  export declare function cancelTask(taskId: string, creds: Creds): Promise<Task>;
39
39
  export declare function getSubtasks(parentTaskId: string, creds: Creds): Promise<Task[]>;
40
40
  export interface PlanReplaceStep {
41
- stepId: string;
41
+ /** Omit to let the server mint `step-<n>` (ZIG-1268). */
42
+ stepId?: string;
42
43
  description: string;
43
- order: number;
44
+ /** Omit to use the array index (ZIG-1268). */
45
+ order?: number;
44
46
  }
45
47
  export declare function replaceTaskPlan(taskId: string, steps: PlanReplaceStep[], creds: Creds): Promise<Task>;
46
48
  export declare function updateTaskPlanStep(taskId: string, stepId: string, status: string, result: unknown, creds: Creds): Promise<Task>;
@@ -21,7 +21,7 @@ export { PaymentsClient } from './PaymentsClient.js';
21
21
  export type { PaymentsError, WalletBalance, WalletRef, PaymentTransactionView, TransferResult, HoldResult, ReleaseResult, PaymentGrantView, PaymentGrantEnvelope, RevokeGrantResult, PaymentApproval, WaitForApprovalResult, } from './PaymentsClient.js';
22
22
  export { ConnectionsClient, assertNoLeakedConnectionSecret, } from './ConnectionsClient.js';
23
23
  export type { ConnectionsError, ConnectionProxyParams, ConnectionGrant, ConnectionWithGrants, McpConnectionRequestParams, } from './ConnectionsClient.js';
24
- export { fetchMyOrgs, resolveOrgSelector, fetchDelegateAccess, } from './OrgsClient.js';
24
+ export { fetchMyOrgs, resolveOrgSelector, fetchDelegateAccess, fetchHostedAgentAccess, fetchSessionAccess, isMcpOAuthDelegateAgentId, MCP_OAUTH_DELEGATE_AGENT_ID_PREFIX, } from './OrgsClient.js';
25
25
  export type { MyOrg, OrgResolution } from './OrgsClient.js';
26
26
  export { AgentSearchClient } from './AgentSearchClient.js';
27
27
  export { TelemetryClient } from './TelemetryClient.js';
@@ -14,7 +14,7 @@ export { ContextGrantsClient } from './ContextGrantsClient.js';
14
14
  export { grantCaveat, CONTEXT_GRANT_SCOPE_KINDS, GRANT_SCOPE_KINDS, } from './grants.js';
15
15
  export { PaymentsClient } from './PaymentsClient.js';
16
16
  export { ConnectionsClient, assertNoLeakedConnectionSecret, } from './ConnectionsClient.js';
17
- export { fetchMyOrgs, resolveOrgSelector, fetchDelegateAccess, } from './OrgsClient.js';
17
+ export { fetchMyOrgs, resolveOrgSelector, fetchDelegateAccess, fetchHostedAgentAccess, fetchSessionAccess, isMcpOAuthDelegateAgentId, MCP_OAUTH_DELEGATE_AGENT_ID_PREFIX, } from './OrgsClient.js';
18
18
  export { AgentSearchClient } from './AgentSearchClient.js';
19
19
  export { TelemetryClient } from './TelemetryClient.js';
20
20
  export { InboxClient } from './InboxClient.js';
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export * from './relay/provisionRelayWorkers.js';
4
4
  export { ConnectionManager } from './ConnectionManager.js';
5
5
  export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, isPersonaRef, isRoomPresentationRef, isOpaquePresentationRef, AGREEMENT_ENGAGEMENT_KIND, isValidContentType, } from './types.js';
6
6
  export type { PrincipalPresentation } from './types.js';
7
- export { getBackendUrl, getWebSocketUrl } from './utils/urlUtils.js';
7
+ export { getBackendUrl } from './utils/urlUtils.js';
8
8
  export { configureApiClient, apiClientConfig } from './config.js';
9
9
  export type { ApiClientConfig, ApiClientLogLevel } from './config.js';
10
10
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ export * from './capabilities/index.js';
3
3
  export * from './relay/provisionRelayWorkers.js';
4
4
  export { ConnectionManager } from './ConnectionManager.js';
5
5
  export { EntryTypes, ContentTypes, OPEN_AGREEMENT_TARGET, ORG_AGREEMENT_TARGET, BROADCAST_TARGETS, isBroadcastTarget, isPersonaRef, isRoomPresentationRef, isOpaquePresentationRef, AGREEMENT_ENGAGEMENT_KIND, isValidContentType, } from './types.js';
6
- export { getBackendUrl, getWebSocketUrl } from './utils/urlUtils.js';
6
+ export { getBackendUrl } from './utils/urlUtils.js';
7
7
  // ZIG-652: the host injects the environment; this package never reads it.
8
8
  export { configureApiClient, apiClientConfig } from './config.js';
9
9
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
package/dist/types.d.ts CHANGED
@@ -244,7 +244,7 @@ export interface MessageMetadata {
244
244
  */
245
245
  presentation?: PrincipalPresentation | null;
246
246
  entryType?: string;
247
- content_type?: string;
247
+ contentType?: string;
248
248
  taskId?: string | null;
249
249
  /**
250
250
  * Optional task / agreement snapshot pinned by the backend on
@@ -1,2 +1 @@
1
1
  export declare function getBackendUrl(): string;
2
- export declare function getWebSocketUrl(): string;
@@ -3,7 +3,3 @@ export function getBackendUrl() {
3
3
  const url = apiClientConfig().httpUrl || 'https://api.ziggsai.com';
4
4
  return url.startsWith('http') ? url : `https://${url}`;
5
5
  }
6
- export function getWebSocketUrl() {
7
- const wsUrl = apiClientConfig().wsUrl || 'wss://api.ziggsai.com';
8
- return wsUrl.startsWith('ws') ? wsUrl : `wss://${wsUrl}`;
9
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/api-client",
3
- "version": "0.9.5",
3
+ "version": "0.9.8",
4
4
  "description": "HTTP and WebSocket client for the Ziggs backend API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",