@rivus/runtime 0.17.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunks/user-input-xml.js +9 -9
- package/dist/index.js +28 -29
- package/dist/pi.js +3 -3
- package/package.json +3 -3
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as isValidUserInput } from "./agent-user-input.js";
|
|
2
|
-
import { Effect,
|
|
2
|
+
import { Effect, Result } from "effect";
|
|
3
3
|
//#region src/core/application/agent-execution/loop/agent-loop.ts
|
|
4
4
|
function createAgentLoopTextDelta(delta) {
|
|
5
5
|
return {
|
|
@@ -161,19 +161,19 @@ function renderImage(part, context) {
|
|
|
161
161
|
size: part.size,
|
|
162
162
|
index: images.length + 1
|
|
163
163
|
})) return Effect.succeed(renderUnavailableNoticeAndRecord(part.attachmentId, "超出本次图片输入预算或当前模型不支持视觉", unavailable));
|
|
164
|
-
return access.readBytes(part.attachmentId).pipe(Effect.
|
|
165
|
-
if (
|
|
166
|
-
if (!withinImageBudget(result.
|
|
164
|
+
return access.readBytes(part.attachmentId).pipe(Effect.result, Effect.map((result) => {
|
|
165
|
+
if (Result.isFailure(result)) return renderUnavailableNoticeAndRecord(part.attachmentId, "图片在执行环境中不可读", unavailable);
|
|
166
|
+
if (!withinImageBudget(result.success.byteLength) || result.success.byteLength === 0) return renderUnavailableNoticeAndRecord(part.attachmentId, "超出本次图片输入预算或图片为空", unavailable);
|
|
167
167
|
if (access.canProvideImage && !access.canProvideImage({
|
|
168
168
|
mimeType: part.mimeType,
|
|
169
|
-
size: result.
|
|
169
|
+
size: result.success.byteLength,
|
|
170
170
|
index: images.length + 1
|
|
171
171
|
})) return renderUnavailableNoticeAndRecord(part.attachmentId, "超出本次图片输入预算或当前模型不支持视觉", unavailable);
|
|
172
172
|
const imageIndex = images.length + 1;
|
|
173
173
|
images.push({
|
|
174
174
|
type: "image",
|
|
175
175
|
attachmentId: part.attachmentId,
|
|
176
|
-
data: Buffer.from(result.
|
|
176
|
+
data: Buffer.from(result.success).toString("base64"),
|
|
177
177
|
imageIndex,
|
|
178
178
|
mimeType: part.mimeType
|
|
179
179
|
});
|
|
@@ -183,9 +183,9 @@ function renderImage(part, context) {
|
|
|
183
183
|
}
|
|
184
184
|
function renderAttachment(part, access, markUsable, unavailable) {
|
|
185
185
|
if (!access) return Effect.succeed(renderUnavailableNoticeAndRecord(part.fileName ?? part.attachmentId, "执行环境未提供文件读取能力", unavailable));
|
|
186
|
-
return access.materialize(part.attachmentId).pipe(Effect.
|
|
187
|
-
if (
|
|
188
|
-
const value = result.
|
|
186
|
+
return access.materialize(part.attachmentId).pipe(Effect.result, Effect.map((result) => {
|
|
187
|
+
if (Result.isFailure(result)) return renderUnavailableNoticeAndRecord(part.fileName ?? part.attachmentId, "附件无法物化到执行环境", unavailable);
|
|
188
|
+
const value = result.success;
|
|
189
189
|
const canUnderstand = access.canUnderstand?.({
|
|
190
190
|
mediaKind: part.mediaKind,
|
|
191
191
|
mimeType: value.mimeType
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as createInvocationAuthority, i as InvalidInvocationAuthority, n as InvalidToolInput, o as resolveInvocationAuthority, r as createToolInputDigest, s as normalizeAgentInvocation, t as requiresToolApproval } from "./chunks/tool-risk-policy.js";
|
|
2
2
|
import { i as isAgentSteeringRequest, n as cloneAgentSteeringInput, o as projectUserInputText, r as cloneUserInput, t as ATTACHMENT_RECOVERY_COMMAND } from "./chunks/agent-user-input.js";
|
|
3
|
-
import { Deferred, Effect, Option, Queue, Stream } from "effect";
|
|
3
|
+
import { Deferred, Effect, Option, Queue, Semaphore, Stream } from "effect";
|
|
4
4
|
import { unwrapExit } from "@rivus/platform/effect";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
import { appendFile, chmod, lstat, mkdir, readFile, realpath, stat } from "node:fs/promises";
|
|
@@ -2023,10 +2023,10 @@ function createAgentRunStreams(runPrompt) {
|
|
|
2023
2023
|
};
|
|
2024
2024
|
}
|
|
2025
2025
|
function createProjectedRunStream(runPrompt, command, project) {
|
|
2026
|
-
return Stream.
|
|
2026
|
+
return Stream.callback((queue) => runPrompt(command, (event, state, previousState) => Option.match(project(event, state, previousState), {
|
|
2027
2027
|
onNone: () => Effect.void,
|
|
2028
|
-
onSome: (value) =>
|
|
2029
|
-
}), "stream interrupted").pipe(Effect.flatMap(() => Effect.
|
|
2028
|
+
onSome: (value) => Queue.offer(queue, value)
|
|
2029
|
+
}), "stream interrupted").pipe(Effect.flatMap(() => Queue.end(queue)), Effect.catchCause((cause) => Queue.failCause(queue, cause)), Effect.forkScoped, Effect.asVoid), { bufferSize: 16 });
|
|
2030
2030
|
}
|
|
2031
2031
|
//#endregion
|
|
2032
2032
|
//#region src/core/application/agent-execution/execution/agent-loop-event-mapper.ts
|
|
@@ -2146,13 +2146,13 @@ function createSteeringChannel() {
|
|
|
2146
2146
|
nextInput: () => Queue.take(queue),
|
|
2147
2147
|
close: () => Effect.gen(function* () {
|
|
2148
2148
|
closed = true;
|
|
2149
|
-
return Array.from(yield* Queue.
|
|
2149
|
+
return Array.from(yield* Queue.clear(queue)).map(toText);
|
|
2150
2150
|
}),
|
|
2151
2151
|
closeInput: () => Effect.gen(function* () {
|
|
2152
2152
|
closed = true;
|
|
2153
|
-
return Array.from(yield* Queue.
|
|
2153
|
+
return Array.from(yield* Queue.clear(queue));
|
|
2154
2154
|
}),
|
|
2155
|
-
push: (input) => Effect.sync(() => !closed && Queue.
|
|
2155
|
+
push: (input) => Effect.sync(() => !closed && Queue.offerUnsafe(queue, input))
|
|
2156
2156
|
};
|
|
2157
2157
|
}));
|
|
2158
2158
|
}
|
|
@@ -2239,7 +2239,7 @@ function createAgentHarness(options) {
|
|
|
2239
2239
|
for (const sink of options.eventSinks ?? []) yield* Effect.try({
|
|
2240
2240
|
try: () => sink.append(event),
|
|
2241
2241
|
catch: (error) => error
|
|
2242
|
-
}).pipe(Effect.flatMap((appendEffect) => appendEffect), Effect.
|
|
2242
|
+
}).pipe(Effect.flatMap((appendEffect) => appendEffect), Effect.catch((error) => Effect.fail(new AgentEventSinkFailed(event.runId, event.type, error))));
|
|
2243
2243
|
events.push(event);
|
|
2244
2244
|
const update = queryStore.project(event);
|
|
2245
2245
|
state = update.state;
|
|
@@ -2249,7 +2249,7 @@ function createAgentHarness(options) {
|
|
|
2249
2249
|
});
|
|
2250
2250
|
const record = (event) => Effect.gen(function* () {
|
|
2251
2251
|
const update = yield* project(event);
|
|
2252
|
-
yield* emit(update.event, update.state, update.previousState).pipe(Effect.
|
|
2252
|
+
yield* emit(update.event, update.state, update.previousState).pipe(Effect.catch((error) => Effect.fail(new AgentEventHandlerFailed(event.runId, event.type, error, state))));
|
|
2253
2253
|
});
|
|
2254
2254
|
const recordWithoutEmit = (event) => project(event).pipe(Effect.asVoid);
|
|
2255
2255
|
const recordInterruptedRun = Effect.gen(function* () {
|
|
@@ -2265,7 +2265,7 @@ function createAgentHarness(options) {
|
|
|
2265
2265
|
occurredAt: interruptedAt,
|
|
2266
2266
|
runId,
|
|
2267
2267
|
type: "agent_run_cancelled"
|
|
2268
|
-
}).pipe(Effect.
|
|
2268
|
+
}).pipe(Effect.catch(() => Effect.void));
|
|
2269
2269
|
settled = true;
|
|
2270
2270
|
});
|
|
2271
2271
|
return yield* Effect.gen(function* () {
|
|
@@ -2306,10 +2306,10 @@ function createAgentHarness(options) {
|
|
|
2306
2306
|
const loop = Effect.try({
|
|
2307
2307
|
try: () => options.loop.run(loopInput),
|
|
2308
2308
|
catch: (error) => error
|
|
2309
|
-
}).pipe(Effect.flatMap((loopStream) => Stream.runForEach(loopStream.pipe(Stream.
|
|
2309
|
+
}).pipe(Effect.flatMap((loopStream) => Stream.runForEach(loopStream.pipe(Stream.interruptWhen(Deferred.await(cancellation.deferred))), (event) => Effect.gen(function* () {
|
|
2310
2310
|
const occurredAt = yield* options.clock.now;
|
|
2311
2311
|
yield* record(toDomainEvent(runId, command.sessionKey, event, occurredAt));
|
|
2312
|
-
}))), Effect.
|
|
2312
|
+
}))), Effect.catch((error) => {
|
|
2313
2313
|
if (error instanceof AgentEventSinkFailed || error instanceof AgentEventHandlerFailed) return Effect.fail(error);
|
|
2314
2314
|
return Effect.gen(function* () {
|
|
2315
2315
|
const occurredAt = yield* options.clock.now;
|
|
@@ -2324,16 +2324,16 @@ function createAgentHarness(options) {
|
|
|
2324
2324
|
return yield* Effect.fail(new AgentLoopFailed(runId, errorMessage, error, state));
|
|
2325
2325
|
});
|
|
2326
2326
|
}));
|
|
2327
|
-
yield* options.runTimeoutMs === void 0 ? loop : Effect.raceFirst(loop, Effect.sleep(options.runTimeoutMs).pipe(Effect.flatMap(() => {
|
|
2327
|
+
yield* options.runTimeoutMs === void 0 ? loop : Effect.raceFirst(loop, Effect.sleep(options.runTimeoutMs).pipe(Effect.flatMap(() => Effect.gen(function* () {
|
|
2328
2328
|
const request = {
|
|
2329
2329
|
reason: `run timed out after ${options.runTimeoutMs}ms`,
|
|
2330
2330
|
runId,
|
|
2331
2331
|
sessionKey: command.sessionKey
|
|
2332
2332
|
};
|
|
2333
2333
|
cancellation.requested = request;
|
|
2334
|
+
yield* Deferred.succeed(cancellation.deferred, request);
|
|
2334
2335
|
cancellation.abortController.abort(request);
|
|
2335
|
-
|
|
2336
|
-
}), Effect.asVoid));
|
|
2336
|
+
}).pipe(Effect.uninterruptible)), Effect.asVoid));
|
|
2337
2337
|
if (cancellation.requested) {
|
|
2338
2338
|
const cancelledAt = yield* options.clock.now;
|
|
2339
2339
|
yield* record({
|
|
@@ -2400,12 +2400,11 @@ function createAgentHarness(options) {
|
|
|
2400
2400
|
runId: activeRun.runId,
|
|
2401
2401
|
sessionKey: activeRun.sessionKey
|
|
2402
2402
|
};
|
|
2403
|
-
const
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
return completed;
|
|
2403
|
+
const cancellation = activeCancellation;
|
|
2404
|
+
cancellation.requested = request;
|
|
2405
|
+
const requested = yield* Deferred.succeed(cancellation.deferred, request);
|
|
2406
|
+
cancellation.abortController.abort(request);
|
|
2407
|
+
return requested;
|
|
2409
2408
|
});
|
|
2410
2409
|
const requestSteering = (runId, text) => requestSteeringInput(runId, text);
|
|
2411
2410
|
const requestSteeringInput = (runId, input) => Effect.gen(function* () {
|
|
@@ -2580,7 +2579,7 @@ function createRunAdmission(options) {
|
|
|
2580
2579
|
const remaining = input.deadlineAt === void 0 ? void 0 : remainingUntil(options.clock, input.deadlineAt);
|
|
2581
2580
|
if (remaining !== void 0 && remaining <= 0) return Effect.fail(new ModelChangeBoundaryDeadlineError("Run admission deadline has passed"));
|
|
2582
2581
|
if (open) return Effect.sync(createLease);
|
|
2583
|
-
const waiting = Effect.
|
|
2582
|
+
const waiting = Effect.callback((resume) => {
|
|
2584
2583
|
let settled = false;
|
|
2585
2584
|
let waiter;
|
|
2586
2585
|
let onAbort;
|
|
@@ -2608,9 +2607,9 @@ function createRunAdmission(options) {
|
|
|
2608
2607
|
if (onAbort && signal) signal.addEventListener("abort", onAbort, { once: true });
|
|
2609
2608
|
return Effect.sync(cleanup);
|
|
2610
2609
|
});
|
|
2611
|
-
return remaining === void 0 ? waiting : waiting.pipe(Effect.
|
|
2610
|
+
return remaining === void 0 ? waiting : waiting.pipe(Effect.timeoutOrElse({
|
|
2612
2611
|
duration: Math.min(remaining, 2147483647),
|
|
2613
|
-
|
|
2612
|
+
orElse: () => Effect.fail(new ModelChangeBoundaryDeadlineError("Run admission deadline has passed"))
|
|
2614
2613
|
}));
|
|
2615
2614
|
});
|
|
2616
2615
|
const fence = () => {
|
|
@@ -2618,7 +2617,7 @@ function createRunAdmission(options) {
|
|
|
2618
2617
|
};
|
|
2619
2618
|
const whenDrained = () => Effect.suspend(() => {
|
|
2620
2619
|
if (active === 0) return Effect.void;
|
|
2621
|
-
return Effect.
|
|
2620
|
+
return Effect.callback((resume) => {
|
|
2622
2621
|
let settled = false;
|
|
2623
2622
|
let waiter;
|
|
2624
2623
|
const cleanup = () => {
|
|
@@ -2736,7 +2735,7 @@ function createInMemoryAgentMemoryRepository(options = {}) {
|
|
|
2736
2735
|
bucket.set(restored.id, restored);
|
|
2737
2736
|
records.set(namespace, bucket);
|
|
2738
2737
|
}
|
|
2739
|
-
const serial =
|
|
2738
|
+
const serial = Semaphore.makeUnsafe(1);
|
|
2740
2739
|
return {
|
|
2741
2740
|
get: (binding, id) => Effect.sync(() => records.get(createMemoryNamespace(binding))?.get(id)),
|
|
2742
2741
|
list: (binding) => Effect.sync(() => [...records.get(createMemoryNamespace(binding))?.values() ?? []]),
|
|
@@ -3182,7 +3181,7 @@ function createToolOperationLedger(options = {}) {
|
|
|
3182
3181
|
if (records.has(operation.operationId)) throw new ToolOperationLedgerError(`duplicate initial tool operation: ${operation.operationId}`);
|
|
3183
3182
|
records.set(operation.operationId, operation);
|
|
3184
3183
|
}
|
|
3185
|
-
const semaphore =
|
|
3184
|
+
const semaphore = Semaphore.makeUnsafe(1);
|
|
3186
3185
|
const exclusive = (effect) => semaphore.withPermits(1)(Effect.uninterruptible(effect));
|
|
3187
3186
|
const save = (operation) => {
|
|
3188
3187
|
const snapshot = operation.toSnapshot();
|
|
@@ -3338,9 +3337,9 @@ function createToolBroker(options) {
|
|
|
3338
3337
|
})).execute(request.input, context);
|
|
3339
3338
|
if (request.operationId) yield* operations.complete(request.operationId, binding, result);
|
|
3340
3339
|
return result;
|
|
3341
|
-
}).pipe(Effect.
|
|
3340
|
+
}).pipe(Effect.catch((error) => {
|
|
3342
3341
|
if (!request.operationId) return Effect.fail(error);
|
|
3343
|
-
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.
|
|
3342
|
+
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.andThen(Effect.fail(error)));
|
|
3344
3343
|
}));
|
|
3345
3344
|
}) };
|
|
3346
3345
|
}
|
package/dist/pi.js
CHANGED
|
@@ -312,7 +312,7 @@ function createPiAgentLoop(options) {
|
|
|
312
312
|
run: (input) => {
|
|
313
313
|
const stream = Stream.fromAsyncIterable(runPiSession(input, options), (error) => error);
|
|
314
314
|
if (!options.runBoundary) return stream;
|
|
315
|
-
return Stream.
|
|
315
|
+
return Stream.unwrap(Effect.acquireRelease(options.runBoundary.acquireRun({ signal: input.abortSignal }), (lease) => Effect.sync(lease.release)).pipe(Effect.as(stream)));
|
|
316
316
|
}
|
|
317
317
|
};
|
|
318
318
|
}
|
|
@@ -1108,13 +1108,13 @@ function streamPaidProbeCall(options) {
|
|
|
1108
1108
|
});
|
|
1109
1109
|
},
|
|
1110
1110
|
catch: (error) => error
|
|
1111
|
-
}).pipe(Effect.
|
|
1111
|
+
}).pipe(Effect.catch((error) => {
|
|
1112
1112
|
const deadlineExceeded = callSignal.isDeadlineExceeded() || error instanceof PiModelCallDeadlineExceeded;
|
|
1113
1113
|
const probeError = new PiModelProbeError(deadlineExceeded ? `${options.description} stream exceeded the model change deadline` : `${options.description} stream failed: ${error instanceof Error ? error.message : String(error)}`, "unknown", { cause: error }, deadlineExceeded ? "model_change_deadline_exceeded" : "model_change_probe_failed");
|
|
1114
1114
|
return settle({
|
|
1115
1115
|
outcome: "unknown",
|
|
1116
1116
|
outputTokens: reservation.maxOutputTokens
|
|
1117
|
-
}).pipe(Effect.
|
|
1117
|
+
}).pipe(Effect.andThen(Effect.fail(probeError)));
|
|
1118
1118
|
}));
|
|
1119
1119
|
const outputTokens = readOutputTokens(message.usage);
|
|
1120
1120
|
yield* settle({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rivus/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
4
4
|
"description": "Execution core, Pi/ACP adapters, memory, and tool brokerage for Rivus.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "GPL-3.0-only",
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"LICENSE"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@rivus/platform": "0.
|
|
43
|
+
"@rivus/platform": "0.18.1",
|
|
44
44
|
"@earendil-works/pi-coding-agent": "0.84.4",
|
|
45
|
-
"effect": "^
|
|
45
|
+
"effect": "^4.0.0",
|
|
46
46
|
"typebox": "^1.3.34",
|
|
47
47
|
"@opentelemetry/api": "^1.9.1",
|
|
48
48
|
"@opentelemetry/exporter-trace-otlp-proto": "^0.222.0",
|