@rivus/agent 0.14.2 → 0.14.4
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/README.md +1 -1
- package/dist/acp.js +1 -2
- package/dist/bootstrap/pi-feishu.d.ts +1 -1
- package/dist/bootstrap/pi-feishu.js +4 -4
- package/dist/chunks/agent-loop.d.ts +55 -300
- package/dist/chunks/agent-loop.js +3 -1123
- package/dist/chunks/background-session-authority.js +230 -0
- package/dist/chunks/background-session-control-input.js +51 -0
- package/dist/chunks/background-session-service.d.ts +382 -0
- package/dist/chunks/index.d.ts +1201 -538
- package/dist/chunks/pi-tool-proxy.d.ts +22 -90
- package/dist/chunks/pi.js +5 -2
- package/dist/chunks/rivus-agent-definition-resolver.js +508 -0
- package/dist/chunks/rivus-daemon-cli.js +2776 -3244
- package/dist/chunks/rivus-plugin-testkit.d.ts +175 -2
- package/dist/chunks/rivus-plugin-testkit.js +11 -4
- package/dist/chunks/rivus-skill.d.ts +95 -0
- package/dist/chunks/sha256-digest.js +2 -7
- package/dist/chunks/src.js +11941 -7001
- package/dist/chunks/tool-input-digest.js +158 -0
- package/dist/cli.js +764 -712
- package/dist/index.d.ts +6 -7
- package/dist/index.js +7 -8
- package/dist/mcp.d.ts +48 -9
- package/dist/mcp.js +146 -20
- package/dist/pi.d.ts +3 -4
- package/dist/pi.js +1 -1
- package/package.json +5 -5
- package/dist/chunks/api.d.ts +0 -70
- package/dist/chunks/api.js +0 -471
- package/dist/chunks/api2.d.ts +0 -387
- package/dist/chunks/api2.js +0 -1331
- package/dist/chunks/api3.d.ts +0 -402
- package/dist/chunks/module.js +0 -267
- package/dist/chunks/pi-skill-tool.js +0 -460
- package/dist/chunks/spi.d.ts +0 -1
- package/dist/chunks/spi.js +0 -2
|
@@ -1,460 +0,0 @@
|
|
|
1
|
-
import { b as restrictMemoryScopesForAudience } from "./api.js";
|
|
2
|
-
import { n as createRandomId, t as createSha256Digest } from "./sha256-digest.js";
|
|
3
|
-
import { Effect } from "effect";
|
|
4
|
-
import { Unsafe } from "typebox";
|
|
5
|
-
//#region src/modules/tool-execution/domain/authority/invocation-authority.ts
|
|
6
|
-
var InvalidInvocationAuthority = class extends Error {
|
|
7
|
-
name = "InvalidInvocationAuthority";
|
|
8
|
-
};
|
|
9
|
-
function normalizeInvocationAuthority(authority) {
|
|
10
|
-
if (!authority.sourceMessageId.trim()) throw new InvalidInvocationAuthority("invocation authority requires a trusted source message id");
|
|
11
|
-
if (authority.endpointId !== void 0 && !authority.endpointId.trim()) throw new InvalidInvocationAuthority("invocation authority requires a trusted endpoint id");
|
|
12
|
-
const memory = authority.memory ? Object.freeze({
|
|
13
|
-
...authority.memory,
|
|
14
|
-
scopes: Object.freeze(restrictMemoryScopesForAudience(authority.memory.scopes, authority.memory.audience))
|
|
15
|
-
}) : void 0;
|
|
16
|
-
return Object.freeze({
|
|
17
|
-
...authority,
|
|
18
|
-
...authority.allowedActorOpenIds ? { allowedActorOpenIds: Object.freeze([...authority.allowedActorOpenIds]) } : {},
|
|
19
|
-
toolGrantSet: Object.freeze({
|
|
20
|
-
revision: authority.toolGrantSet.revision,
|
|
21
|
-
toolIds: Object.freeze([...authority.toolGrantSet.toolIds])
|
|
22
|
-
}),
|
|
23
|
-
...memory ? { memory } : {}
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
//#endregion
|
|
27
|
-
//#region src/modules/tool-execution/domain/authority/tool-risk.ts
|
|
28
|
-
function requiresToolApproval(risk) {
|
|
29
|
-
return risk === "irreversible" || risk === "host-control";
|
|
30
|
-
}
|
|
31
|
-
//#endregion
|
|
32
|
-
//#region src/modules/tool-execution/application/authority/invocation-authority-registry.ts
|
|
33
|
-
const authorities = /* @__PURE__ */ new WeakMap();
|
|
34
|
-
function createInvocationAuthority(authority) {
|
|
35
|
-
const reference = Object.freeze({ id: `authority:${createRandomId()}` });
|
|
36
|
-
authorities.set(reference, normalizeInvocationAuthority(authority));
|
|
37
|
-
return reference;
|
|
38
|
-
}
|
|
39
|
-
function resolveInvocationAuthority(reference) {
|
|
40
|
-
const authority = authorities.get(reference);
|
|
41
|
-
if (!authority) throw new InvalidInvocationAuthority("invocation authority was not issued by this host");
|
|
42
|
-
return authority;
|
|
43
|
-
}
|
|
44
|
-
//#endregion
|
|
45
|
-
//#region src/modules/tool-execution/domain/input/stable-tool-input.ts
|
|
46
|
-
var InvalidStableJson = class extends Error {
|
|
47
|
-
name = "InvalidStableJson";
|
|
48
|
-
};
|
|
49
|
-
var InvalidToolInput = class extends InvalidStableJson {
|
|
50
|
-
name = "InvalidToolInput";
|
|
51
|
-
};
|
|
52
|
-
function createStableToolInputDigest(input, digest) {
|
|
53
|
-
let canonical;
|
|
54
|
-
try {
|
|
55
|
-
canonical = normalizeStableJson(input);
|
|
56
|
-
} catch (error) {
|
|
57
|
-
if (error instanceof InvalidStableJson) throw new InvalidToolInput(error.message);
|
|
58
|
-
throw error;
|
|
59
|
-
}
|
|
60
|
-
return digest(JSON.stringify(canonical));
|
|
61
|
-
}
|
|
62
|
-
function normalizeStableJson(value) {
|
|
63
|
-
return canonicalize(value, /* @__PURE__ */ new Set());
|
|
64
|
-
}
|
|
65
|
-
function canonicalize(value, ancestors) {
|
|
66
|
-
if (value === null || typeof value === "string" || typeof value === "boolean") return value;
|
|
67
|
-
if (typeof value === "number") {
|
|
68
|
-
if (!Number.isFinite(value)) throw new InvalidStableJson("stable JSON numbers must be finite");
|
|
69
|
-
return Object.is(value, -0) ? 0 : value;
|
|
70
|
-
}
|
|
71
|
-
if (typeof value !== "object") throw new InvalidStableJson("value must contain only stable JSON values");
|
|
72
|
-
if (ancestors.has(value)) throw new InvalidStableJson("stable JSON must not contain cycles");
|
|
73
|
-
ancestors.add(value);
|
|
74
|
-
try {
|
|
75
|
-
if (Array.isArray(value)) return Array.from({ length: value.length }, (_, index) => {
|
|
76
|
-
if (!Object.hasOwn(value, index)) throw new InvalidStableJson("stable JSON arrays must not contain holes");
|
|
77
|
-
return canonicalize(value[index], ancestors);
|
|
78
|
-
});
|
|
79
|
-
const prototype = Object.getPrototypeOf(value);
|
|
80
|
-
if (prototype !== Object.prototype && prototype !== null) throw new InvalidStableJson("stable JSON objects must be plain objects");
|
|
81
|
-
return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0).map(([key, entry]) => [key, canonicalize(entry, ancestors)]));
|
|
82
|
-
} finally {
|
|
83
|
-
ancestors.delete(value);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/modules/tool-execution/domain/operation/tool-operation.ts
|
|
88
|
-
var ToolOperationTransitionDenied = class extends Error {
|
|
89
|
-
name = "ToolOperationTransitionDenied";
|
|
90
|
-
};
|
|
91
|
-
function beginToolOperation(current, operationId, binding) {
|
|
92
|
-
if (!current) return {
|
|
93
|
-
record: {
|
|
94
|
-
binding,
|
|
95
|
-
operationId,
|
|
96
|
-
revision: 1,
|
|
97
|
-
state: { status: "pending" }
|
|
98
|
-
},
|
|
99
|
-
status: "acquired"
|
|
100
|
-
};
|
|
101
|
-
if (!isSameToolOperationBinding(current.binding, binding)) return {
|
|
102
|
-
reason: "operation id is bound to another invocation",
|
|
103
|
-
status: "blocked"
|
|
104
|
-
};
|
|
105
|
-
switch (current.state.status) {
|
|
106
|
-
case "completed": return {
|
|
107
|
-
result: structuredClone(current.state.result),
|
|
108
|
-
status: "completed"
|
|
109
|
-
};
|
|
110
|
-
case "aborted": return {
|
|
111
|
-
record: {
|
|
112
|
-
binding: current.binding,
|
|
113
|
-
operationId: current.operationId,
|
|
114
|
-
revision: current.revision + 1,
|
|
115
|
-
state: { status: "pending" }
|
|
116
|
-
},
|
|
117
|
-
status: "acquired"
|
|
118
|
-
};
|
|
119
|
-
case "pending": return {
|
|
120
|
-
reason: "operation is already in progress",
|
|
121
|
-
status: "blocked"
|
|
122
|
-
};
|
|
123
|
-
case "reconciliation-required": return {
|
|
124
|
-
reason: current.state.reason,
|
|
125
|
-
status: "blocked"
|
|
126
|
-
};
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
function inspectToolOperation(current, binding) {
|
|
130
|
-
if (!current || current.state.status === "aborted" && isSameToolOperationBinding(current.binding, binding)) return { status: "missing" };
|
|
131
|
-
if (!isSameToolOperationBinding(current.binding, binding)) return {
|
|
132
|
-
reason: "operation id is bound to another invocation",
|
|
133
|
-
status: "blocked"
|
|
134
|
-
};
|
|
135
|
-
return current.state.status === "completed" ? {
|
|
136
|
-
result: structuredClone(current.state.result),
|
|
137
|
-
status: "completed"
|
|
138
|
-
} : {
|
|
139
|
-
reason: current.state.status === "reconciliation-required" ? current.state.reason : "operation is already in progress",
|
|
140
|
-
status: "blocked"
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
function completeToolOperation(current, operationId, binding, result) {
|
|
144
|
-
return transitionPending(current, operationId, binding, {
|
|
145
|
-
result: normalizeStableJson(result),
|
|
146
|
-
status: "completed"
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
function abortToolOperation(current, operationId, binding) {
|
|
150
|
-
return transitionPending(current, operationId, binding, { status: "aborted" });
|
|
151
|
-
}
|
|
152
|
-
function requireToolOperationReconciliation(current, operationId, binding, reason) {
|
|
153
|
-
return transitionPending(current, operationId, binding, {
|
|
154
|
-
reason,
|
|
155
|
-
status: "reconciliation-required"
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
function reconcileToolOperation(current, input) {
|
|
159
|
-
if (!current || current.state.status !== "reconciliation-required" || current.revision !== input.expectedRevision) throw new ToolOperationTransitionDenied(`tool operation is not the expected reconciliation revision: ${input.operationId}`);
|
|
160
|
-
const action = normalizeReconciliationAction(input.action);
|
|
161
|
-
const result = input.outcome.status === "applied" ? normalizeStableJson(input.outcome.result) : void 0;
|
|
162
|
-
return {
|
|
163
|
-
...current,
|
|
164
|
-
reconciliation: {
|
|
165
|
-
...action,
|
|
166
|
-
outcome: input.outcome.status
|
|
167
|
-
},
|
|
168
|
-
revision: current.revision + 1,
|
|
169
|
-
state: input.outcome.status === "applied" ? {
|
|
170
|
-
result,
|
|
171
|
-
status: "completed"
|
|
172
|
-
} : { status: "aborted" }
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
function recoverInterruptedToolOperation(record) {
|
|
176
|
-
if (record.state.status !== "pending") return record;
|
|
177
|
-
return {
|
|
178
|
-
...record,
|
|
179
|
-
revision: record.revision + 1,
|
|
180
|
-
state: {
|
|
181
|
-
reason: "process exited before the tool outcome was durably recorded",
|
|
182
|
-
status: "reconciliation-required"
|
|
183
|
-
}
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
function isSameToolOperationBinding(left, right) {
|
|
187
|
-
return left.agentId === right.agentId && left.inputDigest === right.inputDigest && left.instanceId === right.instanceId && left.sourceMessageId === right.sourceMessageId && left.toolId === right.toolId && left.toolVersion === right.toolVersion;
|
|
188
|
-
}
|
|
189
|
-
function isValidToolOperationTransition(previous, next) {
|
|
190
|
-
if (!isSameToolOperationBinding(previous.binding, next.binding)) return false;
|
|
191
|
-
switch (previous.state.status) {
|
|
192
|
-
case "pending": return [
|
|
193
|
-
"completed",
|
|
194
|
-
"reconciliation-required",
|
|
195
|
-
"aborted"
|
|
196
|
-
].includes(next.state.status) && isSameReconciliation(previous.reconciliation, next.reconciliation);
|
|
197
|
-
case "aborted": return next.state.status === "pending" && next.reconciliation === void 0;
|
|
198
|
-
case "completed": return false;
|
|
199
|
-
case "reconciliation-required": return (next.state.status === "completed" || next.state.status === "aborted") && next.reconciliation !== void 0 && isValidReconciliation(next.reconciliation) && next.reconciliation.outcome === (next.state.status === "completed" ? "applied" : "not-applied") && !isSameReconciliation(previous.reconciliation, next.reconciliation);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
function transitionPending(current, operationId, binding, state) {
|
|
203
|
-
if (!current || current.state.status !== "pending" || !isSameToolOperationBinding(current.binding, binding)) throw new ToolOperationTransitionDenied(`tool operation is not held by this invocation: ${operationId}`);
|
|
204
|
-
return {
|
|
205
|
-
...current,
|
|
206
|
-
revision: current.revision + 1,
|
|
207
|
-
state
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
function normalizeReconciliationAction(action) {
|
|
211
|
-
const actorId = action.actorId.trim();
|
|
212
|
-
const note = action.note.trim();
|
|
213
|
-
if (!actorId) throw new ToolOperationTransitionDenied("recovery actor must not be empty");
|
|
214
|
-
if (!note) throw new ToolOperationTransitionDenied("recovery note must not be empty");
|
|
215
|
-
if (!Number.isFinite(Date.parse(action.at))) throw new ToolOperationTransitionDenied("recovery timestamp must be an ISO timestamp");
|
|
216
|
-
return Object.freeze({
|
|
217
|
-
actorId,
|
|
218
|
-
at: action.at,
|
|
219
|
-
note
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
function isValidReconciliation(value) {
|
|
223
|
-
return value.actorId.trim().length > 0 && Number.isFinite(Date.parse(value.at)) && value.note.trim().length > 0 && (value.outcome === "applied" || value.outcome === "not-applied");
|
|
224
|
-
}
|
|
225
|
-
function isSameReconciliation(left, right) {
|
|
226
|
-
if (left === void 0 || right === void 0) return left === right;
|
|
227
|
-
return left.actorId === right.actorId && left.at === right.at && left.note === right.note && left.outcome === right.outcome;
|
|
228
|
-
}
|
|
229
|
-
//#endregion
|
|
230
|
-
//#region src/modules/tool-execution/application/operation/tool-operation-ledger.ts
|
|
231
|
-
function createToolOperationLedger(options = {}) {
|
|
232
|
-
const records = new Map(options.initial?.map((record) => [record.operationId, structuredClone(record)]) ?? []);
|
|
233
|
-
const exclusive = Effect.unsafeMakeSemaphore(1).withPermits(1);
|
|
234
|
-
const save = (record) => {
|
|
235
|
-
const snapshot = structuredClone(record);
|
|
236
|
-
return (options.persist ? options.persist(snapshot) : Effect.void).pipe(Effect.tap(() => Effect.sync(() => {
|
|
237
|
-
records.set(snapshot.operationId, structuredClone(snapshot));
|
|
238
|
-
})));
|
|
239
|
-
};
|
|
240
|
-
const transition = (operationId, next) => exclusive(Effect.gen(function* () {
|
|
241
|
-
const record = yield* Effect.try({
|
|
242
|
-
catch: (error) => error,
|
|
243
|
-
try: () => next(records.get(operationId))
|
|
244
|
-
});
|
|
245
|
-
yield* save(record);
|
|
246
|
-
}));
|
|
247
|
-
return {
|
|
248
|
-
abort: (operationId, binding) => transition(operationId, (current) => abortToolOperation(current, operationId, binding)),
|
|
249
|
-
begin: (operationId, binding) => exclusive(Effect.gen(function* () {
|
|
250
|
-
const decision = beginToolOperation(records.get(operationId), operationId, binding);
|
|
251
|
-
if (decision.status !== "acquired") return decision;
|
|
252
|
-
yield* save(decision.record);
|
|
253
|
-
return { status: "acquired" };
|
|
254
|
-
})),
|
|
255
|
-
complete: (operationId, binding, result) => transition(operationId, (current) => completeToolOperation(current, operationId, binding, result)),
|
|
256
|
-
inspect: (operationId, binding) => exclusive(Effect.sync(() => inspectToolOperation(records.get(operationId), binding))),
|
|
257
|
-
reconciliationRequired: () => [...records.values()].filter((record) => record.state.status === "reconciliation-required").map((record) => structuredClone(record)),
|
|
258
|
-
reconcile: (input) => exclusive(Effect.gen(function* () {
|
|
259
|
-
const record = yield* Effect.try({
|
|
260
|
-
catch: (error) => error,
|
|
261
|
-
try: () => reconcileToolOperation(records.get(input.operationId), input)
|
|
262
|
-
});
|
|
263
|
-
yield* save(record);
|
|
264
|
-
return structuredClone(record);
|
|
265
|
-
})),
|
|
266
|
-
requireReconciliation: (operationId, binding, reason) => transition(operationId, (current) => requireToolOperationReconciliation(current, operationId, binding, reason)),
|
|
267
|
-
unresolvedForSource: (sourceMessageId) => [...records.values()].filter((record) => record.binding.sourceMessageId === sourceMessageId && (record.state.status === "pending" || record.state.status === "reconciliation-required")).map((record) => structuredClone(record))
|
|
268
|
-
};
|
|
269
|
-
}
|
|
270
|
-
//#endregion
|
|
271
|
-
//#region src/modules/tool-execution/application/brokerage/tool-input-digest.ts
|
|
272
|
-
function createToolInputDigest(input) {
|
|
273
|
-
return createStableToolInputDigest(input, createSha256Digest);
|
|
274
|
-
}
|
|
275
|
-
//#endregion
|
|
276
|
-
//#region src/modules/tool-execution/application/brokerage/tool-broker-ports.ts
|
|
277
|
-
var ToolExecutorInputRejected = class extends Error {
|
|
278
|
-
name = "ToolExecutorInputRejected";
|
|
279
|
-
};
|
|
280
|
-
//#endregion
|
|
281
|
-
//#region src/modules/tool-execution/application/brokerage/tool-broker.ts
|
|
282
|
-
var ToolInvocationDenied = class extends Error {
|
|
283
|
-
name = "ToolInvocationDenied";
|
|
284
|
-
};
|
|
285
|
-
function createToolBroker(options) {
|
|
286
|
-
const operations = options.operations ?? createToolOperationLedger();
|
|
287
|
-
const hostTools = new Map(options.hostTools?.map((tool) => [tool.id, tool]) ?? []);
|
|
288
|
-
if (hostTools.size !== (options.hostTools?.length ?? 0)) throw new ToolInvocationDenied("duplicate Host Tool id");
|
|
289
|
-
return { execute: (request) => Effect.gen(function* () {
|
|
290
|
-
const prepared = yield* Effect.try({
|
|
291
|
-
catch: (error) => error,
|
|
292
|
-
try: () => prepareInvocation(options.catalog, hostTools, request)
|
|
293
|
-
});
|
|
294
|
-
const policy = yield* options.policy.current();
|
|
295
|
-
if (policy.revokedToolIds.includes(request.toolId)) return yield* Effect.fail(new ToolInvocationDenied(`tool has been revoked: ${request.toolId}`));
|
|
296
|
-
if (prepared.tool.idempotency === "required" && !request.operationId) return yield* Effect.fail(new ToolInvocationDenied(`tool requires a stable operation id: ${request.toolId}`));
|
|
297
|
-
if (requiresToolApproval(prepared.tool.risk) && !request.operationId) return yield* Effect.fail(new ToolInvocationDenied(`tool approval requires a stable operation id: ${request.toolId}`));
|
|
298
|
-
if (requiresToolApproval(prepared.tool.risk) && !request.approvalId) return yield* Effect.fail(new ToolInvocationDenied(`tool requires trusted approval: ${request.toolId}`));
|
|
299
|
-
const binding = yield* Effect.try({
|
|
300
|
-
catch: (error) => error,
|
|
301
|
-
try: () => createOperationBinding(prepared.authority, prepared.tool, request)
|
|
302
|
-
});
|
|
303
|
-
const context = createExecutionContext(prepared.authority, request, policy.epoch, prepared.tool);
|
|
304
|
-
const replayCompleted = (result) => replay(prepared.tool, request.input, result, context);
|
|
305
|
-
if (request.operationId) {
|
|
306
|
-
const inspected = yield* operations.inspect(request.operationId, binding);
|
|
307
|
-
if (inspected.status === "completed") return yield* replayCompleted(inspected.result);
|
|
308
|
-
if (inspected.status === "blocked") return yield* Effect.fail(new ToolInvocationDenied(`tool operation is fenced: ${inspected.reason}`));
|
|
309
|
-
}
|
|
310
|
-
if (requiresToolApproval(prepared.tool.risk)) {
|
|
311
|
-
if (!(yield* options.approvals.consume({
|
|
312
|
-
agentId: prepared.authority.agentId,
|
|
313
|
-
approvalId: request.approvalId,
|
|
314
|
-
callId: request.callId,
|
|
315
|
-
inputDigest: binding.inputDigest,
|
|
316
|
-
instanceId: prepared.authority.instanceId,
|
|
317
|
-
operationId: request.operationId,
|
|
318
|
-
risk: prepared.tool.risk,
|
|
319
|
-
runId: prepared.authority.runId,
|
|
320
|
-
sessionKey: prepared.authority.sessionKey,
|
|
321
|
-
tenantKey: prepared.authority.tenantKey,
|
|
322
|
-
toolId: request.toolId,
|
|
323
|
-
toolVersion: prepared.tool.version
|
|
324
|
-
}))) return yield* Effect.fail(new ToolInvocationDenied(`tool approval is invalid or already consumed: ${request.toolId}`));
|
|
325
|
-
}
|
|
326
|
-
if (request.operationId) {
|
|
327
|
-
const reservation = yield* operations.begin(request.operationId, binding);
|
|
328
|
-
if (reservation.status === "completed") return yield* replayCompleted(reservation.result);
|
|
329
|
-
if (reservation.status === "blocked") return yield* Effect.fail(new ToolInvocationDenied(`tool operation is fenced: ${reservation.reason}`));
|
|
330
|
-
}
|
|
331
|
-
return yield* Effect.gen(function* () {
|
|
332
|
-
const result = yield* (yield* Effect.try({
|
|
333
|
-
catch: (error) => error,
|
|
334
|
-
try: () => prepared.tool.createExecutor({
|
|
335
|
-
toolId: prepared.tool.id,
|
|
336
|
-
toolVersion: prepared.tool.version
|
|
337
|
-
})
|
|
338
|
-
})).execute(request.input, context);
|
|
339
|
-
if (request.operationId) yield* operations.complete(request.operationId, binding, result);
|
|
340
|
-
return result;
|
|
341
|
-
}).pipe(Effect.catchAll((error) => {
|
|
342
|
-
if (!request.operationId) return Effect.fail(error);
|
|
343
|
-
return (prepared.tool.risk === "observe" || error instanceof ToolExecutorInputRejected ? operations.abort(request.operationId, binding) : operations.requireReconciliation(request.operationId, binding, error instanceof Error ? error.message : String(error))).pipe(Effect.zipRight(Effect.fail(error)));
|
|
344
|
-
}));
|
|
345
|
-
}) };
|
|
346
|
-
}
|
|
347
|
-
function prepareInvocation(catalog, hostTools, request) {
|
|
348
|
-
const authority = resolveInvocationAuthority(request.authority);
|
|
349
|
-
if (!authority.toolGrantSet.toolIds.includes(request.toolId)) throw new ToolInvocationDenied(`tool is not granted for this run: ${request.toolId}`);
|
|
350
|
-
const tool = hostTools.get(request.toolId) ?? catalog.snapshot().tools.find(({ id }) => id === request.toolId);
|
|
351
|
-
if (!tool) throw new ToolInvocationDenied(`tool is not present in the trusted catalog: ${request.toolId}`);
|
|
352
|
-
if (tool.version !== request.version) throw new ToolInvocationDenied(`tool version mismatch for ${request.toolId}: expected ${tool.version}`);
|
|
353
|
-
return {
|
|
354
|
-
authority,
|
|
355
|
-
tool
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
function createOperationBinding(authority, tool, request) {
|
|
359
|
-
let inputDigest;
|
|
360
|
-
try {
|
|
361
|
-
inputDigest = createToolInputDigest(request.input);
|
|
362
|
-
} catch (error) {
|
|
363
|
-
if (error instanceof InvalidToolInput) throw new ToolInvocationDenied(`tool input is not stable JSON: ${request.toolId}`);
|
|
364
|
-
throw error;
|
|
365
|
-
}
|
|
366
|
-
return {
|
|
367
|
-
agentId: authority.agentId,
|
|
368
|
-
inputDigest,
|
|
369
|
-
instanceId: authority.instanceId,
|
|
370
|
-
sourceMessageId: authority.sourceMessageId,
|
|
371
|
-
toolId: tool.id,
|
|
372
|
-
toolVersion: tool.version
|
|
373
|
-
};
|
|
374
|
-
}
|
|
375
|
-
function createExecutionContext(authority, request, policyEpoch, tool) {
|
|
376
|
-
return Object.freeze({
|
|
377
|
-
agentId: authority.agentId,
|
|
378
|
-
callId: request.callId,
|
|
379
|
-
instanceId: authority.instanceId,
|
|
380
|
-
...authority.memory ? { memory: authority.memory } : {},
|
|
381
|
-
...request.operationId ? { operationId: request.operationId } : {},
|
|
382
|
-
policyEpoch,
|
|
383
|
-
runId: authority.runId,
|
|
384
|
-
sessionKey: authority.sessionKey,
|
|
385
|
-
toolId: tool.id,
|
|
386
|
-
toolVersion: tool.version,
|
|
387
|
-
...authority.endpointId ? { origin: Object.freeze({
|
|
388
|
-
...authority.allowedActorOpenIds ? { allowedActorOpenIds: authority.allowedActorOpenIds } : { allowedActorOpenIds: Object.freeze([]) },
|
|
389
|
-
endpointId: authority.endpointId,
|
|
390
|
-
tenantKey: authority.tenantKey,
|
|
391
|
-
...authority.conversationId ? { conversationId: authority.conversationId } : {}
|
|
392
|
-
}) } : {},
|
|
393
|
-
...authority.sourceMessageId ? { sourceMessageId: authority.sourceMessageId } : {}
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
function replay(tool, input, result, context) {
|
|
397
|
-
if (!tool.replayCompleted) return Effect.succeed(result);
|
|
398
|
-
return Effect.try({
|
|
399
|
-
catch: (error) => error,
|
|
400
|
-
try: () => tool.replayCompleted(input, result, context)
|
|
401
|
-
}).pipe(Effect.flatMap((effect) => effect));
|
|
402
|
-
}
|
|
403
|
-
//#endregion
|
|
404
|
-
//#region src/adapters/pi/skills/pi-skill-tool.ts
|
|
405
|
-
const PI_SKILL_READER_TOOL_NAME = "rivus_read_skill";
|
|
406
|
-
function createPiSkillRuntime(skills) {
|
|
407
|
-
if (skills.length === 0) return Object.freeze({ prompt: "" });
|
|
408
|
-
const skillsById = new Map(skills.map((skill) => [skill.id, skill]));
|
|
409
|
-
const prompt = [
|
|
410
|
-
"Granted Skills are versioned instructions loaded on demand.",
|
|
411
|
-
`Before following a Skill, call ${PI_SKILL_READER_TOOL_NAME} with its exact ID and follow the returned content.`,
|
|
412
|
-
"Granted Skill catalog:",
|
|
413
|
-
...skills.map((skill) => `- ${skill.id} | ${skill.title} | v${skill.version} | ${skill.digest}`)
|
|
414
|
-
].join("\n");
|
|
415
|
-
const tool = {
|
|
416
|
-
description: "Read the full versioned instructions for one Skill granted to this Agent Runtime.",
|
|
417
|
-
execute: async (_callId, input) => {
|
|
418
|
-
const skillId = readSkillId(input);
|
|
419
|
-
const skill = skillsById.get(skillId);
|
|
420
|
-
if (!skill) throw new Error(`Skill is not granted: ${skillId}`);
|
|
421
|
-
const details = {
|
|
422
|
-
contentLength: skill.content.length,
|
|
423
|
-
digest: skill.digest,
|
|
424
|
-
skillId: skill.id,
|
|
425
|
-
title: skill.title,
|
|
426
|
-
version: skill.version
|
|
427
|
-
};
|
|
428
|
-
return {
|
|
429
|
-
content: [{
|
|
430
|
-
text: skill.content,
|
|
431
|
-
type: "text"
|
|
432
|
-
}],
|
|
433
|
-
details
|
|
434
|
-
};
|
|
435
|
-
},
|
|
436
|
-
executionMode: "sequential",
|
|
437
|
-
label: "Read granted Skill",
|
|
438
|
-
name: PI_SKILL_READER_TOOL_NAME,
|
|
439
|
-
parameters: Unsafe({
|
|
440
|
-
additionalProperties: false,
|
|
441
|
-
properties: { skillId: {
|
|
442
|
-
description: "Exact Skill ID from the granted Skill catalog.",
|
|
443
|
-
type: "string"
|
|
444
|
-
} },
|
|
445
|
-
required: ["skillId"],
|
|
446
|
-
type: "object"
|
|
447
|
-
}),
|
|
448
|
-
promptSnippet: `${PI_SKILL_READER_TOOL_NAME}: read one granted Skill by exact ID`
|
|
449
|
-
};
|
|
450
|
-
return Object.freeze({
|
|
451
|
-
prompt,
|
|
452
|
-
tool
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
function readSkillId(input) {
|
|
456
|
-
if (input === null || typeof input !== "object" || Array.isArray(input) || typeof input.skillId !== "string") throw new Error("Skill reader input requires a string skillId");
|
|
457
|
-
return input.skillId;
|
|
458
|
-
}
|
|
459
|
-
//#endregion
|
|
460
|
-
export { ToolExecutorInputRejected as a, isValidToolOperationTransition as c, InvalidToolInput as d, normalizeStableJson as f, InvalidInvocationAuthority as g, requiresToolApproval as h, createToolBroker as i, recoverInterruptedToolOperation as l, resolveInvocationAuthority as m, createPiSkillRuntime as n, createToolInputDigest as o, createInvocationAuthority as p, ToolInvocationDenied as r, createToolOperationLedger as s, PI_SKILL_READER_TOOL_NAME as t, InvalidStableJson as u };
|
package/dist/chunks/spi.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|
package/dist/chunks/spi.js
DELETED