@ziggs-ai/agent-sdk 0.14.0 → 0.16.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.
- package/dist/AgentHost.d.ts +23 -2
- package/dist/AgentHost.js +102 -2
- package/dist/adapters/McpAdapter.js +1 -1
- package/dist/agent/ClaudeSdkAgent.js +54 -4
- package/dist/agent/claudeSdkProtocol.d.ts +1 -1
- package/dist/agent/claudeSdkProtocol.js +2 -2
- package/dist/agent/claudeSdkTools.d.ts +2 -1
- package/dist/agent/claudeSdkTools.js +29 -58
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2 -2
- package/dist/pricing/fleetTierByAgentId.gen.d.ts +1 -1
- package/dist/pricing/fleetTierByAgentId.gen.js +3 -8
- package/dist/runtime/AgentMachine.d.ts +28 -1
- package/dist/runtime/AgentMachine.js +55 -16
- package/dist/runtime/buildOutcome.d.ts +0 -8
- package/dist/runtime/buildOutcome.js +19 -5
- package/dist/runtime/kickoff.d.ts +23 -1
- package/dist/runtime/kickoff.js +45 -3
- package/dist/runtime/wakeOutcome.d.ts +27 -0
- package/dist/runtime/wakeOutcome.js +43 -0
- package/dist/server/ConnectionPool.js +11 -3
- package/dist/server/EventQueue.d.ts +23 -2
- package/dist/server/EventQueue.js +33 -3
- package/dist/server/agreements/AgreementService.d.ts +10 -1
- package/dist/server/agreements/AgreementService.js +9 -1
- package/dist/server/tools/index.d.ts +2 -0
- package/dist/server/tools/index.js +3 -0
- package/dist/server/tools/tier1/protocolRunner.js +33 -27
- package/dist/server/tools/tier1/protocolTools.js +2 -7
- package/dist/server/tools/tier2/introductionTools.d.ts +6 -0
- package/dist/server/tools/tier2/introductionTools.js +12 -0
- package/dist/server/tools/tier2/taskTools.d.ts +3 -0
- package/dist/server/tools/tier2/taskTools.js +6 -0
- package/dist/tools/recordReport.d.ts +5 -0
- package/dist/tools/recordReport.js +5 -0
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isBroadcastTarget, partyActorIds, } from '@ziggs-ai/api-client';
|
|
1
|
+
import { isBroadcastTarget, partyActorIds, presentClaimResult, } from '@ziggs-ai/api-client';
|
|
2
2
|
import { applyFleetCounterPricing, applyFleetPricingForProtocol, } from '../../../pricing/fleetDefaults.js';
|
|
3
3
|
// the link-summary rule lives in AgreementClient, at the point the
|
|
4
4
|
// document is parsed. Every verb here inherits it through the client instead of
|
|
@@ -71,11 +71,16 @@ cachedAgreements) {
|
|
|
71
71
|
// claim; it does not re-parent the row, which stays in the publisher's
|
|
72
72
|
// tree.
|
|
73
73
|
const declaredMandate = payload.mandateAgreementId;
|
|
74
|
-
|
|
74
|
+
const { agreement, kind } = await agreementService.claim(payload.agreementId, {
|
|
75
75
|
...(typeof declaredMandate === 'string' && declaredMandate
|
|
76
76
|
? { mandateAgreementId: declaredMandate }
|
|
77
77
|
: {}),
|
|
78
78
|
});
|
|
79
|
+
return presentClaimResult(agreement, kind, {
|
|
80
|
+
creds: { operatorKey: 'sdk', agentId: actorId ?? 'agent' },
|
|
81
|
+
surface: 'sdk',
|
|
82
|
+
webUrl: process.env.ZIGGS_WEB_URL,
|
|
83
|
+
});
|
|
79
84
|
}
|
|
80
85
|
case 'agreement-counter-proposal':
|
|
81
86
|
if (!payload.agreementId)
|
|
@@ -221,38 +226,16 @@ async function proposeAgreement(services, payload, chatId, _agents, actingAgentI
|
|
|
221
226
|
throw new Error('agreement-propose requires `description`');
|
|
222
227
|
if (!payload.proposedTo)
|
|
223
228
|
throw new Error('agreement-propose requires `proposedTo` (userId or agentId). To create a task under an existing agreement, use `task_create` instead.');
|
|
224
|
-
const isBroadcast = isBroadcastTarget(payload.proposedTo);
|
|
225
229
|
// a link proposal is an agreement with engagementKind 'link' —
|
|
226
230
|
// no chat, no money; the target owner approves. Folds the old request_link.
|
|
231
|
+
// The shared propose grammar no longer has a link arm (link_propose owns it).
|
|
227
232
|
if (payload.engagementKind === 'link') {
|
|
228
|
-
if (
|
|
233
|
+
if (isBroadcastTarget(payload.proposedTo)) {
|
|
229
234
|
throw new Error('A broadcast link is an invite — use link_propose with no target instead; it returns a share link.');
|
|
230
235
|
}
|
|
231
236
|
return services.agreementService.requestLink(payload.proposedTo, payload.description);
|
|
232
237
|
}
|
|
233
|
-
if (!isBroadcast && !payload.providerId) {
|
|
234
|
-
throw new Error('agreement-propose requires `providerId` — name who does the work: your own id (you are offering to work) or the proposedTo id (you are commissioning the recipient).');
|
|
235
|
-
}
|
|
236
|
-
if (isBroadcast && payload.providerId) {
|
|
237
|
-
// providerId = self on a broadcast publishes a STANDING OFFER
|
|
238
|
-
// (seller side open to any claimer). Any other providerId stays an error.
|
|
239
|
-
if (actingAgentId && payload.providerId === actingAgentId) {
|
|
240
|
-
const priced = applyFleetPricingForProtocol('agreement-propose', payload, actingAgentId);
|
|
241
|
-
return services.agreementService.publishOffer({
|
|
242
|
-
description: String(priced.description ?? ''),
|
|
243
|
-
price: typeof priced.price === 'number' ? priced.price : undefined,
|
|
244
|
-
lifecycle: typeof priced.lifecycle === 'string' ? priced.lifecycle : undefined,
|
|
245
|
-
expiresAt: typeof priced.expiresAt === 'string' ? priced.expiresAt : undefined,
|
|
246
|
-
maxExecutions: typeof priced.maxExecutions === 'number' ? priced.maxExecutions : undefined,
|
|
247
|
-
engagementKind: priced.engagementKind === 'hire' ? 'hire' : priced.engagementKind === 'service' ? 'service' : undefined,
|
|
248
|
-
billing: priced['billing'] === 'per_task' ? 'per_task' : priced['billing'] === 'total' ? 'total' : undefined,
|
|
249
|
-
audience: payload.proposedTo === 'org' ? 'org' : 'everyone',
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
throw new Error('On a broadcast, providerId must be your own agent id (a standing offer) or omitted (a request — the claiming agent fills the open side).');
|
|
253
|
-
}
|
|
254
238
|
const priced = applyFleetPricingForProtocol('agreement-propose', payload, actingAgentId);
|
|
255
|
-
const { operation: _op, ...fields } = priced;
|
|
256
239
|
// Wake-derived idempotency key (delivery law): a crash-replay re-issuing this
|
|
257
240
|
// propose resolves to the already-created agreement server-side instead of
|
|
258
241
|
// minting a duplicate proposal. Keyed on what the proposal writes, so
|
|
@@ -263,7 +246,30 @@ async function proposeAgreement(services, payload, chatId, _agents, actingAgentI
|
|
|
263
246
|
description: payload.description,
|
|
264
247
|
parentAgreementId: payload.parentAgreementId,
|
|
265
248
|
});
|
|
266
|
-
|
|
249
|
+
const engagementKind = priced.engagementKind === 'hire' || priced.engagementKind === 'service'
|
|
250
|
+
? priced.engagementKind
|
|
251
|
+
: undefined;
|
|
252
|
+
const billing = priced['billing'] === 'per_task' || priced['billing'] === 'total'
|
|
253
|
+
? priced['billing']
|
|
254
|
+
: undefined;
|
|
255
|
+
const { agreement, shape } = await services.agreementService.proposeUnified({
|
|
256
|
+
proposedTo: priced.proposedTo ?? payload.proposedTo,
|
|
257
|
+
chatId: chatId ?? undefined,
|
|
258
|
+
description: String(priced.description ?? payload.description),
|
|
259
|
+
providerId: priced.providerId,
|
|
260
|
+
price: typeof priced.price === 'number' ? priced.price : undefined,
|
|
261
|
+
lifecycle: typeof priced.lifecycle === 'string' ? priced.lifecycle : undefined,
|
|
262
|
+
expiresAt: typeof priced.expiresAt === 'string' ? priced.expiresAt : undefined,
|
|
263
|
+
maxExecutions: typeof priced.maxExecutions === 'number' ? priced.maxExecutions : undefined,
|
|
264
|
+
billing,
|
|
265
|
+
agreementDescription: priced.agreementDescription,
|
|
266
|
+
parentAgreementId: priced.parentAgreementId,
|
|
267
|
+
engagementKind,
|
|
268
|
+
idempotencyKey,
|
|
269
|
+
});
|
|
270
|
+
// Keep the agreement fields at the top level (the shape agents already
|
|
271
|
+
// read) and add the discriminant the shared flow returns.
|
|
272
|
+
return { ...agreement, shape };
|
|
267
273
|
}
|
|
268
274
|
// ── deterministic sub-agreement resolution ─────────────────────────
|
|
269
275
|
// The orchestrator delegates one task per worker, but the LLM inconsistently
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineTool } from '../../../tools/defineTool.js';
|
|
2
2
|
import { requireProtocolOperation } from '../../../tasks/protocolRegistry.js';
|
|
3
3
|
import { dispatchProtocolOp } from './protocolRunner.js';
|
|
4
|
-
import { AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION, } from '@ziggs-ai/api-client';
|
|
4
|
+
import { AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION, agreementClaimCapability, } from '@ziggs-ai/api-client';
|
|
5
5
|
/** keep these enums in lockstep with MCP ziggs_agreement_* / ziggs_task_create. */
|
|
6
6
|
const LIFECYCLE_ENUM = ['open', 'time-bound', 'count-bound'];
|
|
7
7
|
const PLAN_REVIEW_TIMING_ENUM = ['with_proposal', 'before_execution'];
|
|
@@ -46,12 +46,7 @@ function handlerFor(toolName) {
|
|
|
46
46
|
export const agreementProposeTool = defineTool('agreement_propose', { description: { type: 'string', required: true }, proposedTo: { type: 'string', required: true }, engagementKind: { type: 'string', enum: ['hire', 'service'], description: 'Contract type. Defaults to service. For a bilateral trust link, use link_propose.' }, parentAgreementId: 'string', providerId: { type: 'string', description: AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION }, price: { type: 'number', description: 'Price in POINTS, as an integer of hundredths — 500 means ϟ5.00. Convert both ways: a human asking for "ϟ2 per task" means 200, not 2. ϟ is the points symbol, not a hundredth.' }, lifecycle: lifecycleParam, expiresAt: 'string', maxExecutions: 'integer', billing: { type: 'string', enum: ['total', 'per_task'], description: "How price reads: 'total' (default, escrowed and paid at the end) or 'per_task' (a rate settled as each task completes — standing agreements only, and the default for a hire)." }, agreementDescription: 'string' }, handlerFor('agreement_propose'), { description: 'Propose an agreement — direct, broadcast, or link; there are no separate publish tools. Engagement precedence (posted-first): 1) REUSE an active agreement on matching terms, 2) CLAIM the counterparty\'s listing (marketplace_view → agreement_claim; never counter a listing), 3) POST a request broadcast here when nothing listed fits, 4) direct-propose ONLY for bespoke terms, renegotiation, or commissioning a named counterparty with no listing — most published agents are claim-only and refuse direct proposals with a pointer at their listing. Direction is stated, never guessed: providerId = your own id ("I work, you pay") or providerId = proposedTo ("you work, I pay") on direct proposals. Broadcast with proposedTo="everyone" (fully public) or "org" (your org only): no providerId publishes a REQUEST any agent may claim; providerId = your own id publishes a STANDING OFFER (claiming is agreement_claim; browsing is marketplace_view). For a bilateral trust link, use link_propose: it takes an email or an agent id, or neither for a share link. engagementKind defaults to service. Agreements are STANDING by default (no expiry, unlimited tasks under one agreement); set expiresAt or maxExecutions only when the engagement should end on its own.', isAgreementCreation: true });
|
|
47
47
|
export const agreementSubcontractTool = defineTool('agreement_subcontract', { description: { type: 'string', required: true }, executorId: { type: 'string', required: true }, parentAgreementId: { type: 'string', required: true }, payerId: 'string', price: { type: 'number', description: 'Price in POINTS, as an integer of hundredths — 500 means ϟ5.00. Convert both ways: a human asking for "ϟ2 per task" means 200, not 2. ϟ is the points symbol, not a hundredth.' }, lifecycle: lifecycleParam, expiresAt: 'string', maxExecutions: 'integer', agreementDescription: 'string' }, handlerFor('agreement_subcontract'), { description: 'Delegate work to another agent under an existing parent agreement. Requires parentAgreementId.', isAgreementCreation: true });
|
|
48
48
|
export const agreementRespondTool = defineTool('agreement_respond', { agreementId: { type: 'string', required: true }, action: { type: 'string', required: true, enum: ['approve', 'reject'] } }, handlerFor('agreement_respond'), { description: 'Approve or reject a pending DIRECT agreement proposal addressed to you. Open broadcasts (requests, standing offers, link invites) have no personal approval slot — claim those with agreement_claim instead, or ignore them to pass. ONE exception: a hand-off that pins YOU as provider carries your pending approval even as an open broadcast — approving consents to serving whoever claims it (the row stays open for claims); rejecting cancels the hand-off. Ignoring it leaves the hand-off unclaimable, so always respond.' });
|
|
49
|
-
export const agreementClaimTool = defineTool('agreement_claim', {
|
|
50
|
-
agreementId: { type: 'string', required: true, description: 'The open agreement to claim (request / offer / link invite id)' },
|
|
51
|
-
// The job this claim is part of. Filled in from the task this wake is
|
|
52
|
-
// executing when the agent does not name one itself.
|
|
53
|
-
mandateAgreementId: { type: 'string', description: 'The active agreement whose work this claim is part of — the job you are doing. Claiming for a job your human already approved needs no second approval from them, but you have to name the job: the server checks you are a party to it, and a wrong name simply earns nothing. Leave it out when the claim belongs to no job.' },
|
|
54
|
-
}, handlerFor('agreement_claim'), { description: '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 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 and the agreement activates. 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.' });
|
|
49
|
+
export const agreementClaimTool = defineTool('agreement_claim', agreementClaimCapability.params, handlerFor('agreement_claim'), { description: agreementClaimCapability.descriptions.sdk });
|
|
55
50
|
export const taskSetResultTool = defineTool('task_set_result', {
|
|
56
51
|
taskId: { type: 'string', required: true },
|
|
57
52
|
// same param name as MCP ziggs_task_set_result / PATCH /tasks/:id/state.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ToolDefinition } from '../../../tools/defineTool.js';
|
|
2
|
+
export declare const introductionMintTool: ToolDefinition;
|
|
3
|
+
export declare const introductionRedeemTool: ToolDefinition;
|
|
4
|
+
export declare const introductionListTool: ToolDefinition;
|
|
5
|
+
export declare const introductionRevokeTool: ToolDefinition;
|
|
6
|
+
export declare const INTRODUCTION_TOOLS: ToolDefinition[];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { INTRODUCTION_CAPABILITIES, mintIntroductionCapability, redeemIntroductionCapability, listIntroductionsCapability, revokeIntroductionCapability, } from '@ziggs-ai/api-client';
|
|
2
|
+
import { toolFromCapability, toolsFromCapabilities } from '../../../tools/capabilityAdapter.js';
|
|
3
|
+
// Introduction tokens: what an agent hands over when it meets another
|
|
4
|
+
// agent somewhere Ziggs does not own. Defined once in api-client's capability
|
|
5
|
+
// layer; this file only adapts them onto the SDK. They sit beside the link tools
|
|
6
|
+
// because a redeemed introduction becomes a link — this rail is how a meeting
|
|
7
|
+
// off-platform turns into one.
|
|
8
|
+
export const introductionMintTool = toolFromCapability(mintIntroductionCapability);
|
|
9
|
+
export const introductionRedeemTool = toolFromCapability(redeemIntroductionCapability);
|
|
10
|
+
export const introductionListTool = toolFromCapability(listIntroductionsCapability);
|
|
11
|
+
export const introductionRevokeTool = toolFromCapability(revokeIntroductionCapability);
|
|
12
|
+
export const INTRODUCTION_TOOLS = toolsFromCapabilities(INTRODUCTION_CAPABILITIES);
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { listTasksCapability, TASK_CAPABILITIES } from '@ziggs-ai/api-client';
|
|
2
|
+
import { toolFromCapability, toolsFromCapabilities } from '../../../tools/capabilityAdapter.js';
|
|
3
|
+
// GET /tasks, defined once in api-client. MCP ziggs_task_list and this
|
|
4
|
+
// hosted-Claude tool used to re-declare the same filters.
|
|
5
|
+
export const listTasksTool = toolFromCapability(listTasksCapability);
|
|
6
|
+
export const TASK_TOOLS = toolsFromCapabilities(TASK_CAPABILITIES);
|
|
@@ -38,6 +38,11 @@ export interface RecordReportResult {
|
|
|
38
38
|
* When `deliverable` is provided, also writes a task-bound result artifact
|
|
39
39
|
* via ArtifactsClient so it is retrievable as `via=task:<taskId>`.
|
|
40
40
|
*
|
|
41
|
+
* One deliverable per task: the idempotency key is `task-result:<taskId>`.
|
|
42
|
+
* A retry after a partial failure reuses that row (intentional). A later
|
|
43
|
+
* revision of the same task still returns the original artifact — change the
|
|
44
|
+
* key if you mean a new deliverable; do not change this helper's key.
|
|
45
|
+
*
|
|
41
46
|
* Implements the B1 convention (Agents/REPORTING.md).
|
|
42
47
|
*/
|
|
43
48
|
export declare function recordReport(input: RecordReportInput): Promise<RecordReportResult>;
|
|
@@ -6,6 +6,11 @@ import { ArtifactsClient, updateTaskState, } from '@ziggs-ai/api-client';
|
|
|
6
6
|
* When `deliverable` is provided, also writes a task-bound result artifact
|
|
7
7
|
* via ArtifactsClient so it is retrievable as `via=task:<taskId>`.
|
|
8
8
|
*
|
|
9
|
+
* One deliverable per task: the idempotency key is `task-result:<taskId>`.
|
|
10
|
+
* A retry after a partial failure reuses that row (intentional). A later
|
|
11
|
+
* revision of the same task still returns the original artifact — change the
|
|
12
|
+
* key if you mean a new deliverable; do not change this helper's key.
|
|
13
|
+
*
|
|
9
14
|
* Implements the B1 convention (Agents/REPORTING.md).
|
|
10
15
|
*/
|
|
11
16
|
export async function recordReport(input) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@anthropic-ai/claude-agent-sdk": "^0.3.204",
|
|
27
27
|
"@anthropic-ai/sdk": "^0.110.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
-
"@ziggs-ai/api-client": "0.
|
|
29
|
+
"@ziggs-ai/api-client": "0.15.1",
|
|
30
30
|
"ajv": "^8.17.1",
|
|
31
31
|
"dotenv": "^17.2.3",
|
|
32
32
|
"openai": "^4.0.0",
|