@ziggs-ai/agent-sdk 0.1.12 → 0.2.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 (218) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +41 -2
  3. package/dist/AgentHost.d.ts +201 -0
  4. package/dist/AgentHost.js +652 -0
  5. package/dist/adapters/AnthropicAdapter.d.ts +39 -0
  6. package/dist/adapters/AnthropicAdapter.js +200 -0
  7. package/dist/adapters/McpAdapter.d.ts +199 -0
  8. package/dist/adapters/McpAdapter.js +468 -0
  9. package/dist/adapters/OpenAIAdapter.d.ts +26 -0
  10. package/dist/adapters/OpenAIAdapter.js +158 -0
  11. package/dist/adapters/index.js +2 -0
  12. package/dist/agent/Agent.d.ts +78 -0
  13. package/dist/agent/Agent.js +58 -0
  14. package/dist/agent/ClaudeSdkAgent.d.ts +38 -0
  15. package/dist/agent/ClaudeSdkAgent.js +322 -0
  16. package/dist/agent/claudeCognition.d.ts +67 -0
  17. package/dist/agent/claudeCognition.js +103 -0
  18. package/dist/agent/claudeSdkProtocol.d.ts +11 -0
  19. package/dist/agent/claudeSdkTools.d.ts +19 -0
  20. package/dist/agent/claudeSdkTools.js +57 -0
  21. package/dist/agent/hostedAgentConnection.d.ts +15 -0
  22. package/dist/agent/hostedAgentConnection.js +29 -0
  23. package/dist/agent/toolManagerToSdkMcp.d.ts +12 -0
  24. package/dist/agent/toolManagerToSdkMcp.js +123 -0
  25. package/dist/brain/index.d.ts +50 -0
  26. package/dist/brain/index.js +45 -0
  27. package/dist/cognition/validateContext.d.ts +11 -0
  28. package/dist/cognition/validateContext.js +117 -0
  29. package/dist/context/applyEffects.d.ts +2 -0
  30. package/dist/context/applyEffects.js +89 -0
  31. package/dist/context/batch.d.ts +2 -0
  32. package/dist/context/batch.js +18 -0
  33. package/dist/context/classifyEnvelope.d.ts +1 -0
  34. package/dist/context/classifyEnvelope.js +58 -0
  35. package/dist/context/routingLabels.d.ts +4 -0
  36. package/dist/context/routingLabels.js +48 -0
  37. package/dist/defineAgent.d.ts +14 -0
  38. package/dist/defineAgent.js +68 -0
  39. package/dist/formatters/AgreementFormatter.d.ts +18 -0
  40. package/dist/formatters/AgreementFormatter.js +130 -0
  41. package/dist/formatters/HistoryFormatter.d.ts +26 -0
  42. package/dist/formatters/HistoryFormatter.js +173 -0
  43. package/dist/formatters/index.js +2 -0
  44. package/{src/index.ts → dist/index.d.ts} +7 -53
  45. package/dist/index.js +66 -0
  46. package/dist/ingress/normalizeIncoming.d.ts +65 -0
  47. package/dist/ingress/normalizeIncoming.js +88 -0
  48. package/dist/memory/MemoryStore.d.ts +55 -0
  49. package/dist/memory/MemoryStore.js +78 -0
  50. package/dist/pricing/fleetDefaults.d.ts +46 -0
  51. package/dist/pricing/fleetDefaults.js +168 -0
  52. package/dist/pricing/fleetEvalFree.d.ts +7 -0
  53. package/dist/pricing/fleetEvalFree.js +24 -0
  54. package/dist/pricing/fleetFreeTierA.gen.d.ts +6 -0
  55. package/{src/pricing/fleetFreeTierA.gen.ts → dist/pricing/fleetFreeTierA.gen.js} +5 -6
  56. package/dist/pricing/fleetTierByAgentId.gen.d.ts +7 -0
  57. package/dist/pricing/fleetTierByAgentId.gen.js +768 -0
  58. package/dist/runtime/AgentMachine.d.ts +143 -0
  59. package/dist/runtime/AgentMachine.js +400 -0
  60. package/dist/runtime/PromptBuilder.d.ts +96 -0
  61. package/dist/runtime/PromptBuilder.js +439 -0
  62. package/{src/runtime/bootstrapCtx.ts → dist/runtime/bootstrapCtx.d.ts} +1 -22
  63. package/dist/runtime/bootstrapCtx.js +37 -0
  64. package/dist/runtime/buildOutcome.d.ts +68 -0
  65. package/dist/runtime/buildOutcome.js +464 -0
  66. package/dist/runtime/defaults.d.ts +54 -0
  67. package/dist/runtime/defaults.js +47 -0
  68. package/dist/runtime/deriveRespondsToProposals.d.ts +9 -0
  69. package/dist/runtime/deriveRespondsToProposals.js +38 -0
  70. package/dist/runtime/kickoff.d.ts +15 -0
  71. package/dist/runtime/kickoff.js +112 -0
  72. package/dist/runtime/runMechanical.d.ts +25 -0
  73. package/dist/runtime/runMechanical.js +74 -0
  74. package/dist/runtime/runTurn.d.ts +63 -0
  75. package/dist/runtime/runTurn.js +800 -0
  76. package/dist/runtime/validateWorkflow.d.ts +17 -0
  77. package/dist/runtime/validateWorkflow.js +209 -0
  78. package/dist/server/ConnectionPool.d.ts +68 -0
  79. package/dist/server/ConnectionPool.js +166 -0
  80. package/dist/server/EventQueue.d.ts +33 -0
  81. package/dist/server/EventQueue.js +98 -0
  82. package/dist/server/InboxCatchUp.d.ts +24 -0
  83. package/dist/server/InboxCatchUp.js +213 -0
  84. package/dist/server/OutboxBuffer.d.ts +33 -0
  85. package/dist/server/OutboxBuffer.js +68 -0
  86. package/dist/server/SeenMessages.d.ts +13 -0
  87. package/dist/server/SeenMessages.js +31 -0
  88. package/dist/server/StateTimers.d.ts +34 -0
  89. package/dist/server/StateTimers.js +70 -0
  90. package/dist/server/ZiggsEffectHandler.d.ts +79 -0
  91. package/dist/server/ZiggsEffectHandler.js +319 -0
  92. package/dist/server/agreements/AgreementService.d.ts +50 -0
  93. package/dist/server/agreements/AgreementService.js +85 -0
  94. package/dist/server/createHealthServer.d.ts +7 -0
  95. package/dist/server/createHealthServer.js +75 -0
  96. package/dist/server/proactive/ProactiveTrigger.d.ts +33 -0
  97. package/dist/server/proactive/ProactiveTrigger.js +71 -0
  98. package/dist/server/runLauncher.d.ts +28 -0
  99. package/dist/server/runLauncher.js +93 -0
  100. package/dist/server/tasks/TaskService.d.ts +25 -0
  101. package/dist/server/tasks/TaskService.js +103 -0
  102. package/dist/server/tasks/index.js +1 -0
  103. package/dist/server/telemetryIngest.d.ts +24 -0
  104. package/dist/server/telemetryIngest.js +62 -0
  105. package/dist/server/tools/index.d.ts +24 -0
  106. package/{src/server/tools/index.ts → dist/server/tools/index.js} +4 -24
  107. package/dist/server/tools/tier1/protocolRunner.d.ts +39 -0
  108. package/dist/server/tools/tier1/protocolRunner.js +288 -0
  109. package/dist/server/tools/tier1/protocolTools.d.ts +12 -0
  110. package/dist/server/tools/tier1/protocolTools.js +37 -0
  111. package/dist/server/tools/tier2/connectionTools.d.ts +4 -0
  112. package/dist/server/tools/tier2/connectionTools.js +63 -0
  113. package/dist/server/tools/tier2/contextTools.d.ts +4 -0
  114. package/dist/server/tools/tier2/contextTools.js +46 -0
  115. package/dist/server/tools/tier2/discoveryTools.d.ts +4 -0
  116. package/dist/server/tools/tier2/discoveryTools.js +25 -0
  117. package/dist/server/tools/tier2/marketplaceTools.d.ts +3 -0
  118. package/dist/server/tools/tier2/marketplaceTools.js +22 -0
  119. package/dist/server/tools/tier2/paymentTools.d.ts +12 -0
  120. package/dist/server/tools/tier2/paymentTools.js +165 -0
  121. package/dist/server/ziggsconnect/ZiggsConnectClient.d.ts +35 -0
  122. package/dist/server/ziggsconnect/ZiggsConnectClient.js +95 -0
  123. package/dist/server/ziggscontext/ZiggsContextClient.d.ts +48 -0
  124. package/dist/server/ziggscontext/ZiggsContextClient.js +90 -0
  125. package/dist/server/ziggspay/ZiggsPayClient.d.ts +82 -0
  126. package/dist/server/ziggspay/ZiggsPayClient.js +188 -0
  127. package/dist/shared/ids.d.ts +1 -0
  128. package/dist/shared/ids.js +3 -0
  129. package/dist/shared/runtimeLog.d.ts +18 -0
  130. package/dist/shared/runtimeLog.js +68 -0
  131. package/dist/shared/types.d.ts +22 -0
  132. package/dist/shared/types.js +23 -0
  133. package/dist/tasks/protocolRegistry.d.ts +16 -0
  134. package/dist/tasks/protocolRegistry.js +20 -0
  135. package/dist/tools/ToolManager.d.ts +12 -0
  136. package/dist/tools/ToolManager.js +74 -0
  137. package/dist/tools/ToolProvider.d.ts +6 -0
  138. package/dist/tools/ToolProvider.js +21 -0
  139. package/dist/tools/defineTool.d.ts +27 -0
  140. package/dist/tools/defineTool.js +62 -0
  141. package/{src/tools/index.ts → dist/tools/index.d.ts} +0 -1
  142. package/dist/tools/index.js +6 -0
  143. package/dist/tools/recordReport.d.ts +41 -0
  144. package/dist/tools/recordReport.js +30 -0
  145. package/dist/types.d.ts +466 -0
  146. package/dist/types.js +7 -0
  147. package/dist/utils/jsonExtractor.d.ts +2 -0
  148. package/dist/utils/jsonExtractor.js +111 -0
  149. package/package.json +13 -5
  150. package/src/AgentHost.ts +0 -814
  151. package/src/adapters/AnthropicAdapter.ts +0 -238
  152. package/src/adapters/McpAdapter.ts +0 -678
  153. package/src/adapters/OpenAIAdapter.ts +0 -194
  154. package/src/agent/Agent.ts +0 -112
  155. package/src/agent/ClaudeSdkAgent.ts +0 -401
  156. package/src/agent/claudeCognition.ts +0 -139
  157. package/src/agent/claudeSdkTools.ts +0 -81
  158. package/src/agent/hostedAgentConnection.ts +0 -41
  159. package/src/agent/toolManagerToSdkMcp.ts +0 -136
  160. package/src/cognition/validateContext.ts +0 -95
  161. package/src/context/applyEffects.ts +0 -80
  162. package/src/context/batch.ts +0 -19
  163. package/src/context/classifyEnvelope.ts +0 -38
  164. package/src/context/routingLabels.ts +0 -46
  165. package/src/defineAgent.ts +0 -77
  166. package/src/formatters/AgreementFormatter.ts +0 -111
  167. package/src/formatters/HistoryFormatter.ts +0 -172
  168. package/src/ingress/normalizeIncoming.ts +0 -162
  169. package/src/memory/MemoryStore.ts +0 -104
  170. package/src/pricing/fleetDefaults.ts +0 -225
  171. package/src/pricing/fleetEvalFree.ts +0 -24
  172. package/src/pricing/fleetTierByAgentId.gen.ts +0 -775
  173. package/src/runtime/AgentMachine.ts +0 -484
  174. package/src/runtime/PromptBuilder.ts +0 -522
  175. package/src/runtime/buildOutcome.ts +0 -563
  176. package/src/runtime/defaults.ts +0 -86
  177. package/src/runtime/deriveRespondsToProposals.ts +0 -35
  178. package/src/runtime/kickoff.ts +0 -117
  179. package/src/runtime/runMechanical.ts +0 -106
  180. package/src/runtime/runTurn.ts +0 -870
  181. package/src/runtime/validateWorkflow.ts +0 -221
  182. package/src/server/ConnectionPool.ts +0 -206
  183. package/src/server/EventQueue.ts +0 -133
  184. package/src/server/InboxCatchUp.ts +0 -291
  185. package/src/server/OutboxBuffer.ts +0 -90
  186. package/src/server/SeenMessages.ts +0 -27
  187. package/src/server/StateTimers.ts +0 -85
  188. package/src/server/ZiggsEffectHandler.ts +0 -427
  189. package/src/server/agreements/AgreementService.ts +0 -118
  190. package/src/server/createHealthServer.ts +0 -85
  191. package/src/server/proactive/ProactiveTrigger.ts +0 -83
  192. package/src/server/runLauncher.ts +0 -146
  193. package/src/server/tasks/TaskService.ts +0 -111
  194. package/src/server/telemetryIngest.ts +0 -91
  195. package/src/server/tools/tier1/protocolRunner.ts +0 -353
  196. package/src/server/tools/tier1/protocolTools.ts +0 -114
  197. package/src/server/tools/tier2/connectionTools.ts +0 -75
  198. package/src/server/tools/tier2/contextTools.ts +0 -63
  199. package/src/server/tools/tier2/discoveryTools.ts +0 -34
  200. package/src/server/tools/tier2/marketplaceTools.ts +0 -27
  201. package/src/server/tools/tier2/paymentTools.ts +0 -170
  202. package/src/server/ziggsconnect/ZiggsConnectClient.ts +0 -126
  203. package/src/server/ziggscontext/ZiggsContextClient.ts +0 -129
  204. package/src/server/ziggspay/ZiggsPayClient.ts +0 -193
  205. package/src/shared/ids.ts +0 -3
  206. package/src/shared/runtimeLog.ts +0 -72
  207. package/src/shared/types.ts +0 -29
  208. package/src/tasks/protocolRegistry.ts +0 -25
  209. package/src/tools/ToolManager.ts +0 -95
  210. package/src/tools/ToolProvider.ts +0 -19
  211. package/src/tools/defineTool.ts +0 -90
  212. package/src/tools/recordReport.ts +0 -82
  213. package/src/types.ts +0 -483
  214. package/src/utils/jsonExtractor.ts +0 -100
  215. /package/{src/adapters/index.ts → dist/adapters/index.d.ts} +0 -0
  216. /package/{src/agent/claudeSdkProtocol.ts → dist/agent/claudeSdkProtocol.js} +0 -0
  217. /package/{src/formatters/index.ts → dist/formatters/index.d.ts} +0 -0
  218. /package/{src/server/tasks/index.ts → dist/server/tasks/index.d.ts} +0 -0
@@ -0,0 +1,439 @@
1
+ import { HistoryFormatter, AgreementFormatter } from '../formatters/index.js';
2
+ import { validateContext } from '../cognition/validateContext.js';
3
+ import { isBroadcastTarget } from '@ziggs-ai/api-client';
4
+ /** Rough chars-per-token ratio for budgeting (English/JSON averages ~4). */
5
+ const CHARS_PER_TOKEN = 4;
6
+ /**
7
+ * Builds the XML prompt for a thinking-state turn:
8
+ * <agent><self/><world/><decision_schema/></agent>
9
+ *
10
+ * Reads Ctx (identity + persistent ids + lastOutcome) for <machine_context>.
11
+ * Action tool binding is direct (action.tool). Decision schema documents the
12
+ * action's `produces` outcome kind.
13
+ */
14
+ export class PromptBuilder {
15
+ description;
16
+ specialization;
17
+ maxHistoryEntries;
18
+ maxHistoryTokens;
19
+ historyFormatter;
20
+ agreementFormatter;
21
+ logger;
22
+ constructor(options = {}) {
23
+ this.description = options.description || 'A capable agent ready to assist';
24
+ this.specialization = options.specialization ?? null;
25
+ this.maxHistoryEntries = options.maxHistoryEntries ?? 50;
26
+ this.maxHistoryTokens = options.maxHistoryTokens ?? 8000;
27
+ this.historyFormatter = options.historyFormatter || new HistoryFormatter();
28
+ this.agreementFormatter = (options.agreementFormatter || new AgreementFormatter());
29
+ this.logger = options.logger || null;
30
+ }
31
+ // Section order is deliberate and cache-stable (ZIG-769): <self> (identity,
32
+ // state, tools) is stable per agent+state and comes first, so OpenAI automatic
33
+ // prompt caching can reuse it as a prefix across a conversation's turns. All
34
+ // volatile content (the incoming event, history, and currentTime) lives later
35
+ // in <world>, so it never invalidates that cacheable prefix.
36
+ buildFromState(args) {
37
+ const { statePrompt, actions, serverContext, incomingEvent, definition, stateId, ctx, omitMessageFromRespond } = args;
38
+ const ctxObj = serverContext?.context || {};
39
+ validateContext(ctxObj, { logger: this.logger });
40
+ const agentId = this._getMyAgentId(ctxObj);
41
+ const senderMeta = this._getSenderMeta(incomingEvent, ctxObj);
42
+ const agreements = ctxObj.agreements || [];
43
+ const otherAgents = (ctxObj.agents || []).filter((a) => !a.isYou);
44
+ const users = ctxObj.users || [];
45
+ const desc = definition?.description || this.description;
46
+ return `<agent>
47
+
48
+ ${this._renderSelfFromState(desc, statePrompt, serverContext?.tools)}
49
+
50
+ ${this._renderWorld(incomingEvent, ctxObj, agentId, senderMeta, agreements, otherAgents, users, stateId, ctx)}
51
+
52
+ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessageFromRespond)}
53
+
54
+ </agent>`;
55
+ }
56
+ _renderSelfFromState(description, statePrompt, tools) {
57
+ const lines = ['<self>'];
58
+ lines.push(`<identity>\nYou are an Autonomous Agent.\n${description}\n</identity>`);
59
+ lines.push('\n<state>');
60
+ if (statePrompt.role)
61
+ lines.push(`Role: ${statePrompt.role}`);
62
+ if (statePrompt.goal)
63
+ lines.push(`Goal: ${statePrompt.goal}`);
64
+ if (statePrompt.context)
65
+ lines.push(`Context: ${statePrompt.context}`);
66
+ if (statePrompt.constraints)
67
+ lines.push(`Constraints: ${statePrompt.constraints}`);
68
+ lines.push('</state>');
69
+ if (tools?.length) {
70
+ lines.push('\n<tools>');
71
+ for (const tool of tools) {
72
+ const toolAny = tool;
73
+ const fn = toolAny.schema?.function || toolAny.schema;
74
+ const name = fn?.name;
75
+ const desc = fn?.description;
76
+ if (name)
77
+ lines.push(`- ${name}${desc ? ': ' + desc : ''}`);
78
+ }
79
+ lines.push('</tools>');
80
+ }
81
+ lines.push('</self>');
82
+ return lines.join('\n');
83
+ }
84
+ _renderWorld(event, ctxObj, agentId, senderMeta, agreements, otherAgents, users, stateId, ctx) {
85
+ const lines = ['<world>'];
86
+ const machineBlock = this._renderMachineContext(stateId, ctx);
87
+ if (machineBlock) {
88
+ lines.push(machineBlock);
89
+ lines.push('');
90
+ }
91
+ lines.push(this._renderEvent(event, senderMeta));
92
+ lines.push('');
93
+ lines.push(this._renderHistory(ctxObj.history, agentId));
94
+ lines.push('');
95
+ lines.push(this._renderAgreements(agreements));
96
+ if (ctx?.collectedResults?.length) {
97
+ lines.push('');
98
+ lines.push(this._renderSubtaskResults(ctx.collectedResults));
99
+ }
100
+ if (users.length > 0 || otherAgents.length > 0) {
101
+ lines.push('');
102
+ lines.push(this._renderRecipients(users, otherAgents, agreements, agentId));
103
+ }
104
+ lines.push(`\n<context>\n currentTime: ${new Date().toISOString()}\n</context>`);
105
+ lines.push('</world>');
106
+ return lines.join('\n');
107
+ }
108
+ _renderMachineContext(stateId, ctx) {
109
+ if (!ctx)
110
+ return stateId ? `<machine_context>\n${JSON.stringify({ stateId }, null, 2)}\n</machine_context>` : '';
111
+ const out = { stateId };
112
+ if (ctx.identity?.sessionId)
113
+ out.chatId = ctx.identity.sessionId;
114
+ if (ctx.identity?.laneKey)
115
+ out.laneKey = ctx.identity.laneKey;
116
+ if (ctx.identity?.agentId)
117
+ out.ownAgentId = ctx.identity.agentId;
118
+ if (ctx.activeAgreementId)
119
+ out.activeAgreementId = ctx.activeAgreementId;
120
+ if (ctx.activeTaskId)
121
+ out.activeTaskId = ctx.activeTaskId;
122
+ if (ctx.pendingProposalAgreementId)
123
+ out.pendingProposalAgreementId = ctx.pendingProposalAgreementId;
124
+ if (ctx.delegatedAgreementIds?.length)
125
+ out.delegatedAgreementIds = ctx.delegatedAgreementIds;
126
+ if (Object.keys(ctx.pendingSubtasks ?? {}).length)
127
+ out.pendingSubtasks = ctx.pendingSubtasks;
128
+ if (ctx.lastOutcome)
129
+ out.lastOutcomeKind = ctx.lastOutcome.kind;
130
+ return `<machine_context>\n${JSON.stringify(out, null, 2)}\n</machine_context>`;
131
+ }
132
+ _renderSubtaskResults(results) {
133
+ const lines = ['<subtask_results>'];
134
+ lines.push(`All ${results.length} finished subtask(s) for the current engagement, oldest first. Synthesize from ALL of them — not just the most recent event.`);
135
+ for (const r of results) {
136
+ const payload = r.result == null ? null : typeof r.result === 'string' ? r.result : JSON.stringify(r.result);
137
+ const display = payload && payload.length > 2000 ? payload.slice(0, 2000) + `… [truncated of ${payload.length} chars]` : payload;
138
+ lines.push(`- taskId=${r.taskId} agent=${r.agentId ?? 'unknown'} status=${r.status}`);
139
+ lines.push(` result: ${display ?? '(none)'}`);
140
+ }
141
+ lines.push('</subtask_results>');
142
+ return lines.join('\n');
143
+ }
144
+ _renderEvent(event, senderMeta) {
145
+ if (!event)
146
+ return '<event type="none">No incoming event.</event>';
147
+ const evAny = event;
148
+ if (evAny.type === 'batch' && Array.isArray(evAny.events) && evAny.events.length > 0) {
149
+ const parts = evAny.events.map((e, i) => {
150
+ const sub = { ...senderMeta, senderId: (e.senderId ?? senderMeta.senderId), senderType: (e.senderType ?? senderMeta.senderType) };
151
+ return (i > 0 ? '\n---\n' : '') + this._renderEvent(e, sub);
152
+ });
153
+ return `<event type="batch" count="${evAny.events.length}">\n${parts.join('')}\n</event>`;
154
+ }
155
+ const eventType = String(evAny.type || 'message');
156
+ const from = `${senderMeta.senderId} (${String(senderMeta.senderType || 'unknown').toLowerCase()})`;
157
+ const result = evAny.result;
158
+ if (eventType === 'task_result' && result?.taskId) {
159
+ return this._renderTaskResultEvent(result, from);
160
+ }
161
+ if (eventType === 'tool_result') {
162
+ const r = typeof result === 'object' ? JSON.stringify(result, null, 2) : String(result);
163
+ return `<event type="${eventType}" from="${from}">\nTool: ${evAny.tool}\nResult:\n${r}\n</event>`;
164
+ }
165
+ if (eventType === 'tool_error') {
166
+ return `<event type="${eventType}" from="${from}">\nTool Error: ${evAny.tool}\nMessage: ${evAny.error}\n</event>`;
167
+ }
168
+ if (eventType === 'message_sent') {
169
+ return `<event type="${eventType}" from="${from}">\nYour message was delivered. Do not repeat it.\n</event>`;
170
+ }
171
+ const content = event.text || event.result || event.content;
172
+ if (!content)
173
+ return `<event type="${eventType}" from="${from}">(Empty)</event>`;
174
+ const str = typeof content === 'object' ? JSON.stringify(content) : String(content);
175
+ // Matches MAX_MSG_CHARS in runTurn.ts — the incoming instruction shouldn't
176
+ // be truncated tighter than what the agent itself is allowed to send back.
177
+ const display = str.length > 3500 ? str.slice(0, 3500) + '...' : str;
178
+ return `<event type="${eventType}" from="${from}">\n${display}\n</event>`;
179
+ }
180
+ _renderTaskResultEvent(task, from) {
181
+ const lines = [];
182
+ const ag = task.agreement;
183
+ const parties = ag?.parties || {};
184
+ const creatorIsYou = task.creatorIsYou;
185
+ const providerIsYou = task.providerIsYou;
186
+ if (ag?.agreementId) {
187
+ lines.push(`Agreement: ${ag.agreementId}${creatorIsYou ? ' (yours)' : ''}`);
188
+ lines.push(` Creator: ${parties.creator ?? 'N/A'}${creatorIsYou ? ' (You)' : ''}`);
189
+ lines.push(` Provider: ${parties.provider ?? 'N/A'}${providerIsYou ? ' (You)' : ''}`);
190
+ const proposal = ag.proposal;
191
+ if (proposal?.status) {
192
+ lines.push(` Proposal: ${proposal.status} (to ${parties.proposedTo}${task.proposedToIsYou ? ' - You' : ''})`);
193
+ }
194
+ const money = ag.money;
195
+ if (typeof money?.price === 'number' && money.price > 0) {
196
+ lines.push(` Price: ${money.price} cents (${money.paymentStatus})`);
197
+ }
198
+ }
199
+ lines.push('');
200
+ lines.push(`Task: ${task.taskId}`);
201
+ lines.push(` Description: ${task.description}`);
202
+ lines.push(` State: ${task.state}`);
203
+ if (task.parentTaskId)
204
+ lines.push(` Parent task: ${task.parentTaskId}`);
205
+ // Tasks are always born active in the new model. Proposal lifecycle lives
206
+ // only on the agreement; the prompt surfaces it through the <agreements>
207
+ // section, not via task state.
208
+ void ag;
209
+ void parties;
210
+ return `<event type="task_result" from="${from}"${creatorIsYou ? ' own_agreement="true"' : ''}>\n${lines.join('\n')}\n</event>`;
211
+ }
212
+ _renderHistory(history, agentId) {
213
+ const all = history || [];
214
+ const charBudget = this.maxHistoryTokens * CHARS_PER_TOKEN;
215
+ // Include entries newest-first, bounded by BOTH a token budget and the
216
+ // entry-count ceiling. The newest entry is always kept even if it alone
217
+ // exceeds the budget, so the most recent turn is never dropped.
218
+ let startIdx = all.length;
219
+ let usedChars = 0;
220
+ for (let i = all.length - 1; i >= 0; i--) {
221
+ if (all.length - i > this.maxHistoryEntries)
222
+ break;
223
+ const size = this._estimateEntryChars(all[i]);
224
+ if (startIdx < all.length && usedChars + size > charBudget)
225
+ break;
226
+ usedChars += size;
227
+ startIdx = i;
228
+ }
229
+ const entries = all.slice(startIdx);
230
+ const dropped = all.length - entries.length;
231
+ const truncNote = dropped > 0
232
+ ? `[Showing last ${entries.length} of ${all.length} entries — older turns dropped to fit the context budget]\n\n`
233
+ : '';
234
+ const formatted = this.historyFormatter.format(entries, agentId ?? '', {});
235
+ return `<history>\n${truncNote}${formatted}\n</history>`;
236
+ }
237
+ /** Rough character size of one history entry, used for the token budget. */
238
+ _estimateEntryChars(entry) {
239
+ try {
240
+ return JSON.stringify(entry)?.length ?? 0;
241
+ }
242
+ catch {
243
+ return 0;
244
+ }
245
+ }
246
+ _renderAgreements(agreements) {
247
+ const formatted = this.agreementFormatter.format(agreements || []);
248
+ return `<agreements>\n${formatted}\n</agreements>`;
249
+ }
250
+ _renderRecipients(users, otherAgents, agreements, myAgentId) {
251
+ // <recipients> is grouped by surface so the LLM knows which ids it can use
252
+ // for each kind of action. Same id appears in multiple subsections when it
253
+ // participates in multiple surfaces. <users> / <agents> stay as the typed
254
+ // directory (existing prompts reference <recipients><users>); the new
255
+ // <chat>/<agreement>/<task>/<transfer> subsections narrow that directory
256
+ // to a specific action surface.
257
+ const userIds = new Set();
258
+ const userLabels = new Map();
259
+ for (const u of users) {
260
+ const id = u?.userId;
261
+ if (!id || id === myAgentId)
262
+ continue;
263
+ userIds.add(id);
264
+ userLabels.set(id, u.userName ? `${u.userName} (${id})` : id);
265
+ }
266
+ const agentIds = new Set();
267
+ const agentLabels = new Map();
268
+ for (const a of otherAgents) {
269
+ const id = a?.agentId;
270
+ if (!id || id === myAgentId)
271
+ continue;
272
+ agentIds.add(id);
273
+ const desc = typeof a.description === 'string' ? `: ${a.description.slice(0, 80)}` : '';
274
+ const name = a.name && a.name !== id ? `${a.name} (${id})` : id;
275
+ agentLabels.set(id, `${name}${desc}`);
276
+ }
277
+ const kindOf = (id) => userIds.has(id) ? 'user' : agentIds.has(id) ? 'agent' : 'unknown';
278
+ const labelOf = (id) => userLabels.get(id) ?? agentLabels.get(id) ?? id;
279
+ const tagged = (id) => `${labelOf(id)} [${kindOf(id)}]`;
280
+ const agreementParties = new Map();
281
+ for (const ag of agreements || []) {
282
+ const agId = ag?.agreementId;
283
+ const parties = ag?.parties || {};
284
+ const roles = [
285
+ ['creator', 'creator'],
286
+ ['provider', 'provider'],
287
+ ['payer', 'payer'],
288
+ ['proposedTo', 'proposedTo'],
289
+ ];
290
+ for (const [field, role] of roles) {
291
+ const pid = parties[field];
292
+ if (!pid || pid === myAgentId)
293
+ continue;
294
+ if (!agreementParties.has(pid))
295
+ agreementParties.set(pid, []);
296
+ agreementParties.get(pid).push({ agreementId: agId ?? '', role });
297
+ }
298
+ }
299
+ // Chat and transfer surfaces default to the full directory: every chat
300
+ // counterparty can receive a chat message; every id can receive a transfer
301
+ // by their principal id until per-wallet routing is wired through.
302
+ const chatIds = new Set([...userIds, ...agentIds]);
303
+ const transferIds = new Set([...userIds, ...agentIds]);
304
+ const lines = ['<recipients>'];
305
+ lines.push('<users>');
306
+ if (userIds.size === 0)
307
+ lines.push(' (none)');
308
+ else
309
+ for (const id of userIds)
310
+ lines.push(` - ${userLabels.get(id)}`);
311
+ lines.push('</users>');
312
+ lines.push('<agents>');
313
+ if (agentIds.size === 0)
314
+ lines.push(' (none)');
315
+ else
316
+ for (const id of agentIds)
317
+ lines.push(` - ${agentLabels.get(id)}`);
318
+ lines.push('</agents>');
319
+ lines.push('<chat>');
320
+ if (chatIds.size === 0)
321
+ lines.push(' (none)');
322
+ else
323
+ for (const id of chatIds)
324
+ lines.push(` - ${tagged(id)}`);
325
+ lines.push('</chat>');
326
+ lines.push('<agreement>');
327
+ if (agreementParties.size === 0)
328
+ lines.push(' (no agreement parties in this chat)');
329
+ else
330
+ for (const [id, hits] of agreementParties) {
331
+ const tag = hits.map((h) => `${h.agreementId}:${h.role}`).join(', ');
332
+ lines.push(` - ${tagged(id)} [${tag}]`);
333
+ }
334
+ lines.push('</agreement>');
335
+ lines.push('<task>');
336
+ if (agreementParties.size === 0)
337
+ lines.push(' (no task parties in this chat)');
338
+ else
339
+ for (const [id, hits] of agreementParties) {
340
+ const tag = hits.map((h) => `${h.agreementId}:${h.role}`).join(', ');
341
+ lines.push(` - ${tagged(id)} [${tag}]`);
342
+ }
343
+ lines.push('</task>');
344
+ lines.push('<transfer>');
345
+ if (transferIds.size === 0)
346
+ lines.push(' (none)');
347
+ else
348
+ for (const id of transferIds)
349
+ lines.push(` - ${tagged(id)}`);
350
+ lines.push('</transfer>');
351
+ lines.push('</recipients>');
352
+ return lines.join('\n');
353
+ }
354
+ _renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage) {
355
+ const lines = ['<decision_schema>'];
356
+ lines.push('Return ONE JSON object. ALWAYS include "thought" as the FIRST field — briefly explain your reasoning before choosing an action.');
357
+ lines.push('Set "action" to exactly one of the action names below.');
358
+ lines.push('Message text is rendered as markdown (CommonMark + GFM). You MAY use **bold**, *italic*, `code`, fenced code blocks, lists, links, and tables when they improve clarity — plain text is also fine.\n');
359
+ const replyTo = senderMeta.defaultReplyReceiverId || '<receiverId>';
360
+ const pendingProposals = (ctxObj.agreements || []).filter((a) => a.proposal?.status === 'pending' && (a.proposedToIsYou || isBroadcastTarget(a.parties?.proposedTo)));
361
+ if (pendingProposals.length > 0) {
362
+ lines.push(`PRIORITY: You have ${pendingProposals.length} pending proposal(s) directed at you. Respond BEFORE other actions.`);
363
+ lines.push(`{"thought": "...", "action": "<action_bound_to_agreement_respond>", "args": {"agreementId": "<id>", "action": "approve|reject"}}\n`);
364
+ }
365
+ for (const [name, actionDef] of Object.entries(actions)) {
366
+ lines.push(`─── "${name}" ───`);
367
+ if (actionDef.prompt?.when)
368
+ lines.push(`Use when: ${actionDef.prompt.when}`);
369
+ if (actionDef.prompt?.instruction)
370
+ lines.push(`Instruction: ${actionDef.prompt.instruction}`);
371
+ if (actionDef.prompt?.format)
372
+ lines.push(`Format: ${actionDef.prompt.format}`);
373
+ const boundTool = actionDef.tool ?? null;
374
+ if (boundTool) {
375
+ lines.push(`Tool: ${boundTool}`);
376
+ lines.push(`Response: {"thought": "...", "action": "${name}", "args": {...}}`);
377
+ }
378
+ else {
379
+ lines.push(this._buildActionSchema(name, replyTo, omitMessage));
380
+ }
381
+ if (actionDef.prompt?.examples?.length) {
382
+ lines.push('Examples:');
383
+ for (const ex of actionDef.prompt.examples) {
384
+ const desc = ex.scenario || ex.input || '';
385
+ const out = ex.output || ex.query || '';
386
+ lines.push(` - ${desc}${out ? ' → ' + out : ''}`);
387
+ }
388
+ }
389
+ lines.push('');
390
+ }
391
+ lines.push('</decision_schema>');
392
+ return lines.join('\n');
393
+ }
394
+ _buildActionSchema(name, replyTo, omitMessage) {
395
+ if (name === 'wait') {
396
+ return `Response: {"thought": "...", "action": "${name}"}`;
397
+ }
398
+ // Never pre-fill a non-routable id (the literal 'system' or 'service'
399
+ // buckets) as the default receiverId. Fall back to an explicit placeholder
400
+ // so the model picks a real recipient from <recipients>.
401
+ const isSystemReplyTo = !replyTo ||
402
+ replyTo === 'system' ||
403
+ replyTo === 'service' ||
404
+ replyTo.startsWith('<');
405
+ const renderedReplyTo = isSystemReplyTo ? '<receiverId from <recipients>>' : replyTo;
406
+ if (omitMessage) {
407
+ return `Response: {"thought": "...", "action": "${name}", "receiverId": "${renderedReplyTo}"}`;
408
+ }
409
+ return `Response: {"thought": "...", "action": "${name}", "receiverId": "${renderedReplyTo}", "message": "..."}`;
410
+ }
411
+ _getSenderMeta(event, ctxObj) {
412
+ const ev = event;
413
+ const senderId = String(ev?.senderId || 'system');
414
+ const senderType = ev?.senderType ? String(ev.senderType).toUpperCase() : 'SYSTEM';
415
+ const myId = this._getMyAgentId(ctxObj);
416
+ const isNonRoutableSenderType = (t) => t === 'SYSTEM' || t === 'SERVICE';
417
+ let defaultReplyReceiverId = senderId;
418
+ const isNonRoutable = isNonRoutableSenderType(senderType);
419
+ if (isNonRoutable) {
420
+ const history = ctxObj.history || [];
421
+ for (let i = history.length - 1; i >= 0; i--) {
422
+ const row = history[i];
423
+ const sender = row.sender;
424
+ const id = String(sender?.id || row.senderId || '');
425
+ const type = String(sender?.type || row.senderType || '').toUpperCase();
426
+ if (id && id !== myId && !isNonRoutableSenderType(type)) {
427
+ defaultReplyReceiverId = id;
428
+ break;
429
+ }
430
+ }
431
+ }
432
+ return { senderId, senderType, myAgentId: myId, defaultReplyReceiverId: defaultReplyReceiverId || senderId };
433
+ }
434
+ _getMyAgentId(ctxObj) {
435
+ const agents = ctxObj.agents || [];
436
+ const me = agents.find((a) => a.isYou);
437
+ return me?.agentId || null;
438
+ }
439
+ }
@@ -1,5 +1,4 @@
1
1
  import type { Ctx, Identity } from '../types.js';
2
-
3
2
  /**
4
3
  * The one place a per-lane `Ctx` is constructed.
5
4
  *
@@ -16,24 +15,4 @@ import type { Ctx, Identity } from '../types.js';
16
15
  * without `pendingSubtasks` / `collectedResults`; default them here, nowhere
17
16
  * else.
18
17
  */
19
- export function bootstrapCtx(identity: Identity, existing?: Ctx | null): Ctx {
20
- if (existing) {
21
- return {
22
- ...existing,
23
- identity,
24
- pendingSubtasks: existing.pendingSubtasks ?? {},
25
- collectedResults: existing.collectedResults ?? [],
26
- };
27
- }
28
- return {
29
- identity,
30
- activeAgreementId: null,
31
- activeTaskId: null,
32
- pendingProposalAgreementId: null,
33
- delegatedAgreementIds: [],
34
- pendingSubtasks: {},
35
- collectedResults: [],
36
- toolResults: [],
37
- lastOutcome: { kind: 'enter' },
38
- };
39
- }
18
+ export declare function bootstrapCtx(identity: Identity, existing?: Ctx | null): Ctx;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * The one place a per-lane `Ctx` is constructed.
3
+ *
4
+ * Both cognitions bootstrap the same Ctx: the FSM (`AgentMachine` constructor)
5
+ * and the Claude Agent SDK brain (`ClaudeSdkAgent.tick`). Before this, each
6
+ * carried its own copy of the fresh-Ctx literal and the restore-path defaulting,
7
+ * and they had already drifted (the "default them ONCE here" comment in
8
+ * AgentMachine no longer held). Keep it here so the shape lives in a single spot.
9
+ *
10
+ * - No `existing` → a fresh Ctx for a brand-new session.
11
+ * - `existing` present → restore it, re-stamping `identity` and defaulting the
12
+ * fields that sessions persisted before they existed may lack. Sessions live
13
+ * up to SESSION_TTL_SECONDS (24h) in DynamoDB, so an old row can come back
14
+ * without `pendingSubtasks` / `collectedResults`; default them here, nowhere
15
+ * else.
16
+ */
17
+ export function bootstrapCtx(identity, existing) {
18
+ if (existing) {
19
+ return {
20
+ ...existing,
21
+ identity,
22
+ pendingSubtasks: existing.pendingSubtasks ?? {},
23
+ collectedResults: existing.collectedResults ?? [],
24
+ };
25
+ }
26
+ return {
27
+ identity,
28
+ activeAgreementId: null,
29
+ activeTaskId: null,
30
+ pendingProposalAgreementId: null,
31
+ delegatedAgreementIds: [],
32
+ pendingSubtasks: {},
33
+ collectedResults: [],
34
+ toolResults: [],
35
+ lastOutcome: { kind: 'enter' },
36
+ };
37
+ }
@@ -0,0 +1,68 @@
1
+ import type { Action, AgreementRef, Ctx, Outcome, TaskRef, ToolResultEntry } from '../types.js';
2
+ /** Wire payload from the backend for task/agreement state. */
3
+ export interface WireResult {
4
+ taskId?: string;
5
+ state?: string;
6
+ status?: string;
7
+ agreement?: AgreementRef;
8
+ agreementId?: string;
9
+ proposal?: {
10
+ status?: 'pending' | 'approved' | 'rejected' | 'cancelled';
11
+ };
12
+ task?: TaskRef;
13
+ success?: boolean;
14
+ error?: string;
15
+ providerIsYou?: boolean;
16
+ [key: string]: unknown;
17
+ }
18
+ export interface RawEvent {
19
+ type?: string;
20
+ result?: WireResult;
21
+ receiverId?: string;
22
+ senderId?: string;
23
+ text?: string;
24
+ events?: RawEvent[];
25
+ [key: string]: unknown;
26
+ }
27
+ export interface EmittedEvent {
28
+ type: string;
29
+ tool?: string;
30
+ result?: WireResult;
31
+ error?: string;
32
+ receiverId?: string;
33
+ chatId?: string;
34
+ message?: string;
35
+ text?: string;
36
+ operation?: string;
37
+ senderId?: string;
38
+ [key: string]: unknown;
39
+ }
40
+ /**
41
+ * Converts a raw incoming event into the single Outcome that re-enters the
42
+ * machine.
43
+ *
44
+ * For batched events, returns the *most significant* outcome (task assignments
45
+ * win over messages). EventQueue already flattened multiple distinct events
46
+ * via re-entry, so a batch here usually means events that arrived together
47
+ * within a single backend frame.
48
+ */
49
+ export declare function outcomeFromEvent(rawEvent: RawEvent | null | undefined, ownAgentId: string | null): Outcome;
50
+ /**
51
+ * Builds the single Outcome that ends a thinking-state turn from the
52
+ * action that ran and the events it emitted.
53
+ *
54
+ * Action's `produces` declares the outcome kind — runtime fills in payload.
55
+ * - static string: kind is fixed; runtime constructs payload from events.
56
+ * - function: receives the tool result and args, returns the kind.
57
+ *
58
+ * If `produces` is missing or doesn't match the events, falls back to a
59
+ * best-effort inference.
60
+ */
61
+ export declare function outcomeFromActionResult(actionName: string | null, action: Action | null, args: unknown, emittedEvents: EmittedEvent[], toolResultsOut: ToolResultEntry[]): Outcome;
62
+ /**
63
+ * Mutates ctx to absorb persistent state from a new outcome:
64
+ * - active agreement/task ids on assignment, cleared on close
65
+ * - pending proposal id on proposal-made, cleared on resolution
66
+ * - delegated task ids accumulated on delegation, used to match later subtask events
67
+ */
68
+ export declare function applyOutcomeToCtx(ctx: Ctx, outcome: Outcome): void;