@ziggs-ai/agent-sdk 0.1.12 → 0.2.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.
- package/CHANGELOG.md +14 -0
- package/README.md +41 -2
- package/dist/AgentHost.d.ts +201 -0
- package/dist/AgentHost.js +652 -0
- package/dist/adapters/AnthropicAdapter.d.ts +39 -0
- package/dist/adapters/AnthropicAdapter.js +200 -0
- package/dist/adapters/McpAdapter.d.ts +199 -0
- package/dist/adapters/McpAdapter.js +468 -0
- package/dist/adapters/OpenAIAdapter.d.ts +26 -0
- package/dist/adapters/OpenAIAdapter.js +158 -0
- package/dist/adapters/index.js +2 -0
- package/dist/agent/Agent.d.ts +78 -0
- package/dist/agent/Agent.js +58 -0
- package/dist/agent/ClaudeSdkAgent.d.ts +38 -0
- package/dist/agent/ClaudeSdkAgent.js +322 -0
- package/dist/agent/claudeCognition.d.ts +67 -0
- package/dist/agent/claudeCognition.js +103 -0
- package/dist/agent/claudeSdkProtocol.d.ts +11 -0
- package/dist/agent/claudeSdkTools.d.ts +19 -0
- package/dist/agent/claudeSdkTools.js +57 -0
- package/dist/agent/hostedAgentConnection.d.ts +15 -0
- package/dist/agent/hostedAgentConnection.js +29 -0
- package/dist/agent/toolManagerToSdkMcp.d.ts +12 -0
- package/dist/agent/toolManagerToSdkMcp.js +123 -0
- package/dist/brain/index.d.ts +50 -0
- package/dist/brain/index.js +45 -0
- package/dist/cognition/validateContext.d.ts +11 -0
- package/dist/cognition/validateContext.js +117 -0
- package/dist/context/applyEffects.d.ts +2 -0
- package/dist/context/applyEffects.js +89 -0
- package/dist/context/batch.d.ts +2 -0
- package/dist/context/batch.js +18 -0
- package/dist/context/classifyEnvelope.d.ts +1 -0
- package/dist/context/classifyEnvelope.js +58 -0
- package/dist/context/routingLabels.d.ts +4 -0
- package/dist/context/routingLabels.js +48 -0
- package/dist/defineAgent.d.ts +14 -0
- package/dist/defineAgent.js +68 -0
- package/dist/formatters/AgreementFormatter.d.ts +18 -0
- package/dist/formatters/AgreementFormatter.js +130 -0
- package/dist/formatters/HistoryFormatter.d.ts +26 -0
- package/dist/formatters/HistoryFormatter.js +173 -0
- package/dist/formatters/index.js +2 -0
- package/{src/index.ts → dist/index.d.ts} +7 -53
- package/dist/index.js +66 -0
- package/dist/ingress/normalizeIncoming.d.ts +65 -0
- package/dist/ingress/normalizeIncoming.js +88 -0
- package/dist/memory/MemoryStore.d.ts +55 -0
- package/dist/memory/MemoryStore.js +78 -0
- package/dist/pricing/fleetDefaults.d.ts +46 -0
- package/dist/pricing/fleetDefaults.js +168 -0
- package/dist/pricing/fleetEvalFree.d.ts +7 -0
- package/dist/pricing/fleetEvalFree.js +24 -0
- package/dist/pricing/fleetFreeTierA.gen.d.ts +6 -0
- package/{src/pricing/fleetFreeTierA.gen.ts → dist/pricing/fleetFreeTierA.gen.js} +5 -6
- package/dist/pricing/fleetTierByAgentId.gen.d.ts +7 -0
- package/dist/pricing/fleetTierByAgentId.gen.js +768 -0
- package/dist/runtime/AgentMachine.d.ts +143 -0
- package/dist/runtime/AgentMachine.js +400 -0
- package/dist/runtime/PromptBuilder.d.ts +96 -0
- package/dist/runtime/PromptBuilder.js +439 -0
- package/{src/runtime/bootstrapCtx.ts → dist/runtime/bootstrapCtx.d.ts} +1 -22
- package/dist/runtime/bootstrapCtx.js +37 -0
- package/dist/runtime/buildOutcome.d.ts +68 -0
- package/dist/runtime/buildOutcome.js +464 -0
- package/dist/runtime/defaults.d.ts +54 -0
- package/dist/runtime/defaults.js +47 -0
- package/dist/runtime/deriveRespondsToProposals.d.ts +9 -0
- package/dist/runtime/deriveRespondsToProposals.js +38 -0
- package/dist/runtime/kickoff.d.ts +15 -0
- package/dist/runtime/kickoff.js +112 -0
- package/dist/runtime/runMechanical.d.ts +25 -0
- package/dist/runtime/runMechanical.js +74 -0
- package/dist/runtime/runTurn.d.ts +63 -0
- package/dist/runtime/runTurn.js +800 -0
- package/dist/runtime/validateWorkflow.d.ts +17 -0
- package/dist/runtime/validateWorkflow.js +209 -0
- package/dist/server/ConnectionPool.d.ts +68 -0
- package/dist/server/ConnectionPool.js +166 -0
- package/dist/server/EventQueue.d.ts +33 -0
- package/dist/server/EventQueue.js +98 -0
- package/dist/server/InboxCatchUp.d.ts +24 -0
- package/dist/server/InboxCatchUp.js +213 -0
- package/dist/server/OutboxBuffer.d.ts +33 -0
- package/dist/server/OutboxBuffer.js +68 -0
- package/dist/server/SeenMessages.d.ts +13 -0
- package/dist/server/SeenMessages.js +31 -0
- package/dist/server/StateTimers.d.ts +34 -0
- package/dist/server/StateTimers.js +70 -0
- package/dist/server/ZiggsEffectHandler.d.ts +79 -0
- package/dist/server/ZiggsEffectHandler.js +319 -0
- package/dist/server/agreements/AgreementService.d.ts +50 -0
- package/dist/server/agreements/AgreementService.js +85 -0
- package/dist/server/createHealthServer.d.ts +7 -0
- package/dist/server/createHealthServer.js +75 -0
- package/dist/server/proactive/ProactiveTrigger.d.ts +33 -0
- package/dist/server/proactive/ProactiveTrigger.js +71 -0
- package/dist/server/runLauncher.d.ts +28 -0
- package/dist/server/runLauncher.js +93 -0
- package/dist/server/tasks/TaskService.d.ts +25 -0
- package/dist/server/tasks/TaskService.js +103 -0
- package/dist/server/tasks/index.js +1 -0
- package/dist/server/telemetryIngest.d.ts +24 -0
- package/dist/server/telemetryIngest.js +62 -0
- package/dist/server/tools/index.d.ts +24 -0
- package/{src/server/tools/index.ts → dist/server/tools/index.js} +4 -24
- package/dist/server/tools/tier1/protocolRunner.d.ts +39 -0
- package/dist/server/tools/tier1/protocolRunner.js +288 -0
- package/dist/server/tools/tier1/protocolTools.d.ts +12 -0
- package/dist/server/tools/tier1/protocolTools.js +37 -0
- package/dist/server/tools/tier2/connectionTools.d.ts +4 -0
- package/dist/server/tools/tier2/connectionTools.js +63 -0
- package/dist/server/tools/tier2/contextTools.d.ts +4 -0
- package/dist/server/tools/tier2/contextTools.js +46 -0
- package/dist/server/tools/tier2/discoveryTools.d.ts +4 -0
- package/dist/server/tools/tier2/discoveryTools.js +25 -0
- package/dist/server/tools/tier2/marketplaceTools.d.ts +3 -0
- package/dist/server/tools/tier2/marketplaceTools.js +22 -0
- package/dist/server/tools/tier2/paymentTools.d.ts +12 -0
- package/dist/server/tools/tier2/paymentTools.js +165 -0
- package/dist/server/ziggsconnect/ZiggsConnectClient.d.ts +35 -0
- package/dist/server/ziggsconnect/ZiggsConnectClient.js +95 -0
- package/dist/server/ziggscontext/ZiggsContextClient.d.ts +48 -0
- package/dist/server/ziggscontext/ZiggsContextClient.js +90 -0
- package/dist/server/ziggspay/ZiggsPayClient.d.ts +82 -0
- package/dist/server/ziggspay/ZiggsPayClient.js +188 -0
- package/dist/shared/ids.d.ts +1 -0
- package/dist/shared/ids.js +3 -0
- package/dist/shared/runtimeLog.d.ts +18 -0
- package/dist/shared/runtimeLog.js +68 -0
- package/dist/shared/types.d.ts +22 -0
- package/dist/shared/types.js +23 -0
- package/dist/tasks/protocolRegistry.d.ts +16 -0
- package/dist/tasks/protocolRegistry.js +20 -0
- package/dist/tools/ToolManager.d.ts +12 -0
- package/dist/tools/ToolManager.js +74 -0
- package/dist/tools/ToolProvider.d.ts +6 -0
- package/dist/tools/ToolProvider.js +21 -0
- package/dist/tools/defineTool.d.ts +27 -0
- package/dist/tools/defineTool.js +62 -0
- package/{src/tools/index.ts → dist/tools/index.d.ts} +0 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/recordReport.d.ts +41 -0
- package/dist/tools/recordReport.js +30 -0
- package/dist/types.d.ts +466 -0
- package/dist/types.js +7 -0
- package/dist/utils/jsonExtractor.d.ts +2 -0
- package/dist/utils/jsonExtractor.js +111 -0
- package/package.json +13 -5
- package/src/AgentHost.ts +0 -814
- package/src/adapters/AnthropicAdapter.ts +0 -238
- package/src/adapters/McpAdapter.ts +0 -678
- package/src/adapters/OpenAIAdapter.ts +0 -194
- package/src/agent/Agent.ts +0 -112
- package/src/agent/ClaudeSdkAgent.ts +0 -401
- package/src/agent/claudeCognition.ts +0 -139
- package/src/agent/claudeSdkTools.ts +0 -81
- package/src/agent/hostedAgentConnection.ts +0 -41
- package/src/agent/toolManagerToSdkMcp.ts +0 -136
- package/src/cognition/validateContext.ts +0 -95
- package/src/context/applyEffects.ts +0 -80
- package/src/context/batch.ts +0 -19
- package/src/context/classifyEnvelope.ts +0 -38
- package/src/context/routingLabels.ts +0 -46
- package/src/defineAgent.ts +0 -77
- package/src/formatters/AgreementFormatter.ts +0 -111
- package/src/formatters/HistoryFormatter.ts +0 -172
- package/src/ingress/normalizeIncoming.ts +0 -162
- package/src/memory/MemoryStore.ts +0 -104
- package/src/pricing/fleetDefaults.ts +0 -225
- package/src/pricing/fleetEvalFree.ts +0 -24
- package/src/pricing/fleetTierByAgentId.gen.ts +0 -775
- package/src/runtime/AgentMachine.ts +0 -484
- package/src/runtime/PromptBuilder.ts +0 -522
- package/src/runtime/buildOutcome.ts +0 -563
- package/src/runtime/defaults.ts +0 -86
- package/src/runtime/deriveRespondsToProposals.ts +0 -35
- package/src/runtime/kickoff.ts +0 -117
- package/src/runtime/runMechanical.ts +0 -106
- package/src/runtime/runTurn.ts +0 -870
- package/src/runtime/validateWorkflow.ts +0 -221
- package/src/server/ConnectionPool.ts +0 -206
- package/src/server/EventQueue.ts +0 -133
- package/src/server/InboxCatchUp.ts +0 -291
- package/src/server/OutboxBuffer.ts +0 -90
- package/src/server/SeenMessages.ts +0 -27
- package/src/server/StateTimers.ts +0 -85
- package/src/server/ZiggsEffectHandler.ts +0 -427
- package/src/server/agreements/AgreementService.ts +0 -118
- package/src/server/createHealthServer.ts +0 -85
- package/src/server/proactive/ProactiveTrigger.ts +0 -83
- package/src/server/runLauncher.ts +0 -146
- package/src/server/tasks/TaskService.ts +0 -111
- package/src/server/telemetryIngest.ts +0 -91
- package/src/server/tools/tier1/protocolRunner.ts +0 -353
- package/src/server/tools/tier1/protocolTools.ts +0 -114
- package/src/server/tools/tier2/connectionTools.ts +0 -75
- package/src/server/tools/tier2/contextTools.ts +0 -63
- package/src/server/tools/tier2/discoveryTools.ts +0 -34
- package/src/server/tools/tier2/marketplaceTools.ts +0 -27
- package/src/server/tools/tier2/paymentTools.ts +0 -170
- package/src/server/ziggsconnect/ZiggsConnectClient.ts +0 -126
- package/src/server/ziggscontext/ZiggsContextClient.ts +0 -129
- package/src/server/ziggspay/ZiggsPayClient.ts +0 -193
- package/src/shared/ids.ts +0 -3
- package/src/shared/runtimeLog.ts +0 -72
- package/src/shared/types.ts +0 -29
- package/src/tasks/protocolRegistry.ts +0 -25
- package/src/tools/ToolManager.ts +0 -95
- package/src/tools/ToolProvider.ts +0 -19
- package/src/tools/defineTool.ts +0 -90
- package/src/tools/recordReport.ts +0 -82
- package/src/types.ts +0 -483
- package/src/utils/jsonExtractor.ts +0 -100
- /package/{src/adapters/index.ts → dist/adapters/index.d.ts} +0 -0
- /package/{src/agent/claudeSdkProtocol.ts → dist/agent/claudeSdkProtocol.js} +0 -0
- /package/{src/formatters/index.ts → dist/formatters/index.d.ts} +0 -0
- /package/{src/server/tasks/index.ts → dist/server/tasks/index.d.ts} +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import type { LlmMessage, LlmResponse, LlmToolSchema } from '../types.js';
|
|
3
|
+
interface AdapterOptions {
|
|
4
|
+
key?: string;
|
|
5
|
+
model?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Anthropic adapter satisfying the same LlmAdapter contract as OpenAIAdapter:
|
|
9
|
+
* OpenAI-wire-shaped LlmMessage[] in, { content, tool_calls, usage } out.
|
|
10
|
+
* Selected by AgentHost when the configured model id starts with "claude".
|
|
11
|
+
*/
|
|
12
|
+
export declare class AnthropicAdapter {
|
|
13
|
+
private client;
|
|
14
|
+
model: string;
|
|
15
|
+
constructor({ key, model }: AdapterOptions);
|
|
16
|
+
chat(prompt: string, tools?: LlmToolSchema[], _temperature?: number, systemHints?: LlmMessage[], options?: Record<string, unknown>): Promise<LlmResponse>;
|
|
17
|
+
chatMessages(messages: LlmMessage[], tools?: LlmToolSchema[], _options?: Record<string, unknown>): Promise<LlmResponse>;
|
|
18
|
+
chatMessagesStream(messages: LlmMessage[], onChunk: (text: string) => void): Promise<{
|
|
19
|
+
text: string;
|
|
20
|
+
usage: {
|
|
21
|
+
prompt_tokens: number;
|
|
22
|
+
completion_tokens: number;
|
|
23
|
+
total_tokens: number;
|
|
24
|
+
} | undefined;
|
|
25
|
+
}>;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Convert the runtime's tool list into Anthropic's `tools` param.
|
|
29
|
+
*
|
|
30
|
+
* The declared `LlmToolSchema` type (`{ type, function }`) is a lie at runtime:
|
|
31
|
+
* `runTurn` launders `ToolDefinition[]` (shape `{ schema: { function } }`)
|
|
32
|
+
* through an `as unknown as LlmToolSchema[]` cast before it reaches any adapter.
|
|
33
|
+
* OpenAIAdapter already reads `t.schema.function || t.schema`; this must do the
|
|
34
|
+
* same, or every claude-backed agent whose state exposes ≥1 tool crashes on
|
|
35
|
+
* `t.function` being undefined ("Cannot read properties of undefined (reading
|
|
36
|
+
* 'name')"). Both shapes are accepted so raw wire-shaped tools also work.
|
|
37
|
+
*/
|
|
38
|
+
export declare function toAnthropicTools(tools?: LlmToolSchema[]): Anthropic.Tool[] | undefined;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
|
+
// Claude 4.7+ models reject sampling params (temperature/top_p/top_k) with a
|
|
4
|
+
// 400 and run without thinking when the `thinking` param is omitted. We omit
|
|
5
|
+
// both on purpose: the SDK's LlmMessage history cannot round-trip thinking
|
|
6
|
+
// blocks through the tool loop, so thinking must stay off.
|
|
7
|
+
const MAX_COMPLETION_TOKENS = 16000;
|
|
8
|
+
/**
|
|
9
|
+
* Anthropic adapter satisfying the same LlmAdapter contract as OpenAIAdapter:
|
|
10
|
+
* OpenAI-wire-shaped LlmMessage[] in, { content, tool_calls, usage } out.
|
|
11
|
+
* Selected by AgentHost when the configured model id starts with "claude".
|
|
12
|
+
*/
|
|
13
|
+
export class AnthropicAdapter {
|
|
14
|
+
client;
|
|
15
|
+
model;
|
|
16
|
+
constructor({ key, model = 'claude-opus-4-8' }) {
|
|
17
|
+
this.client = new Anthropic({ apiKey: key });
|
|
18
|
+
this.model = model;
|
|
19
|
+
}
|
|
20
|
+
async chat(prompt, tools = [], _temperature = 0, systemHints = [], options = {}) {
|
|
21
|
+
const messages = [
|
|
22
|
+
{ role: 'system', content: 'Respond with valid JSON.' },
|
|
23
|
+
...systemHints,
|
|
24
|
+
{ role: 'user', content: prompt },
|
|
25
|
+
];
|
|
26
|
+
return this.chatMessages(messages, tools, options);
|
|
27
|
+
}
|
|
28
|
+
async chatMessages(messages, tools = [], _options = {}) {
|
|
29
|
+
const { system, anthropicMessages } = translateMessages(messages);
|
|
30
|
+
const anthropicTools = toAnthropicTools(tools);
|
|
31
|
+
try {
|
|
32
|
+
const res = await this.client.messages.create({
|
|
33
|
+
model: this.model,
|
|
34
|
+
max_tokens: MAX_COMPLETION_TOKENS,
|
|
35
|
+
...(system ? { system } : {}),
|
|
36
|
+
messages: anthropicMessages,
|
|
37
|
+
...(anthropicTools ? { tools: anthropicTools } : {}),
|
|
38
|
+
});
|
|
39
|
+
if (res.stop_reason === 'refusal') {
|
|
40
|
+
throw new Error(`LLM refused the request (stop_reason=refusal)`);
|
|
41
|
+
}
|
|
42
|
+
const content = res.content
|
|
43
|
+
.filter((b) => b.type === 'text')
|
|
44
|
+
.map(b => b.text)
|
|
45
|
+
.join('')
|
|
46
|
+
.trim() || null;
|
|
47
|
+
const toolCalls = (() => {
|
|
48
|
+
const uses = res.content.filter((b) => b.type === 'tool_use');
|
|
49
|
+
if (!uses.length)
|
|
50
|
+
return null;
|
|
51
|
+
return uses.map(u => ({
|
|
52
|
+
id: u.id,
|
|
53
|
+
function: { name: u.name, arguments: JSON.stringify(u.input ?? {}) },
|
|
54
|
+
}));
|
|
55
|
+
})();
|
|
56
|
+
if (!content && !toolCalls && res.stop_reason === 'max_tokens') {
|
|
57
|
+
throw new Error(`LLM returned no usable output — completion token budget exhausted before any content (stop_reason=max_tokens)`);
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
content: content ?? undefined,
|
|
61
|
+
tool_calls: toolCalls ?? undefined,
|
|
62
|
+
usage: res.usage
|
|
63
|
+
? {
|
|
64
|
+
prompt_tokens: res.usage.input_tokens,
|
|
65
|
+
completion_tokens: res.usage.output_tokens,
|
|
66
|
+
total_tokens: res.usage.input_tokens + res.usage.output_tokens,
|
|
67
|
+
}
|
|
68
|
+
: undefined,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
const err = error;
|
|
73
|
+
runtimeLog.error('AnthropicAdapter', `LLM API call failed: ${err.message}`, {
|
|
74
|
+
model: this.model,
|
|
75
|
+
error: err.message,
|
|
76
|
+
status: err.status ?? 'unknown',
|
|
77
|
+
});
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async chatMessagesStream(messages, onChunk) {
|
|
82
|
+
const { system, anthropicMessages } = translateMessages(messages);
|
|
83
|
+
const stream = this.client.messages.stream({
|
|
84
|
+
model: this.model,
|
|
85
|
+
max_tokens: MAX_COMPLETION_TOKENS,
|
|
86
|
+
...(system ? { system } : {}),
|
|
87
|
+
messages: anthropicMessages,
|
|
88
|
+
});
|
|
89
|
+
let text = '';
|
|
90
|
+
stream.on('text', (delta) => {
|
|
91
|
+
text += delta;
|
|
92
|
+
onChunk(delta);
|
|
93
|
+
});
|
|
94
|
+
const final = await stream.finalMessage();
|
|
95
|
+
const u = final.usage;
|
|
96
|
+
// Fold cache read/creation into prompt tokens so the streamed reply is not
|
|
97
|
+
// undercounted (cache traffic was the bulk of the ZIG-759 drain).
|
|
98
|
+
const usage = u
|
|
99
|
+
? {
|
|
100
|
+
prompt_tokens: (u.input_tokens ?? 0) + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0),
|
|
101
|
+
completion_tokens: u.output_tokens ?? 0,
|
|
102
|
+
total_tokens: (u.input_tokens ?? 0) + (u.cache_read_input_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0) + (u.output_tokens ?? 0),
|
|
103
|
+
}
|
|
104
|
+
: undefined;
|
|
105
|
+
return { text, usage };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Convert the runtime's tool list into Anthropic's `tools` param.
|
|
110
|
+
*
|
|
111
|
+
* The declared `LlmToolSchema` type (`{ type, function }`) is a lie at runtime:
|
|
112
|
+
* `runTurn` launders `ToolDefinition[]` (shape `{ schema: { function } }`)
|
|
113
|
+
* through an `as unknown as LlmToolSchema[]` cast before it reaches any adapter.
|
|
114
|
+
* OpenAIAdapter already reads `t.schema.function || t.schema`; this must do the
|
|
115
|
+
* same, or every claude-backed agent whose state exposes ≥1 tool crashes on
|
|
116
|
+
* `t.function` being undefined ("Cannot read properties of undefined (reading
|
|
117
|
+
* 'name')"). Both shapes are accepted so raw wire-shaped tools also work.
|
|
118
|
+
*/
|
|
119
|
+
export function toAnthropicTools(tools = []) {
|
|
120
|
+
if (!tools.length)
|
|
121
|
+
return undefined;
|
|
122
|
+
return tools.map(t => {
|
|
123
|
+
const td = t;
|
|
124
|
+
const fn = (td.schema?.function ?? td.function ?? {});
|
|
125
|
+
return {
|
|
126
|
+
name: fn['name'],
|
|
127
|
+
description: fn['description'] ?? '',
|
|
128
|
+
input_schema: (fn['parameters'] ?? { type: 'object' }),
|
|
129
|
+
};
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* OpenAI-wire-shaped LlmMessage[] → Anthropic { system, messages }.
|
|
134
|
+
* - system messages concatenate into the top-level system param
|
|
135
|
+
* - assistant tool_calls become tool_use blocks (arguments JSON-parsed)
|
|
136
|
+
* - role:"tool" results become user-turn tool_result blocks
|
|
137
|
+
* Consecutive same-role turns are merged (Anthropic requires alternation to
|
|
138
|
+
* start with user; the API tolerates consecutive same-role, but tool_result
|
|
139
|
+
* blocks must open the user turn that answers a tool_use turn).
|
|
140
|
+
*/
|
|
141
|
+
function translateMessages(messages) {
|
|
142
|
+
const systemParts = [];
|
|
143
|
+
const out = [];
|
|
144
|
+
for (const m of messages) {
|
|
145
|
+
if (m.role === 'system') {
|
|
146
|
+
if (m.content)
|
|
147
|
+
systemParts.push(m.content);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (m.role === 'tool') {
|
|
151
|
+
const block = {
|
|
152
|
+
type: 'tool_result',
|
|
153
|
+
tool_use_id: m.tool_call_id ?? '',
|
|
154
|
+
content: m.content ?? '',
|
|
155
|
+
};
|
|
156
|
+
const last = out[out.length - 1];
|
|
157
|
+
if (last && last.role === 'user' && Array.isArray(last.content)) {
|
|
158
|
+
last.content.push(block);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
out.push({ role: 'user', content: [block] });
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (m.role === 'assistant' && m.tool_calls?.length) {
|
|
166
|
+
const blocks = [];
|
|
167
|
+
if (m.content)
|
|
168
|
+
blocks.push({ type: 'text', text: m.content });
|
|
169
|
+
for (const tc of m.tool_calls) {
|
|
170
|
+
blocks.push({
|
|
171
|
+
type: 'tool_use',
|
|
172
|
+
id: tc.id,
|
|
173
|
+
name: tc.function.name,
|
|
174
|
+
input: safeParseJson(tc.function.arguments),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
out.push({ role: 'assistant', content: blocks });
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
out.push({ role: m.role, content: m.content ?? '' });
|
|
181
|
+
}
|
|
182
|
+
if (!out.length || out[0].role !== 'user') {
|
|
183
|
+
out.unshift({ role: 'user', content: '(session start)' });
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
system: systemParts.length ? systemParts.join('\n\n') : undefined,
|
|
187
|
+
anthropicMessages: out,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function safeParseJson(s) {
|
|
191
|
+
try {
|
|
192
|
+
const v = JSON.parse(s);
|
|
193
|
+
return typeof v === 'object' && v !== null ? v : {};
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Malformed arguments string from a prior turn's history: replaying it as
|
|
197
|
+
// an empty input beats crashing the whole turn on someone else's output.
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
2
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
3
|
+
import { AgentHost, type AgentHostOptions } from '../AgentHost.js';
|
|
4
|
+
import type { ToolDefinition } from '../tools/defineTool.js';
|
|
5
|
+
import type { Workflow } from '../types.js';
|
|
6
|
+
export type McpTransportConfig = {
|
|
7
|
+
type: 'stdio';
|
|
8
|
+
command: string;
|
|
9
|
+
args?: string[];
|
|
10
|
+
env?: Record<string, string>;
|
|
11
|
+
} | {
|
|
12
|
+
type: 'http';
|
|
13
|
+
url: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional static request headers — e.g. a fixed API key the server is
|
|
16
|
+
* keyed by. Sent on every request to the server. Values are used as-is;
|
|
17
|
+
* `$VAR` interpolation (if any) is the caller's job, mirroring how the
|
|
18
|
+
* stdio path leaves `env` interpolation to the caller.
|
|
19
|
+
*/
|
|
20
|
+
headers?: Record<string, string>;
|
|
21
|
+
} | {
|
|
22
|
+
/**
|
|
23
|
+
* Brokered connection through the Ziggs MCP gateway: the agent speaks
|
|
24
|
+
* StreamableHTTP to `/connections/:id/mcp` and Ziggs injects the
|
|
25
|
+
* connection owner's OAuth token upstream. The agent never holds the
|
|
26
|
+
* token; every tools/call is checked against the grant's caveats.
|
|
27
|
+
*/
|
|
28
|
+
type: 'ziggs';
|
|
29
|
+
/** Connection id (`con_…`) of the user's MCP server connection. */
|
|
30
|
+
connectionId: string;
|
|
31
|
+
/** ConnectionGrant id (`cgr_…`) issued to this agent. */
|
|
32
|
+
grantId: string;
|
|
33
|
+
/** Operator key — defaults to ZIGGS_OPERATOR_KEY. */
|
|
34
|
+
operatorKey?: string;
|
|
35
|
+
/** Ziggs backend base URL — defaults to BACKEND_URL / ZIGGS_BACKEND_URL. */
|
|
36
|
+
baseUrl?: string;
|
|
37
|
+
/** Agent to impersonate (X-Agent-Id) — defaults to the host agentId. */
|
|
38
|
+
agentId?: string;
|
|
39
|
+
} | {
|
|
40
|
+
/**
|
|
41
|
+
* Per-user brokered connection (ZIG-771): the agent holds NO
|
|
42
|
+
* connectionId/grantId. It speaks StreamableHTTP to
|
|
43
|
+
* `/connections/mcp/relay` and asserts the invoking end-user via
|
|
44
|
+
* `x-on-behalf-of-user`; the gateway resolves that user's own connection
|
|
45
|
+
* + grant and injects their token. One MCP client is created per invoking
|
|
46
|
+
* user so each keeps an isolated upstream session. Tool schemas cannot be
|
|
47
|
+
* discovered at boot (there is no connection yet) — pass `toolSchema`.
|
|
48
|
+
*/
|
|
49
|
+
type: 'ziggs-per-user';
|
|
50
|
+
/** Operator key — defaults to ZIGGS_OPERATOR_KEY. */
|
|
51
|
+
operatorKey?: string;
|
|
52
|
+
/** Ziggs backend base URL — defaults to BACKEND_URL / ZIGGS_BACKEND_URL. */
|
|
53
|
+
baseUrl?: string;
|
|
54
|
+
/** Agent to impersonate (X-Agent-Id) — defaults to the host agentId. */
|
|
55
|
+
agentId?: string;
|
|
56
|
+
/**
|
|
57
|
+
* The MCP server URL this agent fronts. Not used for gateway calls (the
|
|
58
|
+
* gateway derives the server from the resolved connection), but needed to
|
|
59
|
+
* open a connection request when the invoking user hasn't connected yet
|
|
60
|
+
* (ZIG-771). Without it, a NO_USER_CONNECTION surfaces as an error rather
|
|
61
|
+
* than an auto-created consent prompt.
|
|
62
|
+
*/
|
|
63
|
+
serverUrl?: string;
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Typed failure from the Ziggs MCP gateway (ZIG-702). `code` is the stable
|
|
67
|
+
* machine-readable reason — e.g. `GRANT_REVOKED`, `GRANT_EXPIRED`,
|
|
68
|
+
* `GRANT_HOLDER_MISMATCH`, `GRANT_CONNECTION_MISMATCH` — so agent code can
|
|
69
|
+
* branch ("revoked → tell the user and stop retrying" vs "network blip →
|
|
70
|
+
* retry") instead of parsing transport-error prose.
|
|
71
|
+
*/
|
|
72
|
+
export declare class ZiggsGatewayError extends Error {
|
|
73
|
+
readonly code: string;
|
|
74
|
+
readonly status: number;
|
|
75
|
+
constructor(code: string, message: string, status: number);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Wrap fetch so structured gateway denials (401/403 with a `code` body)
|
|
79
|
+
* surface as ZiggsGatewayError instead of a generic transport failure.
|
|
80
|
+
*/
|
|
81
|
+
export declare function wrapGatewayFetch(baseFetch?: typeof fetch): typeof fetch;
|
|
82
|
+
/** Resolve the gateway URL + auth headers for a `type: 'ziggs'` transport. */
|
|
83
|
+
export declare function resolveZiggsGatewayTarget(config: Extract<McpTransportConfig, {
|
|
84
|
+
type: 'ziggs';
|
|
85
|
+
}>, defaults?: {
|
|
86
|
+
agentId?: string;
|
|
87
|
+
}): {
|
|
88
|
+
url: URL;
|
|
89
|
+
headers: Record<string, string>;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Resolve the per-user gateway URL + headers (ZIG-771). No connectionId/grantId —
|
|
93
|
+
* the gateway resolves the invoking user's own connection + grant from
|
|
94
|
+
* `x-on-behalf-of-user` + the impersonated agent.
|
|
95
|
+
*/
|
|
96
|
+
export declare function resolvePerUserGatewayTarget(config: Extract<McpTransportConfig, {
|
|
97
|
+
type: 'ziggs-per-user';
|
|
98
|
+
}>, agentId: string, userId: string, onBehalfOfAgreementId?: string): {
|
|
99
|
+
url: URL;
|
|
100
|
+
headers: Record<string, string>;
|
|
101
|
+
};
|
|
102
|
+
export interface CreateMcpAgentOptions extends Omit<AgentHostOptions, 'tools' | 'workflow' | 'states' | 'initial'> {
|
|
103
|
+
/** MCP server connection — stdio (local process) or HTTP (remote). */
|
|
104
|
+
transport: McpTransportConfig;
|
|
105
|
+
/** Additional Ziggs tools to register alongside the MCP-derived ones. */
|
|
106
|
+
extraTools?: ToolDefinition[];
|
|
107
|
+
/** Override the default single-state thinking workflow. */
|
|
108
|
+
workflow?: Workflow;
|
|
109
|
+
/**
|
|
110
|
+
* Max tools to bind to the LLM per turn. LLM providers cap the `tools` array
|
|
111
|
+
* (OpenAI: 128); an MCP server exposing more (e.g. PostHog: 146) makes every
|
|
112
|
+
* turn fail with `400 ... array too long`. When the server's tool count
|
|
113
|
+
* exceeds this budget the list is truncated (and logged). Defaults to 128.
|
|
114
|
+
* See ZIG-759; Phase 2 will replace truncation with query-aware selection.
|
|
115
|
+
*/
|
|
116
|
+
maxTools?: number;
|
|
117
|
+
/**
|
|
118
|
+
* Restrict the bound tool set to only tools whose name matches one of these
|
|
119
|
+
* case-insensitive substrings, applied BEFORE the maxTools cap. Lets a large
|
|
120
|
+
* MCP server (e.g. PostHog's 146 tools) be narrowed to the handful this agent
|
|
121
|
+
* actually needs — cutting per-turn cost and stopping the model from thrashing
|
|
122
|
+
* across (or never binding) the tool it should call. Empty/undefined = bind
|
|
123
|
+
* all (unchanged behavior). ZIG-759 Phase 2 = name-based selection.
|
|
124
|
+
*/
|
|
125
|
+
allowedTools?: string[];
|
|
126
|
+
/**
|
|
127
|
+
* Pre-discovered MCP tool schemas. REQUIRED for `type: 'ziggs-per-user'`
|
|
128
|
+
* (ZIG-771) — there is no boot connection to call `tools/list` on, so the
|
|
129
|
+
* schema is baked at provision time and passed here. Ignored for the other
|
|
130
|
+
* transports, which discover tools live at boot.
|
|
131
|
+
*/
|
|
132
|
+
toolSchema?: Array<{
|
|
133
|
+
name: string;
|
|
134
|
+
description?: string;
|
|
135
|
+
inputSchema?: Record<string, unknown>;
|
|
136
|
+
}>;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* How many MCP tools may be bound to the LLM, given the provider cap and the
|
|
140
|
+
* number of extra (non-MCP) tools the agent also carries. Always >= 1 so a
|
|
141
|
+
* pathological config still binds something rather than nothing. ZIG-759.
|
|
142
|
+
*/
|
|
143
|
+
export declare function mcpToolBudget(maxTools: number, extraToolCount: number): number;
|
|
144
|
+
export interface McpAgentHandle {
|
|
145
|
+
host: AgentHost;
|
|
146
|
+
/** Disconnect the MCP client (call on shutdown alongside host.disconnect()). */
|
|
147
|
+
closeMcp: () => Promise<void>;
|
|
148
|
+
/** Names of MCP tools that were mapped to Ziggs tools on startup. */
|
|
149
|
+
toolNames: string[];
|
|
150
|
+
}
|
|
151
|
+
export declare function buildTransport(config: McpTransportConfig, defaults?: {
|
|
152
|
+
agentId?: string;
|
|
153
|
+
}): StdioClientTransport | StreamableHTTPClientTransport;
|
|
154
|
+
/**
|
|
155
|
+
* Max chars for a single tool description bound to the LLM. Verbose MCP servers
|
|
156
|
+
* embed whole manuals in their descriptions (PostHog's `execute-sql` alone is
|
|
157
|
+
* ~30K chars of HogQL docs; its 146 tools total ~54K tokens of descriptions) and
|
|
158
|
+
* that full block rides every turn. Keep the lead — what the tool does + how to
|
|
159
|
+
* call it — and drop the embedded reference; agents fetch detail via dedicated
|
|
160
|
+
* schema/help tools at call time. Tunable; big enough to preserve real guidance.
|
|
161
|
+
* ZIG-759.
|
|
162
|
+
*/
|
|
163
|
+
export declare const MAX_TOOL_DESC_CHARS = 2000;
|
|
164
|
+
/** Truncate one description at a sentence/newline boundary near the cap. */
|
|
165
|
+
export declare function trimDescription(desc: string | undefined): string | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* Wraps any MCP server as a Ziggs AgentHost.
|
|
168
|
+
*
|
|
169
|
+
* 1. Opens a connection to the MCP server (stdio, HTTP, or the Ziggs gateway).
|
|
170
|
+
* 2. Calls tools/list and maps each tool to a Ziggs ToolDefinition.
|
|
171
|
+
* 3. Returns an AgentHost pre-loaded with those tools, ready to connectAsync().
|
|
172
|
+
*
|
|
173
|
+
* Usage (local stdio server):
|
|
174
|
+
* const { host, closeMcp } = await createMcpAgent({
|
|
175
|
+
* transport: { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-github'] },
|
|
176
|
+
* agentId: 'my-github-agent',
|
|
177
|
+
* name: 'GitHub Agent',
|
|
178
|
+
* description: 'Wraps the GitHub MCP server',
|
|
179
|
+
* });
|
|
180
|
+
* await host.connectAsync();
|
|
181
|
+
*
|
|
182
|
+
* Usage (OAuth-protected remote server, brokered through Ziggs — the user
|
|
183
|
+
* connected the server and issued this agent a grant; the agent never sees
|
|
184
|
+
* the user's token):
|
|
185
|
+
* const { host, closeMcp } = await createMcpAgent({
|
|
186
|
+
* transport: { type: 'ziggs', connectionId: 'con_abc', grantId: 'cgr_xyz' },
|
|
187
|
+
* agentId: 'my-notion-agent',
|
|
188
|
+
* name: 'Notion Agent',
|
|
189
|
+
* description: 'Works in the owner\'s Notion via their MCP connection',
|
|
190
|
+
* });
|
|
191
|
+
* await host.connectAsync();
|
|
192
|
+
*
|
|
193
|
+
* process.on('SIGTERM', async () => {
|
|
194
|
+
* host.disconnect();
|
|
195
|
+
* await host.drain();
|
|
196
|
+
* await closeMcp();
|
|
197
|
+
* });
|
|
198
|
+
*/
|
|
199
|
+
export declare function createMcpAgent(options: CreateMcpAgentOptions): Promise<McpAgentHandle>;
|