@ziggs-ai/agent-sdk 0.11.0 → 0.11.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/README.md +1 -1
- package/dist/AgentHost.d.ts +81 -1
- package/dist/AgentHost.js +184 -4
- package/dist/adapters/McpAdapter.js +10 -12
- package/dist/agent/ClaudeSdkAgent.d.ts +9 -0
- package/dist/agent/ClaudeSdkAgent.js +127 -26
- package/dist/agent/claudeSdkTools.js +25 -6
- package/dist/defineAgent.js +31 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -0
- package/dist/pricing/fleetTierByAgentId.gen.d.ts +2 -2
- package/dist/pricing/fleetTierByAgentId.gen.js +9 -2
- package/dist/server/ZiggsEffectHandler.js +10 -1
- package/dist/server/inboxLoop.js +8 -3
- package/dist/server/polls/PollRunner.d.ts +36 -1
- package/dist/server/polls/PollRunner.js +42 -2
- package/dist/server/tasks/TaskService.d.ts +5 -5
- package/dist/server/tools/tier2/mcpConnectionTools.js +1 -1
- package/dist/tools/ToolManager.d.ts +1 -1
- package/dist/tools/ToolManager.js +2 -1
- package/dist/tools/defineTool.d.ts +7 -0
- package/dist/tools/defineTool.js +12 -0
- package/dist/tools/needs.d.ts +54 -0
- package/dist/tools/needs.js +84 -0
- package/dist/types.d.ts +11 -1
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import AjvModule from 'ajv';
|
|
2
2
|
import { ToolProvider } from './ToolProvider.js';
|
|
3
|
+
import { toolName } from './defineTool.js';
|
|
3
4
|
const AjvClass = AjvModule.default ?? AjvModule;
|
|
4
5
|
const ajv = new AjvClass({ allErrors: true, strict: false });
|
|
5
6
|
function makeError(message, type, extra) {
|
|
@@ -49,7 +50,7 @@ export class ToolManager extends ToolProvider {
|
|
|
49
50
|
throw makeError('Tool must have a schema', 'invalid_tool');
|
|
50
51
|
if (typeof tool.handler !== 'function')
|
|
51
52
|
throw makeError('Tool must have a handler function', 'invalid_tool');
|
|
52
|
-
const name = (tool
|
|
53
|
+
const name = toolName(tool);
|
|
53
54
|
if (!name)
|
|
54
55
|
throw makeError('Tool schema must have a name', 'invalid_tool');
|
|
55
56
|
this.tools.set(name, tool);
|
|
@@ -24,4 +24,11 @@ export interface DefineToolOptions {
|
|
|
24
24
|
isAgreementCreation?: boolean;
|
|
25
25
|
isGenericFallback?: boolean;
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* The name a tool registers under. `defineTool` always writes
|
|
29
|
+
* `schema.function.name`, but hand-built and capability-adapted schemas have put
|
|
30
|
+
* it at the top level too, so both are read — in one place, rather than at every
|
|
31
|
+
* call site that needs to identify a tool.
|
|
32
|
+
*/
|
|
33
|
+
export declare function toolName(tool: ToolDefinition | undefined): string | undefined;
|
|
27
34
|
export declare function defineTool(name: string, params: Record<string, unknown>, handler: (args: Record<string, unknown>, context: Record<string, unknown>) => Promise<unknown>, options?: DefineToolOptions): ToolDefinition;
|
package/dist/tools/defineTool.js
CHANGED
|
@@ -43,6 +43,18 @@ function convertObject(fields) {
|
|
|
43
43
|
result['required'] = required;
|
|
44
44
|
return result;
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* The name a tool registers under. `defineTool` always writes
|
|
48
|
+
* `schema.function.name`, but hand-built and capability-adapted schemas have put
|
|
49
|
+
* it at the top level too, so both are read — in one place, rather than at every
|
|
50
|
+
* call site that needs to identify a tool.
|
|
51
|
+
*/
|
|
52
|
+
export function toolName(tool) {
|
|
53
|
+
const fromFunction = tool?.schema?.function?.['name'];
|
|
54
|
+
const fromTop = tool?.schema?.['name'];
|
|
55
|
+
const name = fromFunction ?? fromTop;
|
|
56
|
+
return typeof name === 'string' && name ? name : undefined;
|
|
57
|
+
}
|
|
46
58
|
export function defineTool(name, params, handler, options = {}) {
|
|
47
59
|
if (!name || typeof name !== 'string')
|
|
48
60
|
throw new Error('defineTool: name is required');
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* needs.ts — what an agent cannot work without, declared once.
|
|
3
|
+
*
|
|
4
|
+
* An agent is otherwise two hand-written lists — instructions and tools — with
|
|
5
|
+
* nothing checking they agree, so a prompt can promise work the toolset has no
|
|
6
|
+
* way to do and the mismatch only surfaces on a real hire. A third list to
|
|
7
|
+
* compare against the other two would drift the same way, so the declaration
|
|
8
|
+
* DERIVES the tools instead. The author never writes that part of the list, so
|
|
9
|
+
* the mismatch cannot be written.
|
|
10
|
+
*
|
|
11
|
+
* Scope is agents built on this SDK.
|
|
12
|
+
*/
|
|
13
|
+
import { type ToolDefinition } from './defineTool.js';
|
|
14
|
+
/**
|
|
15
|
+
* A remote MCP server is stored as `provider: 'mcp'` and goes through the
|
|
16
|
+
* gateway. `connection_proxy` resolves a NAMED connector and refuses it with
|
|
17
|
+
* "Unknown provider: mcp" — the second wall linear-janitor hit.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MCP_PROVIDER = "mcp";
|
|
20
|
+
/**
|
|
21
|
+
* One shape for now, the one we have actually hit. A second kind means a case in
|
|
22
|
+
* {@link toolsForNeed}: a need nothing derives tools from is a need nothing
|
|
23
|
+
* enforces.
|
|
24
|
+
*/
|
|
25
|
+
export interface ConnectionNeed {
|
|
26
|
+
/** Provider, e.g. 'mcp' or a named connector like 'github'. */
|
|
27
|
+
connection: string;
|
|
28
|
+
}
|
|
29
|
+
export type AgentNeed = ConnectionNeed;
|
|
30
|
+
/** Reads a manifest's `needs` field defensively — it crosses a package edge. */
|
|
31
|
+
export declare function normalizeNeeds(input: unknown): AgentNeed[];
|
|
32
|
+
/**
|
|
33
|
+
* The tools a stated need implies. `connection_list_grants` rides every need
|
|
34
|
+
* because seeing the grant is half of using it: the janitor's first failure was
|
|
35
|
+
* an agent that held a Linear grant and had no way to notice.
|
|
36
|
+
*/
|
|
37
|
+
export declare function toolsForNeed(need: AgentNeed): ToolDefinition[];
|
|
38
|
+
/** Deduped by tool name, so overlapping needs (and a hand-listed tool) merge. */
|
|
39
|
+
export declare function toolsForNeeds(needs: AgentNeed[]): ToolDefinition[];
|
|
40
|
+
/** One line naming what is missing, for a refusal a human can act on. */
|
|
41
|
+
export declare function describeNeed(need: AgentNeed): string;
|
|
42
|
+
/**
|
|
43
|
+
* Which declared needs have no live grant behind them.
|
|
44
|
+
*
|
|
45
|
+
* `providers` are the providers of the agent's live connection grants. The label
|
|
46
|
+
* a grant carries is the provider, sometimes suffixed with the owner's account
|
|
47
|
+
* ("github — acme/infra"), so the provider is the part before the separator.
|
|
48
|
+
*/
|
|
49
|
+
export declare function unmetNeeds(needs: AgentNeed[], providers: Array<string | null | undefined>): AgentNeed[];
|
|
50
|
+
/**
|
|
51
|
+
* The refusal itself. Names the missing access and who can fix it, because the
|
|
52
|
+
* agent cannot: issuing a connection grant is the connection owner's act.
|
|
53
|
+
*/
|
|
54
|
+
export declare function unmetNeedsMessage(unmet: AgentNeed[]): string;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* needs.ts — what an agent cannot work without, declared once.
|
|
3
|
+
*
|
|
4
|
+
* An agent is otherwise two hand-written lists — instructions and tools — with
|
|
5
|
+
* nothing checking they agree, so a prompt can promise work the toolset has no
|
|
6
|
+
* way to do and the mismatch only surfaces on a real hire. A third list to
|
|
7
|
+
* compare against the other two would drift the same way, so the declaration
|
|
8
|
+
* DERIVES the tools instead. The author never writes that part of the list, so
|
|
9
|
+
* the mismatch cannot be written.
|
|
10
|
+
*
|
|
11
|
+
* Scope is agents built on this SDK.
|
|
12
|
+
*/
|
|
13
|
+
import { toolName } from './defineTool.js';
|
|
14
|
+
import { connectionListGrantsTool, connectionProxyTool } from '../server/tools/tier2/connectionTools.js';
|
|
15
|
+
import { MCP_CONNECTION_TOOLS } from '../server/tools/tier2/mcpConnectionTools.js';
|
|
16
|
+
/**
|
|
17
|
+
* A remote MCP server is stored as `provider: 'mcp'` and goes through the
|
|
18
|
+
* gateway. `connection_proxy` resolves a NAMED connector and refuses it with
|
|
19
|
+
* "Unknown provider: mcp" — the second wall linear-janitor hit.
|
|
20
|
+
*/
|
|
21
|
+
export const MCP_PROVIDER = 'mcp';
|
|
22
|
+
/** Reads a manifest's `needs` field defensively — it crosses a package edge. */
|
|
23
|
+
export function normalizeNeeds(input) {
|
|
24
|
+
if (!Array.isArray(input))
|
|
25
|
+
return [];
|
|
26
|
+
const out = [];
|
|
27
|
+
for (const raw of input) {
|
|
28
|
+
const connection = raw?.connection;
|
|
29
|
+
if (typeof connection === 'string' && connection.trim()) {
|
|
30
|
+
out.push({ connection: connection.trim() });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The tools a stated need implies. `connection_list_grants` rides every need
|
|
37
|
+
* because seeing the grant is half of using it: the janitor's first failure was
|
|
38
|
+
* an agent that held a Linear grant and had no way to notice.
|
|
39
|
+
*/
|
|
40
|
+
export function toolsForNeed(need) {
|
|
41
|
+
return need.connection === MCP_PROVIDER
|
|
42
|
+
? [connectionListGrantsTool, ...MCP_CONNECTION_TOOLS]
|
|
43
|
+
: [connectionListGrantsTool, connectionProxyTool];
|
|
44
|
+
}
|
|
45
|
+
/** Deduped by tool name, so overlapping needs (and a hand-listed tool) merge. */
|
|
46
|
+
export function toolsForNeeds(needs) {
|
|
47
|
+
const byName = new Map();
|
|
48
|
+
for (const need of needs) {
|
|
49
|
+
for (const tool of toolsForNeed(need)) {
|
|
50
|
+
const name = toolName(tool);
|
|
51
|
+
if (name)
|
|
52
|
+
byName.set(name, tool);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return [...byName.values()];
|
|
56
|
+
}
|
|
57
|
+
/** One line naming what is missing, for a refusal a human can act on. */
|
|
58
|
+
export function describeNeed(need) {
|
|
59
|
+
return need.connection === MCP_PROVIDER
|
|
60
|
+
? 'a connection to an MCP server'
|
|
61
|
+
: `a ${need.connection} connection`;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Which declared needs have no live grant behind them.
|
|
65
|
+
*
|
|
66
|
+
* `providers` are the providers of the agent's live connection grants. The label
|
|
67
|
+
* a grant carries is the provider, sometimes suffixed with the owner's account
|
|
68
|
+
* ("github — acme/infra"), so the provider is the part before the separator.
|
|
69
|
+
*/
|
|
70
|
+
export function unmetNeeds(needs, providers) {
|
|
71
|
+
const held = new Set(providers
|
|
72
|
+
.map((p) => String(p ?? '').split('—')[0].trim().toLowerCase())
|
|
73
|
+
.filter(Boolean));
|
|
74
|
+
return needs.filter((n) => !held.has(n.connection.toLowerCase()));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The refusal itself. Names the missing access and who can fix it, because the
|
|
78
|
+
* agent cannot: issuing a connection grant is the connection owner's act.
|
|
79
|
+
*/
|
|
80
|
+
export function unmetNeedsMessage(unmet) {
|
|
81
|
+
const list = unmet.map(describeNeed).join(', ');
|
|
82
|
+
return (`Cannot start this task: no live grant for ${list}. ` +
|
|
83
|
+
'Ask the connection owner to issue one for this agent, then re-assign the task.');
|
|
84
|
+
}
|
package/dist/types.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* One outcome vocabulary, one ctx shape, one transition signature.
|
|
5
5
|
* Every state — parked or thinking — re-enters with exactly one Outcome.
|
|
6
6
|
*/
|
|
7
|
+
import type { AgentNeed } from './tools/needs.js';
|
|
7
8
|
export interface AgreementRef {
|
|
8
9
|
agreementId: string;
|
|
9
10
|
parties?: {
|
|
@@ -202,7 +203,7 @@ export interface Ctx {
|
|
|
202
203
|
* Recent wake timestamps (epoch ms) for this lane (claude-sdk cognition
|
|
203
204
|
* only). Backstop circuit breaker: if a lane wakes faster than any real
|
|
204
205
|
* traffic could drive it, the brain skips the LLM instead of burning the
|
|
205
|
-
*
|
|
206
|
+
* key on a wake storm.
|
|
206
207
|
*/
|
|
207
208
|
recentDeliveries?: number[];
|
|
208
209
|
}
|
|
@@ -534,6 +535,13 @@ export interface DefineAgentInput {
|
|
|
534
535
|
initial: string;
|
|
535
536
|
states: Record<string, State>;
|
|
536
537
|
tools?: unknown[];
|
|
538
|
+
/**
|
|
539
|
+
* Access this agent cannot work without. Declaring a need PRODUCES the tools
|
|
540
|
+
* for it — do not also hand-list them — and makes work that arrives without
|
|
541
|
+
* the grant fail at task start with the missing thing named, instead of
|
|
542
|
+
* part-way through a real hire.
|
|
543
|
+
*/
|
|
544
|
+
needs?: AgentNeed[];
|
|
537
545
|
services?: ServicesConfig;
|
|
538
546
|
operatorKey?: string;
|
|
539
547
|
taskTools?: 'all' | 'none' | string[];
|
|
@@ -557,6 +565,8 @@ export interface AgentConfig {
|
|
|
557
565
|
systemPrompt?: string;
|
|
558
566
|
specialization?: string;
|
|
559
567
|
tools: unknown[];
|
|
568
|
+
/** Normalized declared needs — see DefineAgentInput.needs. */
|
|
569
|
+
needs?: AgentNeed[];
|
|
560
570
|
model: string;
|
|
561
571
|
workflow: Workflow;
|
|
562
572
|
services?: ServicesConfig;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.1",
|
|
4
4
|
"description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@anthropic-ai/claude-agent-sdk": "^0.3.204",
|
|
27
27
|
"@anthropic-ai/sdk": "^0.110.0",
|
|
28
28
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
29
|
-
"@ziggs-ai/api-client": "0.10.
|
|
29
|
+
"@ziggs-ai/api-client": "0.10.4",
|
|
30
30
|
"ajv": "^8.17.1",
|
|
31
31
|
"dotenv": "^17.2.3",
|
|
32
32
|
"openai": "^4.0.0",
|