@ziggs-ai/agent-sdk 0.38.3 → 0.38.4
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/Agent.js +2 -1
- package/dist/brain/claudeSdkTools.js +5 -0
- package/dist/platform/ZiggsEffectHandler.d.ts +2 -1
- package/dist/platform/ZiggsEffectHandler.js +1 -1
- package/dist/platform/tasks/TaskService.d.ts +3 -2
- package/dist/platform/tasks/TaskService.js +4 -3
- package/dist/platform/tools/tier1/protocolRunner.js +11 -2
- package/dist/platform/tools/tier1/protocolTools.js +6 -4
- package/dist/platform/tools/tier2/planTools.js +2 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.js +0 -6
- package/package.json +2 -2
package/dist/Agent.js
CHANGED
|
@@ -314,7 +314,7 @@ export class Agent {
|
|
|
314
314
|
operatorKey: this.options.operatorKey,
|
|
315
315
|
agentId: this.options.agentId,
|
|
316
316
|
};
|
|
317
|
-
const messageSender = async (message, receiverId, sessionId, messageId, conversationAgreementId, underAgreementId, taskId) => {
|
|
317
|
+
const messageSender = async (message, receiverId, sessionId, messageId, conversationAgreementId, underAgreementId, taskId, sources) => {
|
|
318
318
|
const sentId = messageId ?? `sdk_${randomUUID()}`;
|
|
319
319
|
const result = await sendChatMessage({
|
|
320
320
|
chatId: sessionId,
|
|
@@ -330,6 +330,7 @@ export class Agent {
|
|
|
330
330
|
conversationAgreementId,
|
|
331
331
|
underAgreementId,
|
|
332
332
|
taskId,
|
|
333
|
+
...(sources ? { sources } : {}),
|
|
333
334
|
}, creds);
|
|
334
335
|
if (!result.success)
|
|
335
336
|
throw new Error('sendChatMessage: the server did not accept this message — nothing was delivered and nobody was woken. Retry with the same messageId, which the backend dedups on.');
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SOURCES_PARAM, sourcesArg } from '@ziggs-ai/api-client';
|
|
1
2
|
import { isAgreementId, agreementLaneId } from '@ziggs-ai/api-client';
|
|
2
3
|
import { randomUUID } from 'node:crypto';
|
|
3
4
|
import { credsFromToolContext } from '../tools/toolCreds.js';
|
|
@@ -77,8 +78,10 @@ export const chatSendTool = defineTool('chat_send', {
|
|
|
77
78
|
receiverId: { type: 'string', description: 'Name someone only when you mean them. Leave it out to write back in this room: one other participant is the recipient, and with several Jev may select one. Otherwise the message stays in the room with no specific wake. To name a masked party, pass its rpb_ ref as it came. Pass human only for a broadcast to the people in the room; it does not wake assistants or stand-ins. For a reply from a person or their assistant, name that person\'s returned participant id. This does not grant their assistant access or guarantee a reply.' },
|
|
78
79
|
text: { type: 'string', required: true },
|
|
79
80
|
idempotencyKey: { type: 'string', description: 'Reuse for retry-safe resend of the same logical message.' },
|
|
81
|
+
sources: SOURCES_PARAM,
|
|
80
82
|
}, async (args, ctx) => {
|
|
81
83
|
const c = ctx;
|
|
84
|
+
const sources = sourcesArg(args);
|
|
82
85
|
const explicitChatId = asChatLane(firstFilled(args.chatId));
|
|
83
86
|
const to = firstFilled(args.to);
|
|
84
87
|
const text = String(args.text);
|
|
@@ -104,6 +107,7 @@ export const chatSendTool = defineTool('chat_send', {
|
|
|
104
107
|
underAgreementId: firstFilled(args.underAgreementId, c.serviceAgreementId),
|
|
105
108
|
taskId: firstFilled(args.taskId),
|
|
106
109
|
...(namedReceiver ? { receiverId: namedReceiver } : {}),
|
|
110
|
+
...sources,
|
|
107
111
|
}, creds);
|
|
108
112
|
// Never presented as a send that happened: the message does not exist,
|
|
109
113
|
// so whoever was waiting for it is still waiting. Retrying with the same
|
|
@@ -141,6 +145,7 @@ export const chatSendTool = defineTool('chat_send', {
|
|
|
141
145
|
...(receiverId ? { receiverId } : {}),
|
|
142
146
|
text,
|
|
143
147
|
messageId,
|
|
148
|
+
...sources,
|
|
144
149
|
});
|
|
145
150
|
},
|
|
146
151
|
// This line used to read "Conversation only — never use for
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WriteSource } from '@ziggs-ai/api-client';
|
|
1
2
|
/**
|
|
2
3
|
* Ziggs-flavored EffectHandler.
|
|
3
4
|
*
|
|
@@ -36,7 +37,7 @@ export interface ZiggsEffectDeps {
|
|
|
36
37
|
contextReadClient: ContextReadClient;
|
|
37
38
|
taskService: TaskService;
|
|
38
39
|
agreementService: AgreementService;
|
|
39
|
-
messageSender: (text: string, receiverId: string | undefined, sessionId: string, messageId?: string, conversationAgreementId?: string, underAgreementId?: string, taskId?: string) => Promise<unknown>;
|
|
40
|
+
messageSender: (text: string, receiverId: string | undefined, sessionId: string, messageId?: string, conversationAgreementId?: string, underAgreementId?: string, taskId?: string, sources?: WriteSource[]) => Promise<unknown>;
|
|
40
41
|
/** Sends a streaming chunk to a client. Called per-token during stream-text effects. */
|
|
41
42
|
chunkSender?: (sessionId: string, receiverId: string, text: string, messageId: string) => void;
|
|
42
43
|
toolManager: ToolManager;
|
|
@@ -318,7 +318,7 @@ export function createZiggsEffectHandler(deps) {
|
|
|
318
318
|
});
|
|
319
319
|
}
|
|
320
320
|
case 'send-message': {
|
|
321
|
-
const sent = await deps.messageSender(effect.text, effect.receiverId, effect.sessionId, effect.messageId, effect.conversationAgreementId, effect.underAgreementId, effect.taskId);
|
|
321
|
+
const sent = await deps.messageSender(effect.text, effect.receiverId, effect.sessionId, effect.messageId, effect.conversationAgreementId, effect.underAgreementId, effect.taskId, effect.sources);
|
|
322
322
|
outbox.track(effect.sessionId, { text: effect.text, receiverId: effect.receiverId });
|
|
323
323
|
// Carry the send's own report back to whoever asked for the send. A
|
|
324
324
|
// sender that cannot see where its message went cannot tell a delivered
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WriteSource } from '@ziggs-ai/api-client';
|
|
1
2
|
import { type Task, type TaskState } from '@ziggs-ai/api-client';
|
|
2
3
|
import type { CountTasksFilters, CreateTaskData } from '@ziggs-ai/api-client';
|
|
3
4
|
export declare class TaskService {
|
|
@@ -9,7 +10,7 @@ export declare class TaskService {
|
|
|
9
10
|
getActiveTasksForChat(chatId: string): Promise<Task[]>;
|
|
10
11
|
getSubtasks(parentTaskId: string): Promise<Task[]>;
|
|
11
12
|
spawnUnderAgreement(agreementId: string, taskData: Omit<CreateTaskData, 'agreementId'>): Promise<Task>;
|
|
12
|
-
updateState(taskId: string, state: TaskState, result?: unknown, idempotencyKey?: string): Promise<{
|
|
13
|
+
updateState(taskId: string, state: TaskState, result?: unknown, idempotencyKey?: string, sources?: WriteSource[]): Promise<{
|
|
13
14
|
ok: true;
|
|
14
15
|
taskId: string;
|
|
15
16
|
state: string;
|
|
@@ -46,7 +47,7 @@ export declare class TaskService {
|
|
|
46
47
|
updatePlanStep(taskId: string, stepId: string, status: string, result?: unknown, waitingOn?: {
|
|
47
48
|
kind: 'user' | 'agent';
|
|
48
49
|
id: string;
|
|
49
|
-
} | null): Promise<import("@ziggs-ai/api-client").TaskWriteConfirm>;
|
|
50
|
+
} | null, sources?: WriteSource[]): Promise<import("@ziggs-ai/api-client").TaskWriteConfirm>;
|
|
50
51
|
cancel(taskId: string): Promise<import("@ziggs-ai/api-client").TaskWriteConfirm>;
|
|
51
52
|
report(taskId: string, message?: string): Promise<import("@ziggs-ai/api-client").TaskWriteConfirm>;
|
|
52
53
|
setSatisfaction(taskId: string, satisfaction: 'positive' | 'negative'): Promise<import("@ziggs-ai/api-client").TaskWriteConfirm>;
|
|
@@ -60,11 +60,12 @@ export class TaskService {
|
|
|
60
60
|
throw error;
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
async updateState(taskId, state, result, idempotencyKey) {
|
|
63
|
+
async updateState(taskId, state, result, idempotencyKey, sources) {
|
|
64
64
|
try {
|
|
65
65
|
const data = {
|
|
66
66
|
...(result !== undefined ? { result: safeJsonStringify(result) } : {}),
|
|
67
67
|
...(idempotencyKey ? { idempotencyKey } : {}),
|
|
68
|
+
...(sources ? { sources } : {}),
|
|
68
69
|
};
|
|
69
70
|
const updated = await updateTaskState(taskId, state, data, this.creds);
|
|
70
71
|
runtimeLog.info('TaskService', `Task state: ${taskId} → ${state}`);
|
|
@@ -97,9 +98,9 @@ export class TaskService {
|
|
|
97
98
|
throw error;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
|
-
async updatePlanStep(taskId, stepId, status, result, waitingOn) {
|
|
101
|
+
async updatePlanStep(taskId, stepId, status, result, waitingOn, sources) {
|
|
101
102
|
try {
|
|
102
|
-
const updated = await updateTaskPlanStep(taskId, stepId, status, result, this.creds, waitingOn);
|
|
103
|
+
const updated = await updateTaskPlanStep(taskId, stepId, status, result, this.creds, waitingOn, sources);
|
|
103
104
|
runtimeLog.info('TaskService', `Task plan step: ${taskId}/${stepId} → ${status}`);
|
|
104
105
|
return updated;
|
|
105
106
|
}
|
|
@@ -45,6 +45,12 @@ function normalizePlanInPlace(payload) {
|
|
|
45
45
|
? 'before_execution'
|
|
46
46
|
: 'with_proposal';
|
|
47
47
|
}
|
|
48
|
+
/** The `sources` a protocol call carried, when it carried a list. */
|
|
49
|
+
function sourcesOf(payload) {
|
|
50
|
+
return Array.isArray(payload.sources)
|
|
51
|
+
? { sources: payload.sources }
|
|
52
|
+
: {};
|
|
53
|
+
}
|
|
48
54
|
export async function dispatchProtocolOp(services, payload, chatId, _agents = [], actingAgentId = null, writeKeys = null,
|
|
49
55
|
/** #8 — prefer the cached session snapshot over a fresh HTTP read. */
|
|
50
56
|
cachedAgreements) {
|
|
@@ -93,6 +99,7 @@ cachedAgreements) {
|
|
|
93
99
|
lifecycle: payload.lifecycle,
|
|
94
100
|
maxExecutions: payload.maxExecutions,
|
|
95
101
|
description: payload.description,
|
|
102
|
+
...sourcesOf(payload),
|
|
96
103
|
});
|
|
97
104
|
case 'agreement-check-proposal':
|
|
98
105
|
if (!payload.agreementId)
|
|
@@ -182,6 +189,7 @@ cachedAgreements) {
|
|
|
182
189
|
...(payload.checkBack && typeof payload.checkBack === 'object'
|
|
183
190
|
? { checkBack: payload.checkBack }
|
|
184
191
|
: {}),
|
|
192
|
+
...sourcesOf(payload),
|
|
185
193
|
// Wake-derived idempotency key (delivery law): a crash-replay re-issuing
|
|
186
194
|
// this spawn resolves to the already-created task server-side instead of
|
|
187
195
|
// creating a duplicate. Keyed on what is actually written (the resolved
|
|
@@ -204,7 +212,7 @@ cachedAgreements) {
|
|
|
204
212
|
const state = normalizeState(terminalRaw);
|
|
205
213
|
// Wake-derived idempotency key: a crash-replay re-issuing this transition
|
|
206
214
|
// no-ops server-side instead of erroring on the already-terminal task.
|
|
207
|
-
return taskService.updateState(payload.taskId, state, payload.result, writeKeys?.taskStateKey(payload.taskId, state));
|
|
215
|
+
return taskService.updateState(payload.taskId, state, payload.result, writeKeys?.taskStateKey(payload.taskId, state), sourcesOf(payload).sources);
|
|
208
216
|
}
|
|
209
217
|
case 'task-update-plan-step': {
|
|
210
218
|
if (!payload.taskId)
|
|
@@ -225,7 +233,7 @@ cachedAgreements) {
|
|
|
225
233
|
// a stepId that isn't in the plan — the backend 400s on both. That must never
|
|
226
234
|
// hard-fail the tool → fail the task → wake-loop. Make it best-effort.
|
|
227
235
|
try {
|
|
228
|
-
return await taskService.updatePlanStep(payload.taskId, payload.stepId, payload.status, payload.result, waitingOn);
|
|
236
|
+
return await taskService.updatePlanStep(payload.taskId, payload.stepId, payload.status, payload.result, waitingOn, sourcesOf(payload).sources);
|
|
229
237
|
}
|
|
230
238
|
catch {
|
|
231
239
|
return { ok: false, skipped: 'plan-step-not-updatable', stepId: payload.stepId };
|
|
@@ -286,6 +294,7 @@ async function proposeAgreement(services, payload, chatId, writeKeys = null) {
|
|
|
286
294
|
billing,
|
|
287
295
|
...(payload.conversationAllowance !== undefined ? { conversationAllowance: payload.conversationAllowance } : {}),
|
|
288
296
|
agreementDescription: payload.agreementDescription,
|
|
297
|
+
...sourcesOf(payload),
|
|
289
298
|
parentAgreementId: payload.parentAgreementId,
|
|
290
299
|
engagementKind,
|
|
291
300
|
idempotencyKey,
|
|
@@ -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, agreementClaimCapability, agreementSubcontractCapability, } from '@ziggs-ai/api-client';
|
|
4
|
+
import { AGREEMENT_PROPOSE_PROVIDER_ID_DESCRIPTION, agreementClaimCapability, agreementSubcontractCapability, SOURCES_PARAM, } 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'];
|
|
@@ -60,7 +60,7 @@ function handlerFor(toolName) {
|
|
|
60
60
|
return result;
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
-
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', conversationAllowance: { type: 'number', description: 'Incoming-message limit shared across covered rooms; omitted on new agreements means unlimited.' }, 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) and no providerId posts a REQUEST any agent may claim. A person or the deploy publishes a standing listing; this agent does not. 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 });
|
|
63
|
+
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', conversationAllowance: { type: 'number', description: 'Incoming-message limit shared across covered rooms; omitted on new agreements means unlimited.' }, 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', sources: SOURCES_PARAM }, 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) and no providerId posts a REQUEST any agent may claim. A person or the deploy publishes a standing listing; this agent does not. 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 });
|
|
64
64
|
export const agreementSubcontractTool = defineTool('agreement_subcontract', agreementSubcontractCapability.params, handlerFor('agreement_subcontract'), { description: agreementSubcontractCapability.descriptions.sdk, isAgreementCreation: true });
|
|
65
65
|
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.' });
|
|
66
66
|
export const agreementClaimTool = defineTool('agreement_claim', agreementClaimCapability.params, handlerFor('agreement_claim'), { description: agreementClaimCapability.descriptions.sdk });
|
|
@@ -73,8 +73,9 @@ export const taskSetResultTool = defineTool('task_set_result', {
|
|
|
73
73
|
type: 'object',
|
|
74
74
|
description: 'Outcome payload (summary, status, links, …). This is what the next agent reads when it picks the work up from its own inbox.',
|
|
75
75
|
},
|
|
76
|
+
sources: SOURCES_PARAM,
|
|
76
77
|
}, handlerFor('task_set_result'), { description: 'Transition a task to its terminal state, completed or failed, and record the result. To cancel a task use task_cancel. Set the result here as an object ({ summary, status, links }): a task the parties opted into is closed by this call, whatever else you also sent them. Pass state (not status). This closes the task and not the engagement: a standing hire stays active for the next task, ending one is agreement_fulfill. The reply reports what actually happened — what was stored, who the completion was queued for (queued, not read), what per-task metering did — so report those and no more; a completed task is not by itself a paid one.' });
|
|
77
|
-
export const agreementCounterTool = defineTool('agreement_counter', { agreementId: { type: 'string', required: true }, 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.' }, agreementDescription: 'string', expiresAt: 'string', lifecycle: lifecycleParam, maxExecutions: 'integer', conversationAllowance: { type: 'number', description: 'Incoming-message limit shared across covered rooms; omitted on new agreements means unlimited.' }, description: 'string' }, handlerFor('agreement_counter'), { description: 'Counter a pending proposal with revised terms instead of approving or rejecting. Check status first with agreement_get.' });
|
|
78
|
+
export const agreementCounterTool = defineTool('agreement_counter', { agreementId: { type: 'string', required: true }, 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.' }, agreementDescription: 'string', expiresAt: 'string', lifecycle: lifecycleParam, maxExecutions: 'integer', conversationAllowance: { type: 'number', description: 'Incoming-message limit shared across covered rooms; omitted on new agreements means unlimited.' }, description: 'string', sources: SOURCES_PARAM }, handlerFor('agreement_counter'), { description: 'Counter a pending proposal with revised terms instead of approving or rejecting. Check status first with agreement_get.' });
|
|
78
79
|
export const agreementGetTool = defineTool('agreement_get', { agreementId: { type: 'string', required: true } }, handlerFor('agreement_get'), { description: 'Read the current proposal status for an agreement (pending, approved, rejected, countered, expired).' });
|
|
79
80
|
export const agreementRevokeTool = defineTool('agreement_revoke', { agreementId: { type: 'string', required: true } }, handlerFor('agreement_revoke'), { description: 'Revoke a pending proposal you created so it can no longer be approved. Use when the user has clearly moved on to a different request before responding to the previous proposal card.' });
|
|
80
81
|
export const agreementFulfillTool = defineTool('agreement_fulfill', { agreementId: { type: 'string', required: true } }, handlerFor('agreement_fulfill'), { description: 'END an agreement you provide — permanently. Fulfilling terminates the whole relationship, not one deliverable: every grant it conferred is revoked and it cannot be reopened. Linked chats remain independent rooms governed by their own grants. Finished WORK is reported via task_set_result (the task closes; the agreement stays standing for the next task). Only fulfill when the engagement\'s full scope is delivered and nothing more is expected — never a standing hire that just finished a task.' });
|
|
@@ -92,6 +93,7 @@ export const taskUpdatePlanStepTool = defineTool('task_update_plan_step', {
|
|
|
92
93
|
description: 'Step progress. Required with stepId.',
|
|
93
94
|
},
|
|
94
95
|
result: 'string',
|
|
96
|
+
sources: SOURCES_PARAM,
|
|
95
97
|
// Both fields are required, but the required list cannot be declared here:
|
|
96
98
|
// defineTool reads a sibling `required` as the flag that makes waitingOn
|
|
97
99
|
// itself mandatory. The backend enforces the pair; the description says so.
|
|
@@ -108,7 +110,7 @@ export const taskUpdatePlanStepTool = defineTool('task_update_plan_step', {
|
|
|
108
110
|
description: "Who this task now waits on, because you just asked them: { kind: 'user' | 'agent', id } — both fields required. Send it when you ask — with the step you are ticking, or on its own when the ask is all that happened. Your person then sees the task as waiting on them rather than as running, which is the difference between a job that looks stalled and one that is waiting for an answer. It clears itself: any later progress that does not restate it, and any terminal state, drops it.",
|
|
109
111
|
},
|
|
110
112
|
}, handlerFor('task_update_plan_step'), { description: "Update the status of a single step within a task's plan, and say who you are waiting on when you have just asked somebody. A task with no plan can still carry the waiting-on on its own." });
|
|
111
|
-
export const taskCreateTool = defineTool('task_create', { agreementId: { type: 'string', required: true }, description: { type: 'string', required: true }, parentTaskId: 'string', assigneeId: { type: 'string', description: 'Explicitly hand this task to one specific agent (e.g. a worker your orchestrator selected via agent search) instead of leaving it unassigned. Must be a party on the agreement (payer, provider, creator, or creator agent).' }, inputArtifactIds: { type: 'array', items: { type: 'string' }, description: 'Prior-step output artifact handles, for structured input links.' }, plan: { type: 'object' }, planReviewTiming: planReviewTimingParam, requireMidWorkPlanAck: 'boolean', dueAt: dueAtParam, checkBack: checkBackParam }, handlerFor('task_create'), { description: 'Create a new task under an existing approved agreement. Use when the contract is already in place. Pass assigneeId to delegate the task to a specific agent rather than leaving it open. For work that means chasing an answer out of somebody, set dueAt and checkBack so the holder knows when to stop and how often it may remind.' });
|
|
113
|
+
export const taskCreateTool = defineTool('task_create', { agreementId: { type: 'string', required: true }, description: { type: 'string', required: true }, parentTaskId: 'string', assigneeId: { type: 'string', description: 'Explicitly hand this task to one specific agent (e.g. a worker your orchestrator selected via agent search) instead of leaving it unassigned. Must be a party on the agreement (payer, provider, creator, or creator agent).' }, inputArtifactIds: { type: 'array', items: { type: 'string' }, description: 'Prior-step output artifact handles, for structured input links.' }, plan: { type: 'object' }, planReviewTiming: planReviewTimingParam, requireMidWorkPlanAck: 'boolean', dueAt: dueAtParam, checkBack: checkBackParam, sources: SOURCES_PARAM }, handlerFor('task_create'), { description: 'Create a new task under an existing approved agreement. Use when the contract is already in place. Pass assigneeId to delegate the task to a specific agent rather than leaving it open. For work that means chasing an answer out of somebody, set dueAt and checkBack so the holder knows when to stop and how often it may remind.' });
|
|
112
114
|
export const PROTOCOL_TOOLS = [
|
|
113
115
|
agreementProposeTool, agreementSubcontractTool,
|
|
114
116
|
agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { replaceTaskPlan } from '@ziggs-ai/api-client';
|
|
1
|
+
import { replaceTaskPlan, SOURCES_PARAM, } from '@ziggs-ai/api-client';
|
|
2
2
|
import { defineTool } from '../../../tools/defineTool.js';
|
|
3
3
|
import { credsFromToolContext } from '../../../tools/toolCreds.js';
|
|
4
4
|
/**
|
|
@@ -44,6 +44,7 @@ export const taskReplacePlanTool = defineTool('task_replace_plan', {
|
|
|
44
44
|
type: 'object',
|
|
45
45
|
description: 'What this step produced, as an object — e.g. { "agreementId": "agr_…" } for an approval you requested, or { "artifactId": "art_…" } for a pack you recorded. Stored with the step and read back by task_list.',
|
|
46
46
|
},
|
|
47
|
+
sources: SOURCES_PARAM,
|
|
47
48
|
},
|
|
48
49
|
required: ['description'],
|
|
49
50
|
},
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WriteSource } from '@ziggs-ai/api-client';
|
|
1
2
|
/**
|
|
2
3
|
* Foundation types for the agent SDK workflow runtime.
|
|
3
4
|
*
|
|
@@ -519,6 +520,7 @@ export type Effect = {
|
|
|
519
520
|
conversationAgreementId?: string;
|
|
520
521
|
underAgreementId?: string;
|
|
521
522
|
taskId?: string;
|
|
523
|
+
sources?: WriteSource[];
|
|
522
524
|
} | {
|
|
523
525
|
kind: 'record-event';
|
|
524
526
|
sessionId: string;
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.38.
|
|
3
|
+
"version": "0.38.4",
|
|
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.37.
|
|
29
|
+
"@ziggs-ai/api-client": "0.37.6",
|
|
30
30
|
"@ziggs-ai/contracts": "^0.23.3",
|
|
31
31
|
"ajv": "^8.17.1",
|
|
32
32
|
"dotenv": "^17.2.3",
|