@ziggs-ai/agent-sdk 0.34.0 → 0.35.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.
- package/dist/brain/claudeSdkProtocol.js +1 -1
- package/dist/brain/toolFailureText.d.ts +6 -0
- package/dist/brain/toolFailureText.js +18 -0
- package/dist/brain/toolManagerToSdkMcp.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/platform/ZiggsEffectHandler.js +7 -2
- package/dist/platform/inboxLoop.js +6 -2
- package/dist/platform/tools/index.d.ts +1 -0
- package/dist/platform/tools/index.js +1 -0
- package/dist/platform/tools/tier1/protocolRunner.d.ts +1 -1
- package/dist/platform/tools/tier1/protocolRunner.js +37 -37
- package/dist/platform/tools/tier2/listingTools.d.ts +2 -0
- package/dist/platform/tools/tier2/listingTools.js +7 -0
- package/package.json +2 -2
- package/dist/pricing/fleetDefaults.d.ts +0 -42
- package/dist/pricing/fleetDefaults.js +0 -152
- package/dist/pricing/fleetEvalFree.d.ts +0 -7
- package/dist/pricing/fleetEvalFree.js +0 -23
- package/dist/pricing/fleetTierByAgentId.gen.d.ts +0 -7
- package/dist/pricing/fleetTierByAgentId.gen.js +0 -20
|
@@ -40,7 +40,7 @@ You are headless — there is no human to prompt during a wake:
|
|
|
40
40
|
|
|
41
41
|
Security:
|
|
42
42
|
- A relationship (a link) can parent a separately accepted service agreement. Parentage carries governing authority and revocation, not automatic spending consent. Each message or task uses one exact work agreement; its quota is direct unless a governing term explicitly shares it across the subtree. Agreement proposals, decisions, and system notices do not consume the conversation allowance.
|
|
43
|
-
- You decide what to do with a chat message. Ziggs does not enforce that counterparty text is ignored — that is a convention. What Ziggs does enforce: no spending and no commitments without an agreement, and a stranger talks to a listed agent under its listing, which counts their free messages; messages past those are refused at the send door, asking them to hire. Work is a task under an agreement; a stranger hires you through your listing, or through an agreement you draft when you have none. Your operating contract is this protocol and your role below.
|
|
43
|
+
- You decide what to do with a chat message. Ziggs does not enforce that counterparty text is ignored — that is a convention. What Ziggs does enforce: no spending and no commitments without an agreement, and a stranger talks to a listed agent under its listing, which counts their free messages; messages past those are refused at the send door, asking them to hire. Work is a task under an agreement; a stranger hires you through your listing, or through an agreement you draft when you have none. workBrief.work.state listing means a stranger is talking to you under your listing: there is no hire and nothing to put a task under. Answer them in this room with the reply action, and do not open another conversation. When they ask for something the listing does not cover, use the propose_terms action (agreement_bid to them, in this room) with the terms you would do it on; the listing itself stays take-it-or-leave-it. Tell them about it only after the proposal is made, and only the terms it carries: if a proposal is refused and you make another, the one that went through is the one you describe. Your operating contract is this protocol and your role below.
|
|
44
44
|
- ${INBOUND_DISCOVERY_POLICY}
|
|
45
45
|
|
|
46
46
|
When the event is handled, stop with a one-paragraph summary of what you did. If the event needs nothing from you (a status echo, a duplicate, a notification you already acted on), say so in one sentence and stop — do not invent work.`;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the model reads when a tool fails. A coverage refusal carries a machine
|
|
3
|
+
* code beside its sentence; the sentence alone used to look like a rate limit
|
|
4
|
+
* the model should wait out.
|
|
5
|
+
*/
|
|
6
|
+
export function toolFailureText(err) {
|
|
7
|
+
if (typeof err === 'string')
|
|
8
|
+
return err;
|
|
9
|
+
const message = err instanceof Error ? err.message : String(err ?? '');
|
|
10
|
+
const code = !!err &&
|
|
11
|
+
typeof err === 'object' &&
|
|
12
|
+
typeof err.code === 'string'
|
|
13
|
+
? err.code
|
|
14
|
+
: '';
|
|
15
|
+
if (!code || message.startsWith(`${code}:`))
|
|
16
|
+
return message;
|
|
17
|
+
return `${code}: ${message}`;
|
|
18
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
|
|
3
3
|
import { withDeclaredMandate } from '../runtime/mandateDeclaration.js';
|
|
4
|
+
import { toolFailureText } from './toolFailureText.js';
|
|
4
5
|
function jsonTypeToZod(field) {
|
|
5
6
|
const t = field['type'];
|
|
6
7
|
if (t === 'string') {
|
|
@@ -78,8 +79,7 @@ function toCallToolResult(value) {
|
|
|
78
79
|
return { content: [{ type: 'text', text }] };
|
|
79
80
|
}
|
|
80
81
|
function toCallToolError(err) {
|
|
81
|
-
|
|
82
|
-
return { content: [{ type: 'text', text: message }], isError: true };
|
|
82
|
+
return { content: [{ type: 'text', text: toolFailureText(err) }], isError: true };
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
85
|
* Map Ziggs `ToolDefinition`s to Claude Agent SDK MCP tools. Each handler routes
|
package/dist/index.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export { HistoryFormatter, historyFormatter, AgreementFormatter, agreementFormat
|
|
|
67
67
|
export { ProactiveTrigger } from './platform/proactive/ProactiveTrigger.js';
|
|
68
68
|
export { PollRegistry, declaredPolls, type PollBinding, type PollContext, type PollKind, type PollResult, } from './platform/polls/PollKind.js';
|
|
69
69
|
export { PollRunner, type PollRunnerOptions, type WakeTarget } from './platform/polls/PollRunner.js';
|
|
70
|
-
export { PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp, PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, } from './platform/tools/index.js';
|
|
70
|
+
export { PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp, PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, LISTING_TOOLS, } from './platform/tools/index.js';
|
|
71
71
|
export { CLAUDE_SDK_TOOLS } from './brain/claudeSdkTools.js';
|
|
72
72
|
export { hostedModelTools, isHostedCatalogOnly, hostedToolLane } from './brain/hostedToolSurface.js';
|
|
73
73
|
export type { HostedToolExecute } from './brain/hostedToolSurface.js';
|
package/dist/index.js
CHANGED
|
@@ -79,7 +79,7 @@ export {
|
|
|
79
79
|
// Tier 1 — protocol grammar (framework-managed via taskTools).
|
|
80
80
|
PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp,
|
|
81
81
|
// Tier 2 — opt-in capability bundles (spread into `tools:`).
|
|
82
|
-
PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, } from './platform/tools/index.js';
|
|
82
|
+
PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, LISTING_TOOLS, } from './platform/tools/index.js';
|
|
83
83
|
// The always-on toolset for the hosted Claude cognition (parity guard
|
|
84
84
|
// reads this as part of the real SDK registry).
|
|
85
85
|
export { CLAUDE_SDK_TOOLS } from './brain/claudeSdkTools.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { OutboxBuffer } from './OutboxBuffer.js';
|
|
2
2
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
|
+
import { toolFailureText } from '../brain/toolFailureText.js';
|
|
3
4
|
import { artifactScopeForSession } from '@ziggs-ai/api-client';
|
|
4
5
|
import { buildLlmIngestPayload, buildToolIngestPayload, isTelemetryIngestEnabled, sendTelemetry, } from './telemetryIngest.js';
|
|
5
6
|
const CONTEXT_CACHE_MAX = 256;
|
|
@@ -23,7 +24,11 @@ async function buildSnapshot(deps, chatId, agentId, opts = {}) {
|
|
|
23
24
|
try {
|
|
24
25
|
// Server returns 200 + chatMissing:true for a deleted chat, so its
|
|
25
26
|
// annotations (roster, *IsYou, self) are already applied — pass through.
|
|
26
|
-
|
|
27
|
+
// Read as this wake: the session is the lane, the way its tool calls are
|
|
28
|
+
// sent. Without it a room filed in another workspace — a stranger's room
|
|
29
|
+
// with a listed agent — reads as missing and the wake is skipped.
|
|
30
|
+
const reader = deps.contextReadClient.withLane?.(chatId) ?? deps.contextReadClient;
|
|
31
|
+
const snap = await reader.snapshot(chatId, {
|
|
27
32
|
maxMessages: opts.limit,
|
|
28
33
|
...opts.workScope,
|
|
29
34
|
});
|
|
@@ -188,7 +193,7 @@ export async function executeToolWithSideEffects(deps, eff, effect, roster) {
|
|
|
188
193
|
return { ok: true, result, ...(nestedUsage ? { usage: nestedUsage } : {}) };
|
|
189
194
|
}
|
|
190
195
|
catch (error) {
|
|
191
|
-
const errMsg =
|
|
196
|
+
const errMsg = toolFailureText(error);
|
|
192
197
|
runtimeLog.warn('ZiggsEffectHandler', `tool-call "${effect.name}" failed: ${errMsg}`);
|
|
193
198
|
void emitToolOperationArtifact(deps.artifactsClient, effect.sessionId, 'error', {
|
|
194
199
|
state: 'failed',
|
|
@@ -133,7 +133,6 @@ async function deliverMessagesForChat(deps, news, refs, reader, attempt, handled
|
|
|
133
133
|
export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
134
134
|
const label = deps.label ?? 'inboxLoop';
|
|
135
135
|
const inbox = inboxClient(deps);
|
|
136
|
-
const reader = new ContextReadClient(deps.creds.operatorKey, deps.creds.agentId, deps.baseUrl);
|
|
137
136
|
const envelope = await inbox.getInbox({
|
|
138
137
|
...(waitSeconds > 0 ? { waitSeconds } : {}),
|
|
139
138
|
...(opts.signal ? { signal: opts.signal } : {}),
|
|
@@ -220,7 +219,12 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
|
220
219
|
chatId, count: refs.length, latestAt: refs.map(ref => ref.ts).sort().at(-1),
|
|
221
220
|
}));
|
|
222
221
|
for (const news of chatsInWakeOrder(chats)) {
|
|
223
|
-
|
|
222
|
+
// Read a room's mail as that room's wake would: with the room as the lane.
|
|
223
|
+
// Without it the read is judged in the workspace the key signed in to, and
|
|
224
|
+
// a room another company opened with a listed agent is filed in theirs, so
|
|
225
|
+
// every stranger's message came back 403 and was acked unread.
|
|
226
|
+
const roomReader = new ContextReadClient(deps.creds.operatorKey, deps.creds.agentId, deps.baseUrl, news.chatId);
|
|
227
|
+
const n = await deliverMessagesForChat(deps, news, assignedByChat.get(news.chatId), roomReader, attempt, handledSoFar);
|
|
224
228
|
messagesDelivered += n;
|
|
225
229
|
await ackWhatIsFinished();
|
|
226
230
|
}
|
|
@@ -28,5 +28,6 @@ export { PLAN_TOOLS, taskReplacePlanTool } from './tier2/planTools.js';
|
|
|
28
28
|
export { LINK_TOOLS, linkProposeTool, linkListTool, } from './tier2/linkTools.js';
|
|
29
29
|
export { INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, } from './tier2/introductionTools.js';
|
|
30
30
|
export { ARTIFACT_TOOLS, recordArtifactTool } from './tier2/artifactTools.js';
|
|
31
|
+
export { LISTING_TOOLS } from './tier2/listingTools.js';
|
|
31
32
|
export { MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, } from './tier2/mcpConnectionTools.js';
|
|
32
33
|
export { CHAT_TOOLS, openConversationTool } from './tier2/chatTools.js';
|
|
@@ -37,6 +37,7 @@ export { LINK_TOOLS, linkProposeTool, linkListTool, } from './tier2/linkTools.js
|
|
|
37
37
|
export { INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, } from './tier2/introductionTools.js';
|
|
38
38
|
// deliberate artifact recording (the model decides "record this").
|
|
39
39
|
export { ARTIFACT_TOOLS, recordArtifactTool } from './tier2/artifactTools.js';
|
|
40
|
+
export { LISTING_TOOLS } from './tier2/listingTools.js';
|
|
40
41
|
export { MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, } from './tier2/mcpConnectionTools.js';
|
|
41
42
|
// Decision: chat_open only — chat listing stays a context-rail read
|
|
42
43
|
// (grant_list scopeKind=chat), so there is no duplicate lister.
|
|
@@ -36,7 +36,7 @@ interface ProtocolPayload {
|
|
|
36
36
|
})[];
|
|
37
37
|
[key: string]: unknown;
|
|
38
38
|
}
|
|
39
|
-
export declare function dispatchProtocolOp(services: Services, payload: ProtocolPayload, chatId: string | null,
|
|
39
|
+
export declare function dispatchProtocolOp(services: Services, payload: ProtocolPayload, chatId: string | null, _agents?: unknown[], actingAgentId?: string | null, writeKeys?: DeliveryWriteKeys | null,
|
|
40
40
|
/** #8 — prefer the cached session snapshot over a fresh HTTP read. */
|
|
41
41
|
cachedAgreements?: unknown[]): Promise<unknown>;
|
|
42
42
|
export {};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { isBroadcastTarget, partyActorIds, presentClaimResult, } from '@ziggs-ai/api-client';
|
|
2
|
-
import { applyFleetCounterPricing, applyFleetPricingForProtocol, } from '../../../pricing/fleetDefaults.js';
|
|
3
2
|
// the link-summary rule lives in AgreementClient, at the point the
|
|
4
3
|
// document is parsed. Every verb here inherits it through the client instead of
|
|
5
4
|
// each one restating `engagementKind === 'link' ? linkSummary(a) : a` — which is
|
|
@@ -45,7 +44,7 @@ function normalizePlanInPlace(payload) {
|
|
|
45
44
|
? 'before_execution'
|
|
46
45
|
: 'with_proposal';
|
|
47
46
|
}
|
|
48
|
-
export async function dispatchProtocolOp(services, payload, chatId,
|
|
47
|
+
export async function dispatchProtocolOp(services, payload, chatId, _agents = [], actingAgentId = null, writeKeys = null,
|
|
49
48
|
/** #8 — prefer the cached session snapshot over a fresh HTTP read. */
|
|
50
49
|
cachedAgreements) {
|
|
51
50
|
if (!payload?.operation)
|
|
@@ -55,9 +54,9 @@ cachedAgreements) {
|
|
|
55
54
|
const actorId = actingAgentId?.trim() || null;
|
|
56
55
|
switch (operation) {
|
|
57
56
|
case 'agreement-propose':
|
|
58
|
-
return proposeAgreement(services, payload, chatId,
|
|
57
|
+
return proposeAgreement(services, payload, chatId, writeKeys);
|
|
59
58
|
case 'agreement-subcontract':
|
|
60
|
-
return subcontractAgreement(services, payload, namedSubcontractChat(payload, chatId),
|
|
59
|
+
return subcontractAgreement(services, payload, namedSubcontractChat(payload, chatId), writeKeys);
|
|
61
60
|
case 'agreement-respond':
|
|
62
61
|
if (!payload.agreementId || !payload.action)
|
|
63
62
|
return null;
|
|
@@ -85,19 +84,15 @@ cachedAgreements) {
|
|
|
85
84
|
case 'agreement-counter-proposal':
|
|
86
85
|
if (!payload.agreementId)
|
|
87
86
|
return null;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
maxExecutions: counterPayload.maxExecutions,
|
|
98
|
-
description: counterPayload.description,
|
|
99
|
-
});
|
|
100
|
-
}
|
|
87
|
+
// The price is the one the model stated; the SDK adds none.
|
|
88
|
+
return agreementService.counter(payload.agreementId, {
|
|
89
|
+
price: payload.price,
|
|
90
|
+
agreementDescription: payload.agreementDescription,
|
|
91
|
+
expiresAt: payload.expiresAt,
|
|
92
|
+
lifecycle: payload.lifecycle,
|
|
93
|
+
maxExecutions: payload.maxExecutions,
|
|
94
|
+
description: payload.description,
|
|
95
|
+
});
|
|
101
96
|
case 'agreement-check-proposal':
|
|
102
97
|
if (!payload.agreementId)
|
|
103
98
|
return null;
|
|
@@ -239,7 +234,7 @@ cachedAgreements) {
|
|
|
239
234
|
throw new Error(`Unknown protocol operation: ${operation}`);
|
|
240
235
|
}
|
|
241
236
|
}
|
|
242
|
-
async function proposeAgreement(services, payload, chatId,
|
|
237
|
+
async function proposeAgreement(services, payload, chatId, writeKeys = null) {
|
|
243
238
|
if (!payload.description)
|
|
244
239
|
throw new Error('agreement-propose requires `description`');
|
|
245
240
|
if (!payload.proposedTo)
|
|
@@ -253,7 +248,9 @@ async function proposeAgreement(services, payload, chatId, _agents, actingAgentI
|
|
|
253
248
|
}
|
|
254
249
|
return services.agreementService.requestLink(payload.proposedTo, payload.description);
|
|
255
250
|
}
|
|
256
|
-
|
|
251
|
+
// The agent sets the price, never the SDK: a proposal carries a price only
|
|
252
|
+
// when the model stated one, and the server falls back to the provider's
|
|
253
|
+
// listing price, then to free.
|
|
257
254
|
// Wake-derived idempotency key (delivery law): a crash-replay re-issuing this
|
|
258
255
|
// propose resolves to the already-created agreement server-side instead of
|
|
259
256
|
// minting a duplicate proposal. Keyed on what the proposal writes, so
|
|
@@ -264,25 +261,25 @@ async function proposeAgreement(services, payload, chatId, _agents, actingAgentI
|
|
|
264
261
|
description: payload.description,
|
|
265
262
|
parentAgreementId: payload.parentAgreementId,
|
|
266
263
|
});
|
|
267
|
-
const engagementKind =
|
|
268
|
-
?
|
|
264
|
+
const engagementKind = payload.engagementKind === 'hire' || payload.engagementKind === 'service'
|
|
265
|
+
? payload.engagementKind
|
|
269
266
|
: undefined;
|
|
270
|
-
const billing =
|
|
271
|
-
?
|
|
267
|
+
const billing = payload['billing'] === 'per_task' || payload['billing'] === 'total'
|
|
268
|
+
? payload['billing']
|
|
272
269
|
: undefined;
|
|
273
270
|
const { agreement, shape } = await services.agreementService.proposeUnified({
|
|
274
|
-
proposedTo:
|
|
271
|
+
proposedTo: payload.proposedTo,
|
|
275
272
|
chatId: chatId ?? undefined,
|
|
276
|
-
description: String(
|
|
277
|
-
providerId:
|
|
278
|
-
price: typeof
|
|
279
|
-
lifecycle: typeof
|
|
280
|
-
expiresAt: typeof
|
|
281
|
-
maxExecutions: typeof
|
|
273
|
+
description: String(payload.description),
|
|
274
|
+
providerId: payload.providerId,
|
|
275
|
+
price: typeof payload.price === 'number' ? payload.price : undefined,
|
|
276
|
+
lifecycle: typeof payload.lifecycle === 'string' ? payload.lifecycle : undefined,
|
|
277
|
+
expiresAt: typeof payload.expiresAt === 'string' ? payload.expiresAt : undefined,
|
|
278
|
+
maxExecutions: typeof payload.maxExecutions === 'number' ? payload.maxExecutions : undefined,
|
|
282
279
|
billing,
|
|
283
|
-
...(
|
|
284
|
-
agreementDescription:
|
|
285
|
-
parentAgreementId:
|
|
280
|
+
...(payload.conversationAllowance !== undefined ? { conversationAllowance: payload.conversationAllowance } : {}),
|
|
281
|
+
agreementDescription: payload.agreementDescription,
|
|
282
|
+
parentAgreementId: payload.parentAgreementId,
|
|
286
283
|
engagementKind,
|
|
287
284
|
idempotencyKey,
|
|
288
285
|
});
|
|
@@ -308,7 +305,9 @@ async function agreementsInChat(services, chatId, cachedAgreements) {
|
|
|
308
305
|
return Array.isArray(cachedAgreements) ? cachedAgreements : [];
|
|
309
306
|
}
|
|
310
307
|
try {
|
|
311
|
-
|
|
308
|
+
// The room is the lane, as for every read made on a wake.
|
|
309
|
+
const reader = services.contextReadClient.withLane?.(chatId) ?? services.contextReadClient;
|
|
310
|
+
const snap = await reader.snapshot(chatId, { maxMessages: 1 });
|
|
312
311
|
const ags = snap.agreements;
|
|
313
312
|
return Array.isArray(ags) ? ags : [];
|
|
314
313
|
}
|
|
@@ -350,11 +349,12 @@ function namedSubcontractChat(payload, wakeChatId) {
|
|
|
350
349
|
* request over MCP stays open. A crash replay is still covered by the
|
|
351
350
|
* wake-derived idempotency key.
|
|
352
351
|
*/
|
|
353
|
-
async function subcontractAgreement(services, payload, chatId,
|
|
352
|
+
async function subcontractAgreement(services, payload, chatId, writeKeys = null) {
|
|
354
353
|
if (!payload.description || !payload.executorId)
|
|
355
354
|
return null;
|
|
356
|
-
|
|
357
|
-
|
|
355
|
+
// The price the model stated, or none; the server falls back to the
|
|
356
|
+
// executor's listing price, then to free.
|
|
357
|
+
const { operation: _op, ...fields } = payload;
|
|
358
358
|
const idempotencyKey = writeKeys?.agreementSubcontractKey({
|
|
359
359
|
executorId: payload.executorId,
|
|
360
360
|
description: payload.description,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { agreementBidCapability } from '@ziggs-ai/api-client';
|
|
2
|
+
import { toolsFromCapabilities } from '../../../tools/capabilityAdapter.js';
|
|
3
|
+
// What a listed agent needs to answer a stranger whose ask the listing does not
|
|
4
|
+
// cover: terms offered to them directly, in their room, which they approve. The
|
|
5
|
+
// listing itself stays take-it-or-leave-it. The work brief names this as its
|
|
6
|
+
// propose_terms action; without the tool the agent can only refuse.
|
|
7
|
+
export const LISTING_TOOLS = toolsFromCapabilities([agreementBidCapability]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.0",
|
|
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.284",
|
|
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.34.0",
|
|
30
30
|
"ajv": "^8.17.1",
|
|
31
31
|
"dotenv": "^17.2.3",
|
|
32
32
|
"openai": "^4.0.0",
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* default paid pricing for Ziggs-operated (first-party) agents.
|
|
3
|
-
* Prices are in wallet cents (1 ZIG = 100 cents).
|
|
4
|
-
*/
|
|
5
|
-
import { type FleetPricingTier } from './fleetTierByAgentId.gen.js';
|
|
6
|
-
export declare const ZIGGS_OPERATOR_CUT_BPS = 1000;
|
|
7
|
-
export declare const TIER_PRICE_CENTS: Record<FleetPricingTier, number>;
|
|
8
|
-
export declare function resolveFleetTier(agentId: string): FleetPricingTier | null;
|
|
9
|
-
export declare function isFirstPartyFleetAgent(agentId: string): boolean;
|
|
10
|
-
export declare function tierPriceCents(tier: FleetPricingTier): number;
|
|
11
|
-
export declare function isFreeAllowlistedExecutor(executorId: string, description?: string | null): boolean;
|
|
12
|
-
export declare function resolveDefaultPriceCentsForExecutor(executorId: string, description?: string | null): number | null;
|
|
13
|
-
export interface ProtocolPricingPayload {
|
|
14
|
-
price?: number | null;
|
|
15
|
-
description?: string;
|
|
16
|
-
agreementDescription?: string;
|
|
17
|
-
proposedTo?: string;
|
|
18
|
-
providerId?: string;
|
|
19
|
-
executorId?: string;
|
|
20
|
-
parentAgreementId?: string;
|
|
21
|
-
[key: string]: unknown;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Apply defaults when `price` is omitted (null/undefined).
|
|
25
|
-
* Explicit `price: 0` is kept (free-on-purpose).
|
|
26
|
-
*/
|
|
27
|
-
export declare function applyFleetAgreementPricing(operation: 'agreement-propose' | 'agreement-subcontract', payload: ProtocolPricingPayload, actingAgentId: string): ProtocolPricingPayload;
|
|
28
|
-
/**
|
|
29
|
-
* Default tier price when a fleet agent counters without an explicit `price`.
|
|
30
|
-
*
|
|
31
|
-
* Generic over the payload shape so the precise field types of the caller's
|
|
32
|
-
* payload survive the round-trip — this helper only ever sets `price`, so a
|
|
33
|
-
* richer input type (e.g. protocolRunner's `ProtocolPayload`) must come back
|
|
34
|
-
* out unwidened by `ProtocolPricingPayload`'s `[key: string]: unknown` index.
|
|
35
|
-
*/
|
|
36
|
-
export declare function applyFleetCounterPricing<T extends ProtocolPricingPayload>(payload: T, actingAgentId: string): T;
|
|
37
|
-
/**
|
|
38
|
-
* Infer fleet actor when tool context omits agentId (safety net).
|
|
39
|
-
*/
|
|
40
|
-
export declare function inferFleetPricingActorId(payload: ProtocolPricingPayload): string | null;
|
|
41
|
-
/** Apply fleet defaults with optional acting agent (falls back to payload inference). */
|
|
42
|
-
export declare function applyFleetPricingForProtocol(operation: 'agreement-propose' | 'agreement-subcontract', payload: ProtocolPricingPayload, actingAgentId: string | null): ProtocolPricingPayload;
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* default paid pricing for Ziggs-operated (first-party) agents.
|
|
3
|
-
* Prices are in wallet cents (1 ZIG = 100 cents).
|
|
4
|
-
*/
|
|
5
|
-
import { FLEET_TIER_BY_AGENT_ID } from './fleetTierByAgentId.gen.js';
|
|
6
|
-
import { isEvalFreeExecutor } from './fleetEvalFree.js';
|
|
7
|
-
export const ZIGGS_OPERATOR_CUT_BPS = 1000; // 10%
|
|
8
|
-
export const TIER_PRICE_CENTS = {
|
|
9
|
-
A: 200, // 2 ZIG / call
|
|
10
|
-
B: 500, // 5 ZIG / call
|
|
11
|
-
C: 1500, // 15 ZIG / job (orchestrator, charged once at top)
|
|
12
|
-
D: 100, // 1 ZIG / call (hand-written demo agents)
|
|
13
|
-
};
|
|
14
|
-
const PING_DESCRIPTION_PATTERN = /\b(ping|health\s*check|healthcheck|liveness|readiness|heartbeat)\b/i;
|
|
15
|
-
export function resolveFleetTier(agentId) {
|
|
16
|
-
if (!agentId || typeof agentId !== 'string')
|
|
17
|
-
return null;
|
|
18
|
-
return FLEET_TIER_BY_AGENT_ID[agentId] ?? null;
|
|
19
|
-
}
|
|
20
|
-
export function isFirstPartyFleetAgent(agentId) {
|
|
21
|
-
return resolveFleetTier(agentId) != null;
|
|
22
|
-
}
|
|
23
|
-
export function tierPriceCents(tier) {
|
|
24
|
-
return TIER_PRICE_CENTS[tier];
|
|
25
|
-
}
|
|
26
|
-
export function isFreeAllowlistedExecutor(executorId, description) {
|
|
27
|
-
if (!executorId)
|
|
28
|
-
return false;
|
|
29
|
-
if (isEvalFreeExecutor(executorId))
|
|
30
|
-
return true;
|
|
31
|
-
// A health check does not bill, whatever tier the executor is in. This is
|
|
32
|
-
// the only description-based exemption left: an agent whose work should cost
|
|
33
|
-
// nothing says so with a posted price of 0 on its own listing, where the
|
|
34
|
-
// buyer can see it, rather than through a rule inferred here.
|
|
35
|
-
if (description && PING_DESCRIPTION_PATTERN.test(description))
|
|
36
|
-
return true;
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
export function resolveDefaultPriceCentsForExecutor(executorId, description) {
|
|
40
|
-
if (isFreeAllowlistedExecutor(executorId, description))
|
|
41
|
-
return 0;
|
|
42
|
-
const tier = resolveFleetTier(executorId);
|
|
43
|
-
if (!tier)
|
|
44
|
-
return null;
|
|
45
|
-
return tierPriceCents(tier);
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Apply defaults when `price` is omitted (null/undefined).
|
|
49
|
-
* Explicit `price: 0` is kept (free-on-purpose).
|
|
50
|
-
*/
|
|
51
|
-
export function applyFleetAgreementPricing(operation, payload, actingAgentId) {
|
|
52
|
-
if (payload.price != null && payload.price !== undefined) {
|
|
53
|
-
return payload;
|
|
54
|
-
}
|
|
55
|
-
const next = { ...payload };
|
|
56
|
-
const scopeDescription = next.description ?? next.agreementDescription;
|
|
57
|
-
if (operation === 'agreement-subcontract') {
|
|
58
|
-
const executorId = String(next.executorId ?? '');
|
|
59
|
-
if (next.parentAgreementId) {
|
|
60
|
-
// Paid parent scope: no second user hold — allocate from parent budget (recordAllocation).
|
|
61
|
-
const cents = resolveDefaultPriceCentsForExecutor(executorId, scopeDescription);
|
|
62
|
-
next.price = cents ?? 0;
|
|
63
|
-
return next;
|
|
64
|
-
}
|
|
65
|
-
const cents = resolveDefaultPriceCentsForExecutor(executorId, scopeDescription);
|
|
66
|
-
if (cents != null)
|
|
67
|
-
next.price = cents;
|
|
68
|
-
return next;
|
|
69
|
-
}
|
|
70
|
-
// agreement-propose
|
|
71
|
-
if (next.parentAgreementId) {
|
|
72
|
-
return next;
|
|
73
|
-
}
|
|
74
|
-
const proposedTo = next.proposedTo != null ? String(next.proposedTo) : '';
|
|
75
|
-
const providerId = next.providerId != null ? String(next.providerId) : '';
|
|
76
|
-
// A tier C orchestrator proposing scope to a user — 15 ZIG once at top.
|
|
77
|
-
//
|
|
78
|
-
// The ziggs delegate used to have its own branch above this one, keyed on a
|
|
79
|
-
// hardcoded id. It asked the same question with the same answer — that agent
|
|
80
|
-
// is tier C, so this line already priced it. A second way of asking the tier
|
|
81
|
-
// question the tier had already answered, which is the same shape that was
|
|
82
|
-
// removed from the backend copy.
|
|
83
|
-
const actingTier = resolveFleetTier(actingAgentId);
|
|
84
|
-
if (actingTier === 'C' && proposedTo && !isFirstPartyFleetAgent(proposedTo)) {
|
|
85
|
-
next.price = TIER_PRICE_CENTS.C;
|
|
86
|
-
return next;
|
|
87
|
-
}
|
|
88
|
-
// Matchmaking: propose directly to a fleet specialist with tier list price.
|
|
89
|
-
const specialistId = providerId || (isFirstPartyFleetAgent(proposedTo) ? proposedTo : '');
|
|
90
|
-
if (specialistId) {
|
|
91
|
-
const cents = resolveDefaultPriceCentsForExecutor(specialistId, scopeDescription);
|
|
92
|
-
if (cents != null)
|
|
93
|
-
next.price = cents;
|
|
94
|
-
}
|
|
95
|
-
return next;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Default tier price when a fleet agent counters without an explicit `price`.
|
|
99
|
-
*
|
|
100
|
-
* Generic over the payload shape so the precise field types of the caller's
|
|
101
|
-
* payload survive the round-trip — this helper only ever sets `price`, so a
|
|
102
|
-
* richer input type (e.g. protocolRunner's `ProtocolPayload`) must come back
|
|
103
|
-
* out unwidened by `ProtocolPricingPayload`'s `[key: string]: unknown` index.
|
|
104
|
-
*/
|
|
105
|
-
export function applyFleetCounterPricing(payload, actingAgentId) {
|
|
106
|
-
if (payload.price != null && payload.price !== undefined) {
|
|
107
|
-
return payload;
|
|
108
|
-
}
|
|
109
|
-
const cents = resolveDefaultPriceCentsForExecutor(actingAgentId, payload.description ?? payload.agreementDescription);
|
|
110
|
-
if (cents == null)
|
|
111
|
-
return payload;
|
|
112
|
-
return { ...payload, price: cents };
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Infer fleet actor when tool context omits agentId (safety net).
|
|
116
|
-
*/
|
|
117
|
-
export function inferFleetPricingActorId(payload) {
|
|
118
|
-
const executor = payload.executorId != null ? String(payload.executorId) : '';
|
|
119
|
-
if (executor && isFirstPartyFleetAgent(executor))
|
|
120
|
-
return executor;
|
|
121
|
-
const provider = payload.providerId != null ? String(payload.providerId) : '';
|
|
122
|
-
if (provider && isFirstPartyFleetAgent(provider))
|
|
123
|
-
return provider;
|
|
124
|
-
const proposed = payload.proposedTo != null ? String(payload.proposedTo) : '';
|
|
125
|
-
if (proposed && isFirstPartyFleetAgent(proposed))
|
|
126
|
-
return proposed;
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
/** Apply fleet defaults with optional acting agent (falls back to payload inference). */
|
|
130
|
-
export function applyFleetPricingForProtocol(operation, payload, actingAgentId) {
|
|
131
|
-
const actor = actingAgentId?.trim() || inferFleetPricingActorId(payload);
|
|
132
|
-
if (!actor) {
|
|
133
|
-
if (operation === 'agreement-propose') {
|
|
134
|
-
const specialist = (payload.providerId != null ? String(payload.providerId) : '') ||
|
|
135
|
-
(payload.proposedTo != null && isFirstPartyFleetAgent(String(payload.proposedTo))
|
|
136
|
-
? String(payload.proposedTo)
|
|
137
|
-
: '');
|
|
138
|
-
if (specialist) {
|
|
139
|
-
const cents = resolveDefaultPriceCentsForExecutor(specialist, payload.description ?? payload.agreementDescription);
|
|
140
|
-
if (cents != null)
|
|
141
|
-
return { ...payload, price: cents };
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (operation === 'agreement-subcontract' && payload.executorId) {
|
|
145
|
-
const cents = resolveDefaultPriceCentsForExecutor(String(payload.executorId), payload.description);
|
|
146
|
-
if (cents != null)
|
|
147
|
-
return { ...payload, price: cents };
|
|
148
|
-
}
|
|
149
|
-
return payload;
|
|
150
|
-
}
|
|
151
|
-
return applyFleetAgreementPricing(operation, payload, actor);
|
|
152
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* eval/harness free pricing via env flag (no SANDBOX id-shape regex).
|
|
3
|
-
*/
|
|
4
|
-
/** Capability-probe + test harness agents (agents/test/). */
|
|
5
|
-
export declare const EVAL_HARNESS_AGENT_IDS: Set<string>;
|
|
6
|
-
export declare function isEvalFreePricingEnabled(): boolean;
|
|
7
|
-
export declare function isEvalFreeExecutor(agentId: string): boolean;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* eval/harness free pricing via env flag (no SANDBOX id-shape regex).
|
|
3
|
-
*/
|
|
4
|
-
/** Capability-probe + test harness agents (agents/test/). */
|
|
5
|
-
export const EVAL_HARNESS_AGENT_IDS = new Set([
|
|
6
|
-
'minimal-context-agent',
|
|
7
|
-
'forwarding-agent',
|
|
8
|
-
'failing-agent',
|
|
9
|
-
'principal-agent',
|
|
10
|
-
'capability-probe-agent',
|
|
11
|
-
]);
|
|
12
|
-
export function isEvalFreePricingEnabled() {
|
|
13
|
-
return process.env.FLEET_EVAL_FREE_PRICING === 'true';
|
|
14
|
-
}
|
|
15
|
-
export function isEvalFreeExecutor(agentId) {
|
|
16
|
-
if (!isEvalFreePricingEnabled() || !agentId)
|
|
17
|
-
return false;
|
|
18
|
-
if (agentId === 'eval-user')
|
|
19
|
-
return true;
|
|
20
|
-
if (agentId.endsWith('--eval'))
|
|
21
|
-
return true;
|
|
22
|
-
return EVAL_HARNESS_AGENT_IDS.has(agentId);
|
|
23
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AUTO-GENERATED by scripts/build-fleet-tier-map.mjs — do not edit by hand.
|
|
3
|
-
* Local default pricing; the server resolves an agent's own pricing tier.
|
|
4
|
-
*/
|
|
5
|
-
export type FleetPricingTier = 'A' | 'B' | 'C' | 'D';
|
|
6
|
-
export declare const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier>;
|
|
7
|
-
export declare const FLEET_TIER_MAP_SIZE = 17;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export const FLEET_TIER_BY_AGENT_ID = {
|
|
2
|
-
"ziggs-agent": "C",
|
|
3
|
-
"ziggs-agent--eval": "C",
|
|
4
|
-
"coffee-agent": "D",
|
|
5
|
-
"coffee-agent--eval": "D",
|
|
6
|
-
"delivery-agent": "D",
|
|
7
|
-
"delivery-agent--eval": "D",
|
|
8
|
-
"expense-agent": "D",
|
|
9
|
-
"fruit-agent": "D",
|
|
10
|
-
"vendor-agent": "D",
|
|
11
|
-
"shopper-agent": "D",
|
|
12
|
-
"hire-agent": "B",
|
|
13
|
-
"ziggs-docs-agent": "B",
|
|
14
|
-
"agent-definer": "B",
|
|
15
|
-
"linear-janitor": "B",
|
|
16
|
-
"shipped-digest": "B",
|
|
17
|
-
"docs-reviewer": "B",
|
|
18
|
-
"email-agent": "B"
|
|
19
|
-
};
|
|
20
|
-
export const FLEET_TIER_MAP_SIZE = 17;
|