@ziggs-ai/agent-sdk 0.10.7 → 0.11.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 +11 -11
- package/dist/AgentHost.d.ts +15 -15
- package/dist/AgentHost.js +22 -22
- package/dist/adapters/AnthropicAdapter.js +1 -1
- package/dist/adapters/McpAdapter.d.ts +10 -10
- package/dist/adapters/McpAdapter.js +33 -21
- package/dist/adapters/OpenAIAdapter.js +1 -1
- package/dist/agent/Agent.d.ts +2 -2
- package/dist/agent/ClaudeSdkAgent.d.ts +6 -6
- package/dist/agent/ClaudeSdkAgent.js +25 -25
- package/dist/agent/claudeCognition.d.ts +3 -3
- package/dist/agent/claudeCognition.js +7 -7
- package/dist/agent/claudeSdkTools.d.ts +3 -3
- package/dist/agent/claudeSdkTools.js +9 -9
- package/dist/agent/hostedAgentConnection.d.ts +1 -1
- package/dist/agent/hostedAgentConnection.js +1 -1
- package/dist/agent/toolManagerToSdkMcp.d.ts +1 -1
- package/dist/agent/toolManagerToSdkMcp.js +2 -2
- package/dist/context/applyEffects.js +1 -1
- package/dist/defineAgent.js +2 -2
- package/dist/formatters/HistoryFormatter.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -5
- package/dist/ingress/normalizeIncoming.d.ts +1 -1
- package/dist/ingress/normalizeIncoming.js +7 -7
- package/dist/pricing/fleetDefaults.d.ts +3 -3
- package/dist/pricing/fleetDefaults.js +3 -3
- package/dist/pricing/fleetEvalFree.d.ts +1 -1
- package/dist/pricing/fleetEvalFree.js +1 -1
- package/dist/pricing/fleetFreeTierA.gen.d.ts +1 -1
- package/dist/pricing/fleetFreeTierA.gen.js +1 -1
- package/dist/pricing/fleetTierByAgentId.gen.d.ts +1 -1
- package/dist/runtime/AgentMachine.d.ts +1 -1
- package/dist/runtime/AgentMachine.js +8 -8
- package/dist/runtime/PromptBuilder.d.ts +2 -2
- package/dist/runtime/PromptBuilder.js +3 -3
- package/dist/runtime/bootstrapCtx.d.ts +1 -1
- package/dist/runtime/bootstrapCtx.js +2 -2
- package/dist/runtime/buildOutcome.d.ts +1 -1
- package/dist/runtime/buildOutcome.js +4 -4
- package/dist/runtime/defaults.d.ts +5 -5
- package/dist/runtime/defaults.js +4 -4
- package/dist/runtime/deliveryWriteKeys.d.ts +1 -1
- package/dist/runtime/deliveryWriteKeys.js +3 -3
- package/dist/runtime/kickoff.d.ts +3 -3
- package/dist/runtime/kickoff.js +3 -3
- package/dist/runtime/runMechanical.d.ts +1 -1
- package/dist/runtime/runMechanical.js +1 -1
- package/dist/runtime/runTurn.d.ts +1 -1
- package/dist/runtime/runTurn.js +10 -10
- package/dist/runtime/taskBookkeeping.d.ts +3 -3
- package/dist/runtime/taskBookkeeping.js +3 -3
- package/dist/runtime/taskIntake.js +2 -2
- package/dist/server/ConnectionPool.js +1 -1
- package/dist/server/EventQueue.d.ts +1 -1
- package/dist/server/EventQueue.js +1 -1
- package/dist/server/SeenMessages.d.ts +2 -2
- package/dist/server/SeenMessages.js +2 -2
- package/dist/server/ZiggsEffectHandler.d.ts +2 -2
- package/dist/server/ZiggsEffectHandler.js +8 -8
- package/dist/server/agreements/AgreementService.d.ts +3 -8
- package/dist/server/agreements/AgreementService.js +4 -7
- package/dist/server/inboxLoop.d.ts +5 -5
- package/dist/server/inboxLoop.js +21 -10
- package/dist/server/questMatch.d.ts +1 -1
- package/dist/server/questMatch.js +1 -1
- package/dist/server/runLauncher.js +3 -3
- package/dist/server/tools/index.d.ts +1 -0
- package/dist/server/tools/index.js +7 -6
- package/dist/server/tools/tier1/protocolRunner.d.ts +1 -1
- package/dist/server/tools/tier1/protocolRunner.js +19 -19
- package/dist/server/tools/tier1/protocolTools.js +5 -4
- package/dist/server/tools/tier2/artifactTools.js +2 -2
- package/dist/server/tools/tier2/chatTools.js +2 -2
- package/dist/server/tools/tier2/connectionTools.js +3 -3
- package/dist/server/tools/tier2/contextTools.js +1 -1
- package/dist/server/tools/tier2/discoveryTools.js +2 -2
- package/dist/server/tools/tier2/grantsTools.js +1 -1
- package/dist/server/tools/tier2/linkTools.js +3 -3
- package/dist/server/tools/tier2/marketplaceTools.js +1 -1
- package/dist/server/tools/tier2/mcpConnectionTools.d.ts +4 -0
- package/dist/server/tools/tier2/mcpConnectionTools.js +136 -0
- package/dist/server/tools/tier2/paymentTools.js +1 -1
- package/dist/shared/operatorKeyClaims.d.ts +2 -2
- package/dist/shared/operatorKeyClaims.js +1 -1
- package/dist/tasks/protocolRegistry.d.ts +1 -1
- package/dist/tasks/protocolRegistry.js +1 -1
- package/dist/tools/ToolManager.js +1 -1
- package/dist/tools/capabilityAdapter.d.ts +1 -1
- package/dist/tools/capabilityAdapter.js +3 -3
- package/dist/tools/defineTool.js +1 -1
- package/dist/tools/recordReport.d.ts +3 -3
- package/dist/tools/recordReport.js +3 -3
- package/dist/types.d.ts +17 -17
- package/package.json +3 -3
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reserved key for coordinator-side pending/collected state when the lane has
|
|
3
3
|
* an active agreement but no assigned parent task yet (kickoff → spawn).
|
|
4
|
-
* Never deleted by task-closed of a real taskId
|
|
4
|
+
* Never deleted by task-closed of a real taskId.
|
|
5
5
|
*/
|
|
6
6
|
export const LANE_BOOK_KEY = '__lane__';
|
|
7
7
|
export function emptyTaskBook(agreementId = null) {
|
|
@@ -101,9 +101,9 @@ export function removeTaskBook(ctx, taskId) {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
-
* Migrate a pre-
|
|
104
|
+
* Migrate a pre- persisted ctx (lane-level pendingSubtasks /
|
|
105
105
|
* collectedResults / delegatedAgreementIds) into the tasks map.
|
|
106
|
-
*
|
|
106
|
+
* the deprecated lane aggregates are no longer auto-synced —
|
|
107
107
|
* readers use allPendingSubtasks / allCollectedResults / allDelegatedAgreementIds.
|
|
108
108
|
* This migrator stays so a session persisted before the tasks map still boots.
|
|
109
109
|
*/
|
|
@@ -49,7 +49,7 @@ export function buildTaskIntakeState(initial) {
|
|
|
49
49
|
// Function form so a failed task_set_result surfaces as an error outcome
|
|
50
50
|
// (→ dflt error transition) instead of a phantom task-closed.
|
|
51
51
|
produces: (result) => {
|
|
52
|
-
// `state` only
|
|
52
|
+
// `state` only cut `status` from the wire.
|
|
53
53
|
const r = result;
|
|
54
54
|
const state = r?.task?.state ?? r?.state;
|
|
55
55
|
return state === 'completed' || state === 'failed' ? 'task-closed' : 'error';
|
|
@@ -64,7 +64,7 @@ export function buildTaskIntakeState(initial) {
|
|
|
64
64
|
},
|
|
65
65
|
tool: 'task_set_result',
|
|
66
66
|
produces: (result) => {
|
|
67
|
-
// `state` only
|
|
67
|
+
// `state` only cut `status` from the wire.
|
|
68
68
|
const r = result;
|
|
69
69
|
const state = r?.task?.state ?? r?.state;
|
|
70
70
|
return state === 'completed' || state === 'failed' ? 'task-closed' : 'error';
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ConnectionPool — the agents this launcher process hosts.
|
|
3
3
|
*
|
|
4
4
|
* Holds N `AgentHostOptions` configs and connects every one of them at boot
|
|
5
|
-
|
|
5
|
+
*. Each host long-polls its own inbox for the life of the process —
|
|
6
6
|
* there is no agent socket. There is no subset, no cap and no lifecycle policy:
|
|
7
7
|
* a write releasing that poll is the only signal anything needs.
|
|
8
8
|
*
|
|
@@ -8,7 +8,7 @@ export interface EventQueueOptions {
|
|
|
8
8
|
* per laneKey at a time; multiple events arriving while busy are merged
|
|
9
9
|
* into a single { type: 'batch', events: [...] } frame on the next pass.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
11
|
+
* `enqueue` REJECTS when the dispatch failed. It used to log the error
|
|
12
12
|
* and resolve, which made every caller — including the inbox loop, whose next
|
|
13
13
|
* statement is the ack — unable to tell a handled event from a lost one. A
|
|
14
14
|
* caller that has nothing to do with a failure should say so with `.catch()`;
|
|
@@ -5,7 +5,7 @@ import { runtimeLog } from '../shared/runtimeLog.js';
|
|
|
5
5
|
* per laneKey at a time; multiple events arriving while busy are merged
|
|
6
6
|
* into a single { type: 'batch', events: [...] } frame on the next pass.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
8
|
+
* `enqueue` REJECTS when the dispatch failed. It used to log the error
|
|
9
9
|
* and resolve, which made every caller — including the inbox loop, whose next
|
|
10
10
|
* statement is the ack — unable to tell a handled event from a lost one. A
|
|
11
11
|
* caller that has nothing to do with a failure should say so with `.catch()`;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dedupes delivery across push (WS flush) and pull (inbox catch-up).
|
|
3
|
-
*
|
|
3
|
+
* inbox is reconciliation source; stable message ids
|
|
4
4
|
* prevent double-processing when both paths fire for the same row.
|
|
5
5
|
*/
|
|
6
6
|
export declare class SeenMessages {
|
|
@@ -12,7 +12,7 @@ export declare class SeenMessages {
|
|
|
12
12
|
mark(messageId: string | null | undefined): void;
|
|
13
13
|
/**
|
|
14
14
|
* Forget a mark, so the next delivery of the same id is processed rather than
|
|
15
|
-
* skipped.
|
|
15
|
+
* skipped. marking happens BEFORE the work, to hold the door against
|
|
16
16
|
* a concurrent duplicate — which means a failure has to take the mark back, or
|
|
17
17
|
* the redelivery that a held ack buys is silently dropped as a duplicate.
|
|
18
18
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dedupes delivery across push (WS flush) and pull (inbox catch-up).
|
|
3
|
-
*
|
|
3
|
+
* inbox is reconciliation source; stable message ids
|
|
4
4
|
* prevent double-processing when both paths fire for the same row.
|
|
5
5
|
*/
|
|
6
6
|
export class SeenMessages {
|
|
@@ -30,7 +30,7 @@ export class SeenMessages {
|
|
|
30
30
|
}
|
|
31
31
|
/**
|
|
32
32
|
* Forget a mark, so the next delivery of the same id is processed rather than
|
|
33
|
-
* skipped.
|
|
33
|
+
* skipped. marking happens BEFORE the work, to hold the door against
|
|
34
34
|
* a concurrent duplicate — which means a failure has to take the mark back, or
|
|
35
35
|
* the redelivery that a held ack buys is silently dropped as a duplicate.
|
|
36
36
|
*/
|
|
@@ -47,7 +47,7 @@ export interface ZiggsEffectDeps {
|
|
|
47
47
|
effectTap?: (effect: Effect, response: unknown) => void;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
* The single tool-execution path for BOTH cognitions
|
|
50
|
+
* The single tool-execution path for BOTH cognitions.
|
|
51
51
|
*
|
|
52
52
|
* Executing a tool is more than calling its handler: it emits the operation
|
|
53
53
|
* timeline artifacts (started / completed / error) and tool telemetry, and
|
|
@@ -55,7 +55,7 @@ export interface ZiggsEffectDeps {
|
|
|
55
55
|
* `eff({ kind: 'tool-call' })` inside `runTurn`; the Claude Agent SDK bridge
|
|
56
56
|
* (`toolManagerToSdkMcp`) emits the SAME effect — so a hosted Claude-brain
|
|
57
57
|
* agent's tool activity is as observable as an FSM agent's (needed for
|
|
58
|
-
* hired-agent visibility
|
|
58
|
+
* hired-agent visibility). A caller cannot run a tool and skip these
|
|
59
59
|
* side effects — that is the whole point of funneling both paths here.
|
|
60
60
|
*
|
|
61
61
|
* `eff` is threaded into the tool context so eff-backed tools
|
|
@@ -5,7 +5,7 @@ import { buildLlmIngestPayload, buildToolIngestPayload, isTelemetryIngestEnabled
|
|
|
5
5
|
const CONTEXT_CACHE_MAX = 256;
|
|
6
6
|
/**
|
|
7
7
|
* Compose a `ContextSnapshot` for a chatId via the grant-fenced aggregate read
|
|
8
|
-
* (`GET /context/snapshot`,
|
|
8
|
+
* (`GET /context/snapshot`, follow-up). The backend assembles history +
|
|
9
9
|
* agreements + roster through the same `assertScopeAccess` + temporal fence as
|
|
10
10
|
* the per-type context reads, and annotates `*IsYou` / self server-side against
|
|
11
11
|
* the acting agent. This function only preserves the never-throw/degrade
|
|
@@ -75,7 +75,7 @@ async function emitToolOperationArtifact(client, sessionId, phase, payload, idem
|
|
|
75
75
|
const text = `${prefix}:${JSON.stringify(payload)}`;
|
|
76
76
|
try {
|
|
77
77
|
await client.write({
|
|
78
|
-
//
|
|
78
|
+
// an agreement lane (`agrn-…`) is a routing key, not a chat —
|
|
79
79
|
// passing it as chatId asked the backend to write into a chat that does
|
|
80
80
|
// not exist and 403'd every breadcrumb on agreement-lane work.
|
|
81
81
|
...artifactScopeForSession(sessionId),
|
|
@@ -90,7 +90,7 @@ async function emitToolOperationArtifact(client, sessionId, phase, payload, idem
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
|
-
* The single tool-execution path for BOTH cognitions
|
|
93
|
+
* The single tool-execution path for BOTH cognitions.
|
|
94
94
|
*
|
|
95
95
|
* Executing a tool is more than calling its handler: it emits the operation
|
|
96
96
|
* timeline artifacts (started / completed / error) and tool telemetry, and
|
|
@@ -98,7 +98,7 @@ async function emitToolOperationArtifact(client, sessionId, phase, payload, idem
|
|
|
98
98
|
* `eff({ kind: 'tool-call' })` inside `runTurn`; the Claude Agent SDK bridge
|
|
99
99
|
* (`toolManagerToSdkMcp`) emits the SAME effect — so a hosted Claude-brain
|
|
100
100
|
* agent's tool activity is as observable as an FSM agent's (needed for
|
|
101
|
-
* hired-agent visibility
|
|
101
|
+
* hired-agent visibility). A caller cannot run a tool and skip these
|
|
102
102
|
* side effects — that is the whole point of funneling both paths here.
|
|
103
103
|
*
|
|
104
104
|
* `eff` is threaded into the tool context so eff-backed tools
|
|
@@ -109,7 +109,7 @@ export async function executeToolWithSideEffects(deps, eff, effect, roster) {
|
|
|
109
109
|
const toolT0 = Date.now();
|
|
110
110
|
const args = effect.args || {};
|
|
111
111
|
const argsPreview = previewToolArgs(args);
|
|
112
|
-
//
|
|
112
|
+
// #6 — breadcrumbs are best-effort. Awaiting them bracketed every
|
|
113
113
|
// tool call; a slow/wedged artifacts backend stalled the whole wake. Match
|
|
114
114
|
// ClaudeSdkAgent thought writes (fire-and-forget).
|
|
115
115
|
void emitToolOperationArtifact(deps.artifactsClient, effect.sessionId, 'started', {
|
|
@@ -120,7 +120,7 @@ export async function executeToolWithSideEffects(deps, eff, effect, roster) {
|
|
|
120
120
|
try {
|
|
121
121
|
const lastUser = roster.users.find((u) => u.userId || u.id);
|
|
122
122
|
// Accumulate token usage from any nested LLM call the tool makes (llmTool),
|
|
123
|
-
// so it can be folded into the turn's authoritative token count
|
|
123
|
+
// so it can be folded into the turn's authoritative token count.
|
|
124
124
|
let nestedUsage;
|
|
125
125
|
const reportUsage = (u) => {
|
|
126
126
|
if (!u)
|
|
@@ -145,7 +145,7 @@ export async function executeToolWithSideEffects(deps, eff, effect, roster) {
|
|
|
145
145
|
eff,
|
|
146
146
|
agents: roster.agents,
|
|
147
147
|
users: roster.users,
|
|
148
|
-
//
|
|
148
|
+
// #8 — session snapshot already has agreements; protocolRunner
|
|
149
149
|
// used to re-fetch them over HTTP on every spawn/subcontract.
|
|
150
150
|
agreements: roster.agreements ?? [],
|
|
151
151
|
senderId: effect.senderId ?? lastUser?.userId ?? lastUser?.id,
|
|
@@ -286,7 +286,7 @@ export function createZiggsEffectHandler(deps) {
|
|
|
286
286
|
// Roster + agreements come from the cached snapshot (populated by
|
|
287
287
|
// read-context). Both cognitions land here — the FSM via runTurn's
|
|
288
288
|
// executeTool, the Claude Agent SDK via the toolManagerToSdkMcp bridge —
|
|
289
|
-
// so tool side effects are emitted exactly once, in one place
|
|
289
|
+
// so tool side effects are emitted exactly once, in one place.
|
|
290
290
|
const cached = cacheGet(effect.sessionId);
|
|
291
291
|
return executeToolWithSideEffects(deps, handler, effect, {
|
|
292
292
|
agents: cached?.agents || [],
|
|
@@ -20,7 +20,7 @@ export declare class AgreementService {
|
|
|
20
20
|
delegate(payload: DelegateAgreementData): Promise<Agreement>;
|
|
21
21
|
respond(agreementId: string, action: 'approve' | 'reject'): Promise<Agreement>;
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
23
|
+
* claim any open broadcast (quest, standing offer, hand-off,
|
|
24
24
|
* link invite). Routing (offer vs agreement claim endpoint) is decided in
|
|
25
25
|
* the shared flow; `kind` is the api-client ClaimedKind so this signature
|
|
26
26
|
* can't drift from the flow again (a 'hand-off' addition broke the build).
|
|
@@ -30,7 +30,7 @@ export declare class AgreementService {
|
|
|
30
30
|
kind: ClaimedKind;
|
|
31
31
|
}>;
|
|
32
32
|
/**
|
|
33
|
-
*
|
|
33
|
+
* a link proposal is an agreement (engagementKind 'link') to one
|
|
34
34
|
* agent; the target owner approves. Folds the old request_link tool.
|
|
35
35
|
*/
|
|
36
36
|
requestLink(providerId: string, description?: string): Promise<Agreement>;
|
|
@@ -38,7 +38,7 @@ export declare class AgreementService {
|
|
|
38
38
|
getStatus(agreementId: string): Promise<unknown | null>;
|
|
39
39
|
list(filters?: ListAgreementsFilters): Promise<Agreement[]>;
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* despite the name, the default returns every agreement the
|
|
42
42
|
* caller's grant can read in the active org — including ones the caller is
|
|
43
43
|
* not a party to (`isYou` all-false). Pass `{ partyOnly: true }` for only
|
|
44
44
|
* agreements where the caller is a party.
|
|
@@ -59,11 +59,6 @@ export declare class AgreementService {
|
|
|
59
59
|
}>;
|
|
60
60
|
linkToChat(agreementId: string, chatId: string, linkType?: ChatLinkType): Promise<unknown | null>;
|
|
61
61
|
getChats(agreementId: string): Promise<unknown[]>;
|
|
62
|
-
join(agreementId: string): Promise<{
|
|
63
|
-
chatId: string;
|
|
64
|
-
agentId: string | null;
|
|
65
|
-
isNew: boolean;
|
|
66
|
-
}>;
|
|
67
62
|
linkArtifact(agreementId: string, artifactId: string, linkType?: ArtifactLinkType): Promise<unknown | null>;
|
|
68
63
|
getArtifacts(agreementId: string): Promise<unknown[]>;
|
|
69
64
|
linkUser(agreementId: string, userId: string, role: UserRole): Promise<unknown | null>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { proposeAgreement, proposeBroadcast as proposeBroadcastApi, delegateAgreement, respondToAgreement, counterAgreement, claimOpenAgreement, getAgreementStatus, listAgreements, getMyAgreements, getAgreement, publishOffer as publishOfferApi, createAgreement, revokeAgreement, fulfillAgreement, linkAgreementToChat, getChatsForAgreement,
|
|
1
|
+
import { proposeAgreement, proposeBroadcast as proposeBroadcastApi, delegateAgreement, respondToAgreement, counterAgreement, claimOpenAgreement, getAgreementStatus, listAgreements, getMyAgreements, getAgreement, publishOffer as publishOfferApi, createAgreement, revokeAgreement, fulfillAgreement, linkAgreementToChat, getChatsForAgreement, linkArtifactToAgreement, getArtifactsForAgreement, linkUserToAgreement, getUsersForAgreement, } from '@ziggs-ai/api-client';
|
|
2
2
|
export class AgreementService {
|
|
3
3
|
creds;
|
|
4
4
|
constructor(operatorKey, agentId) {
|
|
@@ -38,7 +38,7 @@ export class AgreementService {
|
|
|
38
38
|
return respondToAgreement(agreementId, action, this.creds);
|
|
39
39
|
}
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* claim any open broadcast (quest, standing offer, hand-off,
|
|
42
42
|
* link invite). Routing (offer vs agreement claim endpoint) is decided in
|
|
43
43
|
* the shared flow; `kind` is the api-client ClaimedKind so this signature
|
|
44
44
|
* can't drift from the flow again (a 'hand-off' addition broke the build).
|
|
@@ -47,7 +47,7 @@ export class AgreementService {
|
|
|
47
47
|
return claimOpenAgreement(agreementId, this.creds);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* a link proposal is an agreement (engagementKind 'link') to one
|
|
51
51
|
* agent; the target owner approves. Folds the old request_link tool.
|
|
52
52
|
*/
|
|
53
53
|
async requestLink(providerId, description) {
|
|
@@ -64,7 +64,7 @@ export class AgreementService {
|
|
|
64
64
|
return listAgreements(filters, this.creds);
|
|
65
65
|
}
|
|
66
66
|
/**
|
|
67
|
-
*
|
|
67
|
+
* despite the name, the default returns every agreement the
|
|
68
68
|
* caller's grant can read in the active org — including ones the caller is
|
|
69
69
|
* not a party to (`isYou` all-false). Pass `{ partyOnly: true }` for only
|
|
70
70
|
* agreements where the caller is a party.
|
|
@@ -90,9 +90,6 @@ export class AgreementService {
|
|
|
90
90
|
getChats(agreementId) {
|
|
91
91
|
return getChatsForAgreement(agreementId, this.creds);
|
|
92
92
|
}
|
|
93
|
-
join(agreementId) {
|
|
94
|
-
return joinAgreement(agreementId, this.creds);
|
|
95
|
-
}
|
|
96
93
|
linkArtifact(agreementId, artifactId, linkType = 'produced') {
|
|
97
94
|
return linkArtifactToAgreement(agreementId, artifactId, linkType, this.creds);
|
|
98
95
|
}
|
|
@@ -21,13 +21,13 @@ export interface InboxLoopDeps {
|
|
|
21
21
|
onMessage: (text: string, metadata: Record<string, unknown>) => Promise<void>;
|
|
22
22
|
onResourceEvent: (event: Record<string, unknown>) => Promise<void>;
|
|
23
23
|
/**
|
|
24
|
-
* An open task assigned to this agent
|
|
24
|
+
* An open task assigned to this agent. Delivered from the inbox's
|
|
25
25
|
* own task channel, so work reaches the agent even when no chat row exists
|
|
26
26
|
* for it (chat-less agreement, self-assigned task).
|
|
27
27
|
*/
|
|
28
28
|
onTask?: (task: InboxTaskRef) => Promise<void>;
|
|
29
29
|
/**
|
|
30
|
-
* A marketplace quest doorbell
|
|
30
|
+
* A marketplace quest doorbell. The host MUST triage with a plain
|
|
31
31
|
* string compare and return without an LLM wake on miss — otherwise every
|
|
32
32
|
* public quest burns a full Claude turn per published supplier.
|
|
33
33
|
*/
|
|
@@ -39,16 +39,16 @@ export interface InboxPassResult {
|
|
|
39
39
|
deliveries: number;
|
|
40
40
|
messagesDelivered: number;
|
|
41
41
|
resourceEvents: number;
|
|
42
|
-
/** Assigned open tasks delivered this pass
|
|
42
|
+
/** Assigned open tasks delivered this pass. */
|
|
43
43
|
tasksDelivered: number;
|
|
44
|
-
/** Quest refs triaged this pass
|
|
44
|
+
/** Quest refs triaged this pass — includes misses that only ack. */
|
|
45
45
|
questsTriaged: number;
|
|
46
46
|
/** True when the watermark advanced this pass. */
|
|
47
47
|
acked: boolean;
|
|
48
48
|
/** True when there was more mail than one envelope carries. */
|
|
49
49
|
truncated: boolean;
|
|
50
50
|
/**
|
|
51
|
-
* Handovers into the host that failed this pass
|
|
51
|
+
* Handovers into the host that failed this pass. Non-zero means the
|
|
52
52
|
* watermark was deliberately held, so the same window arrives again.
|
|
53
53
|
*/
|
|
54
54
|
failures: number;
|
package/dist/server/inboxLoop.js
CHANGED
|
@@ -85,7 +85,7 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
|
85
85
|
let tasksDelivered = 0;
|
|
86
86
|
let questsTriaged = 0;
|
|
87
87
|
let failures = 0;
|
|
88
|
-
//
|
|
88
|
+
// a handover that failed must not be acked, and must not be
|
|
89
89
|
// remembered as seen — otherwise the redelivery the held watermark buys is
|
|
90
90
|
// dropped as a duplicate. One failure does not abandon the rest of the
|
|
91
91
|
// envelope: the others are still delivered, and the watermark waits for all.
|
|
@@ -126,7 +126,7 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
|
126
126
|
// Everything that is not chat text is handed over as a resource event, from
|
|
127
127
|
// the delivery itself — the reference already carries the ids the host needs,
|
|
128
128
|
// so nothing has to be re-derived to name what changed.
|
|
129
|
-
// Quests must never take this path
|
|
129
|
+
// Quests must never take this path — even if a pre-cut server
|
|
130
130
|
// left them in `deliveries`, skip so they cannot wake the LLM before triage.
|
|
131
131
|
for (const d of envelope.deliveries) {
|
|
132
132
|
if (d.kind === 'message' || d.kind === 'quest')
|
|
@@ -142,7 +142,7 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
|
142
142
|
...(d.chatId ? { chatId: d.chatId } : {}),
|
|
143
143
|
...(d.agreementId ? { agreementId: d.agreementId } : {}),
|
|
144
144
|
...(d.taskId ? { taskId: d.taskId } : {}),
|
|
145
|
-
//
|
|
145
|
+
// claim/listing wakes carry reason + claimer; host needs
|
|
146
146
|
// both for agrn lane routing, claim kickoff, and chat_open buyer id.
|
|
147
147
|
...(d.reason != null && d.reason !== '' ? { reason: d.reason } : {}),
|
|
148
148
|
...(d.actorId ? { actorId: d.actorId } : {}),
|
|
@@ -151,7 +151,7 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
|
151
151
|
if (handled)
|
|
152
152
|
resourceEvents++;
|
|
153
153
|
}
|
|
154
|
-
//
|
|
154
|
+
// the work channel. An open assigned task is redelivered on every
|
|
155
155
|
// pass until it closes (that IS the durable-wait contract), so dedup on
|
|
156
156
|
// taskId+updatedAt — a genuinely touched task wakes again, an untouched one
|
|
157
157
|
// doesn't storm the lane every long-poll.
|
|
@@ -169,7 +169,7 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
|
169
169
|
if (envelope.truncatedTasks) {
|
|
170
170
|
warn(label, `inbox truncatedTasks=${envelope.truncatedTasks} (more assigned tasks than one pass surfaces — they appear as earlier ones close)`);
|
|
171
171
|
}
|
|
172
|
-
//
|
|
172
|
+
// quest channel. Triage is the host's job (exact string compare);
|
|
173
173
|
// a miss must still count as handled so the watermark can advance with 0 tokens.
|
|
174
174
|
for (const quest of envelope.questsAwaitingMe ?? []) {
|
|
175
175
|
const key = `quest:${quest.agreementId}:${quest.ts}`;
|
|
@@ -211,17 +211,28 @@ export async function pollInboxOnce(deps, waitSeconds = 0, opts = {}) {
|
|
|
211
211
|
// Act, then ack: everything above has been handed to the host, so the
|
|
212
212
|
// watermark may now move past it. A crash before this point redelivers.
|
|
213
213
|
//
|
|
214
|
-
//
|
|
214
|
+
// "act" now means acted, not attempted. A pass with failures holds
|
|
215
215
|
// the watermark so the server redelivers the window — unless `forceAck` says
|
|
216
216
|
// this window has failed too many times in a row and is now poison, in which
|
|
217
217
|
// case it is dropped loudly rather than wedging the agent forever.
|
|
218
218
|
let acked = false;
|
|
219
|
-
|
|
219
|
+
// ZIG-1305 — a capped envelope has unlisted older deliveries behind ackTo;
|
|
220
|
+
// acking would refuse or bury them. Hold until a later uncapped pass.
|
|
221
|
+
if (envelope.deliveriesCapped && envelope.ackTo) {
|
|
222
|
+
warn(label, `holding the watermark at ${envelope.ackTo} — deliveriesCapped; ack would not cover the unlisted tail (ZIG-1305)`);
|
|
223
|
+
}
|
|
224
|
+
else if (envelope.ackTo && (failures === 0 || opts.forceAck)) {
|
|
220
225
|
if (failures > 0) {
|
|
221
226
|
runtimeLog.error(label, `acking a window that failed ${failures} handover(s) — giving up on redelivery to keep the ` +
|
|
222
227
|
`agent alive; this mail is lost (ackTo=${envelope.ackTo})`);
|
|
223
228
|
}
|
|
224
|
-
|
|
229
|
+
const handledResourceIds = [
|
|
230
|
+
...new Set([
|
|
231
|
+
...envelope.deliveries.map((d) => d.resourceId),
|
|
232
|
+
...(envelope.questsAwaitingMe ?? []).map((q) => q.agreementId),
|
|
233
|
+
]),
|
|
234
|
+
].filter((id) => typeof id === 'string' && id.length > 0);
|
|
235
|
+
await inbox.ack(envelope.ackTo, { handledResourceIds });
|
|
225
236
|
acked = true;
|
|
226
237
|
log(label, `acked up to ${envelope.ackTo}`);
|
|
227
238
|
}
|
|
@@ -245,7 +256,7 @@ const ERROR_BACKOFF_BASE_MS = 1_000;
|
|
|
245
256
|
const ERROR_BACKOFF_MAX_MS = 30_000;
|
|
246
257
|
/**
|
|
247
258
|
* How many passes in a row may hold the watermark before the window is treated
|
|
248
|
-
* as poison and acked away
|
|
259
|
+
* as poison and acked away. Three is enough for the failures we have
|
|
249
260
|
* actually seen — a redeployed container, a wedged backend, a transient throw —
|
|
250
261
|
* and short enough that a frame the host can never handle costs three wakes
|
|
251
262
|
* rather than an unbounded loop.
|
|
@@ -289,7 +300,7 @@ export function runInboxLoop(deps, opts = {}) {
|
|
|
289
300
|
if (!running)
|
|
290
301
|
break;
|
|
291
302
|
consecutiveErrors++;
|
|
292
|
-
//
|
|
303
|
+
// a 429 already told us how long to wait, and every refused
|
|
293
304
|
// call still counts against the cap — so the exponential ladder digs
|
|
294
305
|
// the hole deeper (1s, 2s, 4s… of pure refusals). Wait the server's
|
|
295
306
|
// number instead, and do not let a throttle inflate the ladder for the
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* exact-match triage for marketplace quests.
|
|
3
3
|
* Empty match never hits (token-safe default). Comparison is exact after trim.
|
|
4
4
|
*/
|
|
5
5
|
export declare function questExactMatch(match: string, tags: ReadonlyArray<string | null | undefined>): boolean;
|
|
@@ -85,7 +85,7 @@ async function runFleet(configs, { operatorKey, port = process.env.PORT || 8080,
|
|
|
85
85
|
}
|
|
86
86
|
const controlKey = effectiveKey ?? configs.find(c => c.operatorKey)?.operatorKey ?? resolvedPrimaryConfig?.operatorKey;
|
|
87
87
|
if (controlKey) {
|
|
88
|
-
//
|
|
88
|
+
// an agent-bound key half-works in a confusing way — say the big
|
|
89
89
|
// thing once at startup instead of letting N-1 per-agent loops 403.
|
|
90
90
|
const boundWarning = boundKeyFleetWarning(controlKey, pool.size);
|
|
91
91
|
if (boundWarning)
|
|
@@ -104,7 +104,7 @@ async function runFleet(configs, { operatorKey, port = process.env.PORT || 8080,
|
|
|
104
104
|
runtimeLog.warn(label, `Primary agent "${resolvedPrimaryConfig.name || resolvedPrimaryConfig.ownAgentId || 'primary'}" failed to connect at startup: ${err.message} — will retry`);
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
|
-
// Every registered agent connects
|
|
107
|
+
// Every registered agent connects. There is no roster to consult
|
|
108
108
|
// and no reason to defer: an agent this launcher was handed is an agent it
|
|
109
109
|
// hosts, and each host's own inbox long-poll is the only wake signal needed.
|
|
110
110
|
await pool.connectAll();
|
|
@@ -112,7 +112,7 @@ async function runFleet(configs, { operatorKey, port = process.env.PORT || 8080,
|
|
|
112
112
|
if (connected < pool.size) {
|
|
113
113
|
// Say it loudly and with the number. A launcher that silently hosts fewer
|
|
114
114
|
// agents than it was given is exactly how three published, hireable agents
|
|
115
|
-
// ran with no host and nothing noticed
|
|
115
|
+
// ran with no host and nothing noticed.
|
|
116
116
|
runtimeLog.warn(label, `Only ${connected}/${pool.size} agent(s) connected — the rest are registered but unhosted`);
|
|
117
117
|
}
|
|
118
118
|
runtimeLog.info(label, `Ready — ${connected}/${pool.size} agent(s) connected`);
|
|
@@ -25,4 +25,5 @@ export { CONTEXT_TOOLS, contextReadTool, contextDelegateTool, contextExpandReach
|
|
|
25
25
|
export { GRANTS_TOOLS, listGrantsTool } from './tier2/grantsTools.js';
|
|
26
26
|
export { LINK_TOOLS, linkCreateInviteTool, linkListTool, } from './tier2/linkTools.js';
|
|
27
27
|
export { ARTIFACT_TOOLS, recordArtifactTool } from './tier2/artifactTools.js';
|
|
28
|
+
export { MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, } from './tier2/mcpConnectionTools.js';
|
|
28
29
|
export { CHAT_TOOLS, openConversationTool } from './tier2/chatTools.js';
|
|
@@ -24,15 +24,16 @@ export { MARKETPLACE_TOOLS, marketplaceViewTool } from './tier2/marketplaceTools
|
|
|
24
24
|
export { PAYMENT_TOOLS, paymentBalanceTool, paymentTransferTool, paymentWaitForApprovalTool, paymentHoldTool, paymentReleaseTool, paymentResolveWalletTool, paymentIssueGrantTool, paymentAttenuateGrantTool, paymentRevokeGrantTool, } from './tier2/paymentTools.js';
|
|
25
25
|
export { CONNECTION_TOOLS, connectionProxyTool, connectionListGrantsTool, requestConnectionTool, } from './tier2/connectionTools.js';
|
|
26
26
|
export { CONTEXT_TOOLS, contextReadTool, contextDelegateTool, contextExpandReachTool, contextDiscoverGrantableTool, } from './tier2/contextTools.js';
|
|
27
|
-
//
|
|
27
|
+
// one grant lister across every rail (retires context_discover +
|
|
28
28
|
// payment_list_grants). Always-available on the hosted agent — see CLAUDE_SDK_TOOLS.
|
|
29
29
|
export { GRANTS_TOOLS, listGrantsTool } from './tier2/grantsTools.js';
|
|
30
|
-
//
|
|
31
|
-
|
|
30
|
+
// links (agreements with engagementKind 'link') — cross-org reach.
|
|
31
|
+
///1022: the rail is two tools; propose/claim/revoke ride the
|
|
32
32
|
// agreement grammar.
|
|
33
33
|
export { LINK_TOOLS, linkCreateInviteTool, linkListTool, } from './tier2/linkTools.js';
|
|
34
|
-
//
|
|
34
|
+
// deliberate artifact recording (the model decides "record this").
|
|
35
35
|
export { ARTIFACT_TOOLS, recordArtifactTool } from './tier2/artifactTools.js';
|
|
36
|
-
|
|
37
|
-
//
|
|
36
|
+
export { MCP_CONNECTION_TOOLS, mcpToolCallTool, mcpToolsListTool, } from './tier2/mcpConnectionTools.js';
|
|
37
|
+
// Decision: chat_open only — chat listing stays a context-rail read
|
|
38
|
+
// (grant_list scopeKind=chat), so there is no duplicate lister.
|
|
38
39
|
export { CHAT_TOOLS, openConversationTool } from './tier2/chatTools.js';
|
|
@@ -37,6 +37,6 @@ interface ProtocolPayload {
|
|
|
37
37
|
[key: string]: unknown;
|
|
38
38
|
}
|
|
39
39
|
export declare function dispatchProtocolOp(services: Services, payload: ProtocolPayload, chatId: string | null, agents?: unknown[], actingAgentId?: string | null, writeKeys?: DeliveryWriteKeys | null,
|
|
40
|
-
/**
|
|
40
|
+
/** #8 — prefer the cached session snapshot over a fresh HTTP read. */
|
|
41
41
|
cachedAgreements?: unknown[]): Promise<unknown>;
|
|
42
42
|
export {};
|