@ziggs-ai/agent-sdk 0.1.12 → 0.2.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 +14 -0
- package/README.md +41 -2
- package/dist/AgentHost.d.ts +201 -0
- package/dist/AgentHost.js +652 -0
- package/dist/adapters/AnthropicAdapter.d.ts +39 -0
- package/dist/adapters/AnthropicAdapter.js +200 -0
- package/dist/adapters/McpAdapter.d.ts +199 -0
- package/dist/adapters/McpAdapter.js +468 -0
- package/dist/adapters/OpenAIAdapter.d.ts +26 -0
- package/dist/adapters/OpenAIAdapter.js +158 -0
- package/dist/adapters/index.js +2 -0
- package/dist/agent/Agent.d.ts +78 -0
- package/dist/agent/Agent.js +58 -0
- package/dist/agent/ClaudeSdkAgent.d.ts +38 -0
- package/dist/agent/ClaudeSdkAgent.js +322 -0
- package/dist/agent/claudeCognition.d.ts +67 -0
- package/dist/agent/claudeCognition.js +103 -0
- package/dist/agent/claudeSdkProtocol.d.ts +11 -0
- package/dist/agent/claudeSdkTools.d.ts +19 -0
- package/dist/agent/claudeSdkTools.js +57 -0
- package/dist/agent/hostedAgentConnection.d.ts +15 -0
- package/dist/agent/hostedAgentConnection.js +29 -0
- package/dist/agent/toolManagerToSdkMcp.d.ts +12 -0
- package/dist/agent/toolManagerToSdkMcp.js +123 -0
- package/dist/brain/index.d.ts +50 -0
- package/dist/brain/index.js +45 -0
- package/dist/cognition/validateContext.d.ts +11 -0
- package/dist/cognition/validateContext.js +117 -0
- package/dist/context/applyEffects.d.ts +2 -0
- package/dist/context/applyEffects.js +89 -0
- package/dist/context/batch.d.ts +2 -0
- package/dist/context/batch.js +18 -0
- package/dist/context/classifyEnvelope.d.ts +1 -0
- package/dist/context/classifyEnvelope.js +58 -0
- package/dist/context/routingLabels.d.ts +4 -0
- package/dist/context/routingLabels.js +48 -0
- package/dist/defineAgent.d.ts +14 -0
- package/dist/defineAgent.js +68 -0
- package/dist/formatters/AgreementFormatter.d.ts +18 -0
- package/dist/formatters/AgreementFormatter.js +130 -0
- package/dist/formatters/HistoryFormatter.d.ts +26 -0
- package/dist/formatters/HistoryFormatter.js +173 -0
- package/dist/formatters/index.js +2 -0
- package/{src/index.ts → dist/index.d.ts} +7 -53
- package/dist/index.js +66 -0
- package/dist/ingress/normalizeIncoming.d.ts +65 -0
- package/dist/ingress/normalizeIncoming.js +88 -0
- package/dist/memory/MemoryStore.d.ts +55 -0
- package/dist/memory/MemoryStore.js +78 -0
- package/dist/pricing/fleetDefaults.d.ts +46 -0
- package/dist/pricing/fleetDefaults.js +168 -0
- package/dist/pricing/fleetEvalFree.d.ts +7 -0
- package/dist/pricing/fleetEvalFree.js +24 -0
- package/dist/pricing/fleetFreeTierA.gen.d.ts +6 -0
- package/{src/pricing/fleetFreeTierA.gen.ts → dist/pricing/fleetFreeTierA.gen.js} +5 -6
- package/dist/pricing/fleetTierByAgentId.gen.d.ts +7 -0
- package/dist/pricing/fleetTierByAgentId.gen.js +768 -0
- package/dist/runtime/AgentMachine.d.ts +143 -0
- package/dist/runtime/AgentMachine.js +400 -0
- package/dist/runtime/PromptBuilder.d.ts +96 -0
- package/dist/runtime/PromptBuilder.js +439 -0
- package/{src/runtime/bootstrapCtx.ts → dist/runtime/bootstrapCtx.d.ts} +1 -22
- package/dist/runtime/bootstrapCtx.js +37 -0
- package/dist/runtime/buildOutcome.d.ts +68 -0
- package/dist/runtime/buildOutcome.js +464 -0
- package/dist/runtime/defaults.d.ts +54 -0
- package/dist/runtime/defaults.js +47 -0
- package/dist/runtime/deriveRespondsToProposals.d.ts +9 -0
- package/dist/runtime/deriveRespondsToProposals.js +38 -0
- package/dist/runtime/kickoff.d.ts +15 -0
- package/dist/runtime/kickoff.js +112 -0
- package/dist/runtime/runMechanical.d.ts +25 -0
- package/dist/runtime/runMechanical.js +74 -0
- package/dist/runtime/runTurn.d.ts +63 -0
- package/dist/runtime/runTurn.js +800 -0
- package/dist/runtime/validateWorkflow.d.ts +17 -0
- package/dist/runtime/validateWorkflow.js +209 -0
- package/dist/server/ConnectionPool.d.ts +68 -0
- package/dist/server/ConnectionPool.js +166 -0
- package/dist/server/EventQueue.d.ts +33 -0
- package/dist/server/EventQueue.js +98 -0
- package/dist/server/InboxCatchUp.d.ts +24 -0
- package/dist/server/InboxCatchUp.js +213 -0
- package/dist/server/OutboxBuffer.d.ts +33 -0
- package/dist/server/OutboxBuffer.js +68 -0
- package/dist/server/SeenMessages.d.ts +13 -0
- package/dist/server/SeenMessages.js +31 -0
- package/dist/server/StateTimers.d.ts +34 -0
- package/dist/server/StateTimers.js +70 -0
- package/dist/server/ZiggsEffectHandler.d.ts +79 -0
- package/dist/server/ZiggsEffectHandler.js +319 -0
- package/dist/server/agreements/AgreementService.d.ts +50 -0
- package/dist/server/agreements/AgreementService.js +85 -0
- package/dist/server/createHealthServer.d.ts +7 -0
- package/dist/server/createHealthServer.js +75 -0
- package/dist/server/proactive/ProactiveTrigger.d.ts +33 -0
- package/dist/server/proactive/ProactiveTrigger.js +71 -0
- package/dist/server/runLauncher.d.ts +28 -0
- package/dist/server/runLauncher.js +93 -0
- package/dist/server/tasks/TaskService.d.ts +25 -0
- package/dist/server/tasks/TaskService.js +103 -0
- package/dist/server/tasks/index.js +1 -0
- package/dist/server/telemetryIngest.d.ts +24 -0
- package/dist/server/telemetryIngest.js +62 -0
- package/dist/server/tools/index.d.ts +24 -0
- package/{src/server/tools/index.ts → dist/server/tools/index.js} +4 -24
- package/dist/server/tools/tier1/protocolRunner.d.ts +39 -0
- package/dist/server/tools/tier1/protocolRunner.js +288 -0
- package/dist/server/tools/tier1/protocolTools.d.ts +12 -0
- package/dist/server/tools/tier1/protocolTools.js +37 -0
- package/dist/server/tools/tier2/connectionTools.d.ts +4 -0
- package/dist/server/tools/tier2/connectionTools.js +63 -0
- package/dist/server/tools/tier2/contextTools.d.ts +4 -0
- package/dist/server/tools/tier2/contextTools.js +46 -0
- package/dist/server/tools/tier2/discoveryTools.d.ts +4 -0
- package/dist/server/tools/tier2/discoveryTools.js +25 -0
- package/dist/server/tools/tier2/marketplaceTools.d.ts +3 -0
- package/dist/server/tools/tier2/marketplaceTools.js +22 -0
- package/dist/server/tools/tier2/paymentTools.d.ts +12 -0
- package/dist/server/tools/tier2/paymentTools.js +165 -0
- package/dist/server/ziggsconnect/ZiggsConnectClient.d.ts +35 -0
- package/dist/server/ziggsconnect/ZiggsConnectClient.js +95 -0
- package/dist/server/ziggscontext/ZiggsContextClient.d.ts +48 -0
- package/dist/server/ziggscontext/ZiggsContextClient.js +90 -0
- package/dist/server/ziggspay/ZiggsPayClient.d.ts +82 -0
- package/dist/server/ziggspay/ZiggsPayClient.js +188 -0
- package/dist/shared/ids.d.ts +1 -0
- package/dist/shared/ids.js +3 -0
- package/dist/shared/runtimeLog.d.ts +18 -0
- package/dist/shared/runtimeLog.js +68 -0
- package/dist/shared/types.d.ts +22 -0
- package/dist/shared/types.js +23 -0
- package/dist/tasks/protocolRegistry.d.ts +16 -0
- package/dist/tasks/protocolRegistry.js +20 -0
- package/dist/tools/ToolManager.d.ts +12 -0
- package/dist/tools/ToolManager.js +74 -0
- package/dist/tools/ToolProvider.d.ts +6 -0
- package/dist/tools/ToolProvider.js +21 -0
- package/dist/tools/defineTool.d.ts +27 -0
- package/dist/tools/defineTool.js +62 -0
- package/{src/tools/index.ts → dist/tools/index.d.ts} +0 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/recordReport.d.ts +41 -0
- package/dist/tools/recordReport.js +30 -0
- package/dist/types.d.ts +466 -0
- package/dist/types.js +7 -0
- package/dist/utils/jsonExtractor.d.ts +2 -0
- package/dist/utils/jsonExtractor.js +111 -0
- package/package.json +13 -5
- package/src/AgentHost.ts +0 -814
- package/src/adapters/AnthropicAdapter.ts +0 -238
- package/src/adapters/McpAdapter.ts +0 -678
- package/src/adapters/OpenAIAdapter.ts +0 -194
- package/src/agent/Agent.ts +0 -112
- package/src/agent/ClaudeSdkAgent.ts +0 -401
- package/src/agent/claudeCognition.ts +0 -139
- package/src/agent/claudeSdkTools.ts +0 -81
- package/src/agent/hostedAgentConnection.ts +0 -41
- package/src/agent/toolManagerToSdkMcp.ts +0 -136
- package/src/cognition/validateContext.ts +0 -95
- package/src/context/applyEffects.ts +0 -80
- package/src/context/batch.ts +0 -19
- package/src/context/classifyEnvelope.ts +0 -38
- package/src/context/routingLabels.ts +0 -46
- package/src/defineAgent.ts +0 -77
- package/src/formatters/AgreementFormatter.ts +0 -111
- package/src/formatters/HistoryFormatter.ts +0 -172
- package/src/ingress/normalizeIncoming.ts +0 -162
- package/src/memory/MemoryStore.ts +0 -104
- package/src/pricing/fleetDefaults.ts +0 -225
- package/src/pricing/fleetEvalFree.ts +0 -24
- package/src/pricing/fleetTierByAgentId.gen.ts +0 -775
- package/src/runtime/AgentMachine.ts +0 -484
- package/src/runtime/PromptBuilder.ts +0 -522
- package/src/runtime/buildOutcome.ts +0 -563
- package/src/runtime/defaults.ts +0 -86
- package/src/runtime/deriveRespondsToProposals.ts +0 -35
- package/src/runtime/kickoff.ts +0 -117
- package/src/runtime/runMechanical.ts +0 -106
- package/src/runtime/runTurn.ts +0 -870
- package/src/runtime/validateWorkflow.ts +0 -221
- package/src/server/ConnectionPool.ts +0 -206
- package/src/server/EventQueue.ts +0 -133
- package/src/server/InboxCatchUp.ts +0 -291
- package/src/server/OutboxBuffer.ts +0 -90
- package/src/server/SeenMessages.ts +0 -27
- package/src/server/StateTimers.ts +0 -85
- package/src/server/ZiggsEffectHandler.ts +0 -427
- package/src/server/agreements/AgreementService.ts +0 -118
- package/src/server/createHealthServer.ts +0 -85
- package/src/server/proactive/ProactiveTrigger.ts +0 -83
- package/src/server/runLauncher.ts +0 -146
- package/src/server/tasks/TaskService.ts +0 -111
- package/src/server/telemetryIngest.ts +0 -91
- package/src/server/tools/tier1/protocolRunner.ts +0 -353
- package/src/server/tools/tier1/protocolTools.ts +0 -114
- package/src/server/tools/tier2/connectionTools.ts +0 -75
- package/src/server/tools/tier2/contextTools.ts +0 -63
- package/src/server/tools/tier2/discoveryTools.ts +0 -34
- package/src/server/tools/tier2/marketplaceTools.ts +0 -27
- package/src/server/tools/tier2/paymentTools.ts +0 -170
- package/src/server/ziggsconnect/ZiggsConnectClient.ts +0 -126
- package/src/server/ziggscontext/ZiggsContextClient.ts +0 -129
- package/src/server/ziggspay/ZiggsPayClient.ts +0 -193
- package/src/shared/ids.ts +0 -3
- package/src/shared/runtimeLog.ts +0 -72
- package/src/shared/types.ts +0 -29
- package/src/tasks/protocolRegistry.ts +0 -25
- package/src/tools/ToolManager.ts +0 -95
- package/src/tools/ToolProvider.ts +0 -19
- package/src/tools/defineTool.ts +0 -90
- package/src/tools/recordReport.ts +0 -82
- package/src/types.ts +0 -483
- package/src/utils/jsonExtractor.ts +0 -100
- /package/{src/adapters/index.ts → dist/adapters/index.d.ts} +0 -0
- /package/{src/agent/claudeSdkProtocol.ts → dist/agent/claudeSdkProtocol.js} +0 -0
- /package/{src/formatters/index.ts → dist/formatters/index.d.ts} +0 -0
- /package/{src/server/tasks/index.ts → dist/server/tasks/index.d.ts} +0 -0
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { OutboxBuffer } from './OutboxBuffer.js';
|
|
2
|
+
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
|
+
import { buildLlmIngestPayload, buildToolIngestPayload, isTelemetryIngestEnabled, sendTelemetry, } from './telemetryIngest.js';
|
|
4
|
+
const CONTEXT_CACHE_MAX = 256;
|
|
5
|
+
/**
|
|
6
|
+
* Compose a `ContextSnapshot` for a chatId via the grant-fenced aggregate read
|
|
7
|
+
* (`GET /context/snapshot`, ZIG-775 follow-up). The backend assembles history +
|
|
8
|
+
* agreements + roster through the same `assertScopeAccess` + temporal fence as
|
|
9
|
+
* the per-type context reads, and annotates `*IsYou` / self server-side against
|
|
10
|
+
* the acting agent. This function only preserves the never-throw/degrade
|
|
11
|
+
* contract that the cognition code depends on — the shape is unchanged.
|
|
12
|
+
*/
|
|
13
|
+
const emptySnapshot = (agentId, chatMissing = false) => ({
|
|
14
|
+
history: [],
|
|
15
|
+
agreements: [],
|
|
16
|
+
users: [],
|
|
17
|
+
agents: [{ agentId, role: 'self', isYou: true }],
|
|
18
|
+
latestSequence: null,
|
|
19
|
+
...(chatMissing ? { chatMissing: true } : {}),
|
|
20
|
+
});
|
|
21
|
+
async function buildSnapshot(deps, chatId, agentId, opts = {}) {
|
|
22
|
+
try {
|
|
23
|
+
// Server returns 200 + chatMissing:true for a deleted chat, so its
|
|
24
|
+
// annotations (roster, *IsYou, self) are already applied — pass through.
|
|
25
|
+
const snap = await deps.contextReadClient.snapshot(chatId, {
|
|
26
|
+
maxMessages: opts.limit,
|
|
27
|
+
});
|
|
28
|
+
return snap;
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
// Defensive: server normally signals a dead chat as 200 + chatMissing, but
|
|
32
|
+
// a raw 404 degrades the same way so message wakes still skip it.
|
|
33
|
+
if (err?.status === 404) {
|
|
34
|
+
return emptySnapshot(agentId, true);
|
|
35
|
+
}
|
|
36
|
+
runtimeLog.warn('ZiggsEffectHandler', `snapshot fetch failed: ${err?.message ?? err}`);
|
|
37
|
+
return emptySnapshot(agentId);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const OP_ARTIFACT_MAX_CHARS = 900;
|
|
41
|
+
function clipForOperationArtifact(value) {
|
|
42
|
+
if (value == null)
|
|
43
|
+
return value;
|
|
44
|
+
if (typeof value === 'string') {
|
|
45
|
+
return value.length > OP_ARTIFACT_MAX_CHARS ? `${value.slice(0, OP_ARTIFACT_MAX_CHARS - 1)}…` : value;
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const s = JSON.stringify(value);
|
|
49
|
+
if (s.length <= OP_ARTIFACT_MAX_CHARS)
|
|
50
|
+
return value;
|
|
51
|
+
return `${s.slice(0, OP_ARTIFACT_MAX_CHARS - 1)}…`;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return String(value).slice(0, OP_ARTIFACT_MAX_CHARS);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function previewToolArgs(args) {
|
|
58
|
+
const keys = Object.keys(args);
|
|
59
|
+
if (keys.length === 0)
|
|
60
|
+
return undefined;
|
|
61
|
+
const out = {};
|
|
62
|
+
for (let i = 0; i < keys.length && i < 16; i++) {
|
|
63
|
+
const k = keys[i];
|
|
64
|
+
out[k] = clipForOperationArtifact(args[k]);
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Chat timeline: `Message.tsx` parses `entryType: artifact`, `content_type: operation` with
|
|
70
|
+
* `operation_*:{json}` where json includes `state` and `tool`.
|
|
71
|
+
*/
|
|
72
|
+
async function emitToolOperationArtifact(client, chatId, phase, payload) {
|
|
73
|
+
const prefix = phase === 'started' ? 'operation_started' : phase === 'completed' ? 'operation_completed' : 'operation_error';
|
|
74
|
+
const text = `${prefix}:${JSON.stringify(payload)}`;
|
|
75
|
+
try {
|
|
76
|
+
await client.write({
|
|
77
|
+
chatId,
|
|
78
|
+
text,
|
|
79
|
+
content_type: 'operation',
|
|
80
|
+
visibility: 'agent-private',
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
runtimeLog.warn('ZiggsEffectHandler', `tool operation artifact (${phase}): ${e?.message ?? String(e)}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The single tool-execution path for BOTH cognitions (ZIG-775).
|
|
89
|
+
*
|
|
90
|
+
* Executing a tool is more than calling its handler: it emits the operation
|
|
91
|
+
* timeline artifacts (started / completed / error) and tool telemetry, and
|
|
92
|
+
* resolves the invoking user + roster. The FSM reaches this via
|
|
93
|
+
* `eff({ kind: 'tool-call' })` inside `runTurn`; the Claude Agent SDK bridge
|
|
94
|
+
* (`toolManagerToSdkMcp`) emits the SAME effect — so a hosted Claude-brain
|
|
95
|
+
* agent's tool activity is as observable as an FSM agent's (needed for
|
|
96
|
+
* hired-agent visibility, ZIG-535). A caller cannot run a tool and skip these
|
|
97
|
+
* side effects — that is the whole point of funneling both paths here.
|
|
98
|
+
*
|
|
99
|
+
* `eff` is threaded into the tool context so eff-backed tools
|
|
100
|
+
* (`ziggs_context_snapshot`, `ziggs_send_message`) resolve through this same path
|
|
101
|
+
* regardless of which cognition invoked them.
|
|
102
|
+
*/
|
|
103
|
+
export async function executeToolWithSideEffects(deps, eff, effect, roster) {
|
|
104
|
+
const toolT0 = Date.now();
|
|
105
|
+
const args = effect.args || {};
|
|
106
|
+
const argsPreview = previewToolArgs(args);
|
|
107
|
+
await emitToolOperationArtifact(deps.artifactsClient, effect.sessionId, 'started', {
|
|
108
|
+
state: 'started',
|
|
109
|
+
tool: effect.name,
|
|
110
|
+
...(argsPreview ? { args: argsPreview } : {}),
|
|
111
|
+
});
|
|
112
|
+
try {
|
|
113
|
+
const lastUser = roster.users.find((u) => u.userId || u.id);
|
|
114
|
+
// Accumulate token usage from any nested LLM call the tool makes (llmTool),
|
|
115
|
+
// so it can be folded into the turn's authoritative token count (ZIG-813).
|
|
116
|
+
let nestedUsage;
|
|
117
|
+
const reportUsage = (u) => {
|
|
118
|
+
if (!u)
|
|
119
|
+
return;
|
|
120
|
+
const p = u.prompt_tokens ?? u.promptTokens ?? 0;
|
|
121
|
+
const c = u.completion_tokens ?? u.completionTokens ?? 0;
|
|
122
|
+
const t = u.total_tokens ?? u.totalTokens ?? p + c;
|
|
123
|
+
nestedUsage = {
|
|
124
|
+
prompt_tokens: (nestedUsage?.prompt_tokens ?? 0) + p,
|
|
125
|
+
completion_tokens: (nestedUsage?.completion_tokens ?? 0) + c,
|
|
126
|
+
total_tokens: (nestedUsage?.total_tokens ?? 0) + t,
|
|
127
|
+
};
|
|
128
|
+
};
|
|
129
|
+
const result = await deps.toolManager.executeTool(effect.name, args, {
|
|
130
|
+
operatorKey: deps.operatorKey,
|
|
131
|
+
agentId: deps.agentId,
|
|
132
|
+
chatId: effect.sessionId,
|
|
133
|
+
taskService: deps.taskService,
|
|
134
|
+
agreementService: deps.agreementService,
|
|
135
|
+
contextReadClient: deps.contextReadClient,
|
|
136
|
+
sendMessage: deps.messageSender,
|
|
137
|
+
eff,
|
|
138
|
+
agents: roster.agents,
|
|
139
|
+
users: roster.users,
|
|
140
|
+
senderId: effect.senderId ?? lastUser?.userId ?? lastUser?.id,
|
|
141
|
+
senderType: effect.senderType ?? (lastUser ? 'USER' : undefined),
|
|
142
|
+
onBehalfOfAgreementId: effect.onBehalfOfAgreementId,
|
|
143
|
+
memory: effect.memory,
|
|
144
|
+
reportUsage,
|
|
145
|
+
turnScratch: {},
|
|
146
|
+
});
|
|
147
|
+
await emitToolOperationArtifact(deps.artifactsClient, effect.sessionId, 'completed', {
|
|
148
|
+
state: 'completed',
|
|
149
|
+
tool: effect.name,
|
|
150
|
+
result: clipForOperationArtifact(result),
|
|
151
|
+
});
|
|
152
|
+
sendTelemetry(deps.telemetryClient, buildToolIngestPayload({
|
|
153
|
+
sessionId: effect.sessionId,
|
|
154
|
+
tool: effect.name,
|
|
155
|
+
durationMs: Date.now() - toolT0,
|
|
156
|
+
ok: true,
|
|
157
|
+
runId: effect.runId,
|
|
158
|
+
stateId: effect.stateId,
|
|
159
|
+
}), isTelemetryIngestEnabled(deps.telemetryIngest));
|
|
160
|
+
return { ok: true, result, ...(nestedUsage ? { usage: nestedUsage } : {}) };
|
|
161
|
+
}
|
|
162
|
+
catch (error) {
|
|
163
|
+
const errMsg = error?.message ?? String(error);
|
|
164
|
+
runtimeLog.warn('ZiggsEffectHandler', `tool-call "${effect.name}" failed: ${errMsg}`);
|
|
165
|
+
await emitToolOperationArtifact(deps.artifactsClient, effect.sessionId, 'error', {
|
|
166
|
+
state: 'failed',
|
|
167
|
+
tool: effect.name,
|
|
168
|
+
error: errMsg,
|
|
169
|
+
});
|
|
170
|
+
sendTelemetry(deps.telemetryClient, buildToolIngestPayload({
|
|
171
|
+
sessionId: effect.sessionId,
|
|
172
|
+
tool: effect.name,
|
|
173
|
+
durationMs: Date.now() - toolT0,
|
|
174
|
+
ok: false,
|
|
175
|
+
runId: effect.runId,
|
|
176
|
+
stateId: effect.stateId,
|
|
177
|
+
}), isTelemetryIngestEnabled(deps.telemetryIngest));
|
|
178
|
+
return { ok: false, error: errMsg };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Build a single shared EffectHandler. The handler is stateful — it caches
|
|
183
|
+
* the latest ContextSnapshot per sessionId so tool-call effects can resolve
|
|
184
|
+
* session-coupled deps (the `agents` roster) without forcing the Agent to
|
|
185
|
+
* pass them through. Cache is bounded with simple LRU eviction (re-set on
|
|
186
|
+
* read promotes the entry; oldest entry drops when size exceeds the cap).
|
|
187
|
+
*/
|
|
188
|
+
export function createZiggsEffectHandler(deps) {
|
|
189
|
+
const contextCache = new Map();
|
|
190
|
+
const outbox = new OutboxBuffer();
|
|
191
|
+
const cachePut = (sessionId, snap) => {
|
|
192
|
+
if (contextCache.has(sessionId))
|
|
193
|
+
contextCache.delete(sessionId);
|
|
194
|
+
contextCache.set(sessionId, snap);
|
|
195
|
+
if (contextCache.size > CONTEXT_CACHE_MAX) {
|
|
196
|
+
const oldest = contextCache.keys().next().value;
|
|
197
|
+
if (oldest !== undefined)
|
|
198
|
+
contextCache.delete(oldest);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const cacheGet = (sessionId) => {
|
|
202
|
+
const snap = contextCache.get(sessionId);
|
|
203
|
+
if (snap !== undefined) {
|
|
204
|
+
contextCache.delete(sessionId);
|
|
205
|
+
contextCache.set(sessionId, snap);
|
|
206
|
+
}
|
|
207
|
+
return snap;
|
|
208
|
+
};
|
|
209
|
+
const dispatch = async (effect) => {
|
|
210
|
+
switch (effect.kind) {
|
|
211
|
+
case 'read-context': {
|
|
212
|
+
// Grant-fenced aggregate read: the backend composes the ContextSnapshot
|
|
213
|
+
// (GET /context/snapshot) through the same access + temporal fence as
|
|
214
|
+
// the per-type reads. Every producer — ClaudeSdkAgent.tick, runTurn,
|
|
215
|
+
// and the on-demand ziggs_context_snapshot tool — routes through here.
|
|
216
|
+
const snap = await buildSnapshot(deps, effect.sessionId, deps.agentId, {
|
|
217
|
+
limit: effect.opts?.maxMessages,
|
|
218
|
+
});
|
|
219
|
+
const me = snap.agents.find((a) => a?.isYou)?.agentId || null;
|
|
220
|
+
outbox.merge(effect.sessionId, snap.history, me);
|
|
221
|
+
cachePut(effect.sessionId, snap);
|
|
222
|
+
return snap;
|
|
223
|
+
}
|
|
224
|
+
case 'llm-call': {
|
|
225
|
+
if (!deps.llm)
|
|
226
|
+
throw new Error('llm-call effect requires an LLM adapter — none configured for this cognition');
|
|
227
|
+
const t0 = Date.now();
|
|
228
|
+
const r = await deps.llm.chatMessages(effect.messages, effect.tools);
|
|
229
|
+
sendTelemetry(deps.telemetryClient, buildLlmIngestPayload(r, {
|
|
230
|
+
sessionId: effect.sessionId,
|
|
231
|
+
durationMs: Date.now() - t0,
|
|
232
|
+
runId: effect.runId,
|
|
233
|
+
stateId: effect.stateId,
|
|
234
|
+
}), isTelemetryIngestEnabled(deps.telemetryIngest));
|
|
235
|
+
return r;
|
|
236
|
+
}
|
|
237
|
+
case 'stream-text': {
|
|
238
|
+
if (!deps.llm)
|
|
239
|
+
throw new Error('stream-text effect requires an LLM adapter — none configured for this cognition');
|
|
240
|
+
const { sessionId, receiverId, messageId, messages } = effect;
|
|
241
|
+
let text = '';
|
|
242
|
+
let usage;
|
|
243
|
+
if (deps.llm.chatMessagesStream) {
|
|
244
|
+
const streamed = await deps.llm.chatMessagesStream(messages, (chunk) => {
|
|
245
|
+
// Live-stream display is best-effort. The transport's send rejects
|
|
246
|
+
// empty/whitespace-only content (WebSocketClient: content.trim() === ''),
|
|
247
|
+
// and a whitespace-only chunk (e.g. a leading newline) is truthy yet
|
|
248
|
+
// still throws — which, uncaught, aborts the whole stream and loses the
|
|
249
|
+
// entire reply (e.g. a composer's final synthesis). Swallow chunk-send
|
|
250
|
+
// failures; `text` accumulates independently and the final send-message
|
|
251
|
+
// (below, in runTurn) carries the full reply regardless.
|
|
252
|
+
try {
|
|
253
|
+
if (chunk && chunk.trim())
|
|
254
|
+
deps.chunkSender?.(sessionId, receiverId, chunk, messageId);
|
|
255
|
+
}
|
|
256
|
+
catch { /* ignore — streaming display only */ }
|
|
257
|
+
});
|
|
258
|
+
text = streamed.text;
|
|
259
|
+
usage = streamed.usage;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
const r = await deps.llm.chatMessages(messages);
|
|
263
|
+
text = r.content ?? '';
|
|
264
|
+
usage = r.usage;
|
|
265
|
+
if (text)
|
|
266
|
+
deps.chunkSender?.(sessionId, receiverId, text, messageId);
|
|
267
|
+
}
|
|
268
|
+
return { text, usage };
|
|
269
|
+
}
|
|
270
|
+
case 'tool-call': {
|
|
271
|
+
// Roster comes from the cached snapshot (populated by read-context). Both
|
|
272
|
+
// cognitions land here — the FSM via runTurn's executeTool, the Claude
|
|
273
|
+
// Agent SDK via the toolManagerToSdkMcp bridge — so tool side effects are
|
|
274
|
+
// emitted exactly once, in one place (ZIG-775).
|
|
275
|
+
const cached = cacheGet(effect.sessionId);
|
|
276
|
+
return executeToolWithSideEffects(deps, handler, effect, {
|
|
277
|
+
agents: cached?.agents || [],
|
|
278
|
+
users: cached?.users || [],
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
case 'send-message': {
|
|
282
|
+
await deps.messageSender(effect.text, effect.receiverId, effect.sessionId, effect.messageId);
|
|
283
|
+
outbox.track(effect.sessionId, { text: effect.text, receiverId: effect.receiverId });
|
|
284
|
+
return { ok: true };
|
|
285
|
+
}
|
|
286
|
+
case 'record-event': {
|
|
287
|
+
// Routes through ArtifactsClient as an agent-private artifact —
|
|
288
|
+
// visible to this agent across turns, not to other chat parties.
|
|
289
|
+
try {
|
|
290
|
+
if (effect.entry.kind === 'thought' && typeof effect.entry.text === 'string') {
|
|
291
|
+
await deps.artifactsClient.recordThought(effect.sessionId, effect.entry.text);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
await deps.artifactsClient.write({
|
|
295
|
+
chatId: effect.sessionId,
|
|
296
|
+
text: JSON.stringify(effect.entry),
|
|
297
|
+
content_type: String(effect.entry.kind ?? 'event'),
|
|
298
|
+
visibility: 'agent-private',
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
runtimeLog.warn('ZiggsEffectHandler', `record-event failed: ${err?.message ?? String(err)}`);
|
|
304
|
+
}
|
|
305
|
+
return { ok: true };
|
|
306
|
+
}
|
|
307
|
+
default: {
|
|
308
|
+
const exhaustive = effect;
|
|
309
|
+
throw new Error(`ZiggsEffectHandler: unknown effect kind ${exhaustive.kind}`);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
const handler = async (effect) => {
|
|
314
|
+
const response = await dispatch(effect);
|
|
315
|
+
deps.effectTap?.(effect, response);
|
|
316
|
+
return response;
|
|
317
|
+
};
|
|
318
|
+
return handler;
|
|
319
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
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';
|
|
2
|
+
export declare class AgreementService {
|
|
3
|
+
private creds;
|
|
4
|
+
constructor(operatorKey: string, agentId: string);
|
|
5
|
+
/** 1:1 proposal. Server defaults engagementKind to `service` when omitted. */
|
|
6
|
+
proposeDirect(payload: ProposeDirectInput): Promise<Agreement>;
|
|
7
|
+
/**
|
|
8
|
+
* Open buyer-broadcast. `payload.audience` selects who may see/claim it:
|
|
9
|
+
* 'everyone' (default, fully public) or 'org' (members of your active org).
|
|
10
|
+
* Server defaults engagementKind to `service`.
|
|
11
|
+
*/
|
|
12
|
+
proposeBroadcast(payload: ProposeBroadcastInput): Promise<Agreement>;
|
|
13
|
+
/** @deprecated Alias for {@link proposeDirect}. */
|
|
14
|
+
propose(payload: ProposeAgreementData): Promise<Agreement>;
|
|
15
|
+
/**
|
|
16
|
+
* Seller-broadcast marketplace offer. `payload.audience` sets the `payer`
|
|
17
|
+
* sentinel: 'everyone' (default, public) or 'org' (your active org only).
|
|
18
|
+
*/
|
|
19
|
+
publishOffer(payload: PublishOfferPayload): Promise<Agreement>;
|
|
20
|
+
delegate(payload: DelegateAgreementData): Promise<Agreement>;
|
|
21
|
+
respond(agreementId: string, action: 'approve' | 'reject'): Promise<Agreement>;
|
|
22
|
+
counter(agreementId: string, counter: CounterAgreementData): Promise<Agreement>;
|
|
23
|
+
getStatus(agreementId: string): Promise<unknown | null>;
|
|
24
|
+
list(filters?: ListAgreementsFilters): Promise<Agreement[]>;
|
|
25
|
+
mine(filters?: GetMyAgreementsFilters): Promise<Agreement[]>;
|
|
26
|
+
get(agreementId: string): Promise<Agreement | null>;
|
|
27
|
+
create(body: CreateAgreementBody): Promise<{
|
|
28
|
+
ok: boolean;
|
|
29
|
+
agreement: Agreement;
|
|
30
|
+
}>;
|
|
31
|
+
revoke(agreementId: string): Promise<{
|
|
32
|
+
ok: boolean;
|
|
33
|
+
agreement: Agreement;
|
|
34
|
+
}>;
|
|
35
|
+
fulfill(agreementId: string): Promise<{
|
|
36
|
+
ok: boolean;
|
|
37
|
+
agreement: Agreement;
|
|
38
|
+
}>;
|
|
39
|
+
linkToChat(agreementId: string, chatId: string, linkType?: ChatLinkType): Promise<unknown | null>;
|
|
40
|
+
getChats(agreementId: string): Promise<unknown[]>;
|
|
41
|
+
join(agreementId: string): Promise<{
|
|
42
|
+
chatId: string;
|
|
43
|
+
agentId: string | null;
|
|
44
|
+
isNew: boolean;
|
|
45
|
+
}>;
|
|
46
|
+
linkArtifact(agreementId: string, artifactId: string, linkType?: ArtifactLinkType): Promise<unknown | null>;
|
|
47
|
+
getArtifacts(agreementId: string): Promise<unknown[]>;
|
|
48
|
+
linkUser(agreementId: string, userId: string, role: UserRole): Promise<unknown | null>;
|
|
49
|
+
getUsers(agreementId: string): Promise<unknown[]>;
|
|
50
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { proposeAgreement, proposeBroadcast as proposeBroadcastApi, delegateAgreement, respondToAgreement, counterAgreement, getAgreementStatus, listAgreements, getMyAgreements, getAgreement, publishOffer as publishOfferApi, createAgreement, revokeAgreement, fulfillAgreement, linkAgreementToChat, getChatsForAgreement, joinAgreement, linkArtifactToAgreement, getArtifactsForAgreement, linkUserToAgreement, getUsersForAgreement, } from '@ziggs-ai/api-client';
|
|
2
|
+
export class AgreementService {
|
|
3
|
+
creds;
|
|
4
|
+
constructor(operatorKey, agentId) {
|
|
5
|
+
if (!operatorKey)
|
|
6
|
+
throw new Error('AgreementService: operatorKey is required');
|
|
7
|
+
if (!agentId)
|
|
8
|
+
throw new Error('AgreementService: agentId is required (operator-token impersonation)');
|
|
9
|
+
this.creds = { operatorKey, agentId };
|
|
10
|
+
}
|
|
11
|
+
/** 1:1 proposal. Server defaults engagementKind to `service` when omitted. */
|
|
12
|
+
proposeDirect(payload) {
|
|
13
|
+
return proposeAgreement(payload, this.creds);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Open buyer-broadcast. `payload.audience` selects who may see/claim it:
|
|
17
|
+
* 'everyone' (default, fully public) or 'org' (members of your active org).
|
|
18
|
+
* Server defaults engagementKind to `service`.
|
|
19
|
+
*/
|
|
20
|
+
proposeBroadcast(payload) {
|
|
21
|
+
return proposeBroadcastApi(payload, this.creds);
|
|
22
|
+
}
|
|
23
|
+
/** @deprecated Alias for {@link proposeDirect}. */
|
|
24
|
+
propose(payload) {
|
|
25
|
+
return proposeAgreement(payload, this.creds);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Seller-broadcast marketplace offer. `payload.audience` sets the `payer`
|
|
29
|
+
* sentinel: 'everyone' (default, public) or 'org' (your active org only).
|
|
30
|
+
*/
|
|
31
|
+
publishOffer(payload) {
|
|
32
|
+
return publishOfferApi(payload, this.creds);
|
|
33
|
+
}
|
|
34
|
+
delegate(payload) {
|
|
35
|
+
return delegateAgreement(payload, this.creds);
|
|
36
|
+
}
|
|
37
|
+
respond(agreementId, action) {
|
|
38
|
+
return respondToAgreement(agreementId, action, this.creds);
|
|
39
|
+
}
|
|
40
|
+
counter(agreementId, counter) {
|
|
41
|
+
return counterAgreement(agreementId, counter || {}, this.creds);
|
|
42
|
+
}
|
|
43
|
+
getStatus(agreementId) {
|
|
44
|
+
return getAgreementStatus(agreementId, this.creds);
|
|
45
|
+
}
|
|
46
|
+
list(filters = {}) {
|
|
47
|
+
return listAgreements(filters, this.creds);
|
|
48
|
+
}
|
|
49
|
+
mine(filters = {}) {
|
|
50
|
+
return getMyAgreements(filters, this.creds);
|
|
51
|
+
}
|
|
52
|
+
get(agreementId) {
|
|
53
|
+
return getAgreement(agreementId, this.creds);
|
|
54
|
+
}
|
|
55
|
+
create(body) {
|
|
56
|
+
return createAgreement(body, this.creds);
|
|
57
|
+
}
|
|
58
|
+
revoke(agreementId) {
|
|
59
|
+
return revokeAgreement(agreementId, this.creds);
|
|
60
|
+
}
|
|
61
|
+
fulfill(agreementId) {
|
|
62
|
+
return fulfillAgreement(agreementId, this.creds);
|
|
63
|
+
}
|
|
64
|
+
linkToChat(agreementId, chatId, linkType = 'mention') {
|
|
65
|
+
return linkAgreementToChat(agreementId, chatId, linkType, this.creds);
|
|
66
|
+
}
|
|
67
|
+
getChats(agreementId) {
|
|
68
|
+
return getChatsForAgreement(agreementId, this.creds);
|
|
69
|
+
}
|
|
70
|
+
join(agreementId) {
|
|
71
|
+
return joinAgreement(agreementId, this.creds);
|
|
72
|
+
}
|
|
73
|
+
linkArtifact(agreementId, artifactId, linkType = 'produced') {
|
|
74
|
+
return linkArtifactToAgreement(agreementId, artifactId, linkType, this.creds);
|
|
75
|
+
}
|
|
76
|
+
getArtifacts(agreementId) {
|
|
77
|
+
return getArtifactsForAgreement(agreementId, this.creds);
|
|
78
|
+
}
|
|
79
|
+
linkUser(agreementId, userId, role) {
|
|
80
|
+
return linkUserToAgreement(agreementId, userId, role, this.creds);
|
|
81
|
+
}
|
|
82
|
+
getUsers(agreementId) {
|
|
83
|
+
return getUsersForAgreement(agreementId, this.creds);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createServer } from 'http';
|
|
2
|
+
import { runtimeLog } from '../shared/runtimeLog.js';
|
|
3
|
+
function readJsonBody(req) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
const chunks = [];
|
|
6
|
+
req.on('data', (c) => chunks.push(c));
|
|
7
|
+
req.on('end', () => {
|
|
8
|
+
try {
|
|
9
|
+
const raw = Buffer.concat(chunks).toString('utf8');
|
|
10
|
+
resolve(raw ? JSON.parse(raw) : {});
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
reject(err);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
req.on('error', reject);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function createHealthServer({ port = Number(process.env.PORT) || 8080, label = 'agents', pool, } = {}) {
|
|
20
|
+
const server = createServer(async (req, res) => {
|
|
21
|
+
const url = req.url ?? '/';
|
|
22
|
+
const wakeMatch = url.match(/^\/fleet-wake\/([^/?]+)/);
|
|
23
|
+
if (req.method === 'POST' && wakeMatch && pool) {
|
|
24
|
+
const agentId = decodeURIComponent(wakeMatch[1]);
|
|
25
|
+
try {
|
|
26
|
+
await pool.wake(agentId);
|
|
27
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
28
|
+
res.end(JSON.stringify({ ok: true, agentId, active: pool.listActive().includes(agentId) }));
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
32
|
+
res.end(JSON.stringify({ ok: false, error: err.message }));
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (req.method === 'POST' && url === '/fleet-deliver' && pool) {
|
|
37
|
+
try {
|
|
38
|
+
const body = await readJsonBody(req);
|
|
39
|
+
const agentId = String(body.agentId ?? '');
|
|
40
|
+
const chatId = String(body.chatId ?? '');
|
|
41
|
+
const text = String(body.text ?? '');
|
|
42
|
+
const senderId = String(body.senderId ?? '');
|
|
43
|
+
if (!agentId || !chatId || !text || !senderId) {
|
|
44
|
+
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
45
|
+
res.end(JSON.stringify({ ok: false, error: 'agentId, chatId, text, senderId required' }));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const host = (await pool.wake(agentId));
|
|
49
|
+
await host.handleMessage(text, {
|
|
50
|
+
chatId,
|
|
51
|
+
entryType: 'message',
|
|
52
|
+
content_type: 'text',
|
|
53
|
+
sender: { id: senderId, type: 'USER' },
|
|
54
|
+
receiver: { id: agentId, type: 'AGENT' },
|
|
55
|
+
});
|
|
56
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
57
|
+
res.end(JSON.stringify({ ok: true, agentId }));
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
61
|
+
res.end(JSON.stringify({ ok: false, error: err.message }));
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (url === '/health' || url === '/') {
|
|
66
|
+
res.writeHead(200);
|
|
67
|
+
res.end('ok');
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
res.writeHead(404);
|
|
71
|
+
res.end();
|
|
72
|
+
});
|
|
73
|
+
server.listen(port, () => runtimeLog.info(label, `health server on port ${port}`));
|
|
74
|
+
return server;
|
|
75
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type Creds } from '@ziggs-ai/api-client';
|
|
2
|
+
import type { PublishOfferPayload, PullOffersOptions } from '@ziggs-ai/api-client';
|
|
3
|
+
interface TickContext {
|
|
4
|
+
agentId: string;
|
|
5
|
+
marketplace: {
|
|
6
|
+
publishOffer: (payload: PublishOfferPayload) => Promise<unknown>;
|
|
7
|
+
pullOffers: (options?: PullOffersOptions) => Promise<unknown[]>;
|
|
8
|
+
claimOffer: (agreementId: string) => Promise<unknown>;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
interface ProactiveTriggerOptions {
|
|
12
|
+
interval: number;
|
|
13
|
+
creds: Creds;
|
|
14
|
+
onTick: (ctx: TickContext) => Promise<void>;
|
|
15
|
+
onError?: (err: unknown) => void;
|
|
16
|
+
runImmediately?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export declare class ProactiveTrigger {
|
|
19
|
+
private interval;
|
|
20
|
+
private creds;
|
|
21
|
+
private onTick;
|
|
22
|
+
private onError;
|
|
23
|
+
private runImmediately;
|
|
24
|
+
private _running;
|
|
25
|
+
private _timer;
|
|
26
|
+
constructor({ interval, creds, onTick, onError, runImmediately }: ProactiveTriggerOptions);
|
|
27
|
+
start(): void;
|
|
28
|
+
stop(): void;
|
|
29
|
+
private _schedule;
|
|
30
|
+
private _tick;
|
|
31
|
+
private _buildContext;
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { publishOffer, pullOffers, claimOffer } from '@ziggs-ai/api-client';
|
|
2
|
+
import { runtimeLog } from '../../shared/runtimeLog.js';
|
|
3
|
+
export class ProactiveTrigger {
|
|
4
|
+
interval;
|
|
5
|
+
creds;
|
|
6
|
+
onTick;
|
|
7
|
+
onError;
|
|
8
|
+
runImmediately;
|
|
9
|
+
_running;
|
|
10
|
+
_timer;
|
|
11
|
+
constructor({ interval, creds, onTick, onError, runImmediately = false }) {
|
|
12
|
+
if (!interval || typeof interval !== 'number' || interval < 1000)
|
|
13
|
+
throw new Error('ProactiveTrigger: interval must be a number >= 1000ms');
|
|
14
|
+
if (!creds?.operatorKey || !creds?.agentId)
|
|
15
|
+
throw new Error('ProactiveTrigger: creds.operatorKey and creds.agentId are required');
|
|
16
|
+
if (typeof onTick !== 'function')
|
|
17
|
+
throw new Error('ProactiveTrigger: onTick must be a function');
|
|
18
|
+
this.interval = interval;
|
|
19
|
+
this.creds = creds;
|
|
20
|
+
this.onTick = onTick;
|
|
21
|
+
this.onError = onError ?? ((err) => runtimeLog.error('ProactiveTrigger', `tick error: ${String(err)}`));
|
|
22
|
+
this.runImmediately = runImmediately;
|
|
23
|
+
this._running = false;
|
|
24
|
+
this._timer = null;
|
|
25
|
+
}
|
|
26
|
+
start() {
|
|
27
|
+
if (this._running)
|
|
28
|
+
return;
|
|
29
|
+
this._running = true;
|
|
30
|
+
runtimeLog.debug('ProactiveTrigger', `started (agentId=${this.creds.agentId}, interval=${this.interval}ms)`);
|
|
31
|
+
if (this.runImmediately)
|
|
32
|
+
this._tick();
|
|
33
|
+
else
|
|
34
|
+
this._schedule();
|
|
35
|
+
}
|
|
36
|
+
stop() {
|
|
37
|
+
this._running = false;
|
|
38
|
+
if (this._timer) {
|
|
39
|
+
clearTimeout(this._timer);
|
|
40
|
+
this._timer = null;
|
|
41
|
+
}
|
|
42
|
+
runtimeLog.debug('ProactiveTrigger', `stopped (agentId=${this.creds.agentId})`);
|
|
43
|
+
}
|
|
44
|
+
_schedule() {
|
|
45
|
+
if (!this._running)
|
|
46
|
+
return;
|
|
47
|
+
this._timer = setTimeout(() => this._tick(), this.interval);
|
|
48
|
+
}
|
|
49
|
+
async _tick() {
|
|
50
|
+
if (!this._running)
|
|
51
|
+
return;
|
|
52
|
+
try {
|
|
53
|
+
await this.onTick(this._buildContext());
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
this.onError(err);
|
|
57
|
+
}
|
|
58
|
+
this._schedule();
|
|
59
|
+
}
|
|
60
|
+
_buildContext() {
|
|
61
|
+
const creds = this.creds;
|
|
62
|
+
return {
|
|
63
|
+
agentId: creds.agentId,
|
|
64
|
+
marketplace: {
|
|
65
|
+
publishOffer: (payload) => publishOffer(payload, creds),
|
|
66
|
+
pullOffers: (options) => pullOffers(options, creds),
|
|
67
|
+
claimOffer: (agreementId) => claimOffer(agreementId, creds),
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ConnectionPool } from './ConnectionPool.js';
|
|
2
|
+
import { type AgentHostOptions } from '../AgentHost.js';
|
|
3
|
+
type AgentConfig = AgentHostOptions & {
|
|
4
|
+
ownAgentId?: string;
|
|
5
|
+
options?: {
|
|
6
|
+
ownAgentId?: string;
|
|
7
|
+
name?: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
interface SingleOptions {
|
|
11
|
+
operatorKey?: string;
|
|
12
|
+
label?: string;
|
|
13
|
+
port?: number | string;
|
|
14
|
+
healthServer?: boolean;
|
|
15
|
+
onShutdown?: () => Promise<void>;
|
|
16
|
+
}
|
|
17
|
+
interface FleetOptions extends SingleOptions {
|
|
18
|
+
wsUrl?: string;
|
|
19
|
+
agentMeta?: Record<string, unknown>[];
|
|
20
|
+
primary?: AgentConfig | ((pool: ConnectionPool) => AgentConfig);
|
|
21
|
+
preWake?: string[];
|
|
22
|
+
poolOptions?: {
|
|
23
|
+
maxActive?: number;
|
|
24
|
+
idleTimeoutMs?: number;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare function runLauncher(configOrConfigs: AgentConfig | AgentConfig[], opts?: FleetOptions): Promise<unknown>;
|
|
28
|
+
export {};
|