@ziggs-ai/agent-sdk 0.42.2 → 0.43.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +1 -1
  3. package/dist/Agent.d.ts +21 -8
  4. package/dist/Agent.js +173 -97
  5. package/dist/brain/ClaudeBrain.d.ts +0 -1
  6. package/dist/brain/ClaudeBrain.js +18 -42
  7. package/dist/brain/claudeCognition.js +5 -6
  8. package/dist/brain/claudeSdkProtocol.js +9 -9
  9. package/dist/brain/claudeSdkTools.d.ts +3 -3
  10. package/dist/brain/claudeSdkTools.js +37 -133
  11. package/dist/brain/hostedToolSurface.js +1 -1
  12. package/dist/brain/standingOfferNotice.d.ts +0 -2
  13. package/dist/brain/standingOfferNotice.js +1 -21
  14. package/dist/brain/toolManagerToSdkMcp.js +1 -1
  15. package/dist/brain/wakeGate.d.ts +3 -1
  16. package/dist/brain/wakeGate.js +6 -0
  17. package/dist/index.d.ts +4 -3
  18. package/dist/index.js +4 -3
  19. package/dist/ingress/normalizeIncoming.d.ts +5 -3
  20. package/dist/ingress/normalizeIncoming.js +9 -8
  21. package/dist/mcp/createMcpAgent.d.ts +15 -0
  22. package/dist/mcp/createMcpAgent.js +47 -11
  23. package/dist/memory/MemoryStore.d.ts +1 -1
  24. package/dist/memory/MemoryStore.js +1 -6
  25. package/dist/platform/ConnectionPool.js +1 -1
  26. package/dist/platform/OutboxBuffer.d.ts +2 -2
  27. package/dist/platform/OutboxBuffer.js +17 -17
  28. package/dist/platform/StateTimers.d.ts +3 -1
  29. package/dist/platform/StateTimers.js +4 -3
  30. package/dist/platform/WakeLedger.d.ts +10 -6
  31. package/dist/platform/WakeLedger.js +16 -9
  32. package/dist/platform/ZiggsEffectHandler.d.ts +18 -4
  33. package/dist/platform/ZiggsEffectHandler.js +86 -55
  34. package/dist/platform/agreements/AgreementService.d.ts +1 -3
  35. package/dist/platform/agreements/AgreementService.js +1 -7
  36. package/dist/platform/inboxLoop.d.ts +3 -9
  37. package/dist/platform/inboxLoop.js +151 -158
  38. package/dist/platform/polls/PollKind.d.ts +13 -16
  39. package/dist/platform/polls/PollKind.js +4 -4
  40. package/dist/platform/polls/PollRunner.d.ts +3 -20
  41. package/dist/platform/polls/PollRunner.js +13 -15
  42. package/dist/platform/polls/declaredPollRunner.d.ts +1 -1
  43. package/dist/platform/polls/declaredPollRunner.js +1 -1
  44. package/dist/platform/tasks/TaskService.d.ts +4 -3
  45. package/dist/platform/tasks/TaskService.js +1 -4
  46. package/dist/platform/telemetryIngest.js +4 -4
  47. package/dist/platform/tools/index.d.ts +0 -1
  48. package/dist/platform/tools/index.js +0 -3
  49. package/dist/platform/tools/tier1/protocolRunner.d.ts +1 -1
  50. package/dist/platform/tools/tier1/protocolRunner.js +24 -17
  51. package/dist/platform/tools/tier1/protocolTools.js +2 -2
  52. package/dist/platform/tools/tier1/wakeTools.d.ts +1 -1
  53. package/dist/platform/tools/tier1/wakeTools.js +2 -1
  54. package/dist/platform/tools/tier2/mcpConnectionTools.js +1 -1
  55. package/dist/runtime/AgentMachine.d.ts +2 -2
  56. package/dist/runtime/AgentMachine.js +4 -5
  57. package/dist/runtime/PromptBuilder.d.ts +1 -1
  58. package/dist/runtime/PromptBuilder.js +5 -4
  59. package/dist/runtime/buildOutcome.d.ts +1 -1
  60. package/dist/runtime/deliveryWriteKeys.d.ts +1 -1
  61. package/dist/runtime/deliveryWriteKeys.js +1 -1
  62. package/dist/runtime/kickoff.d.ts +14 -43
  63. package/dist/runtime/kickoff.js +22 -178
  64. package/dist/runtime/messageCommand.d.ts +9 -0
  65. package/dist/runtime/messageCommand.js +23 -0
  66. package/dist/runtime/requiredContext.d.ts +6 -0
  67. package/dist/runtime/requiredContext.js +23 -0
  68. package/dist/runtime/runTurn.js +31 -106
  69. package/dist/runtime/taskIntake.js +8 -22
  70. package/dist/runtime/wakeEffects.d.ts +3 -12
  71. package/dist/runtime/wakeEffects.js +17 -48
  72. package/dist/runtime/wakeOutcome.js +1 -1
  73. package/dist/skills/createSkillAgent.js +12 -1
  74. package/dist/tools/capabilityAdapter.js +1 -1
  75. package/dist/tools/recordReport.d.ts +1 -1
  76. package/dist/tools/recordReport.js +3 -3
  77. package/dist/tools/toolCreds.d.ts +1 -1
  78. package/dist/tools/toolCreds.js +4 -2
  79. package/dist/types.d.ts +17 -27
  80. package/package.json +3 -3
  81. package/dist/platform/tools/tier2/chatTools.d.ts +0 -3
  82. package/dist/platform/tools/tier2/chatTools.js +0 -7
  83. package/dist/probeChat.d.ts +0 -10
  84. package/dist/probeChat.js +0 -12
@@ -1,4 +1,4 @@
1
- import { createTask, getTask, getActiveTasksForAgent, getActiveTasksForChat, getSubtasks, updateTaskState, updateTaskPlanStep, updateTaskPlanSteps, cancelTask, reportTask, setTaskSatisfaction, countTasks, acknowledgeTaskControl, presentTaskOutcome, } from '@ziggs-ai/api-client';
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 chatId = ctx.sessionId ?? null;
21
+ const addressId = ctx.sessionId ?? null;
22
22
  return {
23
23
  source: 'agent',
24
- chatId,
25
- sessionId: chatId,
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
- chatId: ctx.sessionId,
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, chatId: string | null, _agents?: unknown[], actingAgentId?: string | null, writeKeys?: DeliveryWriteKeys | null,
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, chatId, _agents = [], actingAgentId = null, writeKeys = null,
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, chatId, writeKeys);
69
+ return proposeAgreement(services, payload, roomOf(addressId), writeKeys);
70
70
  case 'agreement-subcontract':
71
- return subcontractAgreement(services, payload, namedSubcontractChat(payload, chatId), writeKeys);
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 agreementsInChat(services, chatId, cachedAgreements);
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, chatId, writeKeys = null) {
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
- chatId: chatId ?? undefined,
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 chat's existing agreements.
326
+ // using the selected work's authorized agreements.
327
327
  const TERMINAL_STATUS = new Set(AGREEMENT_TERMINAL_STATES);
328
- async function agreementsInChat(services, chatId, cachedAgreements) {
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 chat") — do not re-fetch.
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
- // The room is the lane, as for every read made on a wake.
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(chatId, { maxMessages: 1 });
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.chatId;
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, chatId, writeKeys = null) {
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, chatId, idempotencyKey });
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 in the room where the question was asked, then stop. Do not keep chasing past it. A deadline already past is refused.',
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.chatId ?? null, c.agents ?? [], typeof c.agentId === 'string' ? c.agentId : null, c.writeKeys ?? null, Array.isArray(c.agreements) ? c.agreements : undefined);
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;
@@ -22,7 +22,7 @@ export interface WakeSchedulerPort {
22
22
  };
23
23
  }
24
24
  export interface WakeToolContext {
25
- chatId?: string;
25
+ addressId?: string;
26
26
  sessionId?: string;
27
27
  wakeScheduler?: WakeSchedulerPort;
28
28
  }
@@ -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
- const sessionId = c.chatId ?? c.sessionId;
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
- * `chatId` / `sessionId`, so a key by any other name is always undefined,
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 the injected `claimKickingOff`
153
- * greeting; `claimKickingOff` has no `task-assigned` route, so the task wake
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 the injected `claimKickingOff`
159
- * greeting; `claimKickingOff` has no `task-assigned` route, so the task wake
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 */ }
@@ -25,7 +25,7 @@ interface BuildArgs {
25
25
  definition: {
26
26
  description?: string;
27
27
  };
28
- chatId: string | null;
28
+ addressId: string | null;
29
29
  stateId: string;
30
30
  ctx: Ctx;
31
31
  /** When true, respond-action schemas omit the "message" field — used for 2-call streaming. */
@@ -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.chatId = ctx.identity.sessionId;
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 chatIds = new Set([...userIds, ...agentIds]);
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 (chatIds.size === 0)
348
+ if (addressIds.size === 0)
348
349
  lines.push(' (none)');
349
350
  else
350
- for (const id of chatIds)
351
+ for (const id of addressIds)
351
352
  lines.push(` - ${tagged(id)}`);
352
353
  lines.push('</chat>');
353
354
  lines.push('<agreement>');
@@ -29,7 +29,7 @@ export interface EmittedEvent {
29
29
  result?: WireResult;
30
30
  error?: string;
31
31
  receiverId?: string;
32
- chatId?: string;
32
+ addressId?: string;
33
33
  message?: string;
34
34
  text?: string;
35
35
  operation?: string;
@@ -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 (chatId, messageId),
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 (chatId, messageId),
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
- * Declare that THIS state answers a store-claim wake itself, so the injected
13
- * `claimKickingOff` greeting is not added to it.
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
- * The opt-out has to fire on a claim wake and NOT on a bare counterparty
16
- * approve — `stateHandlesClaimKickoff` uses that difference to tell a
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 defaults. For every state whose transitions do not already
36
- * handle the corresponding probe, add a transition to the injected kickoff
37
- * state. Returns a NEW workflow — input states are not mutated.
38
- *
39
- * Two kickoffs:
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
- * - `kickingOff` is appended LAST. It fires on an approval of a proposal THIS
49
- * agent made, which the author was already expecting — whatever route they
50
- * wrote for it should keep winning.
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;