@ziggs-ai/agent-sdk 0.23.0 → 0.24.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/dist/Agent.d.ts +8 -2
- package/dist/Agent.js +232 -53
- package/dist/brain/ClaudeBrain.d.ts +1 -8
- package/dist/brain/ClaudeBrain.js +13 -42
- package/dist/brain/ZiggsBrain.d.ts +1 -1
- package/dist/brain/ZiggsBrain.js +9 -2
- package/dist/brain/claudeCognition.js +6 -2
- package/dist/brain/claudeSdkProtocol.d.ts +1 -1
- package/dist/brain/claudeSdkProtocol.js +3 -2
- package/dist/brain/claudeSdkTools.d.ts +3 -0
- package/dist/brain/claudeSdkTools.js +10 -1
- package/dist/brain/index.d.ts +9 -1
- package/dist/brain/index.js +5 -1
- package/dist/brain/toolManagerToSdkMcp.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/ingress/normalizeIncoming.d.ts +1 -0
- package/dist/ingress/normalizeIncoming.js +2 -1
- package/dist/platform/ZiggsEffectHandler.d.ts +1 -1
- package/dist/platform/ZiggsEffectHandler.js +20 -10
- package/dist/platform/inboxLoop.d.ts +4 -3
- package/dist/platform/inboxLoop.js +5 -6
- package/dist/platform/tasks/TaskService.d.ts +1 -0
- package/dist/platform/tasks/TaskService.js +4 -1
- package/dist/platform/tools/tier1/protocolRunner.js +1 -0
- package/dist/platform/tools/tier1/protocolTools.js +2 -2
- package/dist/probeChat.d.ts +12 -0
- package/dist/probeChat.js +14 -0
- package/dist/runtime/PromptBuilder.js +4 -1
- package/dist/runtime/agreementContext.d.ts +5 -0
- package/dist/runtime/agreementContext.js +75 -0
- package/dist/runtime/mandateDeclaration.d.ts +1 -1
- package/dist/runtime/mandateDeclaration.js +4 -4
- package/dist/runtime/runTurn.js +3 -2
- package/dist/runtime/wakeEffects.d.ts +5 -0
- package/dist/runtime/wakeEffects.js +14 -1
- package/dist/tools/capabilityAdapter.js +1 -0
- package/dist/types.d.ts +10 -0
- package/package.json +2 -2
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const row = (value) => value && typeof value === 'object' ? value : {};
|
|
2
|
+
/** Enrich each wake from the agreement it actually names, never from the room's
|
|
3
|
+
* latest deal. Reads use the agent's credentials; no grants are inferred here. */
|
|
4
|
+
export async function withAgreementContext(event, read) {
|
|
5
|
+
const reads = new Map();
|
|
6
|
+
const context = (id) => {
|
|
7
|
+
if (!reads.has(id))
|
|
8
|
+
reads.set(id, (async () => {
|
|
9
|
+
try {
|
|
10
|
+
let timer;
|
|
11
|
+
const agreement = row(await Promise.race([
|
|
12
|
+
read(id),
|
|
13
|
+
new Promise((_, reject) => {
|
|
14
|
+
timer = setTimeout(() => reject(new Error('Agreement read timed out')), 5_000);
|
|
15
|
+
}),
|
|
16
|
+
]).finally(() => { if (timer)
|
|
17
|
+
clearTimeout(timer); }));
|
|
18
|
+
if (agreement.agreementId !== id)
|
|
19
|
+
throw new Error('Agreement is unavailable');
|
|
20
|
+
const terms = row(agreement.terms);
|
|
21
|
+
const usage = row(agreement.conversationUsage);
|
|
22
|
+
const money = row(agreement.money);
|
|
23
|
+
const limit = typeof terms.conversationAllowance === 'number' ? terms.conversationAllowance : null;
|
|
24
|
+
const used = typeof usage.messages === 'number' ? usage.messages : 0;
|
|
25
|
+
return {
|
|
26
|
+
agreementId: id, available: true,
|
|
27
|
+
freeConversation: row(agreement.metadata).freeConversation === true,
|
|
28
|
+
status: agreement.status,
|
|
29
|
+
relationship: agreement.engagementKind === 'link' || row(agreement.metadata).freeConversation === true,
|
|
30
|
+
interactionMode: terms.interactionMode ?? 'both',
|
|
31
|
+
parentAgreementId: agreement.parentAgreementId ?? null,
|
|
32
|
+
allowanceScope: terms.conversationAllowanceScope ?? 'direct',
|
|
33
|
+
scope: terms.description,
|
|
34
|
+
lifecycle: terms.lifecycle,
|
|
35
|
+
expiresAt: terms.expiresAt ?? null,
|
|
36
|
+
maxTasks: terms.maxExecutions ?? null,
|
|
37
|
+
wakeCeiling: terms.wakeCeiling ?? null,
|
|
38
|
+
messageLimit: limit,
|
|
39
|
+
messagesUsed: used,
|
|
40
|
+
messagesRemaining: limit === null ? null : Math.max(0, limit - used),
|
|
41
|
+
price: money.price ?? 0,
|
|
42
|
+
billing: terms.billing ?? 'total',
|
|
43
|
+
paymentStatus: money.paymentStatus,
|
|
44
|
+
access: 'Tool and resource access requires separate grants.',
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return { agreementId: id, available: false,
|
|
49
|
+
instruction: 'Agreement terms could not be read. Verify authorization before starting new service work or making commitments.' };
|
|
50
|
+
}
|
|
51
|
+
})());
|
|
52
|
+
return reads.get(id);
|
|
53
|
+
};
|
|
54
|
+
const enrich = async (value) => {
|
|
55
|
+
const frame = row(value);
|
|
56
|
+
if (frame.type === 'batch' && Array.isArray(frame.events)) {
|
|
57
|
+
return { ...frame, events: await Promise.all(frame.events.map(enrich)) };
|
|
58
|
+
}
|
|
59
|
+
const resource = row(frame.resource);
|
|
60
|
+
const result = row(frame.result);
|
|
61
|
+
const id = frame.agreementId ?? resource.agreementId ?? result.agreementId ?? row(result.agreement).agreementId;
|
|
62
|
+
if (typeof id !== 'string' || !id)
|
|
63
|
+
return value;
|
|
64
|
+
return { ...frame, agreementContext: await context(id) };
|
|
65
|
+
};
|
|
66
|
+
return enrich(event);
|
|
67
|
+
}
|
|
68
|
+
/** Free chat supplies conversation context, never consent to another engagement. */
|
|
69
|
+
export function permitsAutomaticMandate(event) {
|
|
70
|
+
const frame = row(event);
|
|
71
|
+
if (frame.type === 'batch' && Array.isArray(frame.events))
|
|
72
|
+
return frame.events.every(permitsAutomaticMandate);
|
|
73
|
+
const context = row(frame.agreementContext);
|
|
74
|
+
return context.relationship !== true && context.freeConversation !== true && context.available !== false;
|
|
75
|
+
}
|
|
@@ -6,4 +6,4 @@ import type { ToolManager } from '../tools/ToolManager.js';
|
|
|
6
6
|
* declaration, the model already made one, or this wake is not running inside a
|
|
7
7
|
* job at all.
|
|
8
8
|
*/
|
|
9
|
-
export declare function withDeclaredMandate(args: Record<string, unknown>, toolName: string | null | undefined, toolManager: ToolManager | undefined, activeAgreementId: string | null | undefined): Record<string, unknown>;
|
|
9
|
+
export declare function withDeclaredMandate(args: Record<string, unknown>, toolName: string | null | undefined, toolManager: ToolManager | undefined, activeAgreementId: string | null | undefined, allowSpendingMandate?: boolean): Record<string, unknown>;
|
|
@@ -30,14 +30,14 @@
|
|
|
30
30
|
*/
|
|
31
31
|
const MANDATE_PARAM_NAMES = ['mandateAgreementId', 'parentAgreementId'];
|
|
32
32
|
/** The mandate parameter this tool declares, if it declares one. */
|
|
33
|
-
function mandateParamOf(toolName, toolManager) {
|
|
33
|
+
function mandateParamOf(toolName, toolManager, allowSpendingMandate = true) {
|
|
34
34
|
if (!toolName)
|
|
35
35
|
return null;
|
|
36
36
|
const schema = toolManager?.getTool?.(toolName)?.schema;
|
|
37
37
|
const properties = schema?.function?.parameters?.properties;
|
|
38
38
|
if (!properties)
|
|
39
39
|
return null;
|
|
40
|
-
for (const name of MANDATE_PARAM_NAMES) {
|
|
40
|
+
for (const name of (allowSpendingMandate ? MANDATE_PARAM_NAMES : ['parentAgreementId'])) {
|
|
41
41
|
if (Object.prototype.hasOwnProperty.call(properties, name))
|
|
42
42
|
return name;
|
|
43
43
|
}
|
|
@@ -50,10 +50,10 @@ function mandateParamOf(toolName, toolManager) {
|
|
|
50
50
|
* declaration, the model already made one, or this wake is not running inside a
|
|
51
51
|
* job at all.
|
|
52
52
|
*/
|
|
53
|
-
export function withDeclaredMandate(args, toolName, toolManager, activeAgreementId) {
|
|
53
|
+
export function withDeclaredMandate(args, toolName, toolManager, activeAgreementId, allowSpendingMandate = true) {
|
|
54
54
|
if (!activeAgreementId)
|
|
55
55
|
return args;
|
|
56
|
-
const param = mandateParamOf(toolName, toolManager);
|
|
56
|
+
const param = mandateParamOf(toolName, toolManager, allowSpendingMandate);
|
|
57
57
|
if (!param)
|
|
58
58
|
return args;
|
|
59
59
|
if (args[param] !== undefined)
|
package/dist/runtime/runTurn.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { permitsAutomaticMandate } from './agreementContext.js';
|
|
1
2
|
import { isAgreementId } from '@ziggs-ai/api-client';
|
|
2
3
|
import { outcomeFromActionResult } from './buildOutcome.js';
|
|
3
4
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
@@ -267,7 +268,7 @@ export async function runTurn(input) {
|
|
|
267
268
|
catch { }
|
|
268
269
|
// Say which job this is part of, when the tool asks and the model did
|
|
269
270
|
// not. The runtime knows; the model would have to be told.
|
|
270
|
-
args = withDeclaredMandate(args, toolName, toolManager, ctx.activeAgreementId);
|
|
271
|
+
args = withDeclaredMandate(args, toolName, toolManager, ctx.activeAgreementId, permitsAutomaticMandate(incomingEvent));
|
|
271
272
|
const decision = { action: matchingAction, tool: toolName, args };
|
|
272
273
|
const result = await executeDecision(decision, actionDef, effWithTrace, sessionId, memory, incomingEvent, addToolUsage, ctx.identity.agentId, Array.isArray(ctxObj.agreements)
|
|
273
274
|
? ctxObj.agreements
|
|
@@ -324,7 +325,7 @@ export async function runTurn(input) {
|
|
|
324
325
|
// Same mandate declaration as the tool-call path above. Both routes reach
|
|
325
326
|
// the same tools, so filling it on only one would make the excuse depend on
|
|
326
327
|
// which shape the model happened to answer in.
|
|
327
|
-
decision.args = withDeclaredMandate((decision.args ?? {}), actionDef?.tool, toolManager, ctx.activeAgreementId);
|
|
328
|
+
decision.args = withDeclaredMandate((decision.args ?? {}), actionDef?.tool, toolManager, ctx.activeAgreementId, permitsAutomaticMandate(incomingEvent));
|
|
328
329
|
if (decision.thought)
|
|
329
330
|
await emitThought(decision.thought);
|
|
330
331
|
// 2-call streaming: if this is a respond action (has receiverId, no bound tool),
|
|
@@ -7,6 +7,11 @@ export interface WorkScope {
|
|
|
7
7
|
export declare function uniqueWorkScope(scopes: WorkScope[]): WorkScope;
|
|
8
8
|
/** Only structured host/backend fields are authority; message text and timer reasons are not. */
|
|
9
9
|
export declare function workScopeFromWake(event: unknown, sessionId?: string): WorkScope;
|
|
10
|
+
/** One packet per distinct work item in a batch; never union their authority. */
|
|
11
|
+
export declare function contextScopesFromWake(event: unknown, sessionId: string): Array<WorkScope & {
|
|
12
|
+
messageId?: string;
|
|
13
|
+
artifactId?: string;
|
|
14
|
+
}>;
|
|
10
15
|
/** Per-wake observation, including effects nested inside tools and cross-room sends. */
|
|
11
16
|
export declare class WakeEffects {
|
|
12
17
|
private readonly initialScope;
|
|
@@ -25,9 +25,22 @@ export function workScopeFromWake(event, sessionId) {
|
|
|
25
25
|
const agreementId = id(rec.agreementId) ?? id(resource.agreementId) ?? id(task.agreementId)
|
|
26
26
|
?? agreementIdFromLane(rec.chatId) ?? agreementIdFromLane(resource.chatId)
|
|
27
27
|
?? agreementIdFromLane(sessionId) ?? undefined;
|
|
28
|
-
const taskId = id(rec.taskId) ?? id(resource.taskId) ?? id(task.taskId);
|
|
28
|
+
const taskId = id(rec.taskId) ?? id(resource.taskId) ?? id(task.taskId) ?? (resource.kind === 'task' ? id(resource.resourceId) : undefined);
|
|
29
29
|
return { ...(agreementId ? { agreementId } : {}), ...(taskId ? { taskId } : {}) };
|
|
30
30
|
}
|
|
31
|
+
/** One packet per distinct work item in a batch; never union their authority. */
|
|
32
|
+
export function contextScopesFromWake(event, sessionId) {
|
|
33
|
+
const frame = record(event);
|
|
34
|
+
if (frame.type === 'batch' && Array.isArray(frame.events)) {
|
|
35
|
+
return [...new Map(frame.events.flatMap(e => contextScopesFromWake(e, sessionId)).map(scope => [JSON.stringify(scope), scope])).values()];
|
|
36
|
+
}
|
|
37
|
+
const scope = workScopeFromWake(event, sessionId);
|
|
38
|
+
const messageId = frame.type === 'message' ? id(frame.messageId) : undefined;
|
|
39
|
+
const resource = record(frame.resource);
|
|
40
|
+
const artifactId = resource.kind === 'artifact' ? id(resource.resourceId) : undefined;
|
|
41
|
+
return scope.agreementId || scope.taskId || messageId || artifactId
|
|
42
|
+
? [{ ...scope, ...(messageId ? { messageId } : {}), ...(artifactId ? { artifactId } : {}) }] : [];
|
|
43
|
+
}
|
|
31
44
|
const TASK_WRITES = new Set(['task_create', 'task_set_result', 'task_update_plan_step', 'task_replace_plan']);
|
|
32
45
|
/** Per-wake observation, including effects nested inside tools and cross-room sends. */
|
|
33
46
|
export class WakeEffects {
|
|
@@ -35,6 +35,7 @@ export function toolFromCapability(cap) {
|
|
|
35
35
|
baseUrl: process.env.BACKEND_URL || process.env.ZIGGS_BACKEND_URL || undefined,
|
|
36
36
|
webUrl: process.env.ZIGGS_WEB_URL,
|
|
37
37
|
surface: 'sdk',
|
|
38
|
+
serviceAgreementId: typeof ctx.serviceAgreementId === 'string' ? ctx.serviceAgreementId : undefined,
|
|
38
39
|
};
|
|
39
40
|
return cap.handler(args, env);
|
|
40
41
|
}, { description: cap.descriptions.sdk, ...(cap.sdkOptions ?? {}) });
|
package/dist/types.d.ts
CHANGED
|
@@ -370,6 +370,12 @@ export interface ContextSnapshot {
|
|
|
370
370
|
[key: string]: unknown;
|
|
371
371
|
}
|
|
372
372
|
export interface ReadContextOpts {
|
|
373
|
+
workScopes?: Array<{
|
|
374
|
+
agreementId?: string;
|
|
375
|
+
taskId?: string;
|
|
376
|
+
messageId?: string;
|
|
377
|
+
artifactId?: string;
|
|
378
|
+
}>;
|
|
373
379
|
maxMessages?: number;
|
|
374
380
|
}
|
|
375
381
|
/**
|
|
@@ -475,6 +481,8 @@ export type Effect = {
|
|
|
475
481
|
} | {
|
|
476
482
|
kind: 'tool-call';
|
|
477
483
|
sessionId: string;
|
|
484
|
+
/** Exact work scope from this wake, independent of connection delegation. */
|
|
485
|
+
serviceAgreementId?: string;
|
|
478
486
|
name: string;
|
|
479
487
|
args: unknown;
|
|
480
488
|
memory?: MemoryStore;
|
|
@@ -506,11 +514,13 @@ export type Effect = {
|
|
|
506
514
|
receiverId?: string;
|
|
507
515
|
text: string;
|
|
508
516
|
messageId?: string;
|
|
517
|
+
conversationAgreementId?: string;
|
|
509
518
|
} | {
|
|
510
519
|
kind: 'record-event';
|
|
511
520
|
sessionId: string;
|
|
512
521
|
entry: RecordedEntry;
|
|
513
522
|
idempotencyKey?: string;
|
|
523
|
+
serviceAgreementId?: string;
|
|
514
524
|
};
|
|
515
525
|
/**
|
|
516
526
|
* Typed result map. With this shape, `await eff({ kind: 'read-context', .. })`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.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.
|
|
29
|
+
"@ziggs-ai/api-client": "0.23.1",
|
|
30
30
|
"ajv": "^8.17.1",
|
|
31
31
|
"dotenv": "^17.2.3",
|
|
32
32
|
"openai": "^4.0.0",
|