@ziggs-ai/agent-sdk 0.1.10 → 0.1.12

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 (35) hide show
  1. package/package.json +6 -3
  2. package/src/AgentHost.ts +347 -28
  3. package/src/adapters/AnthropicAdapter.ts +238 -0
  4. package/src/adapters/McpAdapter.ts +391 -15
  5. package/src/adapters/OpenAIAdapter.ts +20 -8
  6. package/src/adapters/index.ts +1 -0
  7. package/src/agent/Agent.ts +13 -2
  8. package/src/agent/ClaudeSdkAgent.ts +401 -0
  9. package/src/agent/claudeCognition.ts +139 -0
  10. package/src/agent/claudeSdkProtocol.ts +27 -0
  11. package/src/agent/claudeSdkTools.ts +81 -0
  12. package/src/agent/hostedAgentConnection.ts +41 -0
  13. package/src/agent/toolManagerToSdkMcp.ts +136 -0
  14. package/src/defineAgent.ts +22 -7
  15. package/src/index.ts +14 -5
  16. package/src/pricing/fleetTierByAgentId.gen.ts +53 -1
  17. package/src/runtime/AgentMachine.ts +143 -23
  18. package/src/runtime/PromptBuilder.ts +62 -6
  19. package/src/runtime/bootstrapCtx.ts +39 -0
  20. package/src/runtime/buildOutcome.ts +51 -6
  21. package/src/runtime/defaults.ts +12 -1
  22. package/src/runtime/deriveRespondsToProposals.ts +35 -0
  23. package/src/runtime/kickoff.ts +117 -0
  24. package/src/runtime/runMechanical.ts +106 -0
  25. package/src/runtime/runTurn.ts +236 -62
  26. package/src/runtime/validateWorkflow.ts +55 -15
  27. package/src/server/ConnectionPool.ts +56 -5
  28. package/src/server/InboxCatchUp.ts +37 -0
  29. package/src/server/StateTimers.ts +85 -0
  30. package/src/server/ZiggsEffectHandler.ts +198 -180
  31. package/src/server/agreements/AgreementService.ts +3 -3
  32. package/src/server/tasks/TaskService.ts +15 -3
  33. package/src/server/tools/tier1/protocolRunner.ts +221 -3
  34. package/src/server/tools/tier1/protocolTools.ts +19 -4
  35. package/src/types.ts +105 -29
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Hosted fleet agents connect via api-client (AgentHost), never inbound ziggs-mcp.
3
+ * @see ZIG-781
4
+ */
5
+
6
+ export type McpServerSpec = {
7
+ type?: string;
8
+ command?: string;
9
+ args?: string[];
10
+ };
11
+
12
+ export function looksLikeInboundZiggsMcp(command: string, args: string[] = []): boolean {
13
+ const joined = `${command} ${args.join(' ')}`;
14
+ return /ziggs-mcp|@ziggs-ai\/ziggs-mcp/i.test(joined);
15
+ }
16
+
17
+ /**
18
+ * Reject wiring a hosted agent to the inbound Ziggs MCP stdio surface.
19
+ * Claude SDK agents must use in-process ToolManager tools (createSdkMcpServer).
20
+ */
21
+ export function assertHostedAgentZiggsTools(
22
+ mcpServers: Record<string, McpServerSpec | unknown> | undefined,
23
+ ): void {
24
+ if (!mcpServers) return;
25
+ for (const [name, raw] of Object.entries(mcpServers)) {
26
+ if (!raw || typeof raw !== 'object') continue;
27
+ const spec = raw as McpServerSpec;
28
+ if (spec.type === 'stdio') {
29
+ throw new Error(
30
+ `Hosted Ziggs agents must not use stdio MCP (server "${name}"). ` +
31
+ 'Connect via api-client / AgentHost in-process tools.',
32
+ );
33
+ }
34
+ if (looksLikeInboundZiggsMcp(String(spec.command ?? ''), spec.args ?? [])) {
35
+ throw new Error(
36
+ `Hosted Ziggs agents must not spawn ziggs-mcp (inbound MCP server "${name}"). ` +
37
+ 'Use AgentHost + in-process tools.',
38
+ );
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,136 @@
1
+ import { z } from 'zod';
2
+ import { createSdkMcpServer } from '@anthropic-ai/claude-agent-sdk';
3
+ import type { SdkMcpToolDefinition } from '@anthropic-ai/claude-agent-sdk';
4
+ import type { ToolDefinition } from '../tools/defineTool.js';
5
+ import type { ClaudeSdkToolContext } from './claudeSdkTools.js';
6
+
7
+ type JsonSchema = Record<string, unknown>;
8
+
9
+ type CallToolResult = {
10
+ content: Array<{ type: 'text'; text: string }>;
11
+ isError?: boolean;
12
+ };
13
+
14
+ function jsonTypeToZod(field: JsonSchema): z.ZodTypeAny {
15
+ const t = field['type'];
16
+ if (t === 'string') {
17
+ let s: z.ZodTypeAny = z.string();
18
+ if (Array.isArray(field['enum'])) {
19
+ const vals = field['enum'] as string[];
20
+ if (vals.length > 0) s = z.enum(vals as [string, ...string[]]);
21
+ }
22
+ if (typeof field['description'] === 'string') s = s.describe(field['description']);
23
+ return s;
24
+ }
25
+ if (t === 'number' || t === 'integer') {
26
+ let n: z.ZodTypeAny = z.number();
27
+ if (typeof field['description'] === 'string') n = n.describe(field['description']);
28
+ return n;
29
+ }
30
+ if (t === 'boolean') return z.boolean();
31
+ if (t === 'array') {
32
+ const items = (field['items'] as JsonSchema | undefined) ?? { type: 'string' };
33
+ return z.array(jsonTypeToZod(items));
34
+ }
35
+ if (t === 'object') {
36
+ const props = (field['properties'] as Record<string, JsonSchema> | undefined) ?? {};
37
+ const required = new Set((field['required'] as string[] | undefined) ?? []);
38
+ const shape: Record<string, z.ZodTypeAny> = {};
39
+ for (const [key, val] of Object.entries(props)) {
40
+ let node = jsonTypeToZod(val);
41
+ if (!required.has(key)) node = node.optional();
42
+ shape[key] = node;
43
+ }
44
+ return z.object(shape).passthrough();
45
+ }
46
+ return z.unknown();
47
+ }
48
+
49
+ function parametersToZodShape(parameters: JsonSchema | undefined): z.ZodRawShape {
50
+ if (!parameters || parameters['type'] !== 'object') return {};
51
+ const props = (parameters['properties'] as Record<string, JsonSchema> | undefined) ?? {};
52
+ const required = new Set((parameters['required'] as string[] | undefined) ?? []);
53
+ const shape: Record<string, z.ZodTypeAny> = {};
54
+ for (const [key, val] of Object.entries(props)) {
55
+ let node = jsonTypeToZod(val);
56
+ if (!required.has(key)) node = node.optional();
57
+ shape[key] = node;
58
+ }
59
+ return shape;
60
+ }
61
+
62
+ function toCallToolResult(value: unknown): CallToolResult {
63
+ const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
64
+ return { content: [{ type: 'text', text }] };
65
+ }
66
+
67
+ function toCallToolError(err: unknown): CallToolResult {
68
+ const message = err instanceof Error ? err.message : String(err);
69
+ return { content: [{ type: 'text', text: message }], isError: true };
70
+ }
71
+
72
+ /**
73
+ * Map Ziggs `ToolDefinition`s to Claude Agent SDK MCP tools. Each handler routes
74
+ * execution through `eff({ kind: 'tool-call' })` — the shared executor (ZIG-775).
75
+ */
76
+ export function buildSdkToolDefs(
77
+ toolDefs: ToolDefinition[],
78
+ getContext: () => ClaudeSdkToolContext,
79
+ ): Array<SdkMcpToolDefinition> {
80
+ return toolDefs.map((def) => {
81
+ const fn = def.schema.function;
82
+ const name = String(fn['name'] ?? '');
83
+ const description = String(fn['description'] ?? name);
84
+ const shape = parametersToZodShape(fn['parameters'] as JsonSchema | undefined);
85
+ const inputSchema = Object.keys(shape).length > 0
86
+ ? shape
87
+ : { _: z.record(z.string(), z.unknown()).optional() };
88
+
89
+ return {
90
+ name,
91
+ description,
92
+ inputSchema,
93
+ _meta: { 'anthropic/alwaysLoad': true },
94
+ handler: async (args: Record<string, unknown>) => {
95
+ try {
96
+ const ctx = getContext();
97
+ const payload = args._ != null && Object.keys(args).length === 1
98
+ ? (args._ as Record<string, unknown>)
99
+ : args;
100
+ const eff = ctx.eff;
101
+ if (!eff) return toCallToolError(`tool "${name}": missing eff in tool context`);
102
+ const sessionId = ctx.chatId ?? ctx.sessionId;
103
+ if (!sessionId) return toCallToolError(`tool "${name}": missing sessionId in tool context`);
104
+ const r = await eff({
105
+ kind: 'tool-call',
106
+ sessionId,
107
+ name,
108
+ args: payload ?? {},
109
+ senderId: ctx.senderId,
110
+ senderType: ctx.senderType,
111
+ onBehalfOfAgreementId: ctx.onBehalfOfAgreementId as string | undefined,
112
+ runId: ctx.runId,
113
+ });
114
+ if (r.ok) return toCallToolResult(r.result);
115
+ return toCallToolError(r.error ?? `tool "${name}" failed`);
116
+ } catch (err) {
117
+ return toCallToolError(err);
118
+ }
119
+ },
120
+ };
121
+ });
122
+ }
123
+
124
+ export function buildZiggsSdkMcpServer(
125
+ toolDefs: ToolDefinition[],
126
+ getContext: () => ClaudeSdkToolContext,
127
+ options: { name?: string; instructions?: string } = {},
128
+ ) {
129
+ return createSdkMcpServer({
130
+ name: options.name ?? 'ziggs',
131
+ version: '1.0.0',
132
+ instructions: options.instructions,
133
+ tools: buildSdkToolDefs(toolDefs, getContext),
134
+ alwaysLoad: true,
135
+ });
136
+ }
@@ -1,12 +1,18 @@
1
1
  import type { AgentConfig, DefineAgentInput, Workflow } from './types.js';
2
2
  import { validateWorkflow } from './runtime/validateWorkflow.js';
3
+ import { injectKickoffDefault } from './runtime/kickoff.js';
4
+ import { deriveRespondsToProposals } from './runtime/deriveRespondsToProposals.js';
3
5
  import { runtimeLog } from './shared/runtimeLog.js';
6
+ import { DEFAULT_MODEL } from './AgentHost.js';
4
7
 
5
8
  /**
6
9
  * Validates the workflow synchronously, resolves merged tools and model, and
7
- * returns a frozen AgentConfig. Does NOT mutate the input — `wait` action and
8
- * `activeWait` transitions are the workflow author's responsibility (visible
9
- * spread of `thinkingDefaults`).
10
+ * returns a frozen AgentConfig. Never mutates the input. `wait` defaults remain
11
+ * the author's visible spread of `thinkingDefaults`. ONE default is injected (as
12
+ * new objects): the agreement-kickoff state `kickingOff` plus a last-position
13
+ * transition into it, appended to every state that does not already handle a
14
+ * proposer-side proposal-resolved/approve outcome (runtime/kickoff.ts). The
15
+ * state name 'kickingOff' is reserved; defining it throws.
10
16
  *
11
17
  * Validation throws WorkflowValidationError on hard problems and logs warnings
12
18
  * on soft ones (e.g. missing wait fallthrough).
@@ -17,12 +23,14 @@ export function defineAgent(input: DefineAgentInput): AgentConfig {
17
23
  if (!input?.states) throw new Error('[defineAgent] states is required');
18
24
  if (!input?.initial) throw new Error('[defineAgent] initial state is required');
19
25
 
20
- const workflow: Workflow = {
26
+ // Agreement-kickoff default (see runtime/kickoff.ts): injected BEFORE
27
+ // validation so the injected state/transitions are validated too.
28
+ const workflow: Workflow = injectKickoffDefault({
21
29
  id: input.agentId,
22
30
  description: input.description,
23
31
  initial: input.initial,
24
32
  states: input.states,
25
- };
33
+ });
26
34
 
27
35
  const { warnings } = validateWorkflow(workflow);
28
36
  for (const w of warnings) runtimeLog.warn('defineAgent', w);
@@ -32,10 +40,14 @@ export function defineAgent(input: DefineAgentInput): AgentConfig {
32
40
  ...(Array.isArray(input.services?.tools) ? input.services!.tools! : []),
33
41
  ];
34
42
 
43
+ // Model resolution, most-specific-first: a per-agent pin, then the
44
+ // fleet-wide `LLM_MODEL` lever, then the single `DEFAULT_MODEL` fallback (the
45
+ // ONE place the default lives — see AgentHost). The id also picks the provider
46
+ // (claude-* → Anthropic). No agent hardcodes its own fallback.
35
47
  const model =
36
48
  input.services?.llm?.model ||
37
- process.env.OPENAI_MODEL ||
38
- 'gpt-5.4';
49
+ process.env.LLM_MODEL ||
50
+ DEFAULT_MODEL;
39
51
 
40
52
  // Strip the structural fields we already consumed; pass through everything
41
53
  // else (operatorKey, taskTools, custom keys consumed by AgentHost).
@@ -46,6 +58,7 @@ export function defineAgent(input: DefineAgentInput): AgentConfig {
46
58
 
47
59
  const config: AgentConfig = {
48
60
  openaiKey: process.env.OPENAI_API_KEY,
61
+ anthropicKey: process.env.ANTHROPIC_API_KEY,
49
62
  ...(operatorKey ? { operatorKey } : {}),
50
63
  agentId,
51
64
  description,
@@ -53,6 +66,8 @@ export function defineAgent(input: DefineAgentInput): AgentConfig {
53
66
  tools,
54
67
  model,
55
68
  workflow,
69
+ respondsToProposals:
70
+ input.respondsToProposals ?? deriveRespondsToProposals(workflow),
56
71
  ...(input.services ? { services: input.services } : {}),
57
72
  ...(taskTools !== undefined ? { taskTools } : {}),
58
73
  ...rest,
package/src/index.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Foundation:
5
5
  * • Outcome union — discriminated, hybrid (closed core + extension)
6
- * • Workflow shape — explicit kind: 'parked' | 'thinking'
6
+ * • Workflow shape — explicit kind: 'parked' | 'thinking' | 'mechanical'
7
7
  * • Visible defaults — thinkingDefaults({ initial }) spread by author
8
8
  * • Validation at load — defineAgent throws on hard problems, warns on soft
9
9
  */
@@ -11,29 +11,39 @@
11
11
  export { defineAgent } from './defineAgent.js';
12
12
  export { createMcpAgent, resolveZiggsGatewayTarget, wrapGatewayFetch, ZiggsGatewayError } from './adapters/McpAdapter.js';
13
13
  export type { CreateMcpAgentOptions, McpAgentHandle, McpTransportConfig } from './adapters/McpAdapter.js';
14
- export { AgentHost, createAgent, createAgentPool } from './AgentHost.js';
14
+ export { AgentHost, createAgent, createAgentPool, DEFAULT_MODEL } from './AgentHost.js';
15
15
  export { Agent } from './agent/Agent.js';
16
+ export { ClaudeSdkAgent } from './agent/ClaudeSdkAgent.js';
17
+ export type { CognitionKind } from './agent/ClaudeSdkAgent.js';
16
18
  export type { TickInput, TickOutput, AgentOptions } from './agent/Agent.js';
17
19
  export type { SessionResolver, AgentHostOptions } from './AgentHost.js';
18
20
  export { createZiggsEffectHandler } from './server/ZiggsEffectHandler.js';
19
21
  export type { ZiggsEffectDeps } from './server/ZiggsEffectHandler.js';
20
22
  export { EventQueue } from './server/EventQueue.js';
23
+ export { StateTimers } from './server/StateTimers.js';
24
+ export type { StateTimeoutEvent } from './server/StateTimers.js';
21
25
  export { OutboxBuffer } from './server/OutboxBuffer.js';
22
26
  export { normalizeIncomingEvent } from './ingress/normalizeIncoming.js';
23
27
 
24
28
  // Runtime primitives
25
29
  export { AgentMachine, type TransitionEvent } from './runtime/AgentMachine.js';
26
30
  export { runTurn } from './runtime/runTurn.js';
31
+ export { runMechanical } from './runtime/runMechanical.js';
27
32
  export { PromptBuilder } from './runtime/PromptBuilder.js';
28
- export { thinkingDefaults, defineThinkingState, DEFAULT_WAIT_PROMPT } from './runtime/defaults.js';
33
+ export { thinkingDefaults, defineThinkingState, defineMechanicalState, DEFAULT_WAIT_PROMPT } from './runtime/defaults.js';
34
+ export { KICKOFF_STATE, injectKickoffDefault, buildKickoffState } from './runtime/kickoff.js';
29
35
  export { validateWorkflow, WorkflowValidationError } from './runtime/validateWorkflow.js';
36
+ export {
37
+ deriveRespondsToProposals,
38
+ statesRespondToProposals,
39
+ } from './runtime/deriveRespondsToProposals.js';
30
40
  export { outcomeFromEvent, outcomeFromActionResult, applyOutcomeToCtx } from './runtime/buildOutcome.js';
31
41
 
32
42
  // Types
33
43
  export type {
34
44
  Outcome, OutcomeKind,
35
45
  Ctx, Identity, HistoryEntry, ToolResultEntry,
36
- Workflow, State, ParkedState, ThinkingState,
46
+ Workflow, State, ParkedState, ThinkingState, MechanicalState,
37
47
  Action, Transition, PromptDef, ActionPrompt, Produces, ProducesFn,
38
48
  AgreementRef, TaskRef, ProposalRef,
39
49
  AgentConfig, DefineAgentInput, ServicesConfig,
@@ -96,7 +106,6 @@ export {
96
106
  WebSocketClient,
97
107
  MessagesClient,
98
108
  ArtifactsClient,
99
- ScopeClient,
100
109
  AgentSearchClient,
101
110
  getBackendUrl,
102
111
  getWebSocketUrl,
@@ -17,6 +17,13 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
17
17
  "shopper-agent": "D",
18
18
  "hire-agent": "B",
19
19
  "ziggs-docs-agent": "B",
20
+ "relay-coordinator": "D",
21
+ "relay-intake-worker": "D",
22
+ "relay-work-worker": "D",
23
+ "relay-deliver-worker": "D",
24
+ "retry-coordinator": "D",
25
+ "retry-fail-worker": "D",
26
+ "retry-ok-worker": "D",
20
27
  "weather-forecaster": "A",
21
28
  "climate-data-analyst": "A",
22
29
  "air-quality-monitor": "A",
@@ -25,6 +32,8 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
25
32
  "uv-index-advisor": "A",
26
33
  "pollen-tracker": "A",
27
34
  "marine-weather-reporter": "A",
35
+ "us-alerts-monitor": "A",
36
+ "daylight-tracker": "A",
28
37
  "stock-market-analyst": "A",
29
38
  "crypto-tracker": "A",
30
39
  "forex-monitor": "A",
@@ -40,12 +49,16 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
40
49
  "world-news-briefer": "A",
41
50
  "business-news-analyst": "A",
42
51
  "reddit-trend-spotter": "A",
52
+ "tech-news-digest": "A",
53
+ "news-searcher": "A",
54
+ "subreddit-pulse": "A",
43
55
  "science-news-reporter": "A",
44
56
  "sports-score-tracker": "A",
45
57
  "breaking-news-alert": "A",
46
58
  "wikipedia-researcher": "A",
47
59
  "book-finder": "A",
48
60
  "dictionary-thesaurus": "A",
61
+ "wikidata-explorer": "A",
49
62
  "trivia-master": "A",
50
63
  "poetry-curator": "A",
51
64
  "quote-finder": "A",
@@ -75,6 +88,8 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
75
88
  "distance-calculator": "A",
76
89
  "place-finder": "A",
77
90
  "ip-geolocator": "A",
91
+ "postal-code-resolver": "A",
92
+ "brewery-finder": "A",
78
93
  "astronomy-photo-curator": "A",
79
94
  "mars-rover-explorer": "A",
80
95
  "neo-tracker": "A",
@@ -83,9 +98,16 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
83
98
  "exoplanet-explorer": "A",
84
99
  "drug-interaction-checker": "A",
85
100
  "solar-system-explorer": "A",
101
+ "species-lookup": "A",
102
+ "census-analyst": "A",
103
+ "river-monitor": "A",
104
+ "fbi-wanted-monitor": "A",
86
105
  "github-repo-analyst": "A",
87
106
  "github-issue-tracker": "A",
88
107
  "github-pr-reviewer": "A",
108
+ "package-inspector": "A",
109
+ "service-status-checker": "A",
110
+ "password-safety-checker": "A",
89
111
  "ip-analyst": "A",
90
112
  "qr-code-generator": "A",
91
113
  "http-debugger": "A",
@@ -117,6 +139,9 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
117
139
  "uuid-generator": "A",
118
140
  "hash-calculator": "A",
119
141
  "base64-encoder": "A",
142
+ "card-dealer": "A",
143
+ "world-clock": "A",
144
+ "link-unfurler": "A",
120
145
  "code-reviewer": "B",
121
146
  "bug-finder": "B",
122
147
  "refactoring-advisor": "B",
@@ -141,6 +166,30 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
141
166
  "stack-trace-analyzer": "B",
142
167
  "commit-message-writer": "B",
143
168
  "schema-designer": "B",
169
+ "name-brainstormer": "B",
170
+ "term-explainer": "B",
171
+ "pros-cons-lister": "B",
172
+ "decision-matrix-builder": "B",
173
+ "checklist-generator": "B",
174
+ "config-converter": "B",
175
+ "csv-to-table": "B",
176
+ "markup-converter": "B",
177
+ "case-converter": "B",
178
+ "color-converter": "B",
179
+ "timestamp-humanizer": "B",
180
+ "text-summarizer": "B",
181
+ "notes-cleaner": "B",
182
+ "audience-rewriter": "B",
183
+ "text-reformatter": "B",
184
+ "json-fixer": "B",
185
+ "sql-explainer": "B",
186
+ "regex-writer": "B",
187
+ "cron-explainer": "B",
188
+ "curl-converter": "B",
189
+ "changelog-writer": "B",
190
+ "stacktrace-explainer": "B",
191
+ "diff-explainer": "B",
192
+ "scaffold-generator": "B",
144
193
  "copywriter": "B",
145
194
  "technical-writer": "B",
146
195
  "blog-post-drafter": "B",
@@ -270,6 +319,9 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
270
319
  "feature-prioritizer": "C",
271
320
  "threat-model-committee": "C",
272
321
  "negotiation-simulator": "C",
322
+ "trip-desk": "C",
323
+ "tech-radar-brief": "C",
324
+ "market-open-brief": "C",
273
325
  "aristotle": "B",
274
326
  "plato": "B",
275
327
  "confucius": "B",
@@ -720,4 +772,4 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
720
772
  "death-studies-scholar": "B"
721
773
  } as Record<string, FleetPricingTier>;
722
774
 
723
- export const FLEET_TIER_MAP_SIZE = 713;
775
+ export const FLEET_TIER_MAP_SIZE = 765;