@ziggs-ai/agent-sdk 0.38.2 → 0.38.3

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/README.md CHANGED
@@ -131,9 +131,9 @@ configureApiClient({ httpUrl: 'https://api.example.com' });
131
131
 
132
132
  A **runner** is the operator’s process. It starts agents, serves health and
133
133
  coordinates shutdown. It is not another part of the customer’s agent model.
134
- The repository’s private `@ziggs-ai/agent-runner` workspace owns `runAgents` and
135
- `createHealthServer`; these are not SDK exports. An operator deploys the runner
136
- and supplies a supervisor such as ECS to restart the process when it exits.
134
+ `runAgents` and `createHealthServer` are exported from this package. The health
135
+ page answers `/` and `/health`. A process that needs another route, such as
136
+ starting one of our hosted agents, adds it itself.
137
137
 
138
138
  ## Migration
139
139
 
@@ -146,7 +146,7 @@ This is a breaking pre-beta rename; update imports before publishing this releas
146
146
  | `ClaudeSdkAgent`, `ClaudeSdkAgentOptions` | `ClaudeBrain`, `ClaudeBrainOptions` |
147
147
  | `host.agent` | `agent.brain` |
148
148
  | `createMcpAgent(...).host` | `createMcpAgent(...).agent` |
149
- | SDK `runLauncher`, `createHealthServer` | Operator package `runAgents`, `createHealthServer` |
149
+ | SDK `runLauncher`, `createHealthServer` | SDK `runAgents`, `createHealthServer` |
150
150
 
151
151
  `createAgent`, `ziggsBrain`, `claudeBrain` and agent IDs on the wire retain their
152
152
  names. No backend identity or stored data migration is required.
@@ -5,7 +5,7 @@ import type { ToolManager } from '../tools/ToolManager.js';
5
5
  import { type RawEvent } from '../runtime/buildOutcome.js';
6
6
  import type { TickInput, TickOutput } from './ZiggsBrain.js';
7
7
  import { type AskWakeGate } from './wakeGate.js';
8
- export { isPublishProbeChat, isCapabilityProbeSession } from '../probeChat.js';
8
+ export { isPublishProbeChat } from '../probeChat.js';
9
9
  /**
10
10
  * status notices must not spend a Claude turn answering
11
11
  * nobody. Real work wakes arrive as chat `message`, synthetic `task_result`
@@ -17,7 +17,7 @@ import { filterStandingOfferNotices, isReadableAgreementNoticeLane } from './sta
17
17
  import { formedByFromWake, shouldSkipAgentFormedHireActivation, } from './hireActivationNotice.js';
18
18
  import { isPublishProbeChat } from '../probeChat.js';
19
19
  import { gateableMessages, wakeAgreementId } from './wakeGate.js';
20
- export { isPublishProbeChat, isCapabilityProbeSession } from '../probeChat.js';
20
+ export { isPublishProbeChat } from '../probeChat.js';
21
21
  /**
22
22
  * status notices must not spend a Claude turn answering
23
23
  * nobody. Real work wakes arrive as chat `message`, synthetic `task_result`
package/dist/index.d.ts CHANGED
@@ -41,7 +41,7 @@ export { runMechanical } from './runtime/runMechanical.js';
41
41
  export { PromptBuilder } from './runtime/PromptBuilder.js';
42
42
  export { thinkingDefaults, defineThinkingState, defineMechanicalState, DEFAULT_WAIT_PROMPT } from './runtime/defaults.js';
43
43
  export { KICKOFF_STATE, CLAIM_KICKOFF_STATE, injectKickoffDefault, buildKickoffState, buildClaimKickoffState, handlesClaimWake, } from './runtime/kickoff.js';
44
- export { validateWorkflow, WorkflowValidationError } from './runtime/validateWorkflow.js';
44
+ export { validateWorkflow, WorkflowValidationError, PROBE_CTX } from './runtime/validateWorkflow.js';
45
45
  export { outcomeFromEvent, outcomeFromActionResult, applyOutcomeToCtx } from './runtime/buildOutcome.js';
46
46
  export { LANE_BOOK_KEY, allCollectedResults, allDelegatedAgreementIds, allPendingSubtasks, } from './runtime/taskBookkeeping.js';
47
47
  export { createDeliveryWriteKeys } from './runtime/deliveryWriteKeys.js';
@@ -67,7 +67,7 @@ export { HistoryFormatter, historyFormatter, AgreementFormatter, agreementFormat
67
67
  export { ProactiveTrigger } from './platform/proactive/ProactiveTrigger.js';
68
68
  export { PollRegistry, declaredPolls, type PollBinding, type PollContext, type PollKind, type PollResult, } from './platform/polls/PollKind.js';
69
69
  export { PollRunner, type PollRunnerOptions, type WakeTarget } from './platform/polls/PollRunner.js';
70
- export { PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp, PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, LISTING_TOOLS, } from './platform/tools/index.js';
70
+ export { PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp, PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, LISTING_TOOLS, } from './platform/tools/index.js';
71
71
  export { CLAUDE_SDK_TOOLS } from './brain/claudeSdkTools.js';
72
72
  export { hostedModelTools, isHostedDeferred, hostedToolLane } from './brain/hostedToolSurface.js';
73
73
  export { PROTOCOL_TOOL_NAMES, PROTOCOL_TOOL_TO_OPERATION, mapProtocolToolToOperation, isProtocolToolName } from './tasks/protocolRegistry.js';
@@ -83,3 +83,7 @@ export type { ApiClientConfig } from '@ziggs-ai/api-client';
83
83
  export { SeenMessages } from './platform/SeenMessages.js';
84
84
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
85
85
  export type { RuntimeLogLevel } from './shared/runtimeLog.js';
86
+ export { runAgents } from './launcher/runAgents.js';
87
+ export type { RunnerOptions, SingleAgentRun, FleetRun } from './launcher/runAgents.js';
88
+ export { createHealthServer, inboxHealth } from './launcher/createHealthServer.js';
89
+ export type { AgentLiveness, HealthRequest, HealthRequestHandler } from './launcher/createHealthServer.js';
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ export { runMechanical } from './runtime/runMechanical.js';
42
42
  export { PromptBuilder } from './runtime/PromptBuilder.js';
43
43
  export { thinkingDefaults, defineThinkingState, defineMechanicalState, DEFAULT_WAIT_PROMPT } from './runtime/defaults.js';
44
44
  export { KICKOFF_STATE, CLAIM_KICKOFF_STATE, injectKickoffDefault, buildKickoffState, buildClaimKickoffState, handlesClaimWake, } from './runtime/kickoff.js';
45
- export { validateWorkflow, WorkflowValidationError } from './runtime/validateWorkflow.js';
45
+ export { validateWorkflow, WorkflowValidationError, PROBE_CTX } from './runtime/validateWorkflow.js';
46
46
  export { outcomeFromEvent, outcomeFromActionResult, applyOutcomeToCtx } from './runtime/buildOutcome.js';
47
47
  export { LANE_BOOK_KEY, allCollectedResults, allDelegatedAgreementIds, allPendingSubtasks, } from './runtime/taskBookkeeping.js';
48
48
  export { createDeliveryWriteKeys } from './runtime/deliveryWriteKeys.js';
@@ -79,7 +79,7 @@ export {
79
79
  // Tier 1 — protocol grammar (framework-managed via taskTools).
80
80
  PROTOCOL_TOOLS, agreementProposeTool, agreementSubcontractTool, agreementRespondTool, agreementClaimTool, agreementCounterTool, agreementGetTool, agreementRevokeTool, agreementFulfillTool, taskCreateTool, taskSetResultTool, taskUpdatePlanStepTool, dispatchProtocolOp,
81
81
  // Tier 2 — opt-in capability bundles (spread into `tools:`).
82
- PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, LISTING_TOOLS, } from './platform/tools/index.js';
82
+ PAYMENT_TOOLS, paymentBalanceTool, CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, DISCOVERY_TOOLS, agentSearchTool, agentGetTool, MARKETPLACE_TOOLS, marketplaceViewTool, CONTEXT_TOOLS, contextReadTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, GRANTS_TOOLS, listGrantsTool, PLAN_TOOLS, taskReplacePlanTool, LINK_TOOLS, linkProposeTool, linkListTool, INTRODUCTION_TOOLS, introductionMintTool, introductionRedeemTool, introductionListTool, introductionRevokeTool, ARTIFACT_TOOLS, recordArtifactTool, CHAT_TOOLS, openConversationTool, LISTING_TOOLS, } from './platform/tools/index.js';
83
83
  // The always-on toolset for the hosted Claude cognition (parity guard
84
84
  // reads this as part of the real SDK registry).
85
85
  export { CLAUDE_SDK_TOOLS } from './brain/claudeSdkTools.js';
@@ -96,3 +96,5 @@ export { MessagesClient, ArtifactsClient, AgentSearchClient, getBackendUrl,
96
96
  configureApiClient, } from '@ziggs-ai/api-client';
97
97
  export { SeenMessages } from './platform/SeenMessages.js';
98
98
  export { runtimeLog, resetRuntimeLogLevelCache } from './shared/runtimeLog.js';
99
+ export { runAgents } from './launcher/runAgents.js';
100
+ export { createHealthServer, inboxHealth } from './launcher/createHealthServer.js';
@@ -0,0 +1,50 @@
1
+ import { type IncomingMessage, type Server, type ServerResponse } from 'node:http';
2
+ import type { Agent } from '../Agent.js';
3
+ import type { ConnectionPool } from '../platform/ConnectionPool.js';
4
+ /** What one agent reports about its own inbox reading. */
5
+ export type AgentLiveness = ReturnType<Agent['inboxLiveness']>;
6
+ /**
7
+ * The health verdict. A process is alive when its agents are still reading,
8
+ * so the answer is derived from the inbox loop rather than from the fact that
9
+ * this HTTP server replied — a wedged process replies happily while none of
10
+ * its agents read anything.
11
+ *
12
+ * The restart decision reads `lastAttemptAt`, not `lastPassAt`. When the
13
+ * backend is down every pass fails while the loops are perfectly healthy, and
14
+ * restarting the fleet would fix nothing and lose in-flight turns. Read
15
+ * staleness is still reported per agent, for the store and for monitoring.
16
+ */
17
+ export declare function inboxHealth(rows: AgentLiveness[], now?: number, staleMs?: number): {
18
+ ok: boolean;
19
+ reason?: string;
20
+ staleMs: number;
21
+ watching: number;
22
+ oldestAttemptAgeMs: number | null;
23
+ oldestPassAgeMs: number | null;
24
+ agents: (AgentLiveness & {
25
+ passAgeMs: number | null;
26
+ attemptAgeMs: number | null;
27
+ })[];
28
+ };
29
+ export type HealthRequest = {
30
+ req: IncomingMessage;
31
+ res: ServerResponse;
32
+ pool?: ConnectionPool;
33
+ };
34
+ /**
35
+ * A route the embedding process adds. Return true once the response is sent.
36
+ * The health page itself only answers `/` and `/health`.
37
+ */
38
+ export type HealthRequestHandler = (call: HealthRequest) => Promise<boolean>;
39
+ export declare function createHealthServer({ port, label, pool, liveness, onRequest, }?: {
40
+ port?: number;
41
+ label?: string;
42
+ pool?: ConnectionPool;
43
+ /**
44
+ * Every agent this process is responsible for. Omit only when there is
45
+ * nothing to watch: without it `/health` can say no more than "this server
46
+ * replied", which is the answer this route exists to stop giving.
47
+ */
48
+ liveness?: () => AgentLiveness[];
49
+ onRequest?: HealthRequestHandler;
50
+ }): Server;
@@ -0,0 +1,68 @@
1
+ import { createServer } from 'node:http';
2
+ import { runtimeLog } from '../shared/runtimeLog.js';
3
+ /**
4
+ * How long an agent's inbox loop may go without turning before this process is
5
+ * called unhealthy. An idle loop completes a pass every `DEFAULT_WAIT_SECONDS`
6
+ * (110s), so this is three missed cycles plus slack: long enough that a slow
7
+ * server or a long turn never flaps, short enough that a wedged process is
8
+ * replaced within minutes.
9
+ */
10
+ const STALE_MS = Number(process.env.FLEET_INBOX_STALE_MS) || 360_000;
11
+ function age(now, at) {
12
+ return at === null ? null : now - at;
13
+ }
14
+ /**
15
+ * The health verdict. A process is alive when its agents are still reading,
16
+ * so the answer is derived from the inbox loop rather than from the fact that
17
+ * this HTTP server replied — a wedged process replies happily while none of
18
+ * its agents read anything.
19
+ *
20
+ * The restart decision reads `lastAttemptAt`, not `lastPassAt`. When the
21
+ * backend is down every pass fails while the loops are perfectly healthy, and
22
+ * restarting the fleet would fix nothing and lose in-flight turns. Read
23
+ * staleness is still reported per agent, for the store and for monitoring.
24
+ */
25
+ export function inboxHealth(rows, now = Date.now(), staleMs = STALE_MS) {
26
+ const agents = rows.map((r) => ({
27
+ ...r,
28
+ passAgeMs: age(now, r.lastPassAt),
29
+ attemptAgeMs: age(now, r.lastAttemptAt),
30
+ }));
31
+ // Only agents that are supposed to be polling can be stale. A connected
32
+ // agent with the inbox loop off (lab and eval paths) has nothing to report,
33
+ // and an agent that was deliberately stopped is not this process failing.
34
+ const watched = agents.filter((r) => r.pollingInbox && r.connected);
35
+ const turning = watched.filter((r) => r.attemptAgeMs !== null && r.attemptAgeMs <= staleMs);
36
+ const ages = watched.map((r) => r.attemptAgeMs).filter((n) => n !== null);
37
+ const passAges = watched.map((r) => r.passAgeMs).filter((n) => n !== null);
38
+ const ok = watched.length === 0 || turning.length > 0;
39
+ return {
40
+ ok,
41
+ ...(ok ? {} : { reason: `no inbox pass attempted by any of ${watched.length} agent(s) within ${staleMs}ms` }),
42
+ staleMs,
43
+ watching: watched.length,
44
+ oldestAttemptAgeMs: ages.length ? Math.max(...ages) : null,
45
+ oldestPassAgeMs: passAges.length ? Math.max(...passAges) : null,
46
+ agents,
47
+ };
48
+ }
49
+ export function createHealthServer({ port = Number(process.env.PORT) || 8080, label = 'agents', pool, liveness, onRequest, } = {}) {
50
+ const server = createServer(async (req, res) => {
51
+ if (await onRequest?.({ req, res, pool }))
52
+ return;
53
+ const url = req.url ?? '/';
54
+ if (url === '/health' || url === '/') {
55
+ const report = inboxHealth(liveness?.() ?? []);
56
+ if (!report.ok) {
57
+ runtimeLog.warn(label, `health: ${report.reason}`);
58
+ }
59
+ res.writeHead(report.ok ? 200 : 503, { 'Content-Type': 'application/json' });
60
+ res.end(JSON.stringify(report));
61
+ return;
62
+ }
63
+ res.writeHead(404);
64
+ res.end();
65
+ });
66
+ server.listen(port, () => runtimeLog.info(label, `health server on port ${port}`));
67
+ return server;
68
+ }
@@ -0,0 +1,32 @@
1
+ import { type Agent, type AgentOptions } from '../Agent.js';
2
+ import { ConnectionPool } from '../platform/ConnectionPool.js';
3
+ import { type HealthRequestHandler } from './createHealthServer.js';
4
+ import type { Server } from 'node:http';
5
+ /** Process concerns only. Every Agent owns its inbox and external polls. */
6
+ export interface RunnerOptions {
7
+ operatorKey?: string;
8
+ label?: string;
9
+ port?: number | string;
10
+ healthServer?: boolean;
11
+ /** Disable when the embedding process owns its signal handlers. */
12
+ handleSignals?: boolean;
13
+ drainTimeoutMs?: number;
14
+ onShutdown?: () => Promise<void>;
15
+ agentMeta?: Record<string, unknown>[];
16
+ primary?: AgentOptions | ((pool: ConnectionPool) => AgentOptions);
17
+ /** A route this process adds. The health page itself only answers `/` and `/health`. */
18
+ onRequest?: HealthRequestHandler;
19
+ }
20
+ export interface SingleAgentRun {
21
+ agent: Agent;
22
+ healthServer?: Server;
23
+ shutdown(): Promise<void>;
24
+ }
25
+ export interface FleetRun {
26
+ pool: ConnectionPool;
27
+ primary: Agent | null;
28
+ healthServer?: Server;
29
+ shutdown(): Promise<void>;
30
+ }
31
+ export declare function runAgents(config: AgentOptions, options?: RunnerOptions): Promise<SingleAgentRun>;
32
+ export declare function runAgents(configs: AgentOptions[], options?: RunnerOptions): Promise<FleetRun>;
@@ -0,0 +1,119 @@
1
+ import { createAgent } from '../Agent.js';
2
+ import { ConnectionPool } from '../platform/ConnectionPool.js';
3
+ import { boundKeyFleetWarning } from '../shared/operatorKeyClaims.js';
4
+ import { runtimeLog } from '../shared/runtimeLog.js';
5
+ import { createHealthServer } from './createHealthServer.js';
6
+ const DRAIN_TIMEOUT_MS = Number(process.env.FLEET_DRAIN_TIMEOUT_MS) || 90_000;
7
+ function shutdownHandler(stop, server, options) {
8
+ let pending;
9
+ const shutdown = () => {
10
+ if (!pending) {
11
+ process.off('SIGTERM', signal);
12
+ process.off('SIGINT', signal);
13
+ pending = (async () => {
14
+ try {
15
+ await stop();
16
+ await options.onShutdown?.();
17
+ }
18
+ finally {
19
+ if (server)
20
+ await new Promise((resolve) => server.close(() => resolve()));
21
+ }
22
+ })();
23
+ }
24
+ return pending;
25
+ };
26
+ const signal = () => {
27
+ runtimeLog.info(options.label || 'runner', 'Shutting down');
28
+ void shutdown().then(() => process.exit(0), (err) => {
29
+ runtimeLog.error(options.label || 'runner', `Shutdown failed: ${err.message}`);
30
+ process.exit(1);
31
+ });
32
+ };
33
+ if (options.handleSignals !== false) {
34
+ process.on('SIGTERM', signal);
35
+ process.on('SIGINT', signal);
36
+ }
37
+ return shutdown;
38
+ }
39
+ async function healthServer(options, liveness, pool) {
40
+ if (options.healthServer === false)
41
+ return undefined;
42
+ const server = createHealthServer({
43
+ port: Number(options.port ?? process.env.PORT ?? 8080),
44
+ label: options.label || 'runner',
45
+ pool,
46
+ liveness,
47
+ onRequest: options.onRequest,
48
+ });
49
+ await new Promise((resolve, reject) => {
50
+ server.once('error', reject);
51
+ server.once('listening', () => { server.off('error', reject); resolve(); });
52
+ });
53
+ return server;
54
+ }
55
+ export async function runAgents(configOrConfigs, options = {}) {
56
+ const effectiveKey = options.operatorKey ?? process.env.ZIGGS_OPERATOR_KEY;
57
+ const decorate = (config) => effectiveKey && !config.operatorKey ? { ...config, operatorKey: effectiveKey } : config;
58
+ const drainTimeout = options.drainTimeoutMs ?? DRAIN_TIMEOUT_MS;
59
+ if (!Array.isArray(configOrConfigs)) {
60
+ const agent = createAgent(decorate(configOrConfigs));
61
+ let server;
62
+ // One budget for stopping intake and finishing in-flight work: the inbox
63
+ // pass gets up to the whole of it to acknowledge, the queue what is left.
64
+ const stop = async () => {
65
+ const deadline = Date.now() + drainTimeout;
66
+ await agent.disconnect(drainTimeout);
67
+ await agent.drain(Math.max(0, deadline - Date.now()));
68
+ };
69
+ try {
70
+ await agent.connectAsync();
71
+ server = await healthServer(options, () => [agent.inboxLiveness()]);
72
+ }
73
+ catch (err) {
74
+ await stop();
75
+ throw err;
76
+ }
77
+ const shutdown = shutdownHandler(stop, server, options);
78
+ return { agent, healthServer: server, shutdown };
79
+ }
80
+ const pool = new ConnectionPool();
81
+ const configs = configOrConfigs.map(decorate);
82
+ pool.register(configs, options.agentMeta);
83
+ const primaryConfig = typeof options.primary === 'function' ? options.primary(pool) : options.primary;
84
+ let primary = null;
85
+ let server;
86
+ // Same single budget as the one-agent path, shared by the pool and the primary.
87
+ const stop = async () => {
88
+ const deadline = Date.now() + drainTimeout;
89
+ await Promise.all([primary?.disconnect(drainTimeout), pool.shutdown(drainTimeout)]);
90
+ await primary?.drain(Math.max(0, deadline - Date.now()));
91
+ };
92
+ try {
93
+ if (primaryConfig)
94
+ primary = createAgent(decorate(primaryConfig));
95
+ const controlKey = effectiveKey ?? configs.find(c => c.operatorKey)?.operatorKey ?? primary?.options.operatorKey;
96
+ if (controlKey) {
97
+ const warning = boundKeyFleetWarning(controlKey, pool.size + (primary ? 1 : 0));
98
+ if (warning)
99
+ runtimeLog.warn(options.label || 'runner', warning);
100
+ }
101
+ await primary?.connectAsync();
102
+ await pool.connectAll();
103
+ const connected = pool.listActive().length;
104
+ if (configs.length > 0 && connected === 0) {
105
+ throw new Error(`0/${configs.length} agents started; process must restart`);
106
+ }
107
+ if (connected !== pool.size || pool.size !== configs.length) {
108
+ runtimeLog.warn(options.label || 'runner', `Only ${connected}/${configs.length} agents started — hosting the ones that came up`);
109
+ }
110
+ server = await healthServer(options, () => [...(primary ? [primary.inboxLiveness()] : []), ...pool.liveness()], pool);
111
+ runtimeLog.info(options.label || 'runner', `Ready — ${connected}/${pool.size} agents started`);
112
+ }
113
+ catch (err) {
114
+ await stop();
115
+ throw err;
116
+ }
117
+ const shutdown = shutdownHandler(stop, server, options);
118
+ return { pool, primary, healthServer: server, shutdown };
119
+ }
@@ -21,7 +21,7 @@ export { DISCOVERY_TOOLS, agentSearchTool, agentGetTool } from './tier2/discover
21
21
  export { MARKETPLACE_TOOLS, marketplaceViewTool } from './tier2/marketplaceTools.js';
22
22
  export { PAYMENT_TOOLS, paymentBalanceTool } from './tier2/paymentTools.js';
23
23
  export { CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, } from './tier2/connectionTools.js';
24
- export { CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, } from './tier2/contextTools.js';
24
+ export { CONTEXT_TOOLS, contextReadTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, } from './tier2/contextTools.js';
25
25
  export { GRANTS_TOOLS, listGrantsTool } from './tier2/grantsTools.js';
26
26
  export { TASK_TOOLS, listTasksTool, cancelTaskTool } from './tier2/taskTools.js';
27
27
  export { PLAN_TOOLS, taskReplacePlanTool } from './tier2/planTools.js';
@@ -23,7 +23,7 @@ export { DISCOVERY_TOOLS, agentSearchTool, agentGetTool } from './tier2/discover
23
23
  export { MARKETPLACE_TOOLS, marketplaceViewTool } from './tier2/marketplaceTools.js';
24
24
  export { PAYMENT_TOOLS, paymentBalanceTool } from './tier2/paymentTools.js';
25
25
  export { CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, } from './tier2/connectionTools.js';
26
- export { CONTEXT_TOOLS, contextReadTool, contextRequestTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, } from './tier2/contextTools.js';
26
+ export { CONTEXT_TOOLS, contextReadTool, accessRequestTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, } from './tier2/contextTools.js';
27
27
  // one grant lister across every rail (retires context_discover +
28
28
  // payment_list_grants). Always-available on the hosted agent — see CLAUDE_SDK_TOOLS.
29
29
  export { GRANTS_TOOLS, listGrantsTool } from './tier2/grantsTools.js';
@@ -67,13 +67,13 @@ export const agreementClaimTool = defineTool('agreement_claim', agreementClaimCa
67
67
  export const taskSetResultTool = defineTool('task_set_result', {
68
68
  taskId: { type: 'string', required: true },
69
69
  // same param name as MCP ziggs_task_set_result / PATCH /tasks/:id/state.
70
- state: { type: 'string', required: true, enum: ['completed', 'failed', 'cancelled'] },
70
+ state: { type: 'string', required: true, enum: ['completed', 'failed'] },
71
71
  // Same object contract as MCP ({ summary, status, links, … }).
72
72
  result: {
73
73
  type: 'object',
74
74
  description: 'Outcome payload (summary, status, links, …). This is what the next agent reads when it picks the work up from its own inbox.',
75
75
  },
76
- }, handlerFor('task_set_result'), { description: 'Transition a task to its terminal state — completed, failed, or cancelled — and record the result. Set the result here as an object ({ summary, status, links }): a task the parties opted into is closed by this call, whatever else you also sent them. Pass state (not status). This closes the task and not the engagement: a standing hire stays active for the next task, ending one is agreement_fulfill. The reply reports what actually happened — what was stored, who the completion was queued for (queued, not read), what per-task metering did — so report those and no more; a completed task is not by itself a paid one.' });
76
+ }, handlerFor('task_set_result'), { description: 'Transition a task to its terminal state, completed or failed, and record the result. To cancel a task use task_cancel. Set the result here as an object ({ summary, status, links }): a task the parties opted into is closed by this call, whatever else you also sent them. Pass state (not status). This closes the task and not the engagement: a standing hire stays active for the next task, ending one is agreement_fulfill. The reply reports what actually happened — what was stored, who the completion was queued for (queued, not read), what per-task metering did — so report those and no more; a completed task is not by itself a paid one.' });
77
77
  export const agreementCounterTool = defineTool('agreement_counter', { agreementId: { type: 'string', required: true }, price: { type: 'number', description: 'Price in POINTS, as an integer of hundredths — 500 means ϟ5.00. Convert both ways: a human asking for "ϟ2 per task" means 200, not 2. ϟ is the points symbol, not a hundredth.' }, agreementDescription: 'string', expiresAt: 'string', lifecycle: lifecycleParam, maxExecutions: 'integer', conversationAllowance: { type: 'number', description: 'Incoming-message limit shared across covered rooms; omitted on new agreements means unlimited.' }, description: 'string' }, handlerFor('agreement_counter'), { description: 'Counter a pending proposal with revised terms instead of approving or rejecting. Check status first with agreement_get.' });
78
78
  export const agreementGetTool = defineTool('agreement_get', { agreementId: { type: 'string', required: true } }, handlerFor('agreement_get'), { description: 'Read the current proposal status for an agreement (pending, approved, rejected, countered, expired).' });
79
79
  export const agreementRevokeTool = defineTool('agreement_revoke', { agreementId: { type: 'string', required: true } }, handlerFor('agreement_revoke'), { description: 'Revoke a pending proposal you created so it can no longer be approved. Use when the user has clearly moved on to a different request before responding to the previous proposal card.' });
@@ -3,7 +3,6 @@ export declare const contextReadTool: ToolDefinition;
3
3
  export declare const openTool: ToolDefinition;
4
4
  export declare const accessExplainTool: ToolDefinition;
5
5
  export declare const accessRequestTool: ToolDefinition;
6
- export declare const contextRequestTool: ToolDefinition;
7
6
  export declare const contextDelegateTool: ToolDefinition;
8
7
  export declare const contextExpandReachTool: ToolDefinition;
9
8
  export declare const contextDiscoverGrantableTool: ToolDefinition;
@@ -1,4 +1,4 @@
1
- import { CONTEXT_CAPABILITIES, contextReadCapability, openCapability, accessExplainCapability, contextDelegateCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, contextRequestCapability, accessRequestCapability, } from '@ziggs-ai/api-client';
1
+ import { CONTEXT_CAPABILITIES, contextReadCapability, openCapability, accessExplainCapability, contextDelegateCapability, contextExpandReachCapability, contextDiscoverGrantableCapability, accessRequestCapability, } from '@ziggs-ai/api-client';
2
2
  import { toolFromCapability, toolsFromCapabilities } from '../../../tools/capabilityAdapter.js';
3
3
  // context grant tools ride the same api-client
4
4
  // clients as ziggs-mcp; the whole definition (schema + handler) is now shared
@@ -7,7 +7,6 @@ export const contextReadTool = toolFromCapability(contextReadCapability);
7
7
  export const openTool = toolFromCapability(openCapability);
8
8
  export const accessExplainTool = toolFromCapability(accessExplainCapability);
9
9
  export const accessRequestTool = toolFromCapability(accessRequestCapability);
10
- export const contextRequestTool = toolFromCapability(contextRequestCapability);
11
10
  export const contextDelegateTool = toolFromCapability(contextDelegateCapability);
12
11
  export const contextExpandReachTool = toolFromCapability(contextExpandReachCapability);
13
12
  export const contextDiscoverGrantableTool = toolFromCapability(contextDiscoverGrantableCapability);
@@ -1,12 +1,10 @@
1
1
  /**
2
2
  * One classifier for store-publish probe rooms.
3
3
  *
4
- * The runner mints `probe_<agentId>_<ts>`. An id prefix must not buy
5
- * capability evidence or a canned brain reply; it only names the room so
6
- * inbox pin and wake order can find it. Capability vs liveness is decided
7
- * by the store sync, not by this prefix.
4
+ * The runner mints `probe_<agentId>_<ts>`. That prefix skips the wake gate
5
+ * and the wake-rate breaker, so a store publish still hears a model reply.
6
+ * It does not write a canned answer, and it is not capability evidence.
7
+ * Capability versus liveness is decided by the store sync.
8
8
  */
9
9
  export declare const PROBE_CHAT_ID_PREFIX = "probe_";
10
10
  export declare function isPublishProbeChat(chatId: string | undefined | null): boolean;
11
- /** @deprecated use {@link isPublishProbeChat} — same classifier, old name. */
12
- export declare const isCapabilityProbeSession: typeof isPublishProbeChat;
package/dist/probeChat.js CHANGED
@@ -1,14 +1,12 @@
1
1
  /**
2
2
  * One classifier for store-publish probe rooms.
3
3
  *
4
- * The runner mints `probe_<agentId>_<ts>`. An id prefix must not buy
5
- * capability evidence or a canned brain reply; it only names the room so
6
- * inbox pin and wake order can find it. Capability vs liveness is decided
7
- * by the store sync, not by this prefix.
4
+ * The runner mints `probe_<agentId>_<ts>`. That prefix skips the wake gate
5
+ * and the wake-rate breaker, so a store publish still hears a model reply.
6
+ * It does not write a canned answer, and it is not capability evidence.
7
+ * Capability versus liveness is decided by the store sync.
8
8
  */
9
9
  export const PROBE_CHAT_ID_PREFIX = 'probe_';
10
10
  export function isPublishProbeChat(chatId) {
11
11
  return typeof chatId === 'string' && chatId.startsWith(PROBE_CHAT_ID_PREFIX);
12
12
  }
13
- /** @deprecated use {@link isPublishProbeChat} — same classifier, old name. */
14
- export const isCapabilityProbeSession = isPublishProbeChat;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziggs-ai/agent-sdk",
3
- "version": "0.38.2",
3
+ "version": "0.38.3",
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.284",
27
27
  "@anthropic-ai/sdk": "^0.110.0",
28
28
  "@modelcontextprotocol/sdk": "^1.29.0",
29
- "@ziggs-ai/api-client": "0.37.4",
29
+ "@ziggs-ai/api-client": "0.37.5",
30
30
  "@ziggs-ai/contracts": "^0.23.3",
31
31
  "ajv": "^8.17.1",
32
32
  "dotenv": "^17.2.3",