@ziggs-ai/agent-sdk 0.20.0 → 0.22.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 (61) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/Agent.d.ts +28 -7
  3. package/dist/Agent.js +189 -74
  4. package/dist/brain/ClaudeBrain.d.ts +11 -1
  5. package/dist/brain/ClaudeBrain.js +71 -18
  6. package/dist/brain/ZiggsBrain.d.ts +2 -0
  7. package/dist/brain/ZiggsBrain.js +1 -0
  8. package/dist/brain/claudeCognition.d.ts +1 -1
  9. package/dist/brain/claudeCognition.js +54 -7
  10. package/dist/brain/claudeSdkProtocol.d.ts +1 -1
  11. package/dist/brain/claudeSdkProtocol.js +5 -2
  12. package/dist/brain/claudeSdkTools.d.ts +5 -2
  13. package/dist/brain/claudeSdkTools.js +39 -10
  14. package/dist/brain/hireActivationNotice.d.ts +19 -0
  15. package/dist/brain/hireActivationNotice.js +79 -0
  16. package/dist/brain/standingOfferNotice.d.ts +15 -0
  17. package/dist/brain/standingOfferNotice.js +89 -0
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/ingress/normalizeIncoming.d.ts +3 -0
  21. package/dist/ingress/normalizeIncoming.js +8 -0
  22. package/dist/mcp/createMcpAgent.d.ts +1 -1
  23. package/dist/mcp/createMcpAgent.js +1 -1
  24. package/dist/memory/MemoryStore.d.ts +18 -4
  25. package/dist/memory/MemoryStore.js +52 -12
  26. package/dist/platform/ConnectionPool.d.ts +9 -4
  27. package/dist/platform/ConnectionPool.js +16 -6
  28. package/dist/platform/StateTimers.d.ts +12 -6
  29. package/dist/platform/StateTimers.js +26 -6
  30. package/dist/platform/ZiggsEffectHandler.js +17 -3
  31. package/dist/platform/inboxLoop.d.ts +5 -7
  32. package/dist/platform/inboxLoop.js +36 -80
  33. package/dist/platform/polls/declaredPollRunner.d.ts +7 -1
  34. package/dist/platform/polls/declaredPollRunner.js +7 -9
  35. package/dist/platform/tasks/TaskService.d.ts +23 -1
  36. package/dist/platform/tasks/TaskService.js +8 -2
  37. package/dist/platform/tools/index.d.ts +3 -2
  38. package/dist/platform/tools/index.js +3 -2
  39. package/dist/platform/tools/tier1/protocolRunner.js +8 -1
  40. package/dist/platform/tools/tier1/protocolTools.js +3 -3
  41. package/dist/platform/tools/tier2/contextTools.d.ts +3 -0
  42. package/dist/platform/tools/tier2/contextTools.js +4 -1
  43. package/dist/platform/tools/tier2/planTools.d.ts +20 -0
  44. package/dist/platform/tools/tier2/planTools.js +64 -0
  45. package/dist/platform/tools/tier2/taskTools.d.ts +1 -0
  46. package/dist/platform/tools/tier2/taskTools.js +2 -1
  47. package/dist/pricing/fleetDefaults.js +4 -9
  48. package/dist/pricing/fleetTierByAgentId.gen.d.ts +1 -1
  49. package/dist/pricing/fleetTierByAgentId.gen.js +2 -752
  50. package/dist/runtime/AgentMachine.d.ts +3 -0
  51. package/dist/runtime/AgentMachine.js +6 -1
  52. package/dist/runtime/runTurn.d.ts +1 -0
  53. package/dist/runtime/runTurn.js +19 -15
  54. package/dist/runtime/wakeEffects.d.ts +35 -0
  55. package/dist/runtime/wakeEffects.js +121 -0
  56. package/dist/runtime/wakeOutcome.d.ts +33 -0
  57. package/dist/runtime/wakeOutcome.js +61 -6
  58. package/dist/types.d.ts +13 -0
  59. package/package.json +2 -2
  60. package/dist/pricing/fleetFreeTierA.gen.d.ts +0 -6
  61. package/dist/pricing/fleetFreeTierA.gen.js +0 -11
@@ -105,6 +105,8 @@ export declare class AgentMachine {
105
105
  input: number;
106
106
  output: number;
107
107
  };
108
+ /** Last turn skipped the model; host records a no-op naming why. */
109
+ _skippedReason: string | undefined;
108
110
  _lastUserSenderId: string | null;
109
111
  _stateTimeoutUnhandled: boolean;
110
112
  _transitionTap: ((event: TransitionEvent) => void) | undefined;
@@ -117,6 +119,7 @@ export declare class AgentMachine {
117
119
  input: number;
118
120
  output: number;
119
121
  };
122
+ get skippedReason(): string | undefined;
120
123
  get stateTimeoutUnhandled(): boolean;
121
124
  constructor({ workflow, executionCore, eff, toolManager, promptBuilder, memory, input, transitionTap, maxTurnsWithoutUserInput, writeKeys }: MachineOptions);
122
125
  getSnapshot(): MachineSnapshot;
@@ -41,6 +41,8 @@ export class AgentMachine {
41
41
  _draining = false;
42
42
  _llmCalls = 0;
43
43
  _tokens = { total: 0, input: 0, output: 0 };
44
+ /** Last turn skipped the model; host records a no-op naming why. */
45
+ _skippedReason;
44
46
  _lastUserSenderId = null;
45
47
  _stateTimeoutUnhandled = false;
46
48
  _transitionTap;
@@ -49,6 +51,7 @@ export class AgentMachine {
49
51
  _maxTurnsWithoutUserInput;
50
52
  get llmCalls() { return this._llmCalls; }
51
53
  get tokens() { return this._tokens; }
54
+ get skippedReason() { return this._skippedReason; }
52
55
  get stateTimeoutUnhandled() { return this._stateTimeoutUnhandled; }
53
56
  constructor({ workflow, executionCore, eff, toolManager, promptBuilder, memory, input, transitionTap, maxTurnsWithoutUserInput, writeKeys }) {
54
57
  this.workflow = workflow;
@@ -316,7 +319,7 @@ export class AgentMachine {
316
319
  // Thinking: run a turn, produce an outcome, re-step.
317
320
  this._running = true;
318
321
  try {
319
- const { outcome: turnOutcome, toolResults, llmCalls, tokens } = await this.executionCore({
322
+ const { outcome: turnOutcome, toolResults, llmCalls, tokens, skippedReason } = await this.executionCore({
320
323
  stateId: this.state,
321
324
  statePrompt: sd.prompt,
322
325
  actions: sd.actions,
@@ -331,6 +334,8 @@ export class AgentMachine {
331
334
  });
332
335
  this.ctx.toolResults = toolResults;
333
336
  this._llmCalls += llmCalls;
337
+ if (skippedReason)
338
+ this._skippedReason = skippedReason;
334
339
  this._turnsSinceUserInput += 1;
335
340
  this._tokens.total += tokens.total;
336
341
  this._tokens.input += tokens.input;
@@ -44,6 +44,7 @@ interface RunTurnResult {
44
44
  input: number;
45
45
  output: number;
46
46
  };
47
+ skippedReason?: string;
47
48
  }
48
49
  /**
49
50
  * Run a single thinking-state turn.
@@ -112,12 +112,13 @@ export async function runTurn(input) {
112
112
  : [];
113
113
  const serverContext = await effWithTrace({ kind: 'read-context', sessionId, opts: {} });
114
114
  const ctxObj = normalizeContextSnapshot(serverContext);
115
- // A message wake whose chat no longer resolves (deleted, or never visible
116
- // to this agent) has no world to decide over — deciding anyway means
117
- // reasoning about a fabricated empty history plus whatever stale scraps
118
- // other fetches returned. Skip the LLM and park. Gated on message wakes
119
- // only. a bare agreement id as sessionId is a mis-keyed lane —
120
- // loud-log the empty snapshot rather than staying silent.
115
+ // A wake whose chat no longer resolves (deleted, or never visible to this
116
+ // agent) has no world to decide over — deciding anyway means reasoning
117
+ // about a fabricated empty history plus whatever stale scraps other
118
+ // fetches returned. Skip the LLM and park. Resource wakes used to slip
119
+ // past a message-only gate and burn a full turn. A bare
120
+ // agreement id as sessionId is a mis-keyed lane — loud-log the empty
121
+ // snapshot rather than staying silent.
121
122
  if (ctxObj.chatMissing) {
122
123
  const looksLikeBareAgreement = isAgreementId(sessionId);
123
124
  if (looksLikeBareAgreement) {
@@ -125,15 +126,18 @@ export async function runTurn(input) {
125
126
  `lane was keyed by agreementId instead of the agreement's origin/notification chat; ` +
126
127
  `wake continues with an empty snapshot`);
127
128
  }
128
- }
129
- if (ctxObj.chatMissing && ctx.lastOutcome?.kind === 'message-received') {
130
- runtimeLog.warn('runTurn', `chat ${sessionId} not found on backend — skipping message wake (state=${stateId})`);
131
- return {
132
- outcome: { kind: 'wait' },
133
- toolResults: [],
134
- llmCalls: 0,
135
- tokens: { total: 0, input: 0, output: 0 },
136
- };
129
+ else {
130
+ // Any wake in a room this agent cannot read — not only
131
+ // message wakes. Resource notices used to spend a full turn here.
132
+ runtimeLog.warn('runTurn', `chat ${sessionId} not readable — skipping wake (state=${stateId})`);
133
+ return {
134
+ outcome: { kind: 'wait' },
135
+ toolResults: [],
136
+ llmCalls: 0,
137
+ tokens: { total: 0, input: 0, output: 0 },
138
+ skippedReason: `chat_unreadable:${sessionId}`,
139
+ };
140
+ }
137
141
  }
138
142
  const prompt = promptBuilder.buildFromState({
139
143
  statePrompt, actions,
@@ -0,0 +1,35 @@
1
+ import type { Effect } from '../types.js';
2
+ export interface WorkScope {
3
+ agreementId?: string;
4
+ taskId?: string;
5
+ }
6
+ /** Never combine a task from one event with an agreement from another. */
7
+ export declare function uniqueWorkScope(scopes: WorkScope[]): WorkScope;
8
+ /** Only structured host/backend fields are authority; message text and timer reasons are not. */
9
+ export declare function workScopeFromWake(event: unknown, sessionId?: string): WorkScope;
10
+ /** Per-wake observation, including effects nested inside tools and cross-room sends. */
11
+ export declare class WakeEffects {
12
+ private readonly initialScope;
13
+ private readonly sessionId?;
14
+ private readonly inferScope;
15
+ sentMessage: boolean;
16
+ taskWrite: boolean;
17
+ readonly planVersions: Set<string>;
18
+ readonly sentMessageKeys: Set<string>;
19
+ /** Agreements the wake's OWN room reported, from its fenced snapshot. */
20
+ private roomAgreementIds;
21
+ /** Confirmed task writes: work this wake actually performed. */
22
+ private taskWrites;
23
+ constructor(initialScope: WorkScope, sessionId?: string | undefined, inferScope?: boolean);
24
+ static forWake(event: unknown, sessionId: string): WakeEffects;
25
+ /**
26
+ * Structured wake fields first. Otherwise the room's one agreement is the
27
+ * scope — spend follows who the agent acts for, and in a room that is the
28
+ * room's agreement — and a confirmed task write names its task only when
29
+ * the server tied the write to that same agreement. A plan written for
30
+ * customer A from customer B's room stays billed to B and names no task; a
31
+ * write whose agreement the server did not report adds nothing but the room.
32
+ */
33
+ get scope(): WorkScope;
34
+ observe(effect: Effect, response: unknown): void;
35
+ }
@@ -0,0 +1,121 @@
1
+ import { agreementIdFromLane } from '@ziggs-ai/api-client';
2
+ const record = (value) => value && typeof value === 'object' && !Array.isArray(value) ? value : {};
3
+ const id = (value) => typeof value === 'string' && value.trim() ? value : undefined;
4
+ /** Never combine a task from one event with an agreement from another. */
5
+ export function uniqueWorkScope(scopes) {
6
+ const agreements = new Set(scopes.map(s => s.agreementId).filter(Boolean));
7
+ const tasks = new Set(scopes.map(s => s.taskId).filter(Boolean));
8
+ if (agreements.size > 1 || tasks.size > 1)
9
+ return {};
10
+ if (agreements.size && tasks.size && scopes.some(s => s.taskId && !s.agreementId))
11
+ return {};
12
+ return {
13
+ ...(agreements.size ? { agreementId: [...agreements][0] } : {}),
14
+ ...(tasks.size ? { taskId: [...tasks][0] } : {}),
15
+ };
16
+ }
17
+ /** Only structured host/backend fields are authority; message text and timer reasons are not. */
18
+ export function workScopeFromWake(event, sessionId) {
19
+ const rec = record(event);
20
+ if (rec.type === 'batch' && Array.isArray(rec.events)) {
21
+ return uniqueWorkScope(rec.events.map(e => workScopeFromWake(e, sessionId)));
22
+ }
23
+ const resource = record(rec.resource);
24
+ const task = rec.type === 'task_result' || rec.type === 'notification' ? record(rec.result) : {};
25
+ const agreementId = id(rec.agreementId) ?? id(resource.agreementId) ?? id(task.agreementId)
26
+ ?? agreementIdFromLane(rec.chatId) ?? agreementIdFromLane(resource.chatId)
27
+ ?? agreementIdFromLane(sessionId) ?? undefined;
28
+ const taskId = id(rec.taskId) ?? id(resource.taskId) ?? id(task.taskId);
29
+ return { ...(agreementId ? { agreementId } : {}), ...(taskId ? { taskId } : {}) };
30
+ }
31
+ const TASK_WRITES = new Set(['task_create', 'task_set_result', 'task_update_plan_step', 'task_replace_plan']);
32
+ /** Per-wake observation, including effects nested inside tools and cross-room sends. */
33
+ export class WakeEffects {
34
+ initialScope;
35
+ sessionId;
36
+ inferScope;
37
+ sentMessage = false;
38
+ taskWrite = false;
39
+ planVersions = new Set();
40
+ sentMessageKeys = new Set();
41
+ /** Agreements the wake's OWN room reported, from its fenced snapshot. */
42
+ roomAgreementIds = [];
43
+ /** Confirmed task writes: work this wake actually performed. */
44
+ taskWrites = [];
45
+ constructor(initialScope, sessionId, inferScope = true) {
46
+ this.initialScope = initialScope;
47
+ this.sessionId = sessionId;
48
+ this.inferScope = inferScope;
49
+ }
50
+ static forWake(event, sessionId) {
51
+ const initialScope = workScopeFromWake(event, sessionId);
52
+ const frame = record(event);
53
+ const conflictingBatch = frame.type === 'batch' && Array.isArray(frame.events)
54
+ && !initialScope.agreementId && !initialScope.taskId
55
+ && frame.events.some(item => Object.keys(workScopeFromWake(item, sessionId)).length > 0);
56
+ return new WakeEffects(initialScope, sessionId, !conflictingBatch);
57
+ }
58
+ /**
59
+ * Structured wake fields first. Otherwise the room's one agreement is the
60
+ * scope — spend follows who the agent acts for, and in a room that is the
61
+ * room's agreement — and a confirmed task write names its task only when
62
+ * the server tied the write to that same agreement. A plan written for
63
+ * customer A from customer B's room stays billed to B and names no task; a
64
+ * write whose agreement the server did not report adds nothing but the room.
65
+ */
66
+ get scope() {
67
+ if (this.initialScope.agreementId || this.initialScope.taskId)
68
+ return this.initialScope;
69
+ if (!this.inferScope)
70
+ return {};
71
+ const room = new Set(this.roomAgreementIds);
72
+ if (room.size > 1)
73
+ return {};
74
+ const agreementId = [...room][0];
75
+ if (!agreementId)
76
+ return uniqueWorkScope(this.taskWrites);
77
+ const tasks = new Set(this.taskWrites.filter(w => w.agreementId === agreementId).map(w => w.taskId));
78
+ return { agreementId, ...(tasks.size === 1 ? { taskId: [...tasks][0] } : {}) };
79
+ }
80
+ observe(effect, response) {
81
+ const outer = record(response);
82
+ if (effect.kind === 'send-message' && outer.ok === true)
83
+ this.sentMessage = true;
84
+ // This is the fenced snapshot of the wake's own chat, not an arbitrary
85
+ // agreement consulted while answering. A room with multiple agreements
86
+ // remains ambiguous, and cross-room reads cannot change the wake's scope.
87
+ if (effect.kind === 'read-context' && effect.sessionId === this.sessionId
88
+ && outer.chatMissing !== true && Array.isArray(outer.agreements)) {
89
+ for (const row of outer.agreements) {
90
+ const agreementId = id(record(row).agreementId);
91
+ if (agreementId)
92
+ this.roomAgreementIds.push(agreementId);
93
+ }
94
+ }
95
+ if (effect.kind !== 'tool-call' || outer.ok !== true)
96
+ return;
97
+ const result = record(outer.result);
98
+ if (result.ok === false || result.success === false || result.error)
99
+ return;
100
+ const name = effect.name.replace(/^(functions|tools|function|tool)\./, '');
101
+ if (name === 'chat_send') {
102
+ this.sentMessage = true;
103
+ if (id(result.chatId) && id(result.messageId)) {
104
+ this.sentMessageKeys.add(JSON.stringify([result.chatId, result.messageId]));
105
+ }
106
+ }
107
+ if (TASK_WRITES.has(name))
108
+ this.taskWrite = true;
109
+ if ((name === 'task_replace_plan' || name === 'task_update_plan_step') && id(result.taskId)
110
+ && result.taskId === record(effect.args).taskId && id(result.updatedAt)) {
111
+ this.planVersions.add(JSON.stringify([result.taskId, result.updatedAt]));
112
+ }
113
+ // A confirmed task write identifies work actually performed. A broad
114
+ // task_list, arbitrary agreement_get or ids in message prose do not.
115
+ const agreementId = id(result.agreementId);
116
+ const taskId = id(result.taskId);
117
+ if (TASK_WRITES.has(name) && taskId) {
118
+ this.taskWrites.push({ taskId, ...(agreementId ? { agreementId } : {}) });
119
+ }
120
+ }
121
+ }
@@ -7,16 +7,49 @@
7
7
  * no-op with a reason.
8
8
  */
9
9
  export type WakeOutcomeKind = 'replied' | 'task-progress' | 'no-op';
10
+ /**
11
+ * Whether a wake that was ASKED something answered it.
12
+ *
13
+ * A wake handed a counterparty's message and a wake handed a notification are
14
+ * not the same obligation, and the outcome kinds could not tell them apart: an
15
+ * agent that composed a status answer, wrote it as host output and finished
16
+ * clean landed on `no-op / llm_no_visible_effect`, the same row a duplicate
17
+ * echo produces — and an agent that answered by writing the task instead landed
18
+ * on `task-progress`, which reads like success. Neither says the requester got
19
+ * nothing.
20
+ *
21
+ * `sent: false` carries the reason there was no send, because "it decided not
22
+ * to" and "it forgot" are both legitimate outcomes and only one of them is a
23
+ * bug — but they have to be distinguishable to be either.
24
+ */
25
+ export interface WakeReply {
26
+ asked: true;
27
+ sent: boolean;
28
+ reason?: string;
29
+ }
10
30
  export interface WakeOutcome {
11
31
  kind: WakeOutcomeKind;
12
32
  reason?: string;
33
+ /** Present only when this wake was handed a question. */
34
+ reply?: WakeReply;
13
35
  }
36
+ /**
37
+ * Was this wake somebody asking this agent something?
38
+ *
39
+ * A counterparty `message` frame is the one shape that earns a reply. Task
40
+ * results, agreement lifecycle and notifications are news, and the ticket is
41
+ * explicit that they still finish without sending. The agent's own message
42
+ * never counts: a self-addressed frame is an echo, not a question.
43
+ */
44
+ export declare function wakeWasAsked(event: unknown, ownAgentId?: string): boolean;
14
45
  export declare function classifyWakeOutcome(input: {
15
46
  skippedReason?: string;
16
47
  lastOutcomeKind?: string | null;
17
48
  llmCalls: number;
18
49
  sentMessage?: boolean;
19
50
  taskWrite?: boolean;
51
+ /** This wake was handed a question — see {@link wakeWasAsked}. */
52
+ asked?: boolean;
20
53
  }): WakeOutcome;
21
54
  export declare function buildWakeOutcomePayload(input: {
22
55
  agentId: string;
@@ -6,23 +6,67 @@
6
6
  * A wake ends in exactly one of: a reply, task progress, or an explicit
7
7
  * no-op with a reason.
8
8
  */
9
+ const record = (value) => value && typeof value === 'object' && !Array.isArray(value)
10
+ ? value
11
+ : {};
12
+ /**
13
+ * Was this wake somebody asking this agent something?
14
+ *
15
+ * A counterparty `message` frame is the one shape that earns a reply. Task
16
+ * results, agreement lifecycle and notifications are news, and the ticket is
17
+ * explicit that they still finish without sending. The agent's own message
18
+ * never counts: a self-addressed frame is an echo, not a question.
19
+ */
20
+ export function wakeWasAsked(event, ownAgentId) {
21
+ const frame = record(event);
22
+ if (frame.type === 'batch' && Array.isArray(frame.events)) {
23
+ return frame.events.some((item) => wakeWasAsked(item, ownAgentId));
24
+ }
25
+ if (frame.type !== 'message')
26
+ return false;
27
+ const senderId = typeof frame.senderId === 'string' ? frame.senderId : '';
28
+ if (!senderId)
29
+ return false;
30
+ return !ownAgentId || senderId !== ownAgentId;
31
+ }
9
32
  export function classifyWakeOutcome(input) {
33
+ const sent = Boolean(input.sentMessage) || input.lastOutcomeKind === 'message-sent';
34
+ // The answer to "was this wake asked something, and did it answer" is
35
+ // independent of what else the wake did, so it rides alongside the kind
36
+ // rather than competing with it: a wake can make task progress AND leave the
37
+ // question it was handed unanswered, and that is exactly the case that used
38
+ // to disappear.
39
+ const reply = !input.asked
40
+ ? undefined
41
+ : sent
42
+ ? { asked: true, sent: true }
43
+ : {
44
+ asked: true,
45
+ sent: false,
46
+ reason: input.skippedReason ??
47
+ (input.taskWrite
48
+ ? 'recorded_on_the_task_only'
49
+ : input.llmCalls > 0
50
+ ? 'composed_without_sending'
51
+ : 'no_llm'),
52
+ };
53
+ const withReply = (outcome) => reply ? { ...outcome, reply } : outcome;
10
54
  if (input.skippedReason) {
11
- return { kind: 'no-op', reason: input.skippedReason };
55
+ return withReply({ kind: 'no-op', reason: input.skippedReason });
12
56
  }
13
- if (input.sentMessage || input.lastOutcomeKind === 'message-sent') {
14
- return { kind: 'replied' };
57
+ if (sent) {
58
+ return withReply({ kind: 'replied' });
15
59
  }
16
60
  if (input.taskWrite ||
17
61
  input.lastOutcomeKind === 'task-delegated' ||
18
62
  input.lastOutcomeKind === 'task-completed' ||
19
63
  input.lastOutcomeKind === 'task-progress') {
20
- return { kind: 'task-progress' };
64
+ return withReply({ kind: 'task-progress' });
21
65
  }
22
66
  if (input.llmCalls > 0) {
23
- return { kind: 'no-op', reason: 'llm_no_visible_effect' };
67
+ return withReply({ kind: 'no-op', reason: 'llm_no_visible_effect' });
24
68
  }
25
- return { kind: 'no-op', reason: 'no_llm' };
69
+ return withReply({ kind: 'no-op', reason: 'no_llm' });
26
70
  }
27
71
  export function buildWakeOutcomePayload(input) {
28
72
  return {
@@ -36,6 +80,17 @@ export function buildWakeOutcomePayload(input) {
36
80
  effect: 'wake-outcome',
37
81
  kind: input.outcome.kind,
38
82
  ...(input.outcome.reason ? { reason: input.outcome.reason } : {}),
83
+ // A wake that was asked something says whether it answered, and why not.
84
+ // Written flat so a query for unanswered questions is one field compare.
85
+ ...(input.outcome.reply
86
+ ? {
87
+ asked: true,
88
+ answered: input.outcome.reply.sent,
89
+ ...(input.outcome.reply.reason
90
+ ? { unansweredReason: input.outcome.reply.reason }
91
+ : {}),
92
+ }
93
+ : {}),
39
94
  laneKey: input.laneKey,
40
95
  agentId: input.agentId,
41
96
  },
package/dist/types.d.ts CHANGED
@@ -523,8 +523,21 @@ export interface EffectResultMap {
523
523
  usage?: LlmResponse['usage'];
524
524
  };
525
525
  'tool-call': ToolCallResult;
526
+ /**
527
+ * `{ ok: true }` said the call did not throw, and a brain reading it had no
528
+ * way to tell a message that woke the agent it meant to from one the server
529
+ * widened to the room's humans. The send's own report rides along when the
530
+ * backend makes one: where it went. Routing is separate from acceptance.
531
+ */
526
532
  'send-message': {
527
533
  ok: true;
534
+ chatId?: string;
535
+ messageId?: string;
536
+ delivered?: string;
537
+ to?: {
538
+ id: string;
539
+ type: string;
540
+ };
528
541
  };
529
542
  'record-event': {
530
543
  ok: true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/agent-sdk",
3
- "version": "0.20.0",
3
+ "version": "0.22.0",
4
4
  "description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,7 +26,7 @@
26
26
  "@anthropic-ai/claude-agent-sdk": "^0.3.204",
27
27
  "@anthropic-ai/sdk": "^0.110.0",
28
28
  "@modelcontextprotocol/sdk": "^1.29.0",
29
- "@ziggs-ai/api-client": "0.19.0",
29
+ "@ziggs-ai/api-client": "0.21.0",
30
30
  "ajv": "^8.17.1",
31
31
  "dotenv": "^17.2.3",
32
32
  "openai": "^4.0.0",
@@ -1,6 +0,0 @@
1
- /**
2
- * AUTO-GENERATED by scripts/build-fleet-tier-map.mjs — do not edit by hand.
3
- * Tier A trivial public lookups (free when price omitted).
4
- */
5
- export declare const FREE_TIER_A_AGENT_IDS: Set<string>;
6
- export declare const FREE_TIER_A_COUNT = 4;
@@ -1,11 +0,0 @@
1
- /**
2
- * AUTO-GENERATED by scripts/build-fleet-tier-map.mjs — do not edit by hand.
3
- * Tier A trivial public lookups (free when price omitted).
4
- */
5
- export const FREE_TIER_A_AGENT_IDS = new Set([
6
- "site-health-checker",
7
- "timezone-expert",
8
- "uv-index-advisor",
9
- "weather-forecaster"
10
- ]);
11
- export const FREE_TIER_A_COUNT = 4;