@ziggs-ai/agent-sdk 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/AgentHost.d.ts +50 -14
- package/dist/AgentHost.js +129 -7
- package/dist/agent/ClaudeSdkAgent.d.ts +23 -1
- package/dist/agent/ClaudeSdkAgent.js +145 -75
- package/dist/context/applyEffects.js +4 -3
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/runtime/bootstrapCtx.js +6 -8
- package/dist/runtime/buildOutcome.d.ts +9 -1
- package/dist/runtime/buildOutcome.js +29 -6
- package/dist/runtime/taskIntake.js +6 -4
- package/dist/runtime/wakeWriteKeys.js +14 -21
- package/dist/server/ConnectionPool.d.ts +10 -52
- package/dist/server/ConnectionPool.js +26 -57
- package/dist/server/EventQueue.d.ts +6 -0
- package/dist/server/EventQueue.js +21 -6
- package/dist/server/SeenMessages.d.ts +7 -0
- package/dist/server/SeenMessages.js +15 -0
- package/dist/server/ZiggsEffectHandler.d.ts +1 -0
- package/dist/server/ZiggsEffectHandler.js +14 -7
- package/dist/server/inboxLoop.d.ts +17 -2
- package/dist/server/inboxLoop.js +92 -16
- package/dist/server/polls/PollKind.d.ts +72 -0
- package/dist/server/polls/PollKind.js +53 -0
- package/dist/server/polls/PollRunner.d.ts +62 -0
- package/dist/server/polls/PollRunner.js +138 -0
- package/dist/server/questMatch.d.ts +5 -0
- package/dist/server/questMatch.js +14 -0
- package/dist/server/runLauncher.d.ts +0 -6
- package/dist/server/runLauncher.js +54 -27
- package/dist/server/tools/tier1/protocolRunner.d.ts +3 -1
- package/dist/server/tools/tier1/protocolRunner.js +24 -28
- package/dist/server/tools/tier1/protocolTools.js +23 -13
- package/dist/server/tools/tier2/connectionTools.js +12 -1
- package/dist/tasks/protocolRegistry.d.ts +27 -0
- package/dist/tasks/protocolRegistry.js +36 -0
- package/dist/types.d.ts +0 -9
- package/package.json +2 -2
- package/dist/server/staleBacklogGate.d.ts +0 -57
- package/dist/server/staleBacklogGate.js +0 -100
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.0 — unreleased
|
|
4
|
+
|
|
5
|
+
### Removed (breaking)
|
|
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.
|
|
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`.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Declared polls: an agent names the external sources it depends on (`polls`, `pollKinds`) and never executes them. New exports `PollRunner`, `PollRegistry`, `declaredPolls`, and types `PollBinding`, `PollContext`, `PollKind`, `PollResult`, `PollRunnerOptions`, `WakeTarget`. `runLauncher` runs declared polls at fleet level — outside any `AgentHost`, because a host is evicted when idle and that is exactly when its source still needs watching.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- Attention gate: only the addressed agent spends a turn. A message addressed elsewhere in a shared room no longer wakes every participant.
|
|
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
|
+
- 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).
|
|
25
|
+
|
|
3
26
|
## 0.9.0 — 2026-07-30
|
|
4
27
|
|
|
5
28
|
### Changed (breaking)
|
package/dist/AgentHost.d.ts
CHANGED
|
@@ -76,6 +76,12 @@ export interface AgentHostOptions {
|
|
|
76
76
|
/** Claude-brain system prompt (ZIG-1080); falls back to `description`. */
|
|
77
77
|
systemPrompt?: string;
|
|
78
78
|
specialization?: string | null;
|
|
79
|
+
/**
|
|
80
|
+
* ZIG-1185 — strings compared exactly against a quest's `match` field.
|
|
81
|
+
* Miss → ack with zero LLM. Match → normal wake. `specialization` is also
|
|
82
|
+
* checked when set.
|
|
83
|
+
*/
|
|
84
|
+
questMatchTags?: string[];
|
|
79
85
|
tools?: ToolDefinition[];
|
|
80
86
|
taskTools?: 'all' | 'none' | string[];
|
|
81
87
|
/**
|
|
@@ -120,14 +126,6 @@ export interface AgentHostOptions {
|
|
|
120
126
|
sessionStore?: SessionStore;
|
|
121
127
|
/** Observability tap: called after every effect with the effect and its response. */
|
|
122
128
|
effectTap?: (effect: import('./types.js').Effect, response: unknown) => void;
|
|
123
|
-
/**
|
|
124
|
-
* Liveness signal: called whenever the host receives or processes work (an
|
|
125
|
-
* inbox message or resource event delivered to a lane). Hosting pools use it
|
|
126
|
-
* to reset their idle-eviction timer — without it a host that is actively
|
|
127
|
-
* working (but never addressed via pool.sendTo) is torn down mid-stream at
|
|
128
|
-
* the idle timeout, discarding lane state, Claude session ids, and timers.
|
|
129
|
-
*/
|
|
130
|
-
onActivity?: () => void;
|
|
131
129
|
/** Observability tap: called on every FSM state transition, no-match, depth-guard, or error-escape (ZIG-442). */
|
|
132
130
|
transitionTap?: (event: import('./runtime/AgentMachine.js').TransitionEvent) => void;
|
|
133
131
|
/**
|
|
@@ -198,11 +196,54 @@ export declare class AgentHost {
|
|
|
198
196
|
handleResourceEvent(event: Record<string, unknown>): Promise<void>;
|
|
199
197
|
/** Wire entry. Normalize → resolve session → enqueue on the right lane. */
|
|
200
198
|
handleMessage(text: string, metadata?: Record<string, unknown>): Promise<void>;
|
|
199
|
+
/**
|
|
200
|
+
* ZIG-1144 part 3 — an agreement lane outlives the agreement.
|
|
201
|
+
*
|
|
202
|
+
* A lane named `agrn-<agreementId>` keeps its Claude session for the whole
|
|
203
|
+
* engagement, so a trailing event after the deal ends pays for all of it: on
|
|
204
|
+
* 2026-08-03 a cancelled hand-off woke its lane once for 92k tokens, and on
|
|
205
|
+
* 08-04 the same shape cost 147k with the session reaching 399,864 input tokens
|
|
206
|
+
* before it reset. Nothing was produced either time — the work had finished and
|
|
207
|
+
* the contract was gone.
|
|
208
|
+
*
|
|
209
|
+
* So a lane whose agreement is terminal does not get a turn. The event is still
|
|
210
|
+
* consumed (and acked by the inbox loop), the FSM is untouched, and a chat lane
|
|
211
|
+
* is never affected: only the agreement-scoped routing key is checked.
|
|
212
|
+
*
|
|
213
|
+
* Failing open is deliberate. If the lookup errors we run the turn — a missed
|
|
214
|
+
* suppression costs tokens, while a wrongly suppressed turn drops work.
|
|
215
|
+
*/
|
|
216
|
+
private laneAgreementIsTerminal;
|
|
217
|
+
/**
|
|
218
|
+
* ZIG-1153 — the trailing turn on work that is already reported.
|
|
219
|
+
*
|
|
220
|
+
* A lane session carries the whole engagement, so the LAST wake is the most
|
|
221
|
+
* expensive one: on prod, the frame that followed a completed elicitation cost
|
|
222
|
+
* **158,733 tokens** with the session's input at 366,417 before ZIG-816 reset
|
|
223
|
+
* it, and produced nothing — the spec had been written and the task closed one
|
|
224
|
+
* frame earlier.
|
|
225
|
+
*
|
|
226
|
+
* A task frame that carries a terminal state AND a result is an echo of work
|
|
227
|
+
* this agent has already finished: there is no decision left in it. Dropping it
|
|
228
|
+
* is not the same suppression as {@link laneAgreementIsTerminal}, which waits
|
|
229
|
+
* for the agreement to end — this fires while the engagement is still live,
|
|
230
|
+
* which is where the cost actually was.
|
|
231
|
+
*
|
|
232
|
+
* Deliberately narrow: only a `task_result` frame, only with a terminal state,
|
|
233
|
+
* and only when a result is attached. A completed task with no result recorded
|
|
234
|
+
* still gets its turn, because that is an agent with something left to say.
|
|
235
|
+
*/
|
|
236
|
+
private isSettledTaskEcho;
|
|
201
237
|
private _processEvent;
|
|
202
238
|
/** Arms the lane's liveness timer iff stateName is a parked state declaring timeoutMs. */
|
|
203
239
|
private _armIfTimedParked;
|
|
204
240
|
private _resolveOwnAgentId;
|
|
205
241
|
connectAsync(_timeout?: number): Promise<this>;
|
|
242
|
+
/**
|
|
243
|
+
* ZIG-1185 — plain string compare against {@link AgentHostOptions.questMatchTags}
|
|
244
|
+
* and `specialization`. No match → return (caller acks). Match → normal wake.
|
|
245
|
+
*/
|
|
246
|
+
private triageQuestDelivery;
|
|
206
247
|
private _bootstrapAssignedActiveTasks;
|
|
207
248
|
/** ZIG-802: replay task-assigned for an existing active task (demo recovery). */
|
|
208
249
|
wakeTaskAssignment(taskId: string): Promise<void>;
|
|
@@ -217,10 +258,5 @@ export declare class AgentHost {
|
|
|
217
258
|
* createAgentPool([cfg, ...]) → ConnectionPool (lazy fleet, async-loaded)
|
|
218
259
|
*/
|
|
219
260
|
export declare function createAgent(options?: AgentHostOptions | AgentConfig): AgentHost;
|
|
220
|
-
export declare function createAgentPool(configs: AgentHostOptions[] | AgentConfig[]
|
|
221
|
-
poolOptions?: {
|
|
222
|
-
maxActive?: number;
|
|
223
|
-
idleTimeoutMs?: number;
|
|
224
|
-
};
|
|
225
|
-
}): Promise<unknown>;
|
|
261
|
+
export declare function createAgentPool(configs: AgentHostOptions[] | AgentConfig[]): Promise<unknown>;
|
|
226
262
|
export default AgentHost;
|
package/dist/AgentHost.js
CHANGED
|
@@ -18,6 +18,7 @@ import { ArtifactsClient, ContextReadClient, TelemetryClient, sendChatMessage, }
|
|
|
18
18
|
import { TaskService } from './server/tasks/TaskService.js';
|
|
19
19
|
import { AgreementService } from './server/agreements/AgreementService.js';
|
|
20
20
|
import { runInboxLoop } from './server/inboxLoop.js';
|
|
21
|
+
import { questExactMatch } from './server/questMatch.js';
|
|
21
22
|
import { SeenMessages } from './server/SeenMessages.js';
|
|
22
23
|
import { runtimeLog } from './shared/runtimeLog.js';
|
|
23
24
|
/**
|
|
@@ -292,7 +293,14 @@ export class AgentHost {
|
|
|
292
293
|
promptBuilder: services.promptBuilder,
|
|
293
294
|
});
|
|
294
295
|
this.eventQueue = new EventQueue((event, laneKey) => this._processEvent(event, laneKey));
|
|
295
|
-
|
|
296
|
+
// A timer frame is not a delivery: there is no watermark waiting on it and
|
|
297
|
+
// nothing to redeliver, so its failure is logged and dropped here rather
|
|
298
|
+
// than left as an unhandled rejection (ZIG-1191 made enqueue reject).
|
|
299
|
+
this.stateTimers = new StateTimers((ev, laneKey) => {
|
|
300
|
+
void this.eventQueue.enqueue(ev, laneKey).catch((err) => {
|
|
301
|
+
runtimeLog.warn('AgentHost', `state-timer frame failed laneKey=${laneKey}: ${err?.message || err}`);
|
|
302
|
+
});
|
|
303
|
+
});
|
|
296
304
|
}
|
|
297
305
|
/**
|
|
298
306
|
* Handler for a resource change (artifact created, task state transition,
|
|
@@ -371,12 +379,96 @@ export class AgentHost {
|
|
|
371
379
|
// The inbox loop owns ack (act-before-ack, delivery law); the host only
|
|
372
380
|
// routes the event onto its lane. No live-path watermark ack — there is no
|
|
373
381
|
// separate live/push channel to reconcile against anymore.
|
|
374
|
-
|
|
382
|
+
//
|
|
383
|
+
// ZIG-1191: a failure un-marks the messageId. The mark above is what stops
|
|
384
|
+
// the same message being processed twice; leaving it set on a failed wake
|
|
385
|
+
// would make the redelivery this rejection buys us a no-op.
|
|
386
|
+
try {
|
|
387
|
+
await this.eventQueue.enqueue(normalized.event, laneKey);
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
if (messageId)
|
|
391
|
+
this.seenMessages.unmark(messageId);
|
|
392
|
+
throw err;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* ZIG-1144 part 3 — an agreement lane outlives the agreement.
|
|
397
|
+
*
|
|
398
|
+
* A lane named `agrn-<agreementId>` keeps its Claude session for the whole
|
|
399
|
+
* engagement, so a trailing event after the deal ends pays for all of it: on
|
|
400
|
+
* 2026-08-03 a cancelled hand-off woke its lane once for 92k tokens, and on
|
|
401
|
+
* 08-04 the same shape cost 147k with the session reaching 399,864 input tokens
|
|
402
|
+
* before it reset. Nothing was produced either time — the work had finished and
|
|
403
|
+
* the contract was gone.
|
|
404
|
+
*
|
|
405
|
+
* So a lane whose agreement is terminal does not get a turn. The event is still
|
|
406
|
+
* consumed (and acked by the inbox loop), the FSM is untouched, and a chat lane
|
|
407
|
+
* is never affected: only the agreement-scoped routing key is checked.
|
|
408
|
+
*
|
|
409
|
+
* Failing open is deliberate. If the lookup errors we run the turn — a missed
|
|
410
|
+
* suppression costs tokens, while a wrongly suppressed turn drops work.
|
|
411
|
+
*/
|
|
412
|
+
async laneAgreementIsTerminal(sessionId) {
|
|
413
|
+
if (!sessionId.startsWith('agrn-'))
|
|
414
|
+
return false;
|
|
415
|
+
const agreementId = sessionId.slice('agrn-'.length);
|
|
416
|
+
if (!agreementId || !this.agreementService)
|
|
417
|
+
return false;
|
|
418
|
+
try {
|
|
419
|
+
const agreement = await this.agreementService.get(agreementId);
|
|
420
|
+
const status = String(agreement?.status ?? '');
|
|
421
|
+
return (status === 'cancelled' || status === 'refunded' || status === 'fulfilled');
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* ZIG-1153 — the trailing turn on work that is already reported.
|
|
429
|
+
*
|
|
430
|
+
* A lane session carries the whole engagement, so the LAST wake is the most
|
|
431
|
+
* expensive one: on prod, the frame that followed a completed elicitation cost
|
|
432
|
+
* **158,733 tokens** with the session's input at 366,417 before ZIG-816 reset
|
|
433
|
+
* it, and produced nothing — the spec had been written and the task closed one
|
|
434
|
+
* frame earlier.
|
|
435
|
+
*
|
|
436
|
+
* A task frame that carries a terminal state AND a result is an echo of work
|
|
437
|
+
* this agent has already finished: there is no decision left in it. Dropping it
|
|
438
|
+
* is not the same suppression as {@link laneAgreementIsTerminal}, which waits
|
|
439
|
+
* for the agreement to end — this fires while the engagement is still live,
|
|
440
|
+
* which is where the cost actually was.
|
|
441
|
+
*
|
|
442
|
+
* Deliberately narrow: only a `task_result` frame, only with a terminal state,
|
|
443
|
+
* and only when a result is attached. A completed task with no result recorded
|
|
444
|
+
* still gets its turn, because that is an agent with something left to say.
|
|
445
|
+
*/
|
|
446
|
+
isSettledTaskEcho(event) {
|
|
447
|
+
const frame = event;
|
|
448
|
+
if (frame?.type !== 'task_result')
|
|
449
|
+
return false;
|
|
450
|
+
const result = frame.result;
|
|
451
|
+
if (!result)
|
|
452
|
+
return false;
|
|
453
|
+
const state = String(result.state ?? '');
|
|
454
|
+
if (state !== 'completed' && state !== 'cancelled' && state !== 'failed') {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
const reported = result.result;
|
|
458
|
+
return reported !== undefined && reported !== null && reported !== '';
|
|
375
459
|
}
|
|
376
460
|
async _processEvent(event, laneKey) {
|
|
377
461
|
const session = this.sessions.get(laneKey);
|
|
378
462
|
if (!session?.sessionId)
|
|
379
463
|
return;
|
|
464
|
+
if (await this.laneAgreementIsTerminal(session.sessionId)) {
|
|
465
|
+
runtimeLog.info(this.options.name || 'agent', `skipping wake on ${session.sessionId} — its agreement is terminal`);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (this.isSettledTaskEcho(event)) {
|
|
469
|
+
runtimeLog.info(this.options.name || 'agent', `skipping wake on ${session.sessionId} — its task already reported a result`);
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
380
472
|
// Stale timer frames (superseded epoch) are dropped BEFORE touching the
|
|
381
473
|
// live timer — a pure-stale frame must not reset a freshly armed countdown.
|
|
382
474
|
const frame = this.stateTimers.stripStale(event, laneKey);
|
|
@@ -479,6 +571,13 @@ export class AgentHost {
|
|
|
479
571
|
if (senderId && senderType === 'USER') {
|
|
480
572
|
this.eff({ kind: 'send-message', sessionId: session.sessionId, receiverId: senderId, text: 'Something went wrong. Please try again.' }).catch(() => { });
|
|
481
573
|
}
|
|
574
|
+
// ZIG-1191: and then say so. Everything above is recovery for the lane —
|
|
575
|
+
// it does not mean the event was handled, and the caller is about to
|
|
576
|
+
// decide whether the delivery that carried it can be acked. Swallowing
|
|
577
|
+
// here is what turned a failed wake into a lost one: two hand-off publish
|
|
578
|
+
// notifications were acked after failing, so nothing ever redelivered
|
|
579
|
+
// them and a claim stayed blocked on consent that no wake would give.
|
|
580
|
+
throw err;
|
|
482
581
|
}
|
|
483
582
|
finally {
|
|
484
583
|
clearTimeout(tickWatchdog);
|
|
@@ -517,18 +616,15 @@ export class AgentHost {
|
|
|
517
616
|
seen: this.seenMessages,
|
|
518
617
|
label,
|
|
519
618
|
onMessage: (text, metadata) => {
|
|
520
|
-
this.options.onActivity?.();
|
|
521
619
|
return this.handleMessage(text, metadata);
|
|
522
620
|
},
|
|
523
621
|
onResourceEvent: (event) => {
|
|
524
|
-
this.options.onActivity?.();
|
|
525
622
|
return this.handleResourceEvent(event);
|
|
526
623
|
},
|
|
527
624
|
// ZIG-973: work delivered by the inbox's task channel, not by a chat
|
|
528
625
|
// row — this is what reaches a task under a chat-less agreement or one
|
|
529
626
|
// the agent assigned to itself.
|
|
530
627
|
onTask: async (task) => {
|
|
531
|
-
this.options.onActivity?.();
|
|
532
628
|
try {
|
|
533
629
|
await this.wakeTaskAssignment(task.taskId);
|
|
534
630
|
}
|
|
@@ -536,10 +632,35 @@ export class AgentHost {
|
|
|
536
632
|
runtimeLog.warn(this.options.name || 'agent', `inbox task ${task.taskId} could not be woken: ${err.message}`);
|
|
537
633
|
}
|
|
538
634
|
},
|
|
635
|
+
// ZIG-1185: exact-match triage in code — miss acks with 0 tokens.
|
|
636
|
+
onQuest: async (quest) => {
|
|
637
|
+
await this.triageQuestDelivery(quest);
|
|
638
|
+
},
|
|
539
639
|
});
|
|
540
640
|
}
|
|
541
641
|
return this;
|
|
542
642
|
}
|
|
643
|
+
/**
|
|
644
|
+
* ZIG-1185 — plain string compare against {@link AgentHostOptions.questMatchTags}
|
|
645
|
+
* and `specialization`. No match → return (caller acks). Match → normal wake.
|
|
646
|
+
*/
|
|
647
|
+
async triageQuestDelivery(quest) {
|
|
648
|
+
const tags = [
|
|
649
|
+
...(this.options.questMatchTags ?? []),
|
|
650
|
+
...(this.options.specialization ? [this.options.specialization] : []),
|
|
651
|
+
];
|
|
652
|
+
if (!questExactMatch(quest.match, tags)) {
|
|
653
|
+
runtimeLog.debug(this.options.name || 'agent', `quest ${quest.agreementId}: no tag match for ${JSON.stringify(quest.match)} — ack without wake`);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
const needle = quest.match.trim();
|
|
657
|
+
const title = quest.title?.trim() || needle;
|
|
658
|
+
await this.handleMessage(`New marketplace quest matching your tags (${needle}): ${title}. Claim with agreement_claim if you will take it.`, {
|
|
659
|
+
messageId: `quest-wake:${quest.agreementId}:${quest.ts}`,
|
|
660
|
+
chatId: `marketplace:${quest.agreementId}`,
|
|
661
|
+
agreementId: quest.agreementId,
|
|
662
|
+
});
|
|
663
|
+
}
|
|
543
664
|
async _bootstrapAssignedActiveTasks() {
|
|
544
665
|
const agentId = this.options.agentId;
|
|
545
666
|
if (!agentId || !this.taskService)
|
|
@@ -626,10 +747,11 @@ export class AgentHost {
|
|
|
626
747
|
export function createAgent(options = {}) {
|
|
627
748
|
return new AgentHost(options);
|
|
628
749
|
}
|
|
629
|
-
export async function createAgentPool(configs
|
|
750
|
+
export async function createAgentPool(configs) {
|
|
630
751
|
const ConnectionPool = await loadConnectionPool();
|
|
631
|
-
const pool = new ConnectionPool(
|
|
752
|
+
const pool = new ConnectionPool();
|
|
632
753
|
pool.register(configs);
|
|
754
|
+
await pool.connectAll();
|
|
633
755
|
return pool;
|
|
634
756
|
}
|
|
635
757
|
export default AgentHost;
|
|
@@ -15,8 +15,13 @@ import type { TickInput, TickOutput } from './Agent.js';
|
|
|
15
15
|
* `notification` only.
|
|
16
16
|
*
|
|
17
17
|
* Empty / missing batch → notice-only (do not burn a turn on a malformed wake).
|
|
18
|
+
*
|
|
19
|
+
* A message addressed to a DIFFERENT party is notice-only too (attention
|
|
20
|
+
* gate): the sender named who should act, and it wasn't this agent. The
|
|
21
|
+
* message still lands in chat history and arrives as context on the next
|
|
22
|
+
* real wake — skipped here is the LLM turn, not the information.
|
|
18
23
|
*/
|
|
19
|
-
export declare function isNoticeOnlyWake(event: RawEvent | undefined): boolean;
|
|
24
|
+
export declare function isNoticeOnlyWake(event: RawEvent | undefined, ownAgentId?: string | null): boolean;
|
|
20
25
|
export type CognitionKind = 'fsm' | 'claude-sdk';
|
|
21
26
|
export interface ClaudeSdkAgentOptions {
|
|
22
27
|
workflow: Workflow;
|
|
@@ -38,6 +43,16 @@ export interface ClaudeSdkAgentOptions {
|
|
|
38
43
|
/** Injectable for tests. Defaults to @anthropic-ai/claude-agent-sdk query(). */
|
|
39
44
|
queryFn?: typeof query;
|
|
40
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* ZIG-1191 — "the transcript you asked me to resume is not here".
|
|
48
|
+
*
|
|
49
|
+
* Claude Code answers a `resume` of an unknown id with this, and it is the only
|
|
50
|
+
* failure that a fresh session reliably fixes: the id is valid-looking but its
|
|
51
|
+
* transcript lived on a container that is gone. Matched on the message because
|
|
52
|
+
* that is all the CLI gives us — no code, no typed error — so keep it narrow
|
|
53
|
+
* enough that a different failure never claims the retry.
|
|
54
|
+
*/
|
|
55
|
+
export declare function isMissingSessionError(err: unknown): boolean;
|
|
41
56
|
/**
|
|
42
57
|
* A Ziggs agent whose brain is the Claude Agent SDK. Same host, same `eff`
|
|
43
58
|
* side channel, same tool surface as the FSM `Agent` — the ONLY difference is
|
|
@@ -56,6 +71,13 @@ export declare class ClaudeSdkAgent {
|
|
|
56
71
|
private maxTurns;
|
|
57
72
|
private statelessPerWake;
|
|
58
73
|
private queryFn;
|
|
74
|
+
/**
|
|
75
|
+
* ZIG-1120 #7 — tool set is fixed at host construction; rebuilding the
|
|
76
|
+
* in-process MCP server (+ zod schema tree) every wake was pure waste.
|
|
77
|
+
* A mutable holder supplies per-wake context without closing over `tick`.
|
|
78
|
+
*/
|
|
79
|
+
private toolContextHolder;
|
|
80
|
+
private sdkMcpServer;
|
|
59
81
|
constructor(opts: ClaudeSdkAgentOptions);
|
|
60
82
|
tick({ event, ctx, state, identity, eff, signal }: TickInput): Promise<TickOutput>;
|
|
61
83
|
}
|