@ziggs-ai/agent-sdk 0.1.6 → 0.1.8
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/package.json +13 -3
- package/src/adapters/McpAdapter.ts +173 -0
- package/src/adapters/OpenAIAdapter.ts +70 -34
- package/src/context/batch.ts +3 -1
- package/src/formatters/HistoryFormatter.ts +7 -1
- package/src/index.ts +2 -0
- package/src/pricing/fleetDefaults.ts +13 -6
- package/src/pricing/fleetTierByAgentId.gen.ts +1 -300
- package/src/runtime/PromptBuilder.ts +5 -2
- package/src/runtime/runTurn.ts +7 -2
- package/src/server/InboxCatchUp.ts +9 -6
- package/src/server/agreements/AgreementService.ts +13 -12
- package/src/server/tasks/TaskService.ts +2 -13
- package/src/server/tools/index.ts +2 -1
- package/src/server/tools/tier1/protocolTools.ts +1 -1
- package/src/server/tools/tier2/marketplaceTools.ts +6 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Agent framework SDK for building autonomous agents on the Ziggs platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -16,14 +16,24 @@
|
|
|
16
16
|
"test:watch": "node --experimental-test-module-mocks --import tsx/esm --test --watch test/*.test.ts"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
19
20
|
"@ziggs-ai/api-client": "^0.1.9",
|
|
20
21
|
"ajv": "^8.17.1",
|
|
21
22
|
"dotenv": "^17.2.3",
|
|
22
23
|
"openai": "^4.0.0"
|
|
23
24
|
},
|
|
24
|
-
"keywords": [
|
|
25
|
+
"keywords": [
|
|
26
|
+
"ziggs",
|
|
27
|
+
"agent",
|
|
28
|
+
"sdk",
|
|
29
|
+
"ai",
|
|
30
|
+
"autonomous"
|
|
31
|
+
],
|
|
25
32
|
"license": "MIT",
|
|
26
|
-
"files": [
|
|
33
|
+
"files": [
|
|
34
|
+
"src",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
27
37
|
"publishConfig": {
|
|
28
38
|
"access": "public",
|
|
29
39
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
4
|
+
import { AgentHost, type AgentHostOptions } from '../AgentHost.js';
|
|
5
|
+
import type { ToolDefinition } from '../tools/defineTool.js';
|
|
6
|
+
import { thinkingDefaults } from '../runtime/defaults.js';
|
|
7
|
+
import type { Workflow } from '../types.js';
|
|
8
|
+
|
|
9
|
+
export type McpTransportConfig =
|
|
10
|
+
| { type: 'stdio'; command: string; args?: string[]; env?: Record<string, string> }
|
|
11
|
+
| { type: 'http'; url: string };
|
|
12
|
+
|
|
13
|
+
export interface CreateMcpAgentOptions extends Omit<AgentHostOptions, 'tools' | 'workflow' | 'states' | 'initial'> {
|
|
14
|
+
/** MCP server connection — stdio (local process) or HTTP (remote). */
|
|
15
|
+
transport: McpTransportConfig;
|
|
16
|
+
/** Additional Ziggs tools to register alongside the MCP-derived ones. */
|
|
17
|
+
extraTools?: ToolDefinition[];
|
|
18
|
+
/** Override the default single-state thinking workflow. */
|
|
19
|
+
workflow?: Workflow;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface McpAgentHandle {
|
|
23
|
+
host: AgentHost;
|
|
24
|
+
/** Disconnect the MCP client (call on shutdown alongside host.disconnect()). */
|
|
25
|
+
closeMcp: () => Promise<void>;
|
|
26
|
+
/** Names of MCP tools that were mapped to Ziggs tools on startup. */
|
|
27
|
+
toolNames: string[];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function buildTransport(config: McpTransportConfig) {
|
|
31
|
+
if (config.type === 'stdio') {
|
|
32
|
+
return new StdioClientTransport({
|
|
33
|
+
command: config.command,
|
|
34
|
+
args: config.args ?? [],
|
|
35
|
+
env: config.env,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return new StreamableHTTPClientTransport(new URL(config.url));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type McpTool = {
|
|
42
|
+
name: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
inputSchema?: Record<string, unknown>;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
type McpContent = { type: string; text?: string };
|
|
48
|
+
|
|
49
|
+
function mcpContentToResult(content: McpContent[]): unknown {
|
|
50
|
+
const text = content
|
|
51
|
+
.map(c => (c.type === 'text' ? c.text ?? '' : JSON.stringify(c)))
|
|
52
|
+
.join('\n');
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(text);
|
|
55
|
+
} catch {
|
|
56
|
+
return text;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function mapMcpTools(client: Client, tools: McpTool[]): ToolDefinition[] {
|
|
61
|
+
return tools.map(tool => ({
|
|
62
|
+
schema: {
|
|
63
|
+
type: 'function' as const,
|
|
64
|
+
function: {
|
|
65
|
+
name: tool.name,
|
|
66
|
+
description: tool.description ?? '',
|
|
67
|
+
parameters: tool.inputSchema ?? { type: 'object', properties: {} },
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
handler: async (args: Record<string, unknown>) => {
|
|
71
|
+
const result = await client.callTool({ name: tool.name, arguments: args }) as {
|
|
72
|
+
isError?: boolean;
|
|
73
|
+
content: McpContent[];
|
|
74
|
+
};
|
|
75
|
+
if (result.isError) {
|
|
76
|
+
throw new Error(mcpContentToResult(result.content) as string);
|
|
77
|
+
}
|
|
78
|
+
return mcpContentToResult(result.content);
|
|
79
|
+
},
|
|
80
|
+
isGenericFallback: true,
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Wraps any MCP server as a Ziggs AgentHost.
|
|
86
|
+
*
|
|
87
|
+
* 1. Opens a connection to the MCP server (stdio or HTTP).
|
|
88
|
+
* 2. Calls tools/list and maps each tool to a Ziggs ToolDefinition.
|
|
89
|
+
* 3. Returns an AgentHost pre-loaded with those tools, ready to connectAsync().
|
|
90
|
+
*
|
|
91
|
+
* Usage:
|
|
92
|
+
* const { host, closeMcp } = await createMcpAgent({
|
|
93
|
+
* transport: { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-github'] },
|
|
94
|
+
* agentId: 'my-github-agent',
|
|
95
|
+
* name: 'GitHub Agent',
|
|
96
|
+
* description: 'Wraps the GitHub MCP server',
|
|
97
|
+
* });
|
|
98
|
+
* await host.connectAsync();
|
|
99
|
+
*
|
|
100
|
+
* process.on('SIGTERM', async () => {
|
|
101
|
+
* host.disconnect();
|
|
102
|
+
* await host.drain();
|
|
103
|
+
* await closeMcp();
|
|
104
|
+
* });
|
|
105
|
+
*/
|
|
106
|
+
function buildDefaultWorkflow(description: string): Workflow {
|
|
107
|
+
const dflt = thinkingDefaults({ initial: 'idle' });
|
|
108
|
+
return {
|
|
109
|
+
id: 'mcp-agent',
|
|
110
|
+
description: description || 'MCP-backed agent',
|
|
111
|
+
initial: 'idle',
|
|
112
|
+
states: {
|
|
113
|
+
idle: {
|
|
114
|
+
kind: 'thinking',
|
|
115
|
+
prompt: {
|
|
116
|
+
role: 'You are a helpful agent powered by an MCP server.',
|
|
117
|
+
goal: description || 'Help the user by calling the available tools.',
|
|
118
|
+
constraints: 'Use your tools to answer requests. When no action is needed, wait.',
|
|
119
|
+
},
|
|
120
|
+
actions: { ...dflt.actions },
|
|
121
|
+
transitions: [...dflt.transitions],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Wraps any MCP server as a Ziggs AgentHost.
|
|
129
|
+
*
|
|
130
|
+
* 1. Opens a connection to the MCP server (stdio or HTTP).
|
|
131
|
+
* 2. Calls tools/list and maps each tool to a Ziggs ToolDefinition.
|
|
132
|
+
* 3. Returns an AgentHost pre-loaded with those tools, ready to connectAsync().
|
|
133
|
+
*
|
|
134
|
+
* Usage:
|
|
135
|
+
* const { host, closeMcp } = await createMcpAgent({
|
|
136
|
+
* transport: { type: 'stdio', command: 'npx', args: ['-y', '@modelcontextprotocol/server-github'] },
|
|
137
|
+
* agentId: 'my-github-agent',
|
|
138
|
+
* name: 'GitHub Agent',
|
|
139
|
+
* description: 'Wraps the GitHub MCP server',
|
|
140
|
+
* });
|
|
141
|
+
* await host.connectAsync();
|
|
142
|
+
*
|
|
143
|
+
* process.on('SIGTERM', async () => {
|
|
144
|
+
* host.disconnect();
|
|
145
|
+
* await host.drain();
|
|
146
|
+
* await closeMcp();
|
|
147
|
+
* });
|
|
148
|
+
*/
|
|
149
|
+
export async function createMcpAgent(options: CreateMcpAgentOptions): Promise<McpAgentHandle> {
|
|
150
|
+
const { transport: transportConfig, extraTools = [], workflow, ...hostOptions } = options;
|
|
151
|
+
|
|
152
|
+
const transport = buildTransport(transportConfig);
|
|
153
|
+
const client = new Client({ name: 'ziggs-mcp-agent', version: '1.0.0' });
|
|
154
|
+
|
|
155
|
+
await client.connect(transport);
|
|
156
|
+
|
|
157
|
+
const { tools: rawTools } = await client.listTools();
|
|
158
|
+
const mcpTools = mapMcpTools(client, rawTools as McpTool[]);
|
|
159
|
+
|
|
160
|
+
const resolvedWorkflow = workflow ?? buildDefaultWorkflow(hostOptions.description ?? '');
|
|
161
|
+
|
|
162
|
+
const host = new AgentHost({
|
|
163
|
+
...hostOptions,
|
|
164
|
+
workflow: resolvedWorkflow,
|
|
165
|
+
tools: [...mcpTools, ...extraTools],
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
host,
|
|
170
|
+
closeMcp: () => client.close(),
|
|
171
|
+
toolNames: rawTools.map((t: McpTool) => t.name),
|
|
172
|
+
};
|
|
173
|
+
}
|
|
@@ -62,49 +62,85 @@ export class OpenAIAdapter {
|
|
|
62
62
|
: undefined;
|
|
63
63
|
|
|
64
64
|
try {
|
|
65
|
-
const { usage: _u, ...restOptions } = options as Record<string, unknown>;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
const { usage: _u, response_format: _explicitResponseFormat, ...restOptions } = options as Record<string, unknown>;
|
|
66
|
+
const responseFormat = openAITools
|
|
67
|
+
? undefined
|
|
68
|
+
: ((_explicitResponseFormat as OpenAI.ResponseFormatJSONObject) ?? { type: 'json_object' });
|
|
69
|
+
|
|
70
|
+
// OpenAI 400s response_format:{type:'json_object'} unless the word "json"
|
|
71
|
+
// appears somewhere in the messages. Callers are expected to mention it
|
|
72
|
+
// in their system prompt, but that's an implicit cross-file contract —
|
|
73
|
+
// guarantee it here instead of trusting every call site to remember.
|
|
74
|
+
let finalMessages = messages;
|
|
75
|
+
if (
|
|
76
|
+
responseFormat?.type === 'json_object' &&
|
|
77
|
+
!messages.some(m => {
|
|
78
|
+
const c = typeof m.content === 'string' ? m.content : JSON.stringify(m.content ?? '');
|
|
79
|
+
return /json/i.test(c);
|
|
80
|
+
})
|
|
81
|
+
) {
|
|
82
|
+
finalMessages = [...messages, { role: 'system', content: 'Respond with valid JSON.' }];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Verbose LLM request/response logging — enabled for debugging.
|
|
86
|
+
// Comment out again to reduce log noise.
|
|
87
|
+
const divider = '─'.repeat(80);
|
|
88
|
+
console.log(`\n${divider}`);
|
|
89
|
+
console.log(`📤 LLM REQUEST → ${this.model} (${finalMessages.length} msg${finalMessages.length === 1 ? '' : 's'})`);
|
|
90
|
+
console.log(divider);
|
|
91
|
+
for (const m of finalMessages) {
|
|
92
|
+
const content = typeof m.content === 'string' ? m.content : JSON.stringify(m.content);
|
|
93
|
+
const len = content?.length ?? 0;
|
|
94
|
+
console.log(`\n[${m.role.toUpperCase()}] ${len} chars`);
|
|
95
|
+
console.log(content ?? '');
|
|
96
|
+
}
|
|
97
|
+
console.log(`${divider}\n`);
|
|
79
98
|
const res = await this.client.chat.completions.create({
|
|
80
99
|
model: this.model,
|
|
81
|
-
messages,
|
|
100
|
+
messages: finalMessages,
|
|
82
101
|
stream: false,
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
// 25000 reserves room for hidden reasoning tokens on reasoning models
|
|
103
|
+
// (gpt-5.x/o-series) — they're billed against this cap before any
|
|
104
|
+
// visible content, so a low cap can exhaust the budget and return
|
|
105
|
+
// empty content with finish_reason "length".
|
|
106
|
+
max_completion_tokens: 25000,
|
|
107
|
+
response_format: responseFormat,
|
|
85
108
|
...(openAITools && { tools: openAITools }),
|
|
86
109
|
...restOptions,
|
|
87
110
|
} as OpenAI.Chat.ChatCompletionCreateParamsNonStreaming);
|
|
88
111
|
|
|
89
112
|
const msg = res.choices[0].message;
|
|
113
|
+
const finishReason = res.choices[0].finish_reason;
|
|
90
114
|
const content = msg.content?.trim() ?? null;
|
|
91
115
|
const toolCalls = msg.tool_calls?.length ? msg.tool_calls : null;
|
|
92
|
-
// Verbose LLM response logging —
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
116
|
+
// Verbose LLM response logging — enabled for debugging.
|
|
117
|
+
// Comment out again to reduce log noise.
|
|
118
|
+
console.log(`\n${divider}`);
|
|
119
|
+
console.log(`📥 LLM RESPONSE ← ${this.model} finish=${finishReason}`);
|
|
120
|
+
console.log(divider);
|
|
121
|
+
if (content) {
|
|
122
|
+
console.log(`\n[CONTENT] ${content.length} chars`);
|
|
123
|
+
console.log(content);
|
|
124
|
+
}
|
|
125
|
+
if (toolCalls) {
|
|
126
|
+
console.log(`\n[TOOL CALLS] ${toolCalls.length}`);
|
|
127
|
+
for (const tc of toolCalls) {
|
|
128
|
+
console.log(` → ${tc.function.name}(${tc.function.arguments})`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (!content && !toolCalls) console.log('\n(no content, no tool calls)');
|
|
132
|
+
if (res.usage) {
|
|
133
|
+
const u = res.usage as OpenAI.CompletionUsage & { completion_tokens_details?: { reasoning_tokens?: number } };
|
|
134
|
+
console.log(`\n[USAGE] prompt=${u.prompt_tokens} completion=${u.completion_tokens}${u.completion_tokens_details?.reasoning_tokens != null ? ` (reasoning=${u.completion_tokens_details.reasoning_tokens})` : ''} total=${u.total_tokens}`);
|
|
135
|
+
}
|
|
136
|
+
console.log(`${divider}\n`);
|
|
137
|
+
if (!content && !toolCalls && finishReason === 'length') {
|
|
138
|
+
const u = res.usage as (OpenAI.CompletionUsage & { completion_tokens_details?: { reasoning_tokens?: number } }) | undefined;
|
|
139
|
+
throw new Error(
|
|
140
|
+
`LLM returned no usable output — completion token budget exhausted before any content ` +
|
|
141
|
+
`(finish_reason=length, reasoning_tokens=${u?.completion_tokens_details?.reasoning_tokens ?? 'unknown'})`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
108
144
|
return {
|
|
109
145
|
content,
|
|
110
146
|
tool_calls: toolCalls,
|
|
@@ -131,7 +167,7 @@ export class OpenAIAdapter {
|
|
|
131
167
|
model: this.model,
|
|
132
168
|
messages,
|
|
133
169
|
stream: true,
|
|
134
|
-
max_completion_tokens:
|
|
170
|
+
max_completion_tokens: 25000,
|
|
135
171
|
});
|
|
136
172
|
let text = '';
|
|
137
173
|
for await (const chunk of stream) {
|
package/src/context/batch.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isBroadcastTarget } from '@ziggs-ai/api-client';
|
|
2
|
+
|
|
1
3
|
export function getBatchEvents(rawEvent: unknown): unknown[] {
|
|
2
4
|
if (!rawEvent) return [];
|
|
3
5
|
const e = rawEvent as Record<string, unknown>;
|
|
@@ -12,6 +14,6 @@ export function isTaskResultRelevantToAgent(result: Record<string, unknown>, own
|
|
|
12
14
|
result['creatorIsYou'] || result['providerIsYou'] || result['payerIsYou'] || result['proposedToIsYou'] ||
|
|
13
15
|
parties['creator'] === ownAgentId || parties['provider'] === ownAgentId ||
|
|
14
16
|
parties['payer'] === ownAgentId || parties['proposedTo'] === ownAgentId ||
|
|
15
|
-
parties['proposedTo']
|
|
17
|
+
isBroadcastTarget(parties['proposedTo'] as string | undefined)
|
|
16
18
|
);
|
|
17
19
|
}
|
|
@@ -116,7 +116,13 @@ export class HistoryFormatter {
|
|
|
116
116
|
|
|
117
117
|
formatParticipant(participant: AnyObj | null | undefined, agentId: string): string {
|
|
118
118
|
if (!participant) return 'unknown';
|
|
119
|
-
|
|
119
|
+
// Message.sender is stored as {agentId, underAgreementId} (no `id`, no
|
|
120
|
+
// `type`) while Message.receiver is {id, type} — two different shapes on
|
|
121
|
+
// the same document (see backend Message schema). Without this fallback,
|
|
122
|
+
// every sender renders as "unknown (unknown)" and self-sent history rows
|
|
123
|
+
// never match `id === agentId`, so the agent can't recognize its own
|
|
124
|
+
// past messages in <history>.
|
|
125
|
+
const id = (participant['id'] as string) || (participant['agentId'] as string) || 'unknown';
|
|
120
126
|
if (participant['type'] === 'system') return 'System';
|
|
121
127
|
if (id === agentId) return 'You';
|
|
122
128
|
return `${id} (${participant['type'] || 'unknown'})`;
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
export { defineAgent } from './defineAgent.js';
|
|
12
|
+
export { createMcpAgent } from './adapters/McpAdapter.js';
|
|
13
|
+
export type { CreateMcpAgentOptions, McpAgentHandle, McpTransportConfig } from './adapters/McpAdapter.js';
|
|
12
14
|
export { AgentHost, createAgent, createAgentPool } from './AgentHost.js';
|
|
13
15
|
export { Agent } from './agent/Agent.js';
|
|
14
16
|
export type { TickInput, TickOutput, AgentOptions } from './agent/Agent.js';
|
|
@@ -12,7 +12,7 @@ export const TIER_PRICE_CENTS: Record<FleetPricingTier, number> = {
|
|
|
12
12
|
A: 200, // 2 ZIG / call
|
|
13
13
|
B: 500, // 5 ZIG / call
|
|
14
14
|
C: 1500, // 15 ZIG / job (orchestrator, charged once at top)
|
|
15
|
-
D: 100, // 1 ZIG / call (
|
|
15
|
+
D: 100, // 1 ZIG / call (hand-written demo agents)
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const ZIGGS_ORCHESTRATOR_IDS = new Set(['ziggs-agent']);
|
|
@@ -144,11 +144,18 @@ export function applyFleetAgreementPricing(
|
|
|
144
144
|
return next;
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
/**
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
/**
|
|
148
|
+
* Default tier price when a fleet agent counters without an explicit `price`.
|
|
149
|
+
*
|
|
150
|
+
* Generic over the payload shape so the precise field types of the caller's
|
|
151
|
+
* payload survive the round-trip — this helper only ever sets `price`, so a
|
|
152
|
+
* richer input type (e.g. protocolRunner's `ProtocolPayload`) must come back
|
|
153
|
+
* out unwidened by `ProtocolPricingPayload`'s `[key: string]: unknown` index.
|
|
154
|
+
*/
|
|
155
|
+
export function applyFleetCounterPricing<T extends ProtocolPricingPayload>(
|
|
156
|
+
payload: T,
|
|
150
157
|
actingAgentId: string,
|
|
151
|
-
):
|
|
158
|
+
): T {
|
|
152
159
|
if (payload.price != null && payload.price !== undefined) {
|
|
153
160
|
return payload;
|
|
154
161
|
}
|
|
@@ -157,7 +164,7 @@ export function applyFleetCounterPricing(
|
|
|
157
164
|
payload.description ?? payload.agreementDescription,
|
|
158
165
|
);
|
|
159
166
|
if (cents == null) return payload;
|
|
160
|
-
return { ...payload, price: cents };
|
|
167
|
+
return { ...payload, price: cents } as T;
|
|
161
168
|
}
|
|
162
169
|
|
|
163
170
|
/** User or agent direct-create / marketplace: default from provider specialist. */
|
|
@@ -270,305 +270,6 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
|
|
|
270
270
|
"feature-prioritizer": "C",
|
|
271
271
|
"threat-model-committee": "C",
|
|
272
272
|
"negotiation-simulator": "C",
|
|
273
|
-
"pizza-ordering-agent": "D",
|
|
274
|
-
"sushi-ordering-agent": "D",
|
|
275
|
-
"burger-ordering-agent": "D",
|
|
276
|
-
"salad-ordering-agent": "D",
|
|
277
|
-
"coffee-ordering-agent": "D",
|
|
278
|
-
"restaurant-finder": "D",
|
|
279
|
-
"reservation-maker": "D",
|
|
280
|
-
"menu-browser": "D",
|
|
281
|
-
"dietary-filter": "D",
|
|
282
|
-
"review-aggregator": "D",
|
|
283
|
-
"meal-planner": "D",
|
|
284
|
-
"recipe-finder": "D",
|
|
285
|
-
"grocery-list-builder": "D",
|
|
286
|
-
"calorie-counter": "D",
|
|
287
|
-
"wine-pairer": "D",
|
|
288
|
-
"food-delivery-tracker": "D",
|
|
289
|
-
"tip-calculator": "D",
|
|
290
|
-
"split-bill-calculator": "D",
|
|
291
|
-
"allergen-checker": "D",
|
|
292
|
-
"catering-coordinator": "D",
|
|
293
|
-
"party-food-planner": "D",
|
|
294
|
-
"food-truck-finder": "D",
|
|
295
|
-
"brunch-recommender": "D",
|
|
296
|
-
"dessert-advisor": "D",
|
|
297
|
-
"happy-hour-finder": "D",
|
|
298
|
-
"breakfast-planner": "D",
|
|
299
|
-
"late-night-eats-finder": "D",
|
|
300
|
-
"food-allergy-restaurant-finder": "D",
|
|
301
|
-
"kids-menu-finder": "D",
|
|
302
|
-
"flight-searcher": "D",
|
|
303
|
-
"hotel-booker": "D",
|
|
304
|
-
"car-rental": "D",
|
|
305
|
-
"airport-transfer": "D",
|
|
306
|
-
"visa-checker": "D",
|
|
307
|
-
"trip-planner": "D",
|
|
308
|
-
"itinerary-builder": "D",
|
|
309
|
-
"packing-list-maker": "D",
|
|
310
|
-
"currency-advisor": "D",
|
|
311
|
-
"travel-insurance": "D",
|
|
312
|
-
"train-booker": "D",
|
|
313
|
-
"bus-route-finder": "D",
|
|
314
|
-
"ferry-scheduler": "D",
|
|
315
|
-
"road-trip-planner": "D",
|
|
316
|
-
"toll-calculator": "D",
|
|
317
|
-
"rideshare-booker": "D",
|
|
318
|
-
"bike-share": "D",
|
|
319
|
-
"scooter-rental": "D",
|
|
320
|
-
"parking-finder": "D",
|
|
321
|
-
"traffic-checker": "D",
|
|
322
|
-
"travel-photo-finder": "D",
|
|
323
|
-
"local-guide": "D",
|
|
324
|
-
"phrase-book": "D",
|
|
325
|
-
"embassy-locator": "D",
|
|
326
|
-
"timezone-advisor": "D",
|
|
327
|
-
"cruise-finder": "D",
|
|
328
|
-
"camping-booker": "D",
|
|
329
|
-
"hostel-searcher": "D",
|
|
330
|
-
"vacation-rental": "D",
|
|
331
|
-
"loyalty-tracker": "D",
|
|
332
|
-
"electronics-shopper": "D",
|
|
333
|
-
"fashion-advisor": "D",
|
|
334
|
-
"book-recommender": "D",
|
|
335
|
-
"gift-finder": "D",
|
|
336
|
-
"price-comparator": "D",
|
|
337
|
-
"grocery-shopper": "D",
|
|
338
|
-
"furniture-browser": "D",
|
|
339
|
-
"auto-parts-finder": "D",
|
|
340
|
-
"pet-supplies": "D",
|
|
341
|
-
"sports-gear": "D",
|
|
342
|
-
"deal-hunter": "D",
|
|
343
|
-
"coupon-finder": "D",
|
|
344
|
-
"wishlist-manager": "D",
|
|
345
|
-
"return-tracker": "D",
|
|
346
|
-
"warranty-checker": "D",
|
|
347
|
-
"subscription-manager": "D",
|
|
348
|
-
"auction-bidder": "D",
|
|
349
|
-
"local-store-finder": "D",
|
|
350
|
-
"size-converter": "D",
|
|
351
|
-
"product-reviewer": "D",
|
|
352
|
-
"comparison-builder": "D",
|
|
353
|
-
"inventory-checker": "D",
|
|
354
|
-
"price-drop-monitor": "D",
|
|
355
|
-
"flash-sale-alerter": "D",
|
|
356
|
-
"barcode-scanner": "D",
|
|
357
|
-
"doctor-appointment-booker": "D",
|
|
358
|
-
"dentist-scheduler": "D",
|
|
359
|
-
"optometrist-finder": "D",
|
|
360
|
-
"symptom-checker": "D",
|
|
361
|
-
"medication-reminder": "D",
|
|
362
|
-
"prescription-tracker": "D",
|
|
363
|
-
"pharmacy-finder": "D",
|
|
364
|
-
"fitness-trainer": "D",
|
|
365
|
-
"workout-planner": "D",
|
|
366
|
-
"yoga-instructor": "D",
|
|
367
|
-
"meditation-guide": "D",
|
|
368
|
-
"step-counter": "D",
|
|
369
|
-
"nutrition-advisor": "D",
|
|
370
|
-
"diet-planner": "D",
|
|
371
|
-
"water-tracker": "D",
|
|
372
|
-
"sleep-tracker": "D",
|
|
373
|
-
"mood-logger": "D",
|
|
374
|
-
"mental-health-checkin": "D",
|
|
375
|
-
"stress-advisor": "D",
|
|
376
|
-
"breathing-guide": "D",
|
|
377
|
-
"first-aid-advisor": "D",
|
|
378
|
-
"vaccine-tracker": "D",
|
|
379
|
-
"insurance-claim-helper": "D",
|
|
380
|
-
"lab-result-explainer": "D",
|
|
381
|
-
"pet-vet-booker": "D",
|
|
382
|
-
"smart-light-controller": "D",
|
|
383
|
-
"thermostat-manager": "D",
|
|
384
|
-
"smart-lock-controller": "D",
|
|
385
|
-
"camera-monitor": "D",
|
|
386
|
-
"smart-speaker": "D",
|
|
387
|
-
"plumber-finder": "D",
|
|
388
|
-
"electrician-booker": "D",
|
|
389
|
-
"cleaner-scheduler": "D",
|
|
390
|
-
"gardener-finder": "D",
|
|
391
|
-
"pest-control": "D",
|
|
392
|
-
"interior-designer": "D",
|
|
393
|
-
"paint-matcher": "D",
|
|
394
|
-
"furniture-arranger": "D",
|
|
395
|
-
"lighting-planner": "D",
|
|
396
|
-
"utility-tracker": "D",
|
|
397
|
-
"energy-monitor": "D",
|
|
398
|
-
"water-advisor": "D",
|
|
399
|
-
"moving-coordinator": "D",
|
|
400
|
-
"storage-finder": "D",
|
|
401
|
-
"furniture-assembly-helper": "D",
|
|
402
|
-
"home-warranty-manager": "D",
|
|
403
|
-
"renovation-planner": "D",
|
|
404
|
-
"contractor-reviewer": "D",
|
|
405
|
-
"package-tracker": "D",
|
|
406
|
-
"handyman-finder": "D",
|
|
407
|
-
"bank-account-viewer": "D",
|
|
408
|
-
"transaction-categorizer": "D",
|
|
409
|
-
"budget-planner": "D",
|
|
410
|
-
"savings-tracker": "D",
|
|
411
|
-
"credit-card-advisor": "D",
|
|
412
|
-
"loan-calculator": "D",
|
|
413
|
-
"mortgage-estimator": "D",
|
|
414
|
-
"refinance-checker": "D",
|
|
415
|
-
"portfolio-tracker": "D",
|
|
416
|
-
"stock-trader-sim": "D",
|
|
417
|
-
"crypto-trader-sim": "D",
|
|
418
|
-
"robo-advisor": "D",
|
|
419
|
-
"tax-estimator": "D",
|
|
420
|
-
"deduction-finder": "D",
|
|
421
|
-
"tax-filing-assistant": "D",
|
|
422
|
-
"receipt-organizer": "D",
|
|
423
|
-
"auto-insurance-quoter": "D",
|
|
424
|
-
"home-insurance-quoter": "D",
|
|
425
|
-
"life-insurance-quoter": "D",
|
|
426
|
-
"health-insurance-quoter": "D",
|
|
427
|
-
"claim-filer": "D",
|
|
428
|
-
"bill-pay-scheduler": "D",
|
|
429
|
-
"subscription-auditor": "D",
|
|
430
|
-
"retirement-calculator": "D",
|
|
431
|
-
"college-savings-planner": "D",
|
|
432
|
-
"uber-sim": "D",
|
|
433
|
-
"lyft-sim": "D",
|
|
434
|
-
"taxi-booker": "D",
|
|
435
|
-
"shuttle-service": "D",
|
|
436
|
-
"limo-booker": "D",
|
|
437
|
-
"subway-navigator": "D",
|
|
438
|
-
"bus-tracker": "D",
|
|
439
|
-
"commuter-rail": "D",
|
|
440
|
-
"light-rail": "D",
|
|
441
|
-
"ferry-booker": "D",
|
|
442
|
-
"bike-rental": "D",
|
|
443
|
-
"scooter-rental-sim": "D",
|
|
444
|
-
"e-bike-finder": "D",
|
|
445
|
-
"skateboard-rental": "D",
|
|
446
|
-
"segway-tour": "D",
|
|
447
|
-
"parking-meter": "D",
|
|
448
|
-
"garage-finder": "D",
|
|
449
|
-
"valet-service": "D",
|
|
450
|
-
"airport-parking": "D",
|
|
451
|
-
"street-parking": "D",
|
|
452
|
-
"car-wash-finder": "D",
|
|
453
|
-
"oil-change-scheduler": "D",
|
|
454
|
-
"tire-shop": "D",
|
|
455
|
-
"mechanic-finder": "D",
|
|
456
|
-
"roadside-assistance": "D",
|
|
457
|
-
"course-finder": "D",
|
|
458
|
-
"university-searcher": "D",
|
|
459
|
-
"scholarship-finder": "D",
|
|
460
|
-
"admission-advisor": "D",
|
|
461
|
-
"resume-reviewer": "D",
|
|
462
|
-
"job-searcher": "D",
|
|
463
|
-
"interview-prepper": "D",
|
|
464
|
-
"salary-negotiator": "D",
|
|
465
|
-
"career-coach": "D",
|
|
466
|
-
"online-class-enrollor": "D",
|
|
467
|
-
"certificate-tracker": "D",
|
|
468
|
-
"skill-assessor": "D",
|
|
469
|
-
"mentor-matcher": "D",
|
|
470
|
-
"language-lesson-booker": "D",
|
|
471
|
-
"music-lesson-scheduler": "D",
|
|
472
|
-
"tutoring-booker": "D",
|
|
473
|
-
"internship-finder": "D",
|
|
474
|
-
"networking-advisor": "D",
|
|
475
|
-
"linkedin-optimizer": "D",
|
|
476
|
-
"conference-finder": "D",
|
|
477
|
-
"workshop-registrar": "D",
|
|
478
|
-
"webinar-scheduler": "D",
|
|
479
|
-
"library-manager": "D",
|
|
480
|
-
"study-group-coordinator": "D",
|
|
481
|
-
"campus-navigator": "D",
|
|
482
|
-
"concert-ticket-buyer": "D",
|
|
483
|
-
"movie-ticket-booker": "D",
|
|
484
|
-
"theater-booker": "D",
|
|
485
|
-
"party-organizer": "D",
|
|
486
|
-
"wedding-planner": "D",
|
|
487
|
-
"birthday-coordinator": "D",
|
|
488
|
-
"sports-ticket-buyer": "D",
|
|
489
|
-
"gym-membership-manager": "D",
|
|
490
|
-
"spa-booker": "D",
|
|
491
|
-
"streaming-manager": "D",
|
|
492
|
-
"playlist-curator": "D",
|
|
493
|
-
"podcast-recommender": "D",
|
|
494
|
-
"board-game-organizer": "D",
|
|
495
|
-
"trivia-host": "D",
|
|
496
|
-
"karaoke-picker": "D",
|
|
497
|
-
"museum-ticket-buyer": "D",
|
|
498
|
-
"zoo-pass-manager": "D",
|
|
499
|
-
"amusement-park-planner": "D",
|
|
500
|
-
"festival-finder": "D",
|
|
501
|
-
"book-club-organizer": "D",
|
|
502
|
-
"art-class-booker": "D",
|
|
503
|
-
"cooking-class-finder": "D",
|
|
504
|
-
"photography-booker": "D",
|
|
505
|
-
"escape-room-booker": "D",
|
|
506
|
-
"dmv-appointment": "D",
|
|
507
|
-
"passport-renewal": "D",
|
|
508
|
-
"visa-tracker": "D",
|
|
509
|
-
"voter-registration": "D",
|
|
510
|
-
"polling-finder": "D",
|
|
511
|
-
"official-lookup": "D",
|
|
512
|
-
"building-permit-tracker": "D",
|
|
513
|
-
"zoning-info": "D",
|
|
514
|
-
"noise-complaint-filer": "D",
|
|
515
|
-
"jury-duty-manager": "D",
|
|
516
|
-
"court-date-tracker": "D",
|
|
517
|
-
"public-record-searcher": "D",
|
|
518
|
-
"tax-authority-contact": "D",
|
|
519
|
-
"benefits-checker": "D",
|
|
520
|
-
"park-permit": "D",
|
|
521
|
-
"recycling-guide": "D",
|
|
522
|
-
"carbon-calculator": "D",
|
|
523
|
-
"eco-product-finder": "D",
|
|
524
|
-
"volunteer-finder": "D",
|
|
525
|
-
"donation-tracker": "D",
|
|
526
|
-
"charity-evaluator": "D",
|
|
527
|
-
"community-board": "D",
|
|
528
|
-
"neighborhood-alert": "D",
|
|
529
|
-
"lost-and-found": "D",
|
|
530
|
-
"carpool-matcher": "D",
|
|
531
|
-
"bike-route-planner": "D",
|
|
532
|
-
"transit-optimizer": "D",
|
|
533
|
-
"solar-estimator": "D",
|
|
534
|
-
"ev-charger-finder": "D",
|
|
535
|
-
"green-energy-advisor": "D",
|
|
536
|
-
"pet-adoption": "D",
|
|
537
|
-
"breeder-finder": "D",
|
|
538
|
-
"pet-sitter-booker": "D",
|
|
539
|
-
"dog-walker": "D",
|
|
540
|
-
"pet-groomer": "D",
|
|
541
|
-
"pet-boarding": "D",
|
|
542
|
-
"pet-food-delivery": "D",
|
|
543
|
-
"pet-toy-recommender": "D",
|
|
544
|
-
"pet-training-class": "D",
|
|
545
|
-
"pet-insurance-comparer": "D",
|
|
546
|
-
"dry-cleaner": "D",
|
|
547
|
-
"tailor-finder": "D",
|
|
548
|
-
"shoe-repair": "D",
|
|
549
|
-
"watch-repair": "D",
|
|
550
|
-
"phone-repair": "D",
|
|
551
|
-
"car-detailer": "D",
|
|
552
|
-
"car-wash-booker": "D",
|
|
553
|
-
"auto-detailing": "D",
|
|
554
|
-
"mechanic-scheduler": "D",
|
|
555
|
-
"tire-rotator": "D",
|
|
556
|
-
"photo-printer": "D",
|
|
557
|
-
"custom-framer": "D",
|
|
558
|
-
"engraver": "D",
|
|
559
|
-
"embroiderer": "D",
|
|
560
|
-
"storage-unit-finder": "D",
|
|
561
|
-
"junk-removal": "D",
|
|
562
|
-
"donation-pickup": "D",
|
|
563
|
-
"hauler": "D",
|
|
564
|
-
"painter-finder": "D",
|
|
565
|
-
"roofer-finder": "D",
|
|
566
|
-
"window-washer": "D",
|
|
567
|
-
"chimney-sweep": "D",
|
|
568
|
-
"snow-remover": "D",
|
|
569
|
-
"lawn-care": "D",
|
|
570
|
-
"tree-trimmer": "D",
|
|
571
|
-
"power-washer": "D",
|
|
572
273
|
"aristotle": "B",
|
|
573
274
|
"plato": "B",
|
|
574
275
|
"confucius": "B",
|
|
@@ -1019,4 +720,4 @@ export const FLEET_TIER_BY_AGENT_ID: Record<string, FleetPricingTier> = {
|
|
|
1019
720
|
"death-studies-scholar": "B"
|
|
1020
721
|
} as Record<string, FleetPricingTier>;
|
|
1021
722
|
|
|
1022
|
-
export const FLEET_TIER_MAP_SIZE =
|
|
723
|
+
export const FLEET_TIER_MAP_SIZE = 713;
|
|
@@ -2,6 +2,7 @@ import type { Action, Ctx, PromptDef } from '../types.js';
|
|
|
2
2
|
import { HistoryFormatter, AgreementFormatter } from '../formatters/index.js';
|
|
3
3
|
import { validateContext } from '../cognition/validateContext.js';
|
|
4
4
|
import type { RawEvent } from './buildOutcome.js';
|
|
5
|
+
import { isBroadcastTarget } from '@ziggs-ai/api-client';
|
|
5
6
|
|
|
6
7
|
type AnyObj = Record<string, unknown>;
|
|
7
8
|
|
|
@@ -207,7 +208,9 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
207
208
|
const content = event.text || event.result || event.content;
|
|
208
209
|
if (!content) return `<event type="${eventType}" from="${from}">(Empty)</event>`;
|
|
209
210
|
const str = typeof content === 'object' ? JSON.stringify(content) : String(content);
|
|
210
|
-
|
|
211
|
+
// Matches MAX_MSG_CHARS in runTurn.ts — the incoming instruction shouldn't
|
|
212
|
+
// be truncated tighter than what the agent itself is allowed to send back.
|
|
213
|
+
const display = str.length > 3500 ? str.slice(0, 3500) + '...' : str;
|
|
211
214
|
return `<event type="${eventType}" from="${from}">\n${display}\n</event>`;
|
|
212
215
|
}
|
|
213
216
|
|
|
@@ -370,7 +373,7 @@ ${this._renderDecisionSchemaFromActions(actions, senderMeta, ctxObj, omitMessage
|
|
|
370
373
|
|
|
371
374
|
const replyTo = (senderMeta.defaultReplyReceiverId as string) || '<receiverId>';
|
|
372
375
|
const pendingProposals = (ctxObj.agreements || []).filter(
|
|
373
|
-
(a) => (a.proposal as Record<string, unknown> | undefined)?.status === 'pending' && (a.proposedToIsYou || (a.parties as Record<string, unknown> | undefined)?.proposedTo
|
|
376
|
+
(a) => (a.proposal as Record<string, unknown> | undefined)?.status === 'pending' && (a.proposedToIsYou || isBroadcastTarget((a.parties as Record<string, unknown> | undefined)?.proposedTo as string | undefined)),
|
|
374
377
|
);
|
|
375
378
|
|
|
376
379
|
if (pendingProposals.length > 0) {
|
package/src/runtime/runTurn.ts
CHANGED
|
@@ -424,9 +424,13 @@ function eventsAreTerminal(events: EmittedEvent[]): boolean {
|
|
|
424
424
|
// (api-client now returns Agreement directly, not wrapped in { agreement }).
|
|
425
425
|
const ag = (r.agreement ?? (r.agreementId ? r : null)) as Record<string, unknown> | null | undefined;
|
|
426
426
|
const task = (r.task || (r.taskId ? r : null)) as Record<string, unknown> | null | undefined;
|
|
427
|
+
// Agreement's own status lives flat as `proposalStatus` (see api-client
|
|
428
|
+
// Agreement type) — not nested under `.proposal.status`. Check both so
|
|
429
|
+
// a successful agreement_propose is recognized as terminal instead of
|
|
430
|
+
// being re-issued by the LLM on the next loop iteration.
|
|
427
431
|
const agProposal = ag?.proposal as Record<string, unknown> | undefined;
|
|
428
432
|
const taskProposal = task?.proposal as Record<string, unknown> | undefined;
|
|
429
|
-
const proposalStatus = agProposal?.status
|
|
433
|
+
const proposalStatus = ag?.proposalStatus ?? agProposal?.status ?? taskProposal?.status;
|
|
430
434
|
if (proposalStatus === 'pending' || proposalStatus === 'approved') return true;
|
|
431
435
|
const state = task?.state || r.state;
|
|
432
436
|
if (state === 'active' || state === 'in-progress' ||
|
|
@@ -445,10 +449,11 @@ function eventsContainAgreementCreation(events: EmittedEvent[]): boolean {
|
|
|
445
449
|
if (r.success === false || r.error) return false;
|
|
446
450
|
// Support both nested { agreement: {...} } and flat Agreement objects.
|
|
447
451
|
const ag = (r.agreement ?? (r.agreementId ? r : null)) as Record<string, unknown> | undefined;
|
|
452
|
+
// See eventsAreTerminal above: proposalStatus is flat on Agreement, not nested.
|
|
448
453
|
const agProposal = ag?.proposal as Record<string, unknown> | undefined;
|
|
449
454
|
const task = r.task as Record<string, unknown> | undefined;
|
|
450
455
|
const taskProposal = task?.proposal as Record<string, unknown> | undefined;
|
|
451
|
-
const proposalStatus = agProposal?.status
|
|
456
|
+
const proposalStatus = ag?.proposalStatus ?? agProposal?.status ?? taskProposal?.status;
|
|
452
457
|
return proposalStatus === 'pending' || proposalStatus === 'approved';
|
|
453
458
|
});
|
|
454
459
|
}
|
|
@@ -171,7 +171,14 @@ export async function runInboxCatchUp(deps: InboxCatchUpDeps): Promise<InboxCatc
|
|
|
171
171
|
const toAck: InboxAck[] = [];
|
|
172
172
|
|
|
173
173
|
if (envelope.truncatedScopes > 0) {
|
|
174
|
-
|
|
174
|
+
// Informational only — does NOT block acking the scopes actually
|
|
175
|
+
// returned below. truncatedScopes just means the caller's total reach
|
|
176
|
+
// exceeded the server's per-call scope cap (backend/src/inbox/inbox.service.ts,
|
|
177
|
+
// INBOX_MAX_SCOPES); each entry in envelope.scopes is still an
|
|
178
|
+
// independently accurate, safe-to-ack unit of news for that scope. Never
|
|
179
|
+
// acking here meant a busy long-lived agent (reach > cap) would never ack
|
|
180
|
+
// anything and re-deliver its entire backlog on every reconnect forever.
|
|
181
|
+
warn(label, `inbox truncatedScopes=${envelope.truncatedScopes} (reach exceeds per-call cap — examined scopes are still acked normally)`);
|
|
175
182
|
}
|
|
176
183
|
|
|
177
184
|
for (const scope of envelope.scopes) {
|
|
@@ -202,11 +209,7 @@ export async function runInboxCatchUp(deps: InboxCatchUpDeps): Promise<InboxCatc
|
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
211
|
|
|
205
|
-
if (
|
|
206
|
-
envelope.truncatedScopes === 0 &&
|
|
207
|
-
scope.latestAt &&
|
|
208
|
-
(scope.newMessages > 0 || scope.newArtifacts > 0)
|
|
209
|
-
) {
|
|
212
|
+
if (scope.latestAt && (scope.newMessages > 0 || scope.newArtifacts > 0)) {
|
|
210
213
|
toAck.push({
|
|
211
214
|
kind: scope.scope.kind,
|
|
212
215
|
id: scope.scope.id,
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
proposeAgreement, delegateAgreement, respondToAgreement, counterAgreement,
|
|
2
|
+
proposeAgreement, proposeBroadcast as proposeBroadcastApi, delegateAgreement, respondToAgreement, counterAgreement,
|
|
3
3
|
getAgreementStatus, listAgreements, getMyAgreements, getAgreement,
|
|
4
4
|
publishOffer as publishOfferApi, createAgreement, revokeAgreement, getAgreementsByChat, linkAgreementToChat,
|
|
5
5
|
getChatsForAgreement, joinAgreement, linkArtifactToAgreement, getArtifactsForAgreement,
|
|
6
|
-
linkUserToAgreement, getUsersForAgreement,
|
|
7
|
-
OPEN_AGREEMENT_TARGET,
|
|
6
|
+
linkUserToAgreement, getUsersForAgreement,
|
|
8
7
|
type Creds, type Agreement,
|
|
9
8
|
type ProposeAgreementData, type ProposeDirectInput, type ProposeBroadcastInput,
|
|
10
9
|
type PublishOfferPayload,
|
|
11
10
|
type DelegateAgreementData, type CounterAgreementData,
|
|
12
11
|
type CreateAgreementBody, type ListAgreementsFilters, type GetMyAgreementsFilters,
|
|
13
|
-
type ChatLinkType, type ArtifactLinkType, type UserRole,
|
|
12
|
+
type ChatLinkType, type ArtifactLinkType, type UserRole,
|
|
14
13
|
} from '@ziggs-ai/api-client';
|
|
15
14
|
|
|
16
15
|
export class AgreementService {
|
|
@@ -22,19 +21,18 @@ export class AgreementService {
|
|
|
22
21
|
this.creds = { operatorKey, agentId };
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
/** @deprecated Prefer {@link proposeDirect} or {@link proposeBroadcast}. */
|
|
26
|
-
contract(input: CreateContractInput): Promise<Agreement> {
|
|
27
|
-
return createContract(input, this.creds);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
24
|
/** 1:1 proposal. Server defaults engagementKind to `service` when omitted. */
|
|
31
25
|
proposeDirect(payload: ProposeDirectInput): Promise<Agreement> {
|
|
32
26
|
return proposeAgreement(payload, this.creds);
|
|
33
27
|
}
|
|
34
28
|
|
|
35
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Open buyer-broadcast. `payload.audience` selects who may see/claim it:
|
|
31
|
+
* 'everyone' (default, fully public) or 'org' (members of your active org).
|
|
32
|
+
* Server defaults engagementKind to `service`.
|
|
33
|
+
*/
|
|
36
34
|
proposeBroadcast(payload: ProposeBroadcastInput): Promise<Agreement> {
|
|
37
|
-
return
|
|
35
|
+
return proposeBroadcastApi(payload, this.creds);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
38
|
/** @deprecated Alias for {@link proposeDirect}. */
|
|
@@ -42,7 +40,10 @@ export class AgreementService {
|
|
|
42
40
|
return proposeAgreement(payload, this.creds);
|
|
43
41
|
}
|
|
44
42
|
|
|
45
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Seller-broadcast marketplace offer. `payload.audience` sets the `payer`
|
|
45
|
+
* sentinel: 'everyone' (default, public) or 'org' (your active org only).
|
|
46
|
+
*/
|
|
46
47
|
publishOffer(payload: PublishOfferPayload): Promise<Agreement> {
|
|
47
48
|
return publishOfferApi(payload, this.creds);
|
|
48
49
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createTask, getTask, getActiveTasksForAgent, getActiveTasksForChat, getSubtasks,
|
|
3
3
|
updateTaskState, cancelTask,
|
|
4
|
-
|
|
4
|
+
reportTask, setTaskSatisfaction, countTasks,
|
|
5
5
|
type Creds, type Task, type TaskState,
|
|
6
6
|
} from '@ziggs-ai/api-client';
|
|
7
7
|
import type { CountTasksFilters } from '@ziggs-ai/api-client';
|
|
@@ -50,7 +50,7 @@ export class TaskService {
|
|
|
50
50
|
return getSubtasks(parentTaskId, this.creds);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
async spawnUnderAgreement(agreementId: string, taskData: { description: string; parentTaskId?: string; plan?: unknown; planReviewTiming?: string; requireMidWorkPlanAck?: boolean }): Promise<Task> {
|
|
53
|
+
async spawnUnderAgreement(agreementId: string, taskData: { description: string; parentTaskId?: string; plan?: unknown; planReviewTiming?: string; requireMidWorkPlanAck?: boolean; assigneeId?: string }): Promise<Task> {
|
|
54
54
|
if (!agreementId) throw new Error('TaskService.spawnUnderAgreement: agreementId is required');
|
|
55
55
|
try {
|
|
56
56
|
const result = await createTask({ ...taskData, agreementId } as Parameters<typeof createTask>[0], this.creds);
|
|
@@ -85,17 +85,6 @@ export class TaskService {
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
async claimLedgerTask(taskId: string): Promise<Task> {
|
|
89
|
-
try {
|
|
90
|
-
const task = await claimLedgerTask(taskId, this.creds);
|
|
91
|
-
runtimeLog.info('TaskService', `[ledger] Claimed task ${taskId}`);
|
|
92
|
-
return task as unknown as Task;
|
|
93
|
-
} catch (error) {
|
|
94
|
-
runtimeLog.warn('TaskService', `[ledger] Claim failed for ${taskId}: ${(error as Error).message}`);
|
|
95
|
-
throw error;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
88
|
async report(taskId: string, message = ''): Promise<Task> {
|
|
100
89
|
return reportTask(taskId, message, this.creds);
|
|
101
90
|
}
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* config (default 'all'), dispatched to in-process services (taskService /
|
|
8
8
|
* agreementService) injected into tool context — NOT passed in the user `tools:`
|
|
9
9
|
* array. Publishing open work is part of this grammar:
|
|
10
|
-
* agreement_propose({ proposedTo: "everyone" })
|
|
10
|
+
* agreement_propose({ proposedTo: "everyone" }) for a public broadcast, or
|
|
11
|
+
* proposedTo: "org" to scope it to your org — there is no separate publish tool.
|
|
11
12
|
*
|
|
12
13
|
* Tier 2 — capability bundles (tier2/). Opt-in, HTTP-backed tool bundles an agent
|
|
13
14
|
* chooses to have. Off by default; an agent gains a bundle by spreading it into
|
|
@@ -33,7 +33,7 @@ export const agreementProposeTool: ToolDefinition = defineTool(
|
|
|
33
33
|
'agreement_propose',
|
|
34
34
|
{ description: { type: 'string', required: true }, proposedTo: { type: 'string', required: true }, engagementKind: { type: 'string', enum: ['hire', 'service'], description: 'Contract type. Defaults to service when omitted.' }, parentAgreementId: 'string', parentTaskId: 'string', payerId: 'string', providerId: 'string', price: 'number', lifecycle: 'string', expiresAt: 'string', maxExecutions: 'number', agreementDescription: 'string', plan: { type: 'object' }, planReviewTiming: 'string', requireMidWorkPlanAck: 'boolean' },
|
|
35
35
|
handlerFor('agreement-propose'),
|
|
36
|
-
{ description: 'Propose a contract to a user, agent, or everyone (proposedTo="
|
|
36
|
+
{ description: 'Propose a contract to a user, agent, or as an open broadcast. For a broadcast set proposedTo="everyone" (fully public — any agent may claim) or proposedTo="org" (scoped to your org — only members of your org see and claim it). engagementKind defaults to service.', isAgreementCreation: true },
|
|
37
37
|
);
|
|
38
38
|
|
|
39
39
|
export const agreementSubcontractTool: ToolDefinition = defineTool(
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { defineTool, type ToolDefinition } from '../../../tools/defineTool.js';
|
|
2
|
-
import {
|
|
2
|
+
import { pullQuests } from '@ziggs-ai/api-client';
|
|
3
3
|
|
|
4
4
|
type Ctx = Record<string, unknown>;
|
|
5
5
|
|
|
6
6
|
// Read-only marketplace access. Publishing an open quest is NOT here: it is the
|
|
7
|
-
// tier-1 protocol verb agreement_propose({ proposedTo: "everyone" }).
|
|
7
|
+
// tier-1 protocol verb agreement_propose({ proposedTo: "everyone" | "org" }).
|
|
8
|
+
// This feed already returns only quests the caller may see — org-scoped quests
|
|
9
|
+
// appear here only for members of the quest's org (filtered server-side).
|
|
8
10
|
export const marketplaceViewTool: ToolDefinition = defineTool('marketplace_view',
|
|
9
11
|
{ limit: 'number', since: 'string' },
|
|
10
12
|
async (args, ctx) => {
|
|
@@ -16,10 +18,10 @@ export const marketplaceViewTool: ToolDefinition = defineTool('marketplace_view'
|
|
|
16
18
|
limit: typeof args['limit'] === 'number' ? args['limit'] as number : 20,
|
|
17
19
|
};
|
|
18
20
|
if (args['since']) options.since = args['since'] as string;
|
|
19
|
-
const quests = await
|
|
21
|
+
const quests = await pullQuests(options, { operatorKey, agentId });
|
|
20
22
|
return { quests, count: quests.length };
|
|
21
23
|
},
|
|
22
|
-
{ description: 'Browse open quests on the marketplace — work
|
|
24
|
+
{ description: 'Browse open quests on the marketplace — work buyers have broadcast to willing agents. Returns public quests plus any org-scoped quests in your org. To claim a quest, use agreement_respond on the returned agreementId. To publish your own, use agreement_propose({ proposedTo: "everyone" }) for a public quest or proposedTo: "org" to keep it inside your org.' },
|
|
23
25
|
);
|
|
24
26
|
|
|
25
27
|
export const MARKETPLACE_TOOLS: ToolDefinition[] = [marketplaceViewTool];
|