@ziggs-ai/agent-sdk 0.42.2 → 0.43.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/CHANGELOG.md +40 -0
- package/README.md +1 -1
- package/dist/Agent.d.ts +21 -8
- package/dist/Agent.js +173 -97
- package/dist/brain/ClaudeBrain.d.ts +0 -1
- package/dist/brain/ClaudeBrain.js +18 -42
- package/dist/brain/claudeCognition.js +5 -6
- package/dist/brain/claudeSdkProtocol.js +9 -9
- package/dist/brain/claudeSdkTools.d.ts +3 -3
- package/dist/brain/claudeSdkTools.js +37 -133
- package/dist/brain/hostedToolSurface.js +1 -1
- package/dist/brain/standingOfferNotice.d.ts +0 -2
- package/dist/brain/standingOfferNotice.js +1 -21
- package/dist/brain/toolManagerToSdkMcp.js +1 -1
- package/dist/brain/wakeGate.d.ts +3 -1
- package/dist/brain/wakeGate.js +6 -0
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -3
- package/dist/ingress/normalizeIncoming.d.ts +5 -3
- package/dist/ingress/normalizeIncoming.js +9 -8
- package/dist/mcp/createMcpAgent.d.ts +15 -0
- package/dist/mcp/createMcpAgent.js +47 -11
- package/dist/memory/MemoryStore.d.ts +1 -1
- package/dist/memory/MemoryStore.js +1 -6
- package/dist/platform/ConnectionPool.js +1 -1
- package/dist/platform/OutboxBuffer.d.ts +2 -2
- package/dist/platform/OutboxBuffer.js +17 -17
- package/dist/platform/StateTimers.d.ts +3 -1
- package/dist/platform/StateTimers.js +4 -3
- package/dist/platform/WakeLedger.d.ts +10 -6
- package/dist/platform/WakeLedger.js +16 -9
- package/dist/platform/ZiggsEffectHandler.d.ts +18 -4
- package/dist/platform/ZiggsEffectHandler.js +86 -55
- package/dist/platform/agreements/AgreementService.d.ts +1 -3
- package/dist/platform/agreements/AgreementService.js +1 -7
- package/dist/platform/inboxLoop.d.ts +3 -9
- package/dist/platform/inboxLoop.js +151 -158
- package/dist/platform/polls/PollKind.d.ts +13 -16
- package/dist/platform/polls/PollKind.js +4 -4
- package/dist/platform/polls/PollRunner.d.ts +3 -20
- package/dist/platform/polls/PollRunner.js +13 -15
- package/dist/platform/polls/declaredPollRunner.d.ts +1 -1
- package/dist/platform/polls/declaredPollRunner.js +1 -1
- package/dist/platform/tasks/TaskService.d.ts +4 -3
- package/dist/platform/tasks/TaskService.js +1 -4
- package/dist/platform/telemetryIngest.js +4 -4
- package/dist/platform/tools/index.d.ts +0 -1
- package/dist/platform/tools/index.js +0 -3
- package/dist/platform/tools/tier1/protocolRunner.d.ts +1 -1
- package/dist/platform/tools/tier1/protocolRunner.js +24 -17
- package/dist/platform/tools/tier1/protocolTools.js +2 -2
- package/dist/platform/tools/tier1/wakeTools.d.ts +1 -1
- package/dist/platform/tools/tier1/wakeTools.js +2 -1
- package/dist/platform/tools/tier2/mcpConnectionTools.js +1 -1
- package/dist/runtime/AgentMachine.d.ts +2 -2
- package/dist/runtime/AgentMachine.js +4 -5
- package/dist/runtime/PromptBuilder.d.ts +1 -1
- package/dist/runtime/PromptBuilder.js +5 -4
- package/dist/runtime/buildOutcome.d.ts +1 -1
- package/dist/runtime/deliveryWriteKeys.d.ts +1 -1
- package/dist/runtime/deliveryWriteKeys.js +1 -1
- package/dist/runtime/kickoff.d.ts +14 -43
- package/dist/runtime/kickoff.js +22 -178
- package/dist/runtime/messageCommand.d.ts +9 -0
- package/dist/runtime/messageCommand.js +23 -0
- package/dist/runtime/requiredContext.d.ts +6 -0
- package/dist/runtime/requiredContext.js +23 -0
- package/dist/runtime/runTurn.js +31 -106
- package/dist/runtime/taskIntake.js +8 -22
- package/dist/runtime/wakeEffects.d.ts +3 -12
- package/dist/runtime/wakeEffects.js +17 -48
- package/dist/runtime/wakeOutcome.js +1 -1
- package/dist/skills/createSkillAgent.js +12 -1
- package/dist/tools/capabilityAdapter.js +1 -1
- package/dist/tools/recordReport.d.ts +1 -1
- package/dist/tools/recordReport.js +3 -3
- package/dist/tools/toolCreds.d.ts +1 -1
- package/dist/tools/toolCreds.js +4 -2
- package/dist/types.d.ts +17 -27
- package/package.json +3 -3
- package/dist/platform/tools/tier2/chatTools.d.ts +0 -3
- package/dist/platform/tools/tier2/chatTools.js +0 -7
- package/dist/probeChat.d.ts +0 -10
- package/dist/probeChat.js +0 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTask, getTask, getActiveTasksForAgent,
|
|
1
|
+
import { createTask, getTask, getActiveTasksForAgent, getSubtasks, updateTaskState, updateTaskPlanStep, updateTaskPlanSteps, cancelTask, reportTask, setTaskSatisfaction, countTasks, acknowledgeTaskControl, presentTaskOutcome, } from '@ziggs-ai/api-client';
|
|
2
2
|
import { runtimeLog } from '../../shared/runtimeLog.js';
|
|
3
3
|
function safeJsonStringify(value) {
|
|
4
4
|
if (value === null || value === undefined)
|
|
@@ -40,9 +40,6 @@ export class TaskService {
|
|
|
40
40
|
async getActiveTasksForAgent(agentId) {
|
|
41
41
|
return getActiveTasksForAgent(agentId, this.creds);
|
|
42
42
|
}
|
|
43
|
-
async getActiveTasksForChat(chatId) {
|
|
44
|
-
return getActiveTasksForChat(chatId, this.creds);
|
|
45
|
-
}
|
|
46
43
|
async getSubtasks(parentTaskId) {
|
|
47
44
|
return getSubtasks(parentTaskId, this.creds);
|
|
48
45
|
}
|
|
@@ -18,11 +18,11 @@ export function usageFromLlmResponse(response) {
|
|
|
18
18
|
}
|
|
19
19
|
export function buildLlmIngestPayload(response, ctx) {
|
|
20
20
|
const { tokensTotal, tokensInput, tokensOutput } = usageFromLlmResponse(response);
|
|
21
|
-
const
|
|
21
|
+
const addressId = ctx.sessionId ?? null;
|
|
22
22
|
return {
|
|
23
23
|
source: 'agent',
|
|
24
|
-
|
|
25
|
-
sessionId:
|
|
24
|
+
addressId,
|
|
25
|
+
sessionId: addressId,
|
|
26
26
|
execution: {
|
|
27
27
|
llmCallsTotal: 1,
|
|
28
28
|
tokensTotal,
|
|
@@ -41,7 +41,7 @@ export function buildLlmIngestPayload(response, ctx) {
|
|
|
41
41
|
export function buildToolIngestPayload(ctx) {
|
|
42
42
|
return {
|
|
43
43
|
source: 'agent',
|
|
44
|
-
|
|
44
|
+
addressId: ctx.sessionId,
|
|
45
45
|
sessionId: ctx.sessionId,
|
|
46
46
|
execution: { executionLoops: 1 },
|
|
47
47
|
resource: { durationMs: Math.max(0, Math.round(ctx.durationMs)) },
|
|
@@ -32,4 +32,3 @@ export { PARTY_TOOLS, partyNoteTool } from './tier2/partyTools.js';
|
|
|
32
32
|
export { ARTIFACT_TOOLS, recordArtifactTool } from './tier2/artifactTools.js';
|
|
33
33
|
export { LISTING_TOOLS } from './tier2/listingTools.js';
|
|
34
34
|
export { MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, } from './tier2/mcpConnectionTools.js';
|
|
35
|
-
export { CHAT_TOOLS, openConversationTool } from './tier2/chatTools.js';
|
|
@@ -42,6 +42,3 @@ export { PARTY_TOOLS, partyNoteTool } from './tier2/partyTools.js';
|
|
|
42
42
|
export { ARTIFACT_TOOLS, recordArtifactTool } from './tier2/artifactTools.js';
|
|
43
43
|
export { LISTING_TOOLS } from './tier2/listingTools.js';
|
|
44
44
|
export { MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, } from './tier2/mcpConnectionTools.js';
|
|
45
|
-
// Decision: chat_open only — chat listing stays a context-rail read
|
|
46
|
-
// (grant_list scopeKind=chat), so there is no duplicate lister.
|
|
47
|
-
export { CHAT_TOOLS, openConversationTool } from './tier2/chatTools.js';
|
|
@@ -36,7 +36,7 @@ interface ProtocolPayload {
|
|
|
36
36
|
})[];
|
|
37
37
|
[key: string]: unknown;
|
|
38
38
|
}
|
|
39
|
-
export declare function dispatchProtocolOp(services: Services, payload: ProtocolPayload,
|
|
39
|
+
export declare function dispatchProtocolOp(services: Services, payload: ProtocolPayload, addressId: 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,5 @@
|
|
|
1
1
|
import { AGREEMENT_TERMINAL_STATES } from '@ziggs-ai/contracts';
|
|
2
|
-
import { isBroadcastTarget, partyActorIds, presentClaimResult, } from '@ziggs-ai/api-client';
|
|
2
|
+
import { isAgreementLaneId, currentWorkExecution, isBroadcastTarget, partyActorIds, presentClaimResult, } from '@ziggs-ai/api-client';
|
|
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
|
|
5
5
|
// each one restating `engagementKind === 'link' ? linkSummary(a) : a` — which is
|
|
@@ -56,7 +56,7 @@ function sourcesOf(payload) {
|
|
|
56
56
|
? { sources: payload.sources }
|
|
57
57
|
: {};
|
|
58
58
|
}
|
|
59
|
-
export async function dispatchProtocolOp(services, payload,
|
|
59
|
+
export async function dispatchProtocolOp(services, payload, addressId, _agents = [], actingAgentId = null, writeKeys = null,
|
|
60
60
|
/** #8 — prefer the cached session snapshot over a fresh HTTP read. */
|
|
61
61
|
cachedAgreements) {
|
|
62
62
|
if (!payload?.operation)
|
|
@@ -66,9 +66,9 @@ cachedAgreements) {
|
|
|
66
66
|
const actorId = actingAgentId?.trim() || null;
|
|
67
67
|
switch (operation) {
|
|
68
68
|
case 'agreement-propose':
|
|
69
|
-
return proposeAgreement(services, payload,
|
|
69
|
+
return proposeAgreement(services, payload, roomOf(addressId), writeKeys);
|
|
70
70
|
case 'agreement-subcontract':
|
|
71
|
-
return subcontractAgreement(services, payload, namedSubcontractChat(payload,
|
|
71
|
+
return subcontractAgreement(services, payload, roomOf(namedSubcontractChat(payload, addressId)), writeKeys);
|
|
72
72
|
case 'agreement-respond':
|
|
73
73
|
if (!payload.agreementId || !payload.action)
|
|
74
74
|
return null;
|
|
@@ -129,7 +129,7 @@ cachedAgreements) {
|
|
|
129
129
|
if (!payload.agreementId || !payload.description)
|
|
130
130
|
return null;
|
|
131
131
|
let spawnAgreementId = payload.agreementId;
|
|
132
|
-
const ags = await
|
|
132
|
+
const ags = await agreementsForWork(services, payload.agreementId, cachedAgreements);
|
|
133
133
|
// b2: if the assignee is not a party on the cited agreement,
|
|
134
134
|
// redirect the spawn to the ACTIVE sub-agreement (same root) where the
|
|
135
135
|
// assignee IS the provider — the orchestrator often cites the top-level
|
|
@@ -255,7 +255,7 @@ cachedAgreements) {
|
|
|
255
255
|
throw new Error(`Unknown protocol operation: ${operation}`);
|
|
256
256
|
}
|
|
257
257
|
}
|
|
258
|
-
async function proposeAgreement(services, payload,
|
|
258
|
+
async function proposeAgreement(services, payload, addressId, writeKeys = null) {
|
|
259
259
|
if (!payload.description)
|
|
260
260
|
throw new Error('agreement-propose requires `description`');
|
|
261
261
|
if (!payload.proposedTo)
|
|
@@ -297,7 +297,7 @@ async function proposeAgreement(services, payload, chatId, writeKeys = null) {
|
|
|
297
297
|
const interactionMode = oneOf(payload['interactionMode'], ['messages', 'tasks', 'both']);
|
|
298
298
|
const { agreement, shape } = await services.agreementService.proposeUnified({
|
|
299
299
|
proposedTo: payload.proposedTo,
|
|
300
|
-
|
|
300
|
+
addressId: addressId ?? undefined,
|
|
301
301
|
description: String(payload.description),
|
|
302
302
|
providerId: payload.providerId,
|
|
303
303
|
price: typeof payload.price === 'number' ? payload.price : undefined,
|
|
@@ -323,21 +323,21 @@ async function proposeAgreement(services, payload, chatId, writeKeys = null) {
|
|
|
323
323
|
// task_spawns a worker under the TOP-LEVEL hire — where the worker is not a
|
|
324
324
|
// party — instead of under that worker's sub-agreement, which the backend
|
|
325
325
|
// rejects with 400 "assignee is not a party". Both are made deterministic here
|
|
326
|
-
// using the
|
|
326
|
+
// using the selected work's authorized agreements.
|
|
327
327
|
const TERMINAL_STATUS = new Set(AGREEMENT_TERMINAL_STATES);
|
|
328
|
-
async function
|
|
329
|
-
if (!chatId)
|
|
330
|
-
return [];
|
|
328
|
+
async function agreementsForWork(services, agreementId, cachedAgreements) {
|
|
331
329
|
// #8 — createZiggsEffectHandler already cached the session snapshot;
|
|
332
330
|
// prefer that over another GET /context/snapshot just for the agreements array.
|
|
333
|
-
// Empty array is a real answer ("none in this
|
|
331
|
+
// Empty array is a real answer ("none in this work") — do not re-fetch.
|
|
334
332
|
if (cachedAgreements !== undefined) {
|
|
335
333
|
return Array.isArray(cachedAgreements) ? cachedAgreements : [];
|
|
336
334
|
}
|
|
337
335
|
try {
|
|
338
|
-
|
|
336
|
+
const execution = currentWorkExecution();
|
|
337
|
+
const via = execution?.taskId ? `task:${execution.taskId}` : execution?.agreementId ? `agreement:${execution.agreementId}`
|
|
338
|
+
: execution?.action?.kind === 'message' ? `message:${execution.action.id}` : `agreement:${agreementId}`;
|
|
339
339
|
const reader = services.contextReadClient;
|
|
340
|
-
const snap = await reader.snapshot(
|
|
340
|
+
const snap = await reader.snapshot({ maxMessages: 1, via });
|
|
341
341
|
const ags = snap.agreements;
|
|
342
342
|
return Array.isArray(ags) ? ags : [];
|
|
343
343
|
}
|
|
@@ -358,9 +358,16 @@ function agIsParty(a, agentId) {
|
|
|
358
358
|
function agIsActiveStatus(a) {
|
|
359
359
|
return String(a.status ?? '') === 'active';
|
|
360
360
|
}
|
|
361
|
+
/**
|
|
362
|
+
* The room a new agreement is discussed in. An agreement lane (`agrn-…`) is
|
|
363
|
+
* a session key, not a room, so it names none.
|
|
364
|
+
*/
|
|
365
|
+
function roomOf(addressId) {
|
|
366
|
+
return addressId && !isAgreementLaneId(addressId) ? addressId : null;
|
|
367
|
+
}
|
|
361
368
|
/** A named room on the call wins; otherwise the wake's chat. Empty is omit. */
|
|
362
369
|
function namedSubcontractChat(payload, wakeChatId) {
|
|
363
|
-
const named = payload.
|
|
370
|
+
const named = payload.addressId;
|
|
364
371
|
if (typeof named === 'string' && named.trim())
|
|
365
372
|
return named.trim();
|
|
366
373
|
return wakeChatId;
|
|
@@ -379,7 +386,7 @@ function namedSubcontractChat(payload, wakeChatId) {
|
|
|
379
386
|
* request over MCP stays open. A crash replay is still covered by the
|
|
380
387
|
* wake-derived idempotency key.
|
|
381
388
|
*/
|
|
382
|
-
async function subcontractAgreement(services, payload,
|
|
389
|
+
async function subcontractAgreement(services, payload, addressId, writeKeys = null) {
|
|
383
390
|
if (!payload.description || !payload.executorId)
|
|
384
391
|
return null;
|
|
385
392
|
// The price the model stated, or none; the server falls back to the
|
|
@@ -390,5 +397,5 @@ async function subcontractAgreement(services, payload, chatId, writeKeys = null)
|
|
|
390
397
|
description: payload.description,
|
|
391
398
|
parentAgreementId: payload.parentAgreementId ?? '',
|
|
392
399
|
});
|
|
393
|
-
return services.agreementService.delegate({ ...fields,
|
|
400
|
+
return services.agreementService.delegate({ ...fields, addressId, idempotencyKey });
|
|
394
401
|
}
|
|
@@ -19,7 +19,7 @@ const planReviewTimingParam = {
|
|
|
19
19
|
*/
|
|
20
20
|
const dueAtParam = {
|
|
21
21
|
type: 'string',
|
|
22
|
-
description: 'Deadline, ISO 8601 (e.g. 2026-09-12T17:00:00Z). When you hold a task with this set: at the deadline, post what you have and where you are stuck
|
|
22
|
+
description: 'Deadline, ISO 8601 (e.g. 2026-09-12T17:00:00Z). When you hold a task with this set: at the deadline, post what you have and where you are stuck to the task’s authorized recipients, then stop. Do not keep chasing past it. A deadline already past is refused.',
|
|
23
23
|
};
|
|
24
24
|
const checkBackParam = {
|
|
25
25
|
type: 'object',
|
|
@@ -47,7 +47,7 @@ function handlerFor(toolName) {
|
|
|
47
47
|
taskService: c.taskService,
|
|
48
48
|
agreementService: c.agreementService,
|
|
49
49
|
contextReadClient: c.contextReadClient,
|
|
50
|
-
}, { operation, ...args }, c.
|
|
50
|
+
}, { operation, ...args }, c.addressId ?? null, c.agents ?? [], typeof c.agentId === 'string' ? c.agentId : null, c.writeKeys ?? null, Array.isArray(c.agreements) ? c.agreements : undefined);
|
|
51
51
|
if (result == null)
|
|
52
52
|
throw new Error(`Operation ${operation} returned no result`);
|
|
53
53
|
return result;
|
|
@@ -15,7 +15,8 @@ export const wakeAtTool = defineTool('wake_at', {
|
|
|
15
15
|
if (!scheduler) {
|
|
16
16
|
throw new Error('wake_at is unavailable here (no wake scheduler in tool context — expected when running under Agent)');
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
// The timer belongs to the processing lane, not to a conversation.
|
|
19
|
+
const sessionId = c.sessionId;
|
|
19
20
|
if (!sessionId)
|
|
20
21
|
throw new Error('wake_at: no session in tool context');
|
|
21
22
|
const raw = typeof args.at === 'string' ? args.at.trim() : '';
|
|
@@ -66,7 +66,7 @@ async function withClient(ctx, toolName, connectionId, grantId, run) {
|
|
|
66
66
|
* The lane comes from `credsFromToolContext`, the same reader every other
|
|
67
67
|
* tool uses. Reading it off a field of its own (`ctx.laneId`) is how this
|
|
68
68
|
* door came to send no lane at all: the executor states the lane as
|
|
69
|
-
* `
|
|
69
|
+
* `addressId` / `sessionId`, so a key by any other name is always undefined,
|
|
70
70
|
* and the gateway then resolves the wake to the agent's own operator and
|
|
71
71
|
* refuses every grant its customer gave it.
|
|
72
72
|
*/
|
|
@@ -149,8 +149,8 @@ export declare class AgentMachine {
|
|
|
149
149
|
* it is a lane stuck in a room whose transitions were written for one
|
|
150
150
|
* occasion, so every later event is evaluated against the wrong state and
|
|
151
151
|
* anything that state does not route is swallowed. Measured: three lab
|
|
152
|
-
* workers tripped the depth guard inside
|
|
153
|
-
*
|
|
152
|
+
* workers tripped the depth guard inside an injected claim greeting (since
|
|
153
|
+
* removed) that had no `task-assigned` route, so the task wake
|
|
154
154
|
* that arrived next was dropped and three graph nodes were never worked at
|
|
155
155
|
* all. The greeting is best-effort; the work is not.
|
|
156
156
|
*
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { responseCommand } from './messageCommand.js';
|
|
1
2
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
2
3
|
import { applyOutcomeToCtx, outcomeFromEvent } from './buildOutcome.js';
|
|
3
4
|
import { runMechanical } from './runMechanical.js';
|
|
@@ -155,8 +156,8 @@ export class AgentMachine {
|
|
|
155
156
|
* it is a lane stuck in a room whose transitions were written for one
|
|
156
157
|
* occasion, so every later event is evaluated against the wrong state and
|
|
157
158
|
* anything that state does not route is swallowed. Measured: three lab
|
|
158
|
-
* workers tripped the depth guard inside
|
|
159
|
-
*
|
|
159
|
+
* workers tripped the depth guard inside an injected claim greeting (since
|
|
160
|
+
* removed) that had no `task-assigned` route, so the task wake
|
|
160
161
|
* that arrived next was dropped and three graph nodes were never worked at
|
|
161
162
|
* all. The greeting is best-effort; the work is not.
|
|
162
163
|
*
|
|
@@ -400,9 +401,7 @@ export class AgentMachine {
|
|
|
400
401
|
await this.eff({
|
|
401
402
|
kind: 'send-message',
|
|
402
403
|
sessionId,
|
|
403
|
-
receiverId: userId,
|
|
404
|
-
text,
|
|
405
|
-
messageId: this.writeKeys?.messageKey({ text, sessionId, receiverId: userId }),
|
|
404
|
+
command: await responseCommand(this.eff, sessionId, text, { recipientId: userId, operationId: this.writeKeys?.messageKey({ text, sessionId, receiverId: userId }) }),
|
|
406
405
|
});
|
|
407
406
|
}
|
|
408
407
|
catch { /* best-effort */ }
|
|
@@ -115,8 +115,9 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
115
115
|
if (!ctx)
|
|
116
116
|
return stateId ? `<machine_context>\n${JSON.stringify({ stateId }, null, 2)}\n</machine_context>` : '';
|
|
117
117
|
const out = { stateId };
|
|
118
|
+
// The processing lane, shown as what it is: a lane name is not an address.
|
|
118
119
|
if (ctx.identity?.sessionId)
|
|
119
|
-
out.
|
|
120
|
+
out.lane = ctx.identity.sessionId;
|
|
120
121
|
if (ctx.identity?.laneKey)
|
|
121
122
|
out.laneKey = ctx.identity.laneKey;
|
|
122
123
|
if (ctx.identity?.agentId)
|
|
@@ -326,7 +327,7 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
326
327
|
// ref as it came; the backend resolves it in-room. Transfer (and any
|
|
327
328
|
// account-id action) must never list opaque refs — lookup / wake / pay
|
|
328
329
|
// against them 400s.
|
|
329
|
-
const
|
|
330
|
+
const addressIds = new Set([...userIds, ...agentIds]);
|
|
330
331
|
const transferIds = new Set([...userIds, ...agentIds].filter((id) => !isOpaquePresentationRef(id)));
|
|
331
332
|
const lines = ['<recipients>'];
|
|
332
333
|
lines.push('<users>');
|
|
@@ -344,10 +345,10 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
344
345
|
lines.push(` - ${agentLabels.get(id)}`);
|
|
345
346
|
lines.push('</agents>');
|
|
346
347
|
lines.push('<chat>');
|
|
347
|
-
if (
|
|
348
|
+
if (addressIds.size === 0)
|
|
348
349
|
lines.push(' (none)');
|
|
349
350
|
else
|
|
350
|
-
for (const id of
|
|
351
|
+
for (const id of addressIds)
|
|
351
352
|
lines.push(` - ${tagged(id)}`);
|
|
352
353
|
lines.push('</chat>');
|
|
353
354
|
lines.push('<agreement>');
|
|
@@ -10,7 +10,7 @@ import type { DeliveryWriteKeys } from '../types.js';
|
|
|
10
10
|
* the transition itself, so it dedups regardless of the order in which the
|
|
11
11
|
* replayed wake happens to re-issue its tool calls.
|
|
12
12
|
* - chat messages: `sdk_idem_wk_<wake-hash>_m_<hash(chat, receiver, text)>`
|
|
13
|
-
* — used directly as the messageId (the backend dedups on (
|
|
13
|
+
* — used directly as the messageId (the backend dedups on (addressId, messageId),
|
|
14
14
|
*). Content-derived, not ordinal: a wake may emit several
|
|
15
15
|
* distinct messages without colliding, and a crash-replay that re-sends the
|
|
16
16
|
* same text reuses the key; a re-think with different text gets a new key
|
|
@@ -79,7 +79,7 @@ function sha(input) {
|
|
|
79
79
|
* the transition itself, so it dedups regardless of the order in which the
|
|
80
80
|
* replayed wake happens to re-issue its tool calls.
|
|
81
81
|
* - chat messages: `sdk_idem_wk_<wake-hash>_m_<hash(chat, receiver, text)>`
|
|
82
|
-
* — used directly as the messageId (the backend dedups on (
|
|
82
|
+
* — used directly as the messageId (the backend dedups on (addressId, messageId),
|
|
83
83
|
*). Content-derived, not ordinal: a wake may emit several
|
|
84
84
|
* distinct messages without colliding, and a crash-replay that re-sends the
|
|
85
85
|
* same text reuses the key; a re-think with different text gets a new key
|
|
@@ -1,60 +1,31 @@
|
|
|
1
1
|
import type { ThinkingState, Transition, Workflow } from '../types.js';
|
|
2
2
|
/** Reserved state name for the injected agreement-kickoff default (proposer). */
|
|
3
3
|
export declare const KICKOFF_STATE = "kickingOff";
|
|
4
|
-
/**
|
|
5
|
-
* reserved state for the injected claim/provider kickoff default.
|
|
6
|
-
* Store listing claimed → open buyer chat + greet (not task_create).
|
|
7
|
-
*/
|
|
8
|
-
export declare const CLAIM_KICKOFF_STATE = "claimKickingOff";
|
|
9
4
|
export declare function buildKickoffState(initial: string): ThinkingState;
|
|
10
|
-
/** provider side after a store/listing claim. */
|
|
11
5
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
6
|
+
* Route a store-claim wake from this state to `to`. The SDK no longer greets
|
|
7
|
+
* on a claim (a claim opens no room; the buyer writes first in the agreement's
|
|
8
|
+
* conversation), so this is only for an author who wants to act on the claim
|
|
9
|
+
* itself.
|
|
14
10
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* deliberate claim handler from a generic `proposal-resolved` route that
|
|
18
|
-
* happens to match. Writing that predicate by hand is easy to get subtly wrong,
|
|
19
|
-
* and getting it wrong is silent: the agent greets on every claim while its
|
|
20
|
-
* author believes it opted out. That cost one lab cast 100% of its token spend
|
|
21
|
-
* and three wedged workers before anyone noticed.
|
|
11
|
+
* It fires on a claim wake and NOT on a bare counterparty approve, which also
|
|
12
|
+
* keeps it out of the way of the proposer-side kickoff.
|
|
22
13
|
*
|
|
23
14
|
* transitions: [
|
|
24
15
|
* handlesClaimWake('idle'), // a claim does not make this agent talk
|
|
25
16
|
* { to: 'idle', when: (o) => o.kind === 'proposal-resolved' && o.action === 'approve' },
|
|
26
17
|
* ]
|
|
27
|
-
*
|
|
28
|
-
* Note the second route is still worth keeping when you also want to sit out
|
|
29
|
-
* the PROPOSER-side kickoff: that one probes with a bare approve, which this
|
|
30
|
-
* helper deliberately does not match.
|
|
31
18
|
*/
|
|
32
19
|
export declare function handlesClaimWake(to: string): Transition;
|
|
33
|
-
export declare function buildClaimKickoffState(initial: string): ThinkingState;
|
|
34
20
|
/**
|
|
35
|
-
* Agreement-kickoff
|
|
36
|
-
* handle
|
|
37
|
-
* state
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* - `kickingOff` — proposer-side approval → task_create
|
|
41
|
-
* - `claimKickingOff` — store-claim provider wake → chat_open + greet
|
|
42
|
-
* Direct-proposal counterparties (lifecycle approve, !proposedByMe, no
|
|
43
|
-
* fromClaimWake) still never auto-kickoff.
|
|
44
|
-
*
|
|
45
|
-
* **They are ordered differently on purpose** (first match wins in
|
|
46
|
-
* AgentMachine._evaluateTransitions):
|
|
21
|
+
* Agreement-kickoff default. For every state whose transitions do not already
|
|
22
|
+
* handle a proposer-side approval, append a transition to the injected
|
|
23
|
+
* `kickingOff` state, which spawns the first task. Appended LAST: the approval
|
|
24
|
+
* is of a proposal THIS agent made, so a route its author wrote keeps winning.
|
|
25
|
+
* Returns a NEW workflow; input states are not mutated.
|
|
47
26
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
* - `claimKickingOff` is inserted FIRST. It fires on a wake the author never
|
|
52
|
-
* wrote a route for, and it has to beat the unconditional fallthrough an
|
|
53
|
-
* `idle` state uses to reach its listening loop — otherwise the claim is
|
|
54
|
-
* swallowed into the idle loop and the buyer is never greeted. Going first
|
|
55
|
-
* is safe because its `when` is narrow: only a `fromClaimWake` approve
|
|
56
|
-
* matches, so nothing else is shadowed. An author who wants the claim for
|
|
57
|
-
* themselves keys on `fromClaimWake`, which suppresses the injection
|
|
58
|
-
* outright (stateHandlesClaimKickoff).
|
|
27
|
+
* Counterparties never auto-kickoff, and neither does a store claim: a claim
|
|
28
|
+
* opens no room, and the buyer's first message or task is what wakes the
|
|
29
|
+
* provider.
|
|
59
30
|
*/
|
|
60
31
|
export declare function injectKickoffDefault(workflow: Workflow): Workflow;
|