@ziggs-ai/agent-sdk 0.7.2 → 0.8.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/ClaudeSdkAgent.d.ts +15 -0
- package/dist/agent/ClaudeSdkAgent.js +14 -10
- package/dist/agent/claudeCognition.js +15 -5
- package/dist/ingress/normalizeIncoming.d.ts +8 -1
- package/dist/ingress/normalizeIncoming.js +37 -7
- package/dist/server/agreements/AgreementService.d.ts +6 -4
- package/dist/server/agreements/AgreementService.js +4 -2
- package/package.json +2 -2
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
2
2
|
import type { Workflow } from '../types.js';
|
|
3
3
|
import type { ToolManager } from '../tools/ToolManager.js';
|
|
4
|
+
import { type RawEvent } from '../runtime/buildOutcome.js';
|
|
4
5
|
import type { TickInput, TickOutput } from './Agent.js';
|
|
6
|
+
/**
|
|
7
|
+
* ZIG-1035 / ZIG-1052: status notices must not spend a Claude turn answering
|
|
8
|
+
* nobody. Real work wakes arrive as chat `message`, synthetic `task_result`
|
|
9
|
+
* from `wakeTaskAssignment`, or `agreement_lifecycle` (hire / proposal
|
|
10
|
+
* resolution — the FSM kickoffs on the same event; Claude must act too).
|
|
11
|
+
*
|
|
12
|
+
* Intentionally not mirrored as an FSM "notice skip": the FSM already no-ops
|
|
13
|
+
* enter-only outcomes in AgentMachine; `agreement_lifecycle` never produces
|
|
14
|
+
* `enter`, so hire wakes always step. Claude's filter is narrower — pure
|
|
15
|
+
* `notification` only.
|
|
16
|
+
*
|
|
17
|
+
* Empty / missing batch → notice-only (do not burn a turn on a malformed wake).
|
|
18
|
+
*/
|
|
19
|
+
export declare function isNoticeOnlyWake(event: RawEvent | undefined): boolean;
|
|
5
20
|
export type CognitionKind = 'fsm' | 'claude-sdk';
|
|
6
21
|
export interface ClaudeSdkAgentOptions {
|
|
7
22
|
workflow: Workflow;
|
|
@@ -9,19 +9,23 @@ import { claudeQueryOptions, buildClaudeEventPrompt, summarizeContext, extractAs
|
|
|
9
9
|
import { assertHostedAgentZiggsTools } from './hostedAgentConnection.js';
|
|
10
10
|
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
11
11
|
/**
|
|
12
|
-
* ZIG-1035
|
|
13
|
-
* nobody. Real work wakes arrive as chat `message
|
|
14
|
-
* from `wakeTaskAssignment` (
|
|
15
|
-
*
|
|
12
|
+
* ZIG-1035 / ZIG-1052: status notices must not spend a Claude turn answering
|
|
13
|
+
* nobody. Real work wakes arrive as chat `message`, synthetic `task_result`
|
|
14
|
+
* from `wakeTaskAssignment`, or `agreement_lifecycle` (hire / proposal
|
|
15
|
+
* resolution — the FSM kickoffs on the same event; Claude must act too).
|
|
16
|
+
*
|
|
17
|
+
* Intentionally not mirrored as an FSM "notice skip": the FSM already no-ops
|
|
18
|
+
* enter-only outcomes in AgentMachine; `agreement_lifecycle` never produces
|
|
19
|
+
* `enter`, so hire wakes always step. Claude's filter is narrower — pure
|
|
20
|
+
* `notification` only.
|
|
21
|
+
*
|
|
22
|
+
* Empty / missing batch → notice-only (do not burn a turn on a malformed wake).
|
|
16
23
|
*/
|
|
17
|
-
function isNoticeOnlyWake(event) {
|
|
24
|
+
export function isNoticeOnlyWake(event) {
|
|
18
25
|
const events = getBatchEvents(event);
|
|
19
26
|
if (events.length === 0)
|
|
20
|
-
return
|
|
21
|
-
return events.every((ev) =>
|
|
22
|
-
const t = ev?.type;
|
|
23
|
-
return t === 'notification' || t === 'agreement_lifecycle';
|
|
24
|
-
});
|
|
27
|
+
return true;
|
|
28
|
+
return events.every((ev) => ev?.type === 'notification');
|
|
25
29
|
}
|
|
26
30
|
const DEFAULT_STATE = 'ready';
|
|
27
31
|
/**
|
|
@@ -72,17 +72,27 @@ export function summarizeContext(snap) {
|
|
|
72
72
|
function renderEventLines(event, lines) {
|
|
73
73
|
if (event?.type)
|
|
74
74
|
lines.push(`Event type: ${event.type}`);
|
|
75
|
-
// ZIG-1035:
|
|
75
|
+
// ZIG-1035 / ZIG-1052: notifications are not counterparty speech.
|
|
76
|
+
// agreement_lifecycle is a work signal (hire approval) — label it as such.
|
|
76
77
|
if (event?.text) {
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
event.entryType === 'notification'
|
|
80
|
-
|
|
78
|
+
const label = event.type === 'agreement_lifecycle'
|
|
79
|
+
? 'Agreement lifecycle'
|
|
80
|
+
: event.type === 'notification' || event.entryType === 'notification'
|
|
81
|
+
? 'Notification'
|
|
82
|
+
: 'Message';
|
|
83
|
+
lines.push(`${label}: ${event.text}`);
|
|
81
84
|
}
|
|
82
85
|
if (event?.senderId)
|
|
83
86
|
lines.push(`Sender: ${event.senderId}`);
|
|
84
87
|
if (event?.operation)
|
|
85
88
|
lines.push(`Operation: ${event.operation}`);
|
|
89
|
+
if (event?.type === 'agreement_lifecycle' &&
|
|
90
|
+
(event.operation === 'proposal_approved' || event.operation === 'proposal_approved_execute')) {
|
|
91
|
+
lines.push('Work signal: proposal approved. If you proposed this agreement, spawn the first task (task_create) under it now. If you are the hired provider, begin fulfilling per the agreement — do not ignore this wake.');
|
|
92
|
+
}
|
|
93
|
+
if (typeof event?.agreementId === 'string' && event.agreementId) {
|
|
94
|
+
lines.push(`Agreement: ${event.agreementId}`);
|
|
95
|
+
}
|
|
86
96
|
// ZIG-832: surface the task/agreement this event carries. Without it the brain
|
|
87
97
|
// can't tell WHICH task to update/complete (workers otherwise stall asking for
|
|
88
98
|
// their own taskId) and can't see whether the referenced step already ran or
|
|
@@ -64,7 +64,14 @@ interface WireMetadata {
|
|
|
64
64
|
service?: {
|
|
65
65
|
task?: WireTask;
|
|
66
66
|
operation?: string;
|
|
67
|
-
agreement?:
|
|
67
|
+
agreement?: {
|
|
68
|
+
agreementId?: string;
|
|
69
|
+
status?: string;
|
|
70
|
+
proposal?: {
|
|
71
|
+
status?: string;
|
|
72
|
+
};
|
|
73
|
+
parties?: WireParties;
|
|
74
|
+
};
|
|
68
75
|
agreementId?: string;
|
|
69
76
|
};
|
|
70
77
|
[key: string]: unknown;
|
|
@@ -19,12 +19,41 @@ function isTaskRelated(metadata, taskData) {
|
|
|
19
19
|
|| contentType === 'task' || contentType === 'task_update'
|
|
20
20
|
|| Boolean(taskData.state || taskData.proposal || taskData.parentTaskId || taskData.executorId || taskData.agentId || taskData.payerId || taskData.createdBy));
|
|
21
21
|
}
|
|
22
|
+
function wireOperation(metadata) {
|
|
23
|
+
const op = metadata.service?.operation ?? metadata.operation;
|
|
24
|
+
return typeof op === 'string' ? op : undefined;
|
|
25
|
+
}
|
|
26
|
+
function wireAgreementId(metadata) {
|
|
27
|
+
const raw = metadata.service?.agreementId ??
|
|
28
|
+
metadata.service?.agreement?.agreementId ??
|
|
29
|
+
metadata.agreementId;
|
|
30
|
+
return typeof raw === 'string' ? raw : '';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Self-hire / fully-consented create activates before the chat fan-out lands.
|
|
34
|
+
* The wire still says `proposal_created`, but the embedded agreement is already
|
|
35
|
+
* `active` / proposal `approved`. That is the hire work signal (same as
|
|
36
|
+
* `proposal_approved_execute`) — Claude must not park it as a notice (ZIG-1052).
|
|
37
|
+
*/
|
|
38
|
+
function isAlreadyActivatedProposalCreated(metadata) {
|
|
39
|
+
if (wireOperation(metadata) !== 'proposal_created')
|
|
40
|
+
return false;
|
|
41
|
+
const agr = metadata.service?.agreement;
|
|
42
|
+
if (!agr || typeof agr !== 'object')
|
|
43
|
+
return false;
|
|
44
|
+
const status = agr.status;
|
|
45
|
+
const proposalStatus = agr.proposal?.status;
|
|
46
|
+
return status === 'active' || proposalStatus === 'approved';
|
|
47
|
+
}
|
|
22
48
|
function isAgreementLifecycleNotification(metadata) {
|
|
23
49
|
const entryType = metadata.entryType || 'message';
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
50
|
+
if (entryType !== 'notification')
|
|
51
|
+
return false;
|
|
52
|
+
const operation = wireOperation(metadata);
|
|
53
|
+
if (typeof operation === 'string' && PROPOSAL_RESOLVED_OPERATIONS.has(operation)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
return isAlreadyActivatedProposalCreated(metadata);
|
|
28
57
|
}
|
|
29
58
|
function isTerminalTaskState(state) {
|
|
30
59
|
return state === 'completed' || state === 'failed' || state === 'cancelled';
|
|
@@ -57,9 +86,10 @@ export function normalizeIncomingEvent({ text, metadata = {} }) {
|
|
|
57
86
|
...(entryType ? { entryType } : {}),
|
|
58
87
|
};
|
|
59
88
|
if (isAgreementLifecycleNotification(metadata)) {
|
|
60
|
-
const operation = metadata
|
|
61
|
-
|
|
62
|
-
|
|
89
|
+
const operation = isAlreadyActivatedProposalCreated(metadata)
|
|
90
|
+
? 'proposal_approved_execute'
|
|
91
|
+
: wireOperation(metadata);
|
|
92
|
+
const agreementId = wireAgreementId(metadata);
|
|
63
93
|
return {
|
|
64
94
|
chatId,
|
|
65
95
|
event: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Agreement, type ProposeAgreementData, type ProposeDirectInput, type ProposeBroadcastInput, type PublishOfferPayload, type DelegateAgreementData, type CounterAgreementData, type CreateAgreementBody, type ListAgreementsFilters, type GetMyAgreementsFilters, type ChatLinkType, type ArtifactLinkType, type UserRole } from '@ziggs-ai/api-client';
|
|
1
|
+
import { type Agreement, type ClaimedKind, type ProposeAgreementData, type ProposeDirectInput, type ProposeBroadcastInput, type PublishOfferPayload, type DelegateAgreementData, type CounterAgreementData, type CreateAgreementBody, type ListAgreementsFilters, type GetMyAgreementsFilters, type ChatLinkType, type ArtifactLinkType, type UserRole } from '@ziggs-ai/api-client';
|
|
2
2
|
export declare class AgreementService {
|
|
3
3
|
private creds;
|
|
4
4
|
constructor(operatorKey: string, agentId: string);
|
|
@@ -20,12 +20,14 @@ export declare class AgreementService {
|
|
|
20
20
|
delegate(payload: DelegateAgreementData): Promise<Agreement>;
|
|
21
21
|
respond(agreementId: string, action: 'approve' | 'reject'): Promise<Agreement>;
|
|
22
22
|
/**
|
|
23
|
-
* ZIG-1021 — claim any open broadcast (quest, standing offer,
|
|
24
|
-
* Routing (offer vs agreement claim endpoint) is decided in
|
|
23
|
+
* ZIG-1021 — claim any open broadcast (quest, standing offer, hand-off,
|
|
24
|
+
* link invite). Routing (offer vs agreement claim endpoint) is decided in
|
|
25
|
+
* the shared flow; `kind` is the api-client ClaimedKind so this signature
|
|
26
|
+
* can't drift from the flow again (a 'hand-off' addition broke the build).
|
|
25
27
|
*/
|
|
26
28
|
claim(agreementId: string): Promise<{
|
|
27
29
|
agreement: Agreement;
|
|
28
|
-
kind:
|
|
30
|
+
kind: ClaimedKind;
|
|
29
31
|
}>;
|
|
30
32
|
/**
|
|
31
33
|
* ZIG-1022 — a link proposal is an agreement (engagementKind 'link') to one
|
|
@@ -38,8 +38,10 @@ export class AgreementService {
|
|
|
38
38
|
return respondToAgreement(agreementId, action, this.creds);
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
* ZIG-1021 — claim any open broadcast (quest, standing offer,
|
|
42
|
-
* Routing (offer vs agreement claim endpoint) is decided in
|
|
41
|
+
* ZIG-1021 — claim any open broadcast (quest, standing offer, hand-off,
|
|
42
|
+
* link invite). Routing (offer vs agreement claim endpoint) is decided in
|
|
43
|
+
* the shared flow; `kind` is the api-client ClaimedKind so this signature
|
|
44
|
+
* can't drift from the flow again (a 'hand-off' addition broke the build).
|
|
43
45
|
*/
|
|
44
46
|
claim(agreementId) {
|
|
45
47
|
return claimOpenAgreement(agreementId, this.creds);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ziggs-ai/agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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.7.1",
|
|
30
30
|
"ajv": "^8.17.1",
|
|
31
31
|
"dotenv": "^17.2.3",
|
|
32
32
|
"openai": "^4.0.0",
|