@ziggs-ai/agent-sdk 0.10.7 → 0.11.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 (95) hide show
  1. package/CHANGELOG.md +11 -11
  2. package/dist/AgentHost.d.ts +15 -15
  3. package/dist/AgentHost.js +22 -22
  4. package/dist/adapters/AnthropicAdapter.js +1 -1
  5. package/dist/adapters/McpAdapter.d.ts +10 -10
  6. package/dist/adapters/McpAdapter.js +33 -21
  7. package/dist/adapters/OpenAIAdapter.js +1 -1
  8. package/dist/agent/Agent.d.ts +2 -2
  9. package/dist/agent/ClaudeSdkAgent.d.ts +6 -6
  10. package/dist/agent/ClaudeSdkAgent.js +25 -25
  11. package/dist/agent/claudeCognition.d.ts +3 -3
  12. package/dist/agent/claudeCognition.js +7 -7
  13. package/dist/agent/claudeSdkTools.d.ts +3 -3
  14. package/dist/agent/claudeSdkTools.js +9 -9
  15. package/dist/agent/hostedAgentConnection.d.ts +1 -1
  16. package/dist/agent/hostedAgentConnection.js +1 -1
  17. package/dist/agent/toolManagerToSdkMcp.d.ts +1 -1
  18. package/dist/agent/toolManagerToSdkMcp.js +2 -2
  19. package/dist/context/applyEffects.js +1 -1
  20. package/dist/defineAgent.js +2 -2
  21. package/dist/formatters/HistoryFormatter.js +2 -2
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.js +5 -5
  24. package/dist/ingress/normalizeIncoming.d.ts +1 -1
  25. package/dist/ingress/normalizeIncoming.js +7 -7
  26. package/dist/pricing/fleetDefaults.d.ts +3 -3
  27. package/dist/pricing/fleetDefaults.js +3 -3
  28. package/dist/pricing/fleetEvalFree.d.ts +1 -1
  29. package/dist/pricing/fleetEvalFree.js +1 -1
  30. package/dist/pricing/fleetFreeTierA.gen.d.ts +1 -1
  31. package/dist/pricing/fleetFreeTierA.gen.js +1 -1
  32. package/dist/pricing/fleetTierByAgentId.gen.d.ts +1 -1
  33. package/dist/runtime/AgentMachine.d.ts +1 -1
  34. package/dist/runtime/AgentMachine.js +8 -8
  35. package/dist/runtime/PromptBuilder.d.ts +2 -2
  36. package/dist/runtime/PromptBuilder.js +3 -3
  37. package/dist/runtime/bootstrapCtx.d.ts +1 -1
  38. package/dist/runtime/bootstrapCtx.js +2 -2
  39. package/dist/runtime/buildOutcome.d.ts +1 -1
  40. package/dist/runtime/buildOutcome.js +4 -4
  41. package/dist/runtime/defaults.d.ts +5 -5
  42. package/dist/runtime/defaults.js +4 -4
  43. package/dist/runtime/deliveryWriteKeys.d.ts +1 -1
  44. package/dist/runtime/deliveryWriteKeys.js +3 -3
  45. package/dist/runtime/kickoff.d.ts +3 -3
  46. package/dist/runtime/kickoff.js +3 -3
  47. package/dist/runtime/runMechanical.d.ts +1 -1
  48. package/dist/runtime/runMechanical.js +1 -1
  49. package/dist/runtime/runTurn.d.ts +1 -1
  50. package/dist/runtime/runTurn.js +10 -10
  51. package/dist/runtime/taskBookkeeping.d.ts +3 -3
  52. package/dist/runtime/taskBookkeeping.js +3 -3
  53. package/dist/runtime/taskIntake.js +2 -2
  54. package/dist/server/ConnectionPool.js +1 -1
  55. package/dist/server/EventQueue.d.ts +1 -1
  56. package/dist/server/EventQueue.js +1 -1
  57. package/dist/server/SeenMessages.d.ts +2 -2
  58. package/dist/server/SeenMessages.js +2 -2
  59. package/dist/server/ZiggsEffectHandler.d.ts +2 -2
  60. package/dist/server/ZiggsEffectHandler.js +8 -8
  61. package/dist/server/agreements/AgreementService.d.ts +3 -8
  62. package/dist/server/agreements/AgreementService.js +4 -7
  63. package/dist/server/inboxLoop.d.ts +5 -5
  64. package/dist/server/inboxLoop.js +21 -10
  65. package/dist/server/questMatch.d.ts +1 -1
  66. package/dist/server/questMatch.js +1 -1
  67. package/dist/server/runLauncher.js +3 -3
  68. package/dist/server/tools/index.d.ts +1 -0
  69. package/dist/server/tools/index.js +7 -6
  70. package/dist/server/tools/tier1/protocolRunner.d.ts +1 -1
  71. package/dist/server/tools/tier1/protocolRunner.js +19 -19
  72. package/dist/server/tools/tier1/protocolTools.js +5 -4
  73. package/dist/server/tools/tier2/artifactTools.js +2 -2
  74. package/dist/server/tools/tier2/chatTools.js +2 -2
  75. package/dist/server/tools/tier2/connectionTools.js +3 -3
  76. package/dist/server/tools/tier2/contextTools.js +1 -1
  77. package/dist/server/tools/tier2/discoveryTools.js +2 -2
  78. package/dist/server/tools/tier2/grantsTools.js +1 -1
  79. package/dist/server/tools/tier2/linkTools.js +3 -3
  80. package/dist/server/tools/tier2/marketplaceTools.js +1 -1
  81. package/dist/server/tools/tier2/mcpConnectionTools.d.ts +4 -0
  82. package/dist/server/tools/tier2/mcpConnectionTools.js +136 -0
  83. package/dist/server/tools/tier2/paymentTools.js +1 -1
  84. package/dist/shared/operatorKeyClaims.d.ts +2 -2
  85. package/dist/shared/operatorKeyClaims.js +1 -1
  86. package/dist/tasks/protocolRegistry.d.ts +1 -1
  87. package/dist/tasks/protocolRegistry.js +1 -1
  88. package/dist/tools/ToolManager.js +1 -1
  89. package/dist/tools/capabilityAdapter.d.ts +1 -1
  90. package/dist/tools/capabilityAdapter.js +3 -3
  91. package/dist/tools/defineTool.js +1 -1
  92. package/dist/tools/recordReport.d.ts +3 -3
  93. package/dist/tools/recordReport.js +3 -3
  94. package/dist/types.d.ts +17 -17
  95. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -4,10 +4,10 @@
4
4
 
5
5
  ### Removed (breaking)
6
6
 
7
- - Removed exports `createStaleBacklogGate`, `resolveReplayPolicy`, `newestActionableAt`, `parseReplayMaxAge`. The launcher rewrite deleted the wake machinery these gated: every agent stays connected and the write signals it, so there is no backlog to age out and nothing to replay-gate (ZIG-993). Pinned to 0.4.x and importing any of the four? Delete the call — the behaviour it bought is now unconditional. There is no replacement API.
7
+ - Removed exports `createStaleBacklogGate`, `resolveReplayPolicy`, `newestActionableAt`, `parseReplayMaxAge`. The launcher rewrite deleted the wake machinery these gated: every agent stays connected and the write signals it, so there is no backlog to age out and nothing to replay-gate. Pinned to 0.4.x and importing any of the four? Delete the call — the behaviour it bought is now unconditional. There is no replacement API.
8
8
  - `FLEET_REPLAY_MAX_AGE` is no longer read; the replay window it set no longer exists. Nothing in this repo sets it, but it can come out of any deployment env that does.
9
- - `Ctx` no longer carries `pendingSubtasks`, `collectedResults`, or `delegatedAgreementIds`. ZIG-977 moved the real bookkeeping into `Ctx.tasks` (keyed by taskId) and ZIG-1057 stopped syncing these mirrors, but they stayed on the interface as required-and-always-empty — so a workflow guard reading one saw empty forever and silently checked nothing. Read via `allPendingSubtasks(ctx)` / `allCollectedResults(ctx)` / `allDelegatedAgreementIds(ctx)`. Sessions persisted before `tasks` existed are still migrated on restore.
10
- - `WireResult.status` removed. ZIG-1057 cut `status` from the wire in favour of `state`; four readers kept a `|| r.status` tail, which would have absorbed a backend regression instead of failing on it. Task state resolves as `task?.state || r.state`.
9
+ - `Ctx` no longer carries `pendingSubtasks`, `collectedResults`, or `delegatedAgreementIds`. The real bookkeeping moved into `Ctx.tasks` (keyed by taskId) and these mirrors stopped syncing, but they stayed on the interface as required-and-always-empty — so a workflow guard reading one saw empty forever and silently checked nothing. Read via `allPendingSubtasks(ctx)` / `allCollectedResults(ctx)` / `allDelegatedAgreementIds(ctx)`. Sessions persisted before `tasks` existed are still migrated on restore.
10
+ - `WireResult.status` removed. The wire carries `state` only; the `|| r.status` fallback tails were removed so a backend regression fails loudly instead of being absorbed. Task state resolves as `task?.state || r.state`.
11
11
 
12
12
  ### Added
13
13
 
@@ -18,16 +18,16 @@
18
18
  - Attention gate: only the addressed agent spends a turn. A message addressed elsewhere in a shared room no longer wakes every participant.
19
19
  - No turn on a lane whose agreement has ended, and none on the echo of a task that already reported — both previously cost a turn and produced nothing.
20
20
  - Persona wire shapes are understood on inbound frames.
21
- - A wake declares its lane so the backend can fence reach (ZIG-1092).
22
- - A proposal awaiting the agent's own consent counts as actionable rather than a notice to park (ZIG-1078).
23
- - Artifact idempotency keys are derived from content (ZIG-1083).
24
- - Blank tool arguments fall back to the wake's lane (ZIG-1081).
21
+ - A wake declares its lane so the backend can fence reach.
22
+ - A proposal awaiting the agent's own consent counts as actionable rather than a notice to park.
23
+ - Artifact idempotency keys are derived from content.
24
+ - Blank tool arguments fall back to the wake's lane.
25
25
 
26
26
  ## 0.9.0 — 2026-07-30
27
27
 
28
28
  ### Changed (breaking)
29
29
 
30
- - `task-update` / `task_set_result` accept `state` only — legacy `status` alias removed (ZIG-1057).
30
+ - `task-update` / `task_set_result` accept `state` only — legacy `status` alias removed.
31
31
  - Removed export `syncAggregateTaskViews`; read pending/collected/delegated via `allPendingSubtasks` / `allCollectedResults` / `allDelegatedAgreementIds`. Ctx aggregate mirrors stay empty.
32
32
 
33
33
  ## 0.4.0 — 2026-07-23
@@ -38,8 +38,8 @@
38
38
 
39
39
  ### Changed (breaking)
40
40
 
41
- - Removed legacy socket-frame aliases; wire frames use canonical names only (ZIG-913, ZIG-915).
42
- - Delivery-law: classify inbound messages from the `service` wire shape (ZIG-936).
41
+ - Removed legacy socket-frame aliases; wire frames use canonical names only.
42
+ - Delivery-law: classify inbound messages from the `service` wire shape.
43
43
  - Bumped `@ziggs-ai/api-client` to `^0.3.0`.
44
44
 
45
45
  ## 0.3.0 — 2026-07-22
@@ -50,7 +50,7 @@
50
50
 
51
51
  ## 0.2.0 — 2026-07-16
52
52
 
53
- ### Added (ZIG-784)
53
+ ### Added
54
54
 
55
55
  - Public brain selection API: `ziggsBrain()`, `claudeBrain()`, and `Brain` interface (`tick()`).
56
56
  - `AgentHost` / `createAgent` accept `brain` — preferred over legacy `cognition: 'fsm' | 'claude-sdk'`.
@@ -41,13 +41,13 @@ export declare const DEFAULT_MODEL = "claude-haiku-4-5";
41
41
  */
42
42
  export type SessionResolver = (normalized: NormalizedEvent, ownAgentId: string) => string | null;
43
43
  /**
44
- * ZIG-975: one lane key per unit of work, derived the same way as inbox wakes.
44
+ * one lane key per unit of work, derived the same way as inbox wakes.
45
45
  *
46
46
  * Inbox deliveries key on `chatId` (DEFAULT_SESSION_RESOLVER). Bootstrap used to
47
47
  * prefer bare `agreementId`, which opened a second lane for the same task and
48
48
  * made the snapshot read treat the agreement id as a chat (`chatMissing: true`,
49
49
  * empty context). Prefer the origin chat when present; otherwise the agreement's
50
- * notification chat (`agrn-<agreementId>`), which is always linked after ZIG-966.
50
+ * notification chat (`agrn-<agreementId>`), which is always linked after.
51
51
  */
52
52
  export declare function laneSessionIdForTask(task: {
53
53
  originChatId?: string | null;
@@ -72,11 +72,11 @@ export interface AgentHostOptions {
72
72
  name?: string | null;
73
73
  /** Store-facing one-liner. See DefineAgentInput.description. */
74
74
  description?: string;
75
- /** Claude-brain system prompt (ZIG-1080); falls back to `description`. */
75
+ /** Claude-brain system prompt; falls back to `description`. */
76
76
  systemPrompt?: string;
77
77
  specialization?: string | null;
78
78
  /**
79
- * ZIG-1185 — strings compared exactly against a quest's `match` field.
79
+ * strings compared exactly against a quest's `match` field.
80
80
  * Miss → ack with zero LLM. Match → normal wake. `specialization` is also
81
81
  * checked when set.
82
82
  */
@@ -96,7 +96,7 @@ export interface AgentHostOptions {
96
96
  /** Max agentic turns per Claude SDK wake. Default 30. */
97
97
  claudeMaxTurns?: number;
98
98
  /**
99
- * ZIG-860: claude-sdk agents resume their transcript across wakes by default,
99
+ * claude-sdk agents resume their transcript across wakes by default,
100
100
  * so per-wake input grows monotonically on a long lane. When true, each wake
101
101
  * starts a fresh Claude session — the protocol is backend-authoritative (the
102
102
  * brain re-reads via context_snapshot / the wake event), so the
@@ -125,14 +125,14 @@ export interface AgentHostOptions {
125
125
  sessionStore?: SessionStore;
126
126
  /** Observability tap: called after every effect with the effect and its response. */
127
127
  effectTap?: (effect: import('./types.js').Effect, response: unknown) => void;
128
- /** Observability tap: called on every FSM state transition, no-match, depth-guard, or error-escape (ZIG-442). */
128
+ /** Observability tap: called on every FSM state transition, no-match, depth-guard, or error-escape. */
129
129
  transitionTap?: (event: import('./runtime/AgentMachine.js').TransitionEvent) => void;
130
130
  /**
131
131
  * Usage/cost tap: called once per settled tick with the tick's authoritative
132
132
  * token usage (result.metrics). This is the SINGLE source of truth for
133
133
  * usage/cost across every cognition — the FSM (llm-call + streamed reply +
134
134
  * tool-internal LLM) and the Claude brain (incl. cache tokens) both funnel
135
- * their spend here (ZIG-813). effectTap / tool generations are structural
135
+ * their spend here. effectTap / tool generations are structural
136
136
  * tracing only and must NOT also carry billable usage, or cost double-counts.
137
137
  */
138
138
  metricsTap?: (info: {
@@ -142,10 +142,10 @@ export interface AgentHostOptions {
142
142
  cognition: string;
143
143
  metrics: import('./agent/Agent.js').TickOutput['metrics'];
144
144
  }) => void;
145
- /** Production monitoring ingest (ZIG-360). Default on; set false to disable. */
145
+ /** Production monitoring ingest. Default on; set false to disable. */
146
146
  telemetryIngest?: boolean;
147
147
  /**
148
- * Pull inbox on every WS connect/reconnect (ZIG-454). Default true.
148
+ * Pull inbox on every WS connect/reconnect. Default true.
149
149
  * Recovers messages lost when backend in-memory pending queues are dropped.
150
150
  */
151
151
  inboxCatchUp?: boolean;
@@ -167,7 +167,7 @@ export declare function warnOnShadowedPlatformTools(platformTools: ToolDefinitio
167
167
  * a transport (Ziggs WebSocket), and the lane router (per-session FIFO queue
168
168
  * + in-memory session state).
169
169
  *
170
- * transport (WS) → handleMessage → agent.tick(... , eff) → ...
170
+ * transport (WS) → handleMessage → agent.tick(.. , eff) → ..
171
171
  */
172
172
  export declare class AgentHost {
173
173
  options: Required<Pick<AgentHostOptions, 'agentId' | 'operatorKey' | 'openaiKey'>> & AgentHostOptions;
@@ -208,7 +208,7 @@ export declare class AgentHost {
208
208
  /** Wire entry. Normalize → resolve session → enqueue on the right lane. */
209
209
  handleMessage(text: string, metadata?: Record<string, unknown>): Promise<void>;
210
210
  /**
211
- * ZIG-1144 part 3 — an agreement lane outlives the agreement.
211
+ * part 3 — an agreement lane outlives the agreement.
212
212
  *
213
213
  * A lane named `agrn-<agreementId>` keeps its Claude session for the whole
214
214
  * engagement, so a trailing event after the deal ends pays for all of it: on
@@ -226,11 +226,11 @@ export declare class AgentHost {
226
226
  */
227
227
  private laneAgreementIsTerminal;
228
228
  /**
229
- * ZIG-1153 — the trailing turn on work that is already reported.
229
+ * the trailing turn on work that is already reported.
230
230
  *
231
231
  * A lane session carries the whole engagement, so the LAST wake is the most
232
232
  * expensive one: on prod, the frame that followed a completed elicitation cost
233
- * **158,733 tokens** with the session's input at 366,417 before ZIG-816 reset
233
+ * **158,733 tokens** with the session's input at 366,417 before reset
234
234
  * it, and produced nothing — the spec had been written and the task closed one
235
235
  * frame earlier.
236
236
  *
@@ -251,12 +251,12 @@ export declare class AgentHost {
251
251
  private _resolveOwnAgentId;
252
252
  connectAsync(_timeout?: number): Promise<this>;
253
253
  /**
254
- * ZIG-1185 — plain string compare against {@link AgentHostOptions.questMatchTags}
254
+ * plain string compare against {@link AgentHostOptions.questMatchTags}
255
255
  * and `specialization`. No match → return (caller acks). Match → normal wake.
256
256
  */
257
257
  private triageQuestDelivery;
258
258
  private _bootstrapAssignedActiveTasks;
259
- /** ZIG-802: replay task-assigned for an existing active task (demo recovery). */
259
+ /** replay task-assigned for an existing active task (demo recovery). */
260
260
  wakeTaskAssignment(taskId: string): Promise<void>;
261
261
  disconnect(): void;
262
262
  /** Waits for all in-flight ticks to complete. Call before process.exit() on SIGTERM. */
package/dist/AgentHost.js CHANGED
@@ -40,13 +40,13 @@ async function loadConnectionPool() {
40
40
  }
41
41
  const DEFAULT_SESSION_RESOLVER = (normalized) => normalized.chatId;
42
42
  /**
43
- * ZIG-975: one lane key per unit of work, derived the same way as inbox wakes.
43
+ * one lane key per unit of work, derived the same way as inbox wakes.
44
44
  *
45
45
  * Inbox deliveries key on `chatId` (DEFAULT_SESSION_RESOLVER). Bootstrap used to
46
46
  * prefer bare `agreementId`, which opened a second lane for the same task and
47
47
  * made the snapshot read treat the agreement id as a chat (`chatMissing: true`,
48
48
  * empty context). Prefer the origin chat when present; otherwise the agreement's
49
- * notification chat (`agrn-<agreementId>`), which is always linked after ZIG-966.
49
+ * notification chat (`agrn-<agreementId>`), which is always linked after.
50
50
  */
51
51
  export function laneSessionIdForTask(task) {
52
52
  if (typeof task.originChatId === 'string' && task.originChatId) {
@@ -69,13 +69,13 @@ function createToolManager(options) {
69
69
  taskTools = PROTOCOL_TOOLS; // 'all' or undefined
70
70
  const claudeSdkTools = isClaudeCognition(options.cognition) ? CLAUDE_SDK_TOOLS : [];
71
71
  const ownTools = Array.isArray(userTools) ? userTools : [];
72
- // ZIG-1280 — browse rides wherever claim rides. Posted-first engagements
72
+ // browse rides wherever claim rides. Posted-first engagements
73
73
  // START at marketplace_view (find the listing), so an agent that can
74
74
  // agreement_claim but cannot browse holds a default pathway it cannot begin.
75
75
  // Both directions: shedding claim (taskTools array without it) sheds browse.
76
76
  const canClaim = taskTools.some((t) => t.schema.function.name === 'agreement_claim');
77
77
  const browseTools = canClaim ? [marketplaceViewTool] : [];
78
- // ZIG-1278 — chat_open is always-on so claim/provider kickoff (FSM) and the
78
+ // chat_open is always-on so claim/provider kickoff (FSM) and the
79
79
  // Claude always-on set can open the buyer chat after a store claim. CHAT_TOOLS
80
80
  // is also folded into CLAUDE_SDK_TOOLS; Map registration makes duplicates a no-op.
81
81
  const platformTools = [...taskTools, ...CHAT_TOOLS, ...browseTools, ...claudeSdkTools];
@@ -128,7 +128,7 @@ function createBackendServices(options) {
128
128
  const agentId = options.agentId;
129
129
  const artifactsClient = new ArtifactsClient(operatorKey, agentId);
130
130
  const contextReadClient = new ContextReadClient(operatorKey, agentId);
131
- // ZIG-1080: the role text is the prompt when the author split the two; the
131
+ // the role text is the prompt when the author split the two; the
132
132
  // store-facing `description` is only the fallback for agents that never did.
133
133
  const promptBuilder = new PromptBuilder({
134
134
  description: options.systemPrompt || options.description,
@@ -153,7 +153,7 @@ function createBackendServices(options) {
153
153
  * a transport (Ziggs WebSocket), and the lane router (per-session FIFO queue
154
154
  * + in-memory session state).
155
155
  *
156
- * transport (WS) → handleMessage → agent.tick(... , eff) → ...
156
+ * transport (WS) → handleMessage → agent.tick(.. , eff) → ..
157
157
  */
158
158
  export class AgentHost {
159
159
  options;
@@ -210,7 +210,7 @@ export class AgentHost {
210
210
  this.sessionResolver = options.sessionResolver || DEFAULT_SESSION_RESOLVER;
211
211
  // A Claude-brain wake legitimately runs long (multi-turn query, prose
212
212
  // deliverables) — 120s watchdogged real spec-writing wakes mid-flight,
213
- // which then redelivered and re-ran (ZIG-924 dogfood, 2026-07-26). FSM
213
+ // which then redelivered and re-ran (dogfood, 2026-07-26). FSM
214
214
  // turns stay on the tight default.
215
215
  this.tickTimeoutMs =
216
216
  options.tickTimeoutMs ??
@@ -319,7 +319,7 @@ export class AgentHost {
319
319
  agentId: this.options.agentId,
320
320
  // No taskService/agreementService: Claude-brain tools execute through
321
321
  // eff({ kind: 'tool-call' }) → the shared executor, which sources those
322
- // services from the effect handler's deps like the FSM path (ZIG-775).
322
+ // services from the effect handler's deps like the FSM path.
323
323
  maxTurns: this.options.claudeMaxTurns,
324
324
  statelessPerWake: this.options.claudeStatelessPerWake,
325
325
  })
@@ -331,7 +331,7 @@ export class AgentHost {
331
331
  this.eventQueue = new EventQueue((event, laneKey) => this._processEvent(event, laneKey));
332
332
  // A timer frame is not a delivery: there is no watermark waiting on it and
333
333
  // nothing to redeliver, so its failure is logged and dropped here rather
334
- // than left as an unhandled rejection (ZIG-1191 made enqueue reject).
334
+ // than left as an unhandled rejection (made enqueue reject).
335
335
  this.stateTimers = new StateTimers((ev, laneKey) => {
336
336
  void this.eventQueue.enqueue(ev, laneKey).catch((err) => {
337
337
  runtimeLog.warn('AgentHost', `state-timer frame failed laneKey=${laneKey}: ${err?.message || err}`);
@@ -366,7 +366,7 @@ export class AgentHost {
366
366
  event: { type: 'message', timestamp: Date.now(), text: '' },
367
367
  };
368
368
  let sessionId = this.sessionResolver(fakeNormalized, ownAgentId);
369
- // ZIG-1278 — store claims deliver agreement wakes with no chatId. Do not
369
+ // store claims deliver agreement wakes with no chatId. Do not
370
370
  // drop them; lane by agreement the same way task bootstrap does
371
371
  // (`agrn-<agreementId>`), never a bare agreement id.
372
372
  if (!sessionId) {
@@ -415,7 +415,7 @@ export class AgentHost {
415
415
  }
416
416
  let enrichedText = typeof text === 'string' ? text : '';
417
417
  if (!enrichedText.trim()) {
418
- // ZIG-936: agreement rides under `service` on the inbox-pull wire; fall
418
+ // agreement rides under `service` on the inbox-pull wire; fall
419
419
  // back to top-level for hand-built metadata.
420
420
  const svc = metadata.service;
421
421
  const agreement = (svc?.agreement ?? metadata.agreement);
@@ -441,7 +441,7 @@ export class AgentHost {
441
441
  // routes the event onto its lane. No live-path watermark ack — there is no
442
442
  // separate live/push channel to reconcile against anymore.
443
443
  //
444
- // ZIG-1191: a failure un-marks the messageId. The mark above is what stops
444
+ // a failure un-marks the messageId. The mark above is what stops
445
445
  // the same message being processed twice; leaving it set on a failed wake
446
446
  // would make the redelivery this rejection buys us a no-op.
447
447
  try {
@@ -454,7 +454,7 @@ export class AgentHost {
454
454
  }
455
455
  }
456
456
  /**
457
- * ZIG-1144 part 3 — an agreement lane outlives the agreement.
457
+ * part 3 — an agreement lane outlives the agreement.
458
458
  *
459
459
  * A lane named `agrn-<agreementId>` keeps its Claude session for the whole
460
460
  * engagement, so a trailing event after the deal ends pays for all of it: on
@@ -486,11 +486,11 @@ export class AgentHost {
486
486
  }
487
487
  }
488
488
  /**
489
- * ZIG-1153 — the trailing turn on work that is already reported.
489
+ * the trailing turn on work that is already reported.
490
490
  *
491
491
  * A lane session carries the whole engagement, so the LAST wake is the most
492
492
  * expensive one: on prod, the frame that followed a completed elicitation cost
493
- * **158,733 tokens** with the session's input at 366,417 before ZIG-816 reset
493
+ * **158,733 tokens** with the session's input at 366,417 before reset
494
494
  * it, and produced nothing — the spec had been written and the task closed one
495
495
  * frame earlier.
496
496
  *
@@ -589,7 +589,7 @@ export class AgentHost {
589
589
  runtimeLog.info('AgentHost', `wake agent=${identity.agentId} lane=${laneKey} llmCalls=${m.llmCalls} ` +
590
590
  `tokens_in=${m.tokens.input} tokens_out=${m.tokens.output} total=${m.tokens.total}`);
591
591
  }
592
- // Single source of truth for usage/cost (ZIG-813): emit the tick's
592
+ // Single source of truth for usage/cost: emit the tick's
593
593
  // authoritative token metrics once, for every cognition. Never let an
594
594
  // observability failure break the tick.
595
595
  if (this.options.metricsTap && result.metrics) {
@@ -624,7 +624,7 @@ export class AgentHost {
624
624
  // again unless a real event happens to arrive.
625
625
  this._armIfTimedParked(laneKey, session.state ?? this.agent.workflow.initial);
626
626
  // Best-effort: also notify the user so the conversation isn't silently
627
- // stuck (ZIG-607). Complements the timer re-arm above — that recovers a
627
+ // stuck. Complements the timer re-arm above — that recovers a
628
628
  // parked lane; this tells a waiting human.
629
629
  const ev = event;
630
630
  const senderType = String(ev?.senderType ?? '').toUpperCase();
@@ -632,7 +632,7 @@ export class AgentHost {
632
632
  if (senderId && senderType === 'USER') {
633
633
  this.eff({ kind: 'send-message', sessionId: session.sessionId, receiverId: senderId, text: 'Something went wrong. Please try again.' }).catch(() => { });
634
634
  }
635
- // ZIG-1191: and then say so. Everything above is recovery for the lane —
635
+ // and then say so. Everything above is recovery for the lane —
636
636
  // it does not mean the event was handled, and the caller is about to
637
637
  // decide whether the delivery that carried it can be acked. Swallowing
638
638
  // here is what turned a failed wake into a lost one: two hand-off publish
@@ -682,7 +682,7 @@ export class AgentHost {
682
682
  onResourceEvent: (event) => {
683
683
  return this.handleResourceEvent(event);
684
684
  },
685
- // ZIG-973: work delivered by the inbox's task channel, not by a chat
685
+ // work delivered by the inbox's task channel, not by a chat
686
686
  // row — this is what reaches a task under a chat-less agreement or one
687
687
  // the agent assigned to itself.
688
688
  onTask: async (task) => {
@@ -693,7 +693,7 @@ export class AgentHost {
693
693
  runtimeLog.warn(this.options.name || 'agent', `inbox task ${task.taskId} could not be woken: ${err.message}`);
694
694
  }
695
695
  },
696
- // ZIG-1185: exact-match triage in code — miss acks with 0 tokens.
696
+ // exact-match triage in code — miss acks with 0 tokens.
697
697
  onQuest: async (quest) => {
698
698
  await this.triageQuestDelivery(quest);
699
699
  },
@@ -702,7 +702,7 @@ export class AgentHost {
702
702
  return this;
703
703
  }
704
704
  /**
705
- * ZIG-1185 — plain string compare against {@link AgentHostOptions.questMatchTags}
705
+ * plain string compare against {@link AgentHostOptions.questMatchTags}
706
706
  * and `specialization`. No match → return (caller acks). Match → normal wake.
707
707
  */
708
708
  async triageQuestDelivery(quest) {
@@ -768,7 +768,7 @@ export class AgentHost {
768
768
  }, laneKey);
769
769
  }
770
770
  }
771
- /** ZIG-802: replay task-assigned for an existing active task (demo recovery). */
771
+ /** replay task-assigned for an existing active task (demo recovery). */
772
772
  async wakeTaskAssignment(taskId) {
773
773
  const agentId = this.options.agentId;
774
774
  if (!agentId || !this.taskService) {
@@ -94,7 +94,7 @@ export class AnthropicAdapter {
94
94
  const final = await stream.finalMessage();
95
95
  const u = final.usage;
96
96
  // Fold cache read/creation into prompt tokens so the streamed reply is not
97
- // undercounted (cache traffic was the bulk of the ZIG-759 drain).
97
+ // undercounted (cache traffic was the bulk of the drain).
98
98
  const usage = u
99
99
  ? {
100
100
  prompt_tokens: (u.input_tokens ?? 0) + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0),
@@ -38,7 +38,7 @@ export type McpTransportConfig = {
38
38
  agentId?: string;
39
39
  } | {
40
40
  /**
41
- * Per-user brokered connection (ZIG-771): the agent holds NO
41
+ * Per-user brokered connection: the agent holds NO
42
42
  * connectionId/grantId. It speaks StreamableHTTP to
43
43
  * `/connections/mcp/relay` and asserts the invoking end-user via
44
44
  * `x-on-behalf-of-user`; the gateway resolves that user's own connection
@@ -57,13 +57,13 @@ export type McpTransportConfig = {
57
57
  * The MCP server URL this agent fronts. Not used for gateway calls (the
58
58
  * gateway derives the server from the resolved connection), but needed to
59
59
  * open a connection request when the invoking user hasn't connected yet
60
- * (ZIG-771). Without it, a NO_USER_CONNECTION surfaces as an error rather
60
+ *. Without it, a NO_USER_CONNECTION surfaces as an error rather
61
61
  * than an auto-created consent prompt.
62
62
  */
63
63
  serverUrl?: string;
64
64
  };
65
65
  /**
66
- * Typed failure from the Ziggs MCP gateway (ZIG-702). `code` is the stable
66
+ * Typed failure from the Ziggs MCP gateway. `code` is the stable
67
67
  * machine-readable reason — e.g. `GRANT_REVOKED`, `GRANT_EXPIRED`,
68
68
  * `GRANT_HOLDER_MISMATCH`, `GRANT_CONNECTION_MISMATCH` — so agent code can
69
69
  * branch ("revoked → tell the user and stop retrying" vs "network blip →
@@ -89,7 +89,7 @@ export declare function resolveZiggsGatewayTarget(config: Extract<McpTransportCo
89
89
  headers: Record<string, string>;
90
90
  };
91
91
  /**
92
- * Resolve the per-user gateway URL + headers (ZIG-771). No connectionId/grantId —
92
+ * Resolve the per-user gateway URL + headers. No connectionId/grantId —
93
93
  * the gateway resolves the invoking user's own connection + grant from
94
94
  * `x-on-behalf-of-user` + the impersonated agent.
95
95
  */
@@ -109,9 +109,9 @@ export interface CreateMcpAgentOptions extends Omit<AgentHostOptions, 'tools' |
109
109
  /**
110
110
  * Max tools to bind to the LLM per turn. LLM providers cap the `tools` array
111
111
  * (OpenAI: 128); an MCP server exposing more (e.g. PostHog: 146) makes every
112
- * turn fail with `400 ... array too long`. When the server's tool count
112
+ * turn fail with `400 .. array too long`. When the server's tool count
113
113
  * exceeds this budget the list is truncated (and logged). Defaults to 128.
114
- * See ZIG-759; Phase 2 will replace truncation with query-aware selection.
114
+ * See; Phase 2 will replace truncation with query-aware selection.
115
115
  */
116
116
  maxTools?: number;
117
117
  /**
@@ -120,12 +120,12 @@ export interface CreateMcpAgentOptions extends Omit<AgentHostOptions, 'tools' |
120
120
  * MCP server (e.g. PostHog's 146 tools) be narrowed to the handful this agent
121
121
  * actually needs — cutting per-turn cost and stopping the model from thrashing
122
122
  * across (or never binding) the tool it should call. Empty/undefined = bind
123
- * all (unchanged behavior). ZIG-759 Phase 2 = name-based selection.
123
+ * all (unchanged behavior). Phase 2 = name-based selection.
124
124
  */
125
125
  allowedTools?: string[];
126
126
  /**
127
127
  * Pre-discovered MCP tool schemas. REQUIRED for `type: 'ziggs-per-user'`
128
- * (ZIG-771) — there is no boot connection to call `tools/list` on, so the
128
+ * — there is no boot connection to call `tools/list` on, so the
129
129
  * schema is baked at provision time and passed here. Ignored for the other
130
130
  * transports, which discover tools live at boot.
131
131
  */
@@ -138,7 +138,7 @@ export interface CreateMcpAgentOptions extends Omit<AgentHostOptions, 'tools' |
138
138
  /**
139
139
  * How many MCP tools may be bound to the LLM, given the provider cap and the
140
140
  * number of extra (non-MCP) tools the agent also carries. Always >= 1 so a
141
- * pathological config still binds something rather than nothing. ZIG-759.
141
+ * pathological config still binds something rather than nothing.
142
142
  */
143
143
  export declare function mcpToolBudget(maxTools: number, extraToolCount: number): number;
144
144
  export interface McpAgentHandle {
@@ -158,7 +158,7 @@ export declare function buildTransport(config: McpTransportConfig, defaults?: {
158
158
  * that full block rides every turn. Keep the lead — what the tool does + how to
159
159
  * call it — and drop the embedded reference; agents fetch detail via dedicated
160
160
  * schema/help tools at call time. Tunable; big enough to preserve real guidance.
161
- * ZIG-759.
161
+ *.
162
162
  */
163
163
  export declare const MAX_TOOL_DESC_CHARS = 2000;
164
164
  /** Truncate one description at a sentence/newline boundary near the cap. */
@@ -1,11 +1,11 @@
1
1
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
2
  import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
3
3
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
4
- import { ConnectionsClient } from '@ziggs-ai/api-client';
4
+ import { ConnectionsClient, getBackendUrl } from '@ziggs-ai/api-client';
5
5
  import { AgentHost } from '../AgentHost.js';
6
6
  import { thinkingDefaults } from '../runtime/defaults.js';
7
7
  /**
8
- * Typed failure from the Ziggs MCP gateway (ZIG-702). `code` is the stable
8
+ * Typed failure from the Ziggs MCP gateway. `code` is the stable
9
9
  * machine-readable reason — e.g. `GRANT_REVOKED`, `GRANT_EXPIRED`,
10
10
  * `GRANT_HOLDER_MISMATCH`, `GRANT_CONNECTION_MISMATCH` — so agent code can
11
11
  * branch ("revoked → tell the user and stop retrying" vs "network blip →
@@ -56,10 +56,16 @@ export function resolveZiggsGatewayTarget(config, defaults = {}) {
56
56
  if (!agentId) {
57
57
  throw new Error('ziggs MCP transport requires an agentId to impersonate (X-Agent-Id)');
58
58
  }
59
+ // ZIG-1104: explicit overrides still win, but the LAST resort is
60
+ // `getBackendUrl()` — the resolution every other SDK call uses — not
61
+ // `localhost:3000`. The fleet task sets neither BACKEND_URL nor
62
+ // ZIGGS_BACKEND_URL (it sets HTTP_URL), so the old chain silently pointed every
63
+ // gateway call at localhost inside the container: the requests never reached the
64
+ // backend at all, and the agent reported the server as unreachable.
59
65
  const baseUrl = (config.baseUrl ||
60
- process.env.BACKEND_URL ||
61
66
  process.env.ZIGGS_BACKEND_URL ||
62
- 'http://localhost:3000').replace(/\/$/, '');
67
+ process.env.BACKEND_URL ||
68
+ getBackendUrl()).replace(/\/$/, '');
63
69
  return {
64
70
  url: new URL(`${baseUrl}/connections/${encodeURIComponent(config.connectionId)}/mcp`),
65
71
  headers: {
@@ -70,7 +76,7 @@ export function resolveZiggsGatewayTarget(config, defaults = {}) {
70
76
  };
71
77
  }
72
78
  /**
73
- * Resolve the per-user gateway URL + headers (ZIG-771). No connectionId/grantId —
79
+ * Resolve the per-user gateway URL + headers. No connectionId/grantId —
74
80
  * the gateway resolves the invoking user's own connection + grant from
75
81
  * `x-on-behalf-of-user` + the impersonated agent.
76
82
  */
@@ -79,17 +85,23 @@ export function resolvePerUserGatewayTarget(config, agentId, userId, onBehalfOfA
79
85
  if (!operatorKey) {
80
86
  throw new Error('ziggs-per-user MCP transport requires an operatorKey (or ZIGGS_OPERATOR_KEY)');
81
87
  }
88
+ // ZIG-1104: explicit overrides still win, but the LAST resort is
89
+ // `getBackendUrl()` — the resolution every other SDK call uses — not
90
+ // `localhost:3000`. The fleet task sets neither BACKEND_URL nor
91
+ // ZIGGS_BACKEND_URL (it sets HTTP_URL), so the old chain silently pointed every
92
+ // gateway call at localhost inside the container: the requests never reached the
93
+ // backend at all, and the agent reported the server as unreachable.
82
94
  const baseUrl = (config.baseUrl ||
83
- process.env.BACKEND_URL ||
84
95
  process.env.ZIGGS_BACKEND_URL ||
85
- 'http://localhost:3000').replace(/\/$/, '');
96
+ process.env.BACKEND_URL ||
97
+ getBackendUrl()).replace(/\/$/, '');
86
98
  return {
87
99
  url: new URL(`${baseUrl}/connections/mcp/relay`),
88
100
  headers: {
89
101
  authorization: `Bearer ${operatorKey}`,
90
102
  'x-agent-id': agentId,
91
103
  'x-on-behalf-of-user': userId,
92
- // ZIG-831: when this call runs under a delegation, userId is the delegating
104
+ // when this call runs under a delegation, userId is the delegating
93
105
  // agent (senderId), not the end-user who owns the connection. The gateway
94
106
  // uses this agreement to resolve the delegation root's user.
95
107
  ...(onBehalfOfAgreementId ? { 'x-on-behalf-of-agreement': onBehalfOfAgreementId } : {}),
@@ -103,7 +115,7 @@ const CONTROL_TOOL_RESERVE = 4;
103
115
  /**
104
116
  * How many MCP tools may be bound to the LLM, given the provider cap and the
105
117
  * number of extra (non-MCP) tools the agent also carries. Always >= 1 so a
106
- * pathological config still binds something rather than nothing. ZIG-759.
118
+ * pathological config still binds something rather than nothing.
107
119
  */
108
120
  export function mcpToolBudget(maxTools, extraToolCount) {
109
121
  return Math.max(1, maxTools - CONTROL_TOOL_RESERVE - extraToolCount);
@@ -218,7 +230,7 @@ function buildDefaultWorkflow(description, mcpTools) {
218
230
  * that full block rides every turn. Keep the lead — what the tool does + how to
219
231
  * call it — and drop the embedded reference; agents fetch detail via dedicated
220
232
  * schema/help tools at call time. Tunable; big enough to preserve real guidance.
221
- * ZIG-759.
233
+ *.
222
234
  */
223
235
  export const MAX_TOOL_DESC_CHARS = 2000;
224
236
  /** Truncate one description at a sentence/newline boundary near the cap. */
@@ -230,7 +242,7 @@ export function trimDescription(desc) {
230
242
  const head = boundary > MAX_TOOL_DESC_CHARS * 0.6 ? slice.slice(0, boundary + 1) : slice;
231
243
  return `${head.trimEnd()} […description truncated; use the server's schema/help tools for full detail]`;
232
244
  }
233
- /** Trim oversized descriptions across the tool set (cost control, ZIG-759). */
245
+ /** Trim oversized descriptions across the tool set (cost control). */
234
246
  function trimToolDescriptions(tools, agentId) {
235
247
  let trimmedCount = 0;
236
248
  let savedChars = 0;
@@ -243,14 +255,14 @@ function trimToolDescriptions(tools, agentId) {
243
255
  return { ...t, description: nextDesc };
244
256
  });
245
257
  if (trimmedCount > 0) {
246
- console.warn(`[McpAdapter] ${agentId}: trimmed ${trimmedCount} oversized tool description(s) to ${MAX_TOOL_DESC_CHARS} chars, saving ~${Math.round(savedChars / 4 / 1000)}K tokens/turn. (ZIG-759)`);
258
+ console.warn(`[McpAdapter] ${agentId}: trimmed ${trimmedCount} oversized tool description(s) to ${MAX_TOOL_DESC_CHARS} chars, saving ~${Math.round(savedChars / 4 / 1000)}K tokens/turn.`);
247
259
  }
248
260
  return out;
249
261
  }
250
262
  /**
251
263
  * Keep only tools whose name matches one of the allowlist substrings
252
264
  * (case-insensitive). No allowlist → pass through unchanged. Applied before the
253
- * maxTools cap so a targeted agent binds exactly the tools it needs. ZIG-759.
265
+ * maxTools cap so a targeted agent binds exactly the tools it needs.
254
266
  */
255
267
  function filterToolsByAllowlist(tools, allowedTools, agentId) {
256
268
  if (!allowedTools || allowedTools.length === 0)
@@ -263,7 +275,7 @@ function filterToolsByAllowlist(tools, allowedTools, agentId) {
263
275
  /**
264
276
  * Cap the tool set bound to the LLM at the provider limit (OpenAI 128) —
265
277
  * truncate and log rather than crash — and trim oversized descriptions so the
266
- * bound schema doesn't ship a manual every turn. ZIG-759 Phase 1. Shared by the
278
+ * bound schema doesn't ship a manual every turn. Phase 1. Shared by the
267
279
  * boot-time (single-client) and per-user paths. When `allowedTools` is set the
268
280
  * server's tools are narrowed by name first, so the cap rarely bites.
269
281
  */
@@ -273,7 +285,7 @@ function capTools(tools, agentId, maxTools, extraToolCount, allowedTools) {
273
285
  const budget = mcpToolBudget(maxTools, extraToolCount);
274
286
  if (trimmed.length <= budget)
275
287
  return trimmed;
276
- console.warn(`[McpAdapter] ${agentId}: MCP server exposes ${trimmed.length} tools, over the ${maxTools}-tool LLM cap; binding the first ${budget}, dropping ${trimmed.length - budget}. (ZIG-759 Phase 2 will select per query.)`);
288
+ console.warn(`[McpAdapter] ${agentId}: MCP server exposes ${trimmed.length} tools, over the ${maxTools}-tool LLM cap; binding the first ${budget}, dropping ${trimmed.length - budget}.`);
277
289
  return trimmed.slice(0, budget);
278
290
  }
279
291
  /**
@@ -311,7 +323,7 @@ function capTools(tools, agentId, maxTools, extraToolCount, allowedTools) {
311
323
  */
312
324
  export async function createMcpAgent(options) {
313
325
  const { transport: transportConfig, extraTools = [], workflow, maxTools = DEFAULT_MAX_TOOLS, allowedTools, toolSchema, ...hostOptions } = options;
314
- // ── Per-user path (ZIG-771): no boot connection; one MCP client per invoking
326
+ // ── Per-user path: no boot connection; one MCP client per invoking
315
327
  // user, each carrying that user's on-behalf-of header for an isolated session.
316
328
  if (transportConfig.type === 'ziggs-per-user') {
317
329
  const agentId = transportConfig.agentId || hostOptions.agentId;
@@ -351,12 +363,12 @@ export async function createMcpAgent(options) {
351
363
  // When the invoking user hasn't connected this server, open a connection
352
364
  // request targeting THEM (X-On-Behalf-Of-User) so the consent prompt lands
353
365
  // in their inbox. The backend dedups pending requests, so retrying every
354
- // turn is safe. ZIG-771.
366
+ // turn is safe.
355
367
  const backendBase = (transportConfig.baseUrl ||
356
368
  process.env.BACKEND_URL ||
357
369
  process.env.ZIGGS_BACKEND_URL ||
358
370
  'http://localhost:3000').replace(/\/$/, '');
359
- // App URL for the user-facing connect link (ZIG-790): api.ziggsai.com → ziggsai.com.
371
+ // App URL for the user-facing connect link: api.ziggsai.com → ziggsai.com.
360
372
  const appUrl = backendBase.includes('localhost')
361
373
  ? 'http://localhost:1234'
362
374
  : backendBase.replace(/\/\/api\./, '//');
@@ -364,7 +376,7 @@ export async function createMcpAgent(options) {
364
376
  ? new URL(transportConfig.serverUrl).host
365
377
  : 'the external service';
366
378
  // Open a connection request for this user; returns its id so the caller can
367
- // deep-link the user straight to it on the Connections page (ZIG-790).
379
+ // deep-link the user straight to it on the Connections page.
368
380
  const triggerConnectionRequest = async (userId) => {
369
381
  if (!transportConfig.serverUrl)
370
382
  return null;
@@ -390,11 +402,11 @@ export async function createMcpAgent(options) {
390
402
  if (!userId) {
391
403
  throw new Error('per-user MCP tool call requires an invoking user (context.senderId is missing)');
392
404
  }
393
- // ZIG-831: for a delegated wake, senderId is the delegating agent, not the
405
+ // for a delegated wake, senderId is the delegating agent, not the
394
406
  // connection-owning end-user; pass the agreement so the gateway resolves
395
407
  // the delegation root's user.
396
408
  const onBehalfOfAgreementId = typeof context.onBehalfOfAgreementId === 'string' ? context.onBehalfOfAgreementId : undefined;
397
- // ZIG-832 (B): per-user resolution is intermittently flaky even when the
409
+ // (B): per-user resolution is intermittently flaky even when the
398
410
  // connection is valid and resolvable — the same on-behalf call fails with
399
411
  // NO_USER_CONNECTION on one wake and succeeds on the next. clientFor never
400
412
  // caches a failed connect, so each attempt re-resolves from scratch. Retry
@@ -137,7 +137,7 @@ export class OpenAIAdapter {
137
137
  stream: true,
138
138
  // Without this, a streamed completion never returns a usage block — the
139
139
  // streamed reply (often the largest output) would bill tokens that are
140
- // counted nowhere (ZIG-813). The usage arrives on a final chunk whose
140
+ // counted nowhere. The usage arrives on a final chunk whose
141
141
  // `choices` is empty.
142
142
  stream_options: { include_usage: true },
143
143
  max_completion_tokens: maxCompletionTokensForModel(this.model),