@rivus/gateway 0.17.0 → 0.18.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.
|
@@ -4,7 +4,7 @@ import { createRandomId, createSha256Digest, createStableId } from "@rivus/platf
|
|
|
4
4
|
import { ATTACHMENT_RECOVERY_COMMAND, AgentEventHandlerFailed, AgentEventSinkFailed, AgentLoopFailed, AgentRunCancelled, ModelChangeBoundaryDeadlineError, RivusToolInputRejected, ToolExecutorInputRejected, ToolInvocationDenied, createAgentHarness, createAgentsMdInstructionsSource, createInvocationAuthority, createJsonlAgentEventLog, createLangfuseAgentTelemetry, createMemoryService, createProjectMemoryPromptPreparer, createRecoveryAction, createRivusMemoryToolDescriptor, createRunAdmission, createTelemetryContentRedactor, createToolBroker, createToolInputDigest, createWorkspaceInstructionsResolver, createWorkspaceRootHandle, normalizeAgentInvocation, openJsonlAgentMemoryRepository, openJsonlToolOperationLedger, remainingUntil, resolveInvocationAuthority, resolveLangfuseTelemetryConfig, restoreAgentHistory } from "@rivus/runtime";
|
|
5
5
|
import { homedir, tmpdir } from "node:os";
|
|
6
6
|
import { delimiter, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
7
|
-
import { Cause, Deferred, Effect,
|
|
7
|
+
import { Cause, Deferred, Effect, Exit, Fiber, Result, Semaphore } from "effect";
|
|
8
8
|
import { access, appendFile, chmod, constants, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
9
9
|
import { createHash, randomUUID } from "node:crypto";
|
|
10
10
|
import { appendJsonlRecord, isRecord, loadJsonlSnapshotStore, readPersistenceFile, writeAtomicTextFile, writePersistenceFile } from "@rivus/platform/persistence";
|
|
@@ -976,7 +976,7 @@ var ModelStateRepositoryConflict = class extends Error {
|
|
|
976
976
|
};
|
|
977
977
|
function createInMemoryModelStateRepository(options) {
|
|
978
978
|
let current = cloneAndValidate$1(options.initial);
|
|
979
|
-
const serial =
|
|
979
|
+
const serial = Semaphore.makeUnsafe(1);
|
|
980
980
|
return {
|
|
981
981
|
load: () => Effect.sync(() => structuredClone(current)),
|
|
982
982
|
persist: (input) => serial.withPermits(1)(Effect.uninterruptible(Effect.gen(function* () {
|
|
@@ -1071,9 +1071,9 @@ function createModelChangeRunBoundary(options) {
|
|
|
1071
1071
|
admission.fence();
|
|
1072
1072
|
const remaining = remainingUntil(options.clock, input.deadlineAt);
|
|
1073
1073
|
if (remaining <= 0) return yield* Effect.fail(new ModelChangeBoundaryDeadlineError("Model change boundary deadline has passed"));
|
|
1074
|
-
yield* admission.whenDrained().pipe(Effect.
|
|
1074
|
+
yield* admission.whenDrained().pipe(Effect.timeoutOrElse({
|
|
1075
1075
|
duration: Math.min(remaining, 2147483647),
|
|
1076
|
-
|
|
1076
|
+
orElse: () => Effect.fail(new ModelChangeBoundaryDeadlineError("Active Runs did not drain before the model change deadline"))
|
|
1077
1077
|
}));
|
|
1078
1078
|
return {
|
|
1079
1079
|
activeRuns: 0,
|
|
@@ -1099,7 +1099,7 @@ const TOOL_VERSION = "1";
|
|
|
1099
1099
|
/** Reuses Broker policy, exact approval binding and its durable operation ledger. */
|
|
1100
1100
|
function createModelChangeAuthorization(options) {
|
|
1101
1101
|
if (typeof options.managementAgentId !== "string" || options.managementAgentId.trim() === "") throw new Error("managementAgentId must be a non-empty string");
|
|
1102
|
-
const serial =
|
|
1102
|
+
const serial = Semaphore.makeUnsafe(1);
|
|
1103
1103
|
const digest = (value) => createToolInputDigest(value, options.digest);
|
|
1104
1104
|
const admissions = /* @__PURE__ */ new Map();
|
|
1105
1105
|
const broker = createToolBroker({
|
|
@@ -1666,46 +1666,46 @@ function executeModelChangePending(options, initialState, initialPending) {
|
|
|
1666
1666
|
phase: "waiting-for-boundary"
|
|
1667
1667
|
});
|
|
1668
1668
|
boundaryHeld = true;
|
|
1669
|
-
const boundary = yield* Effect.
|
|
1669
|
+
const boundary = yield* Effect.result(options.boundary.waitForSafeBoundary({
|
|
1670
1670
|
deadlineAt: pending.budget.deadlineAt,
|
|
1671
1671
|
requestId: pending.request.requestId
|
|
1672
1672
|
}));
|
|
1673
|
-
if (
|
|
1674
|
-
const authorization = yield* Effect.
|
|
1675
|
-
if (
|
|
1676
|
-
if (authorization.
|
|
1673
|
+
if (Result.isFailure(boundary)) return yield* saveFailed(modelErrorFrom(boundary.failure, "boundary"));
|
|
1674
|
+
const authorization = yield* Effect.result(revalidateAcceptedBinding());
|
|
1675
|
+
if (Result.isFailure(authorization)) return yield* saveFailed(modelErrorFrom(authorization.failure, "boundary"));
|
|
1676
|
+
if (authorization.success.status === "rejected") return yield* saveFailed(modelError(authorization.success.code, authorization.success.reason, "boundary"));
|
|
1677
1677
|
yield* savePending({
|
|
1678
1678
|
...pending,
|
|
1679
1679
|
phase: "validating"
|
|
1680
1680
|
});
|
|
1681
1681
|
const context = runtimeContext(state, pending);
|
|
1682
|
-
const drained = yield* Effect.
|
|
1682
|
+
const drained = yield* Effect.result(options.runtime.drain({
|
|
1683
1683
|
...context,
|
|
1684
1684
|
deadlineAt: pending.budget.deadlineAt
|
|
1685
1685
|
}));
|
|
1686
|
-
if (
|
|
1686
|
+
if (Result.isFailure(drained)) return yield* restoreAfterFailure({
|
|
1687
1687
|
context,
|
|
1688
|
-
error: modelErrorFrom(drained.
|
|
1688
|
+
error: modelErrorFrom(drained.failure, "activation"),
|
|
1689
1689
|
options,
|
|
1690
1690
|
saveFinal,
|
|
1691
1691
|
savePending,
|
|
1692
1692
|
state: () => state,
|
|
1693
1693
|
pending: () => pending
|
|
1694
1694
|
});
|
|
1695
|
-
const validated = yield* Effect.
|
|
1695
|
+
const validated = yield* Effect.result(options.runtime.validate({
|
|
1696
1696
|
context,
|
|
1697
1697
|
budget: executionBudget
|
|
1698
1698
|
}));
|
|
1699
|
-
if (
|
|
1699
|
+
if (Result.isFailure(validated)) return yield* restoreAfterFailure({
|
|
1700
1700
|
context,
|
|
1701
|
-
error: modelErrorFrom(validated.
|
|
1701
|
+
error: modelErrorFrom(validated.failure, "validation"),
|
|
1702
1702
|
options,
|
|
1703
1703
|
saveFinal,
|
|
1704
1704
|
savePending,
|
|
1705
1705
|
state: () => state,
|
|
1706
1706
|
pending: () => pending
|
|
1707
1707
|
});
|
|
1708
|
-
if (!validated.
|
|
1708
|
+
if (!validated.success.passed || !sameTarget(validated.success.model, target)) return yield* restoreAfterFailure({
|
|
1709
1709
|
context,
|
|
1710
1710
|
error: modelError("validation_failed", "Model validation did not prove the requested target", "validation"),
|
|
1711
1711
|
options,
|
|
@@ -1714,25 +1714,25 @@ function executeModelChangePending(options, initialState, initialPending) {
|
|
|
1714
1714
|
state: () => state,
|
|
1715
1715
|
pending: () => pending
|
|
1716
1716
|
});
|
|
1717
|
-
const activationAuthorization = yield* Effect.
|
|
1718
|
-
if (
|
|
1719
|
-
if (activationAuthorization.
|
|
1717
|
+
const activationAuthorization = yield* Effect.result(revalidateAcceptedBinding());
|
|
1718
|
+
if (Result.isFailure(activationAuthorization)) return yield* saveFailed(modelErrorFrom(activationAuthorization.failure, "activation"));
|
|
1719
|
+
if (activationAuthorization.success.status === "rejected") return yield* saveFailed(modelError(activationAuthorization.success.code, activationAuthorization.success.reason, "activation"));
|
|
1720
1720
|
yield* savePending({
|
|
1721
1721
|
...pending,
|
|
1722
1722
|
phase: "activating"
|
|
1723
1723
|
});
|
|
1724
|
-
const activated = yield* Effect.
|
|
1724
|
+
const activated = yield* Effect.result(options.runtime.activate({
|
|
1725
1725
|
beforeApply: () => Effect.gen(function* () {
|
|
1726
1726
|
const guard = yield* revalidateAcceptedBinding();
|
|
1727
1727
|
if (guard.status === "rejected") return yield* Effect.fail(new Error(guard.reason));
|
|
1728
1728
|
}),
|
|
1729
1729
|
context,
|
|
1730
|
-
validation: validated.
|
|
1730
|
+
validation: validated.success,
|
|
1731
1731
|
budget: executionBudget
|
|
1732
1732
|
}));
|
|
1733
|
-
if (
|
|
1733
|
+
if (Result.isFailure(activated)) return yield* restoreAfterFailure({
|
|
1734
1734
|
context,
|
|
1735
|
-
error: modelErrorFrom(activated.
|
|
1735
|
+
error: modelErrorFrom(activated.failure, "activation"),
|
|
1736
1736
|
options,
|
|
1737
1737
|
saveFinal,
|
|
1738
1738
|
savePending,
|
|
@@ -1755,7 +1755,7 @@ function executeModelChangePending(options, initialState, initialPending) {
|
|
|
1755
1755
|
const now = requireNow(options);
|
|
1756
1756
|
const applied = {
|
|
1757
1757
|
...pendingReceipt(state, pending, now),
|
|
1758
|
-
current: validated.
|
|
1758
|
+
current: validated.success.model,
|
|
1759
1759
|
phase: options.notification ? "notifying" : "completed",
|
|
1760
1760
|
previous: state.current,
|
|
1761
1761
|
revision: state.revision + 1,
|
|
@@ -1768,7 +1768,7 @@ function executeModelChangePending(options, initialState, initialPending) {
|
|
|
1768
1768
|
const { pending: _pending, recoveryRequired: _recoveryRequired, ...stateWithoutTransient } = state;
|
|
1769
1769
|
const appliedState = {
|
|
1770
1770
|
...stateWithoutTransient,
|
|
1771
|
-
current: validated.
|
|
1771
|
+
current: validated.success.model,
|
|
1772
1772
|
previous: state.current,
|
|
1773
1773
|
requests: {
|
|
1774
1774
|
...state.requests,
|
|
@@ -1777,28 +1777,28 @@ function executeModelChangePending(options, initialState, initialPending) {
|
|
|
1777
1777
|
revision: state.revision + 1,
|
|
1778
1778
|
updatedAt: now
|
|
1779
1779
|
};
|
|
1780
|
-
const committed = yield* Effect.
|
|
1781
|
-
if (
|
|
1780
|
+
const committed = yield* Effect.result(persistState(options, appliedState));
|
|
1781
|
+
if (Result.isFailure(committed)) return yield* restoreAfterFailure({
|
|
1782
1782
|
context,
|
|
1783
|
-
error: modelErrorFrom(committed.
|
|
1783
|
+
error: modelErrorFrom(committed.failure, "commit"),
|
|
1784
1784
|
options,
|
|
1785
1785
|
saveFinal,
|
|
1786
1786
|
savePending,
|
|
1787
1787
|
state: () => state,
|
|
1788
1788
|
pending: () => pending
|
|
1789
1789
|
});
|
|
1790
|
-
state = committed.
|
|
1790
|
+
state = committed.success;
|
|
1791
1791
|
pending = {
|
|
1792
1792
|
...pending,
|
|
1793
1793
|
phase: "completed",
|
|
1794
1794
|
updatedAt: now
|
|
1795
1795
|
};
|
|
1796
|
-
const release = yield* Effect.
|
|
1796
|
+
const release = yield* Effect.result(options.runtime.releasePrevious({
|
|
1797
1797
|
...context,
|
|
1798
1798
|
deadlineAt: pending.budget.deadlineAt
|
|
1799
1799
|
}));
|
|
1800
|
-
if (
|
|
1801
|
-
const releaseError = modelErrorFrom(release.
|
|
1800
|
+
if (Result.isFailure(release)) {
|
|
1801
|
+
const releaseError = modelErrorFrom(release.failure, "activation");
|
|
1802
1802
|
const withReleaseError = {
|
|
1803
1803
|
...applied,
|
|
1804
1804
|
error: releaseError,
|
|
@@ -1834,16 +1834,16 @@ function restoreAfterFailure(input) {
|
|
|
1834
1834
|
const { unknownPaidCallId: _unknownPaidCallId, ...withoutUnknown } = marked;
|
|
1835
1835
|
yield* input.savePending({ ...withoutUnknown });
|
|
1836
1836
|
}
|
|
1837
|
-
const restored = yield* Effect.
|
|
1837
|
+
const restored = yield* Effect.result(input.options.runtime.restore({
|
|
1838
1838
|
budget: executionBudgetForRecovery(input),
|
|
1839
1839
|
context: input.context,
|
|
1840
1840
|
reason: input.error.message
|
|
1841
1841
|
}));
|
|
1842
|
-
if (
|
|
1842
|
+
if (Result.isSuccess(restored) && !input.pending().unknownPaidCallId && Object.keys(input.pending().budget.reservations).length === 0) {
|
|
1843
1843
|
const receipt = restoredReceipt(input.state(), input.pending(), input.error, requireNow(input.options));
|
|
1844
1844
|
return yield* input.saveFinal(receipt);
|
|
1845
1845
|
}
|
|
1846
|
-
const recoveryError =
|
|
1846
|
+
const recoveryError = Result.isFailure(restored) ? modelErrorFrom(restored.failure, "restore") : modelError("recovery_unknown", "Model restore outcome is unknown", "restore", "unknown");
|
|
1847
1847
|
const receipt = recoveryReceipt(input.state(), input.pending(), recoveryError, requireNow(input.options));
|
|
1848
1848
|
return yield* input.saveFinal(receipt, true);
|
|
1849
1849
|
});
|
|
@@ -1950,7 +1950,7 @@ function recoverModelChangePending(options, initialState, initialPending) {
|
|
|
1950
1950
|
updatedAt: requireNow(options)
|
|
1951
1951
|
};
|
|
1952
1952
|
state = yield* persistState(options, stateWithPending(state, pending, pendingReceipt(state, pending, pending.updatedAt)));
|
|
1953
|
-
const restored = yield* Effect.
|
|
1953
|
+
const restored = yield* Effect.result(options.runtime.restore({
|
|
1954
1954
|
budget: executionBudgetForRecovery({
|
|
1955
1955
|
options,
|
|
1956
1956
|
pending: () => pending,
|
|
@@ -1964,11 +1964,11 @@ function recoverModelChangePending(options, initialState, initialPending) {
|
|
|
1964
1964
|
context,
|
|
1965
1965
|
reason: "recovering an interrupted Model change"
|
|
1966
1966
|
}));
|
|
1967
|
-
if (
|
|
1967
|
+
if (Result.isSuccess(restored) && !pending.unknownPaidCallId && Object.keys(pending.budget.reservations).length === 0) {
|
|
1968
1968
|
const receipt = restoredReceipt(state, pending, void 0, requireNow(options));
|
|
1969
1969
|
return yield* persistRecoveryReceipt(options, state, receipt);
|
|
1970
1970
|
}
|
|
1971
|
-
const error =
|
|
1971
|
+
const error = Result.isFailure(restored) ? modelErrorFrom(restored.failure, "restore") : modelError("recovery_unknown", "interrupted Model restore outcome is unknown", "restore", "unknown");
|
|
1972
1972
|
const receipt = recoveryReceipt(state, pending, error, requireNow(options));
|
|
1973
1973
|
return yield* persistRecoveryReceipt(options, state, receipt, error);
|
|
1974
1974
|
});
|
|
@@ -2022,7 +2022,7 @@ function notifyModelChangeReceipt(options, requestId, retry, withModelSerial) {
|
|
|
2022
2022
|
return Effect.gen(function* () {
|
|
2023
2023
|
const attempted = yield* withModelSerial(beginNotificationAttempt(options, requestId));
|
|
2024
2024
|
if (!attempted) return;
|
|
2025
|
-
return yield* withModelSerial(finishNotificationAttempt(options, requestId, attempted, yield* Effect.
|
|
2025
|
+
return yield* withModelSerial(finishNotificationAttempt(options, requestId, attempted, yield* Effect.result(notification.notify({
|
|
2026
2026
|
receipt: toPublicReceipt(attempted),
|
|
2027
2027
|
retry
|
|
2028
2028
|
}))));
|
|
@@ -2051,7 +2051,7 @@ function finishNotificationAttempt(options, requestId, attempted, delivered) {
|
|
|
2051
2051
|
const latest = state.requests[requestId];
|
|
2052
2052
|
if (!latest || !latest.notification || latest.notification.status === "sent") return latest;
|
|
2053
2053
|
const updatedAt = requireNow(options);
|
|
2054
|
-
return (yield* persistReceiptPatch(options, state,
|
|
2054
|
+
return (yield* persistReceiptPatch(options, state, Result.isSuccess(delivered) ? {
|
|
2055
2055
|
...latest,
|
|
2056
2056
|
notification: {
|
|
2057
2057
|
...latest.notification,
|
|
@@ -2083,8 +2083,8 @@ function persistReceiptPatch(options, state, receipt) {
|
|
|
2083
2083
|
//#endregion
|
|
2084
2084
|
//#region src/core/application/deployment/model/model-change-coordinator.ts
|
|
2085
2085
|
function createModelChangeCoordinator(options) {
|
|
2086
|
-
const serial =
|
|
2087
|
-
const notificationSerial =
|
|
2086
|
+
const serial = Semaphore.makeUnsafe(1);
|
|
2087
|
+
const notificationSerial = Semaphore.makeUnsafe(1);
|
|
2088
2088
|
return {
|
|
2089
2089
|
accept: (submission, transport) => serial.withPermits(1)(Effect.uninterruptible(acceptRequest(options, submission, transport))).pipe(Effect.flatMap((receipt) => notifyPendingReceipt(options, receipt, serial, notificationSerial))),
|
|
2090
2090
|
recover: () => serial.withPermits(1)(Effect.uninterruptible(recoverModelChangeState(options))).pipe(Effect.flatMap(() => retryPendingNotifications(options, serial, notificationSerial))),
|
|
@@ -2099,7 +2099,7 @@ function createModelChangeCoordinator(options) {
|
|
|
2099
2099
|
}),
|
|
2100
2100
|
status: (requestId) => Effect.gen(function* () {
|
|
2101
2101
|
const state = yield* loadState$1(options);
|
|
2102
|
-
const actual = options.runtime.current ? yield* options.runtime.current().pipe(Effect.
|
|
2102
|
+
const actual = options.runtime.current ? yield* options.runtime.current().pipe(Effect.catch(() => Effect.succeed(void 0))) : void 0;
|
|
2103
2103
|
const receipt = requestId === void 0 ? void 0 : state.requests[requestId];
|
|
2104
2104
|
if (requestId !== void 0 && !receipt) return yield* Effect.fail(new ModelChangeNotFound(`unknown Model change request: ${requestId}`));
|
|
2105
2105
|
return toStatusView(state, actual, receipt);
|
|
@@ -2735,14 +2735,14 @@ function createBackgroundSessionRunStep(input) {
|
|
|
2735
2735
|
})));
|
|
2736
2736
|
return yield* Effect.raceFirst(run, waitForAbort$2(signal));
|
|
2737
2737
|
}).pipe(Effect.onExit((exit) => Effect.suspend(() => {
|
|
2738
|
-
cancellationRequested = signal.aborted || Exit.
|
|
2738
|
+
cancellationRequested = signal.aborted || Exit.hasInterrupts(exit);
|
|
2739
2739
|
return cancellationRequested ? cancelAcceptedRun() : Effect.void;
|
|
2740
2740
|
})));
|
|
2741
2741
|
});
|
|
2742
2742
|
};
|
|
2743
2743
|
}
|
|
2744
2744
|
function waitForAbort$2(signal) {
|
|
2745
|
-
return Effect.
|
|
2745
|
+
return Effect.callback((resume) => {
|
|
2746
2746
|
const aborted = () => resume(Effect.fail(signal.reason ?? /* @__PURE__ */ new Error("background session step aborted")));
|
|
2747
2747
|
if (signal.aborted) {
|
|
2748
2748
|
aborted();
|
|
@@ -4494,7 +4494,7 @@ function createFeishuCardRollover(options) {
|
|
|
4494
4494
|
const latestTextByRun = /* @__PURE__ */ new Map();
|
|
4495
4495
|
const generationBaselineByRun = /* @__PURE__ */ new Map();
|
|
4496
4496
|
const liveRuns = /* @__PURE__ */ new Map();
|
|
4497
|
-
const semaphore =
|
|
4497
|
+
const semaphore = Semaphore.makeUnsafe(1);
|
|
4498
4498
|
const exclusive = (effect) => semaphore.withPermits(1)(effect);
|
|
4499
4499
|
const exclusiveDeferred = (factory) => semaphore.withPermits(1)(Effect.suspend(factory));
|
|
4500
4500
|
const record = (event, at) => {
|
|
@@ -4508,7 +4508,7 @@ function createFeishuCardRollover(options) {
|
|
|
4508
4508
|
const failHandoffAndRecord = (input) => options.store.failHandoff({
|
|
4509
4509
|
failedAt: input.failedAt,
|
|
4510
4510
|
runId: input.runId
|
|
4511
|
-
}).pipe(Effect.
|
|
4511
|
+
}).pipe(Effect.catch((storeError) => recordNow({
|
|
4512
4512
|
error: storeError,
|
|
4513
4513
|
runId: input.runId,
|
|
4514
4514
|
type: "presentation_write_failed"
|
|
@@ -4548,7 +4548,7 @@ function createFeishuCardRollover(options) {
|
|
|
4548
4548
|
if (run && acceptsProgress) {
|
|
4549
4549
|
const now = yield* options.clock.now;
|
|
4550
4550
|
if (visibleChanged && isCardPresentationHandoffDue(chain, now.toISOString())) {
|
|
4551
|
-
if (yield* options.publisher.flush(action.runId).pipe(Effect.map(() => true), Effect.
|
|
4551
|
+
if (yield* options.publisher.flush(action.runId).pipe(Effect.map(() => true), Effect.catch((error) => recordNow({
|
|
4552
4552
|
error,
|
|
4553
4553
|
runId: action.runId,
|
|
4554
4554
|
type: "presentation_write_failed"
|
|
@@ -4605,7 +4605,7 @@ function createFeishuCardRollover(options) {
|
|
|
4605
4605
|
})), Effect.tap(() => options.store.markTerminal({
|
|
4606
4606
|
runId: action.runId,
|
|
4607
4607
|
terminalReceiptId: `${action.runId}:${action.type}`
|
|
4608
|
-
}).pipe(Effect.
|
|
4608
|
+
}).pipe(Effect.catch((error) => recordNow({
|
|
4609
4609
|
error,
|
|
4610
4610
|
runId: action.runId,
|
|
4611
4611
|
type: "presentation_write_failed"
|
|
@@ -4643,7 +4643,7 @@ function createFeishuCardRollover(options) {
|
|
|
4643
4643
|
const start = yield* options.store.beginHandoff({
|
|
4644
4644
|
handoffAt: startedAt.toISOString(),
|
|
4645
4645
|
runId
|
|
4646
|
-
}).pipe(Effect.
|
|
4646
|
+
}).pipe(Effect.catch(() => Effect.succeed(void 0)));
|
|
4647
4647
|
if (!start) return {
|
|
4648
4648
|
reason: "not-streaming",
|
|
4649
4649
|
status: "skipped"
|
|
@@ -4667,7 +4667,7 @@ function createFeishuCardRollover(options) {
|
|
|
4667
4667
|
generation,
|
|
4668
4668
|
presentationId: successorId,
|
|
4669
4669
|
run
|
|
4670
|
-
}).pipe(Effect.map((target) => ({ target })), Effect.
|
|
4670
|
+
}).pipe(Effect.map((target) => ({ target })), Effect.catch((error) => failHandoffAndRecord({
|
|
4671
4671
|
error,
|
|
4672
4672
|
failedAt: startedAt.toISOString(),
|
|
4673
4673
|
generation,
|
|
@@ -4689,7 +4689,7 @@ function createFeishuCardRollover(options) {
|
|
|
4689
4689
|
leaseDeadlineAt: leaseDeadline(adoptedAt),
|
|
4690
4690
|
presentationId: successorId
|
|
4691
4691
|
}
|
|
4692
|
-
}).pipe(Effect.map((presentation) => ({ presentation })), Effect.
|
|
4692
|
+
}).pipe(Effect.map((presentation) => ({ presentation })), Effect.catch((error) => failHandoffAndRecord({
|
|
4693
4693
|
error,
|
|
4694
4694
|
failedAt: adoptedAt.toISOString(),
|
|
4695
4695
|
generation,
|
|
@@ -4980,7 +4980,7 @@ function createCoalescingFeishuPublisher(options) {
|
|
|
4980
4980
|
//#region src/adapters/feishu/card-presentation/streaming/feishu-rate-limited-publisher.ts
|
|
4981
4981
|
function createRateLimitedFeishuPublisher(options) {
|
|
4982
4982
|
let hasPublished = false;
|
|
4983
|
-
const semaphore =
|
|
4983
|
+
const semaphore = Semaphore.makeUnsafe(1);
|
|
4984
4984
|
return { publish: (action) => semaphore.withPermits(1)(Effect.gen(function* () {
|
|
4985
4985
|
if (hasPublished) yield* options.sleep(options.minIntervalMs);
|
|
4986
4986
|
yield* options.publisher.publish(action);
|
|
@@ -5156,7 +5156,7 @@ function createFeishuCardKitOpenApiClient(options) {
|
|
|
5156
5156
|
const updateTerminal = (request, status) => updateWholeCard(baseUrl, agentName, request, status, call, options.progressDisplay).pipe(Effect.tap(() => Effect.sync(() => streamingClosedCards.delete(request.cardId))));
|
|
5157
5157
|
const publishStreamingUpdate = (cardId, update) => {
|
|
5158
5158
|
if (streamingClosedCards.has(cardId)) return Effect.void;
|
|
5159
|
-
return update.pipe(Effect.
|
|
5159
|
+
return update.pipe(Effect.catch((error) => {
|
|
5160
5160
|
if (!isStreamingClosed(error)) return Effect.fail(error);
|
|
5161
5161
|
return Effect.sync(() => {
|
|
5162
5162
|
streamingClosedCards.add(cardId);
|
|
@@ -5313,7 +5313,7 @@ function createCardDeliveryLedger(repository) {
|
|
|
5313
5313
|
//#region src/adapters/outbound/persistence/card-delivery/in-memory-card-delivery-repository.ts
|
|
5314
5314
|
function createInMemoryCardDeliveryRepository(options = {}) {
|
|
5315
5315
|
const records = new Map(options.initial?.map((record) => [record.runId, cloneRecord(record)]) ?? []);
|
|
5316
|
-
const semaphore =
|
|
5316
|
+
const semaphore = Semaphore.makeUnsafe(1);
|
|
5317
5317
|
return {
|
|
5318
5318
|
get: (runId) => cloneOptional(records.get(runId)),
|
|
5319
5319
|
transact: (runId, decide) => semaphore.withPermits(1)(Effect.uninterruptible(Effect.gen(function* () {
|
|
@@ -5812,7 +5812,7 @@ function createFeishuCardDeliveryReconciler(options) {
|
|
|
5812
5812
|
let skipped = 0;
|
|
5813
5813
|
for (const [runId, action] of terminalByRun) {
|
|
5814
5814
|
if (options.ledger.isTerminalPublished(runId)) continue;
|
|
5815
|
-
yield* options.publish(action).pipe(Effect.
|
|
5815
|
+
yield* options.publish(action).pipe(Effect.catch((error) => {
|
|
5816
5816
|
if (isMissingPresentationError(error)) {
|
|
5817
5817
|
skipped += 1;
|
|
5818
5818
|
return Effect.void;
|
|
@@ -6046,7 +6046,7 @@ function createConfiguredFeishuCardRolloverRuntime(options) {
|
|
|
6046
6046
|
transport: {
|
|
6047
6047
|
running: () => supervisor.running() && streaming.running(),
|
|
6048
6048
|
start: async () => {
|
|
6049
|
-
await Effect.runPromise(supervisor.recover().pipe(Effect.
|
|
6049
|
+
await Effect.runPromise(supervisor.recover().pipe(Effect.catch((error) => {
|
|
6050
6050
|
const reported = options.onError?.(error);
|
|
6051
6051
|
return reported instanceof Promise ? Effect.promise(() => reported) : Effect.void;
|
|
6052
6052
|
})));
|
|
@@ -6262,7 +6262,7 @@ function readResource(baseUrl, fetchImpl, getTenantAccessToken, input) {
|
|
|
6262
6262
|
message: "Feishu tenant access token is unavailable"
|
|
6263
6263
|
})));
|
|
6264
6264
|
if (input.signal?.aborted === true) return yield* Effect.fail(cancelledError$1());
|
|
6265
|
-
return yield* Effect.
|
|
6265
|
+
return yield* Effect.callback((resume, effectSignal) => {
|
|
6266
6266
|
const controller = new AbortController();
|
|
6267
6267
|
const onAbort = () => controller.abort();
|
|
6268
6268
|
const cleanupCaller = addAbortListener(input.signal, onAbort);
|
|
@@ -7481,14 +7481,14 @@ function readPages(readPage, input, limits) {
|
|
|
7481
7481
|
...pageToken === void 0 ? {} : { pageToken },
|
|
7482
7482
|
...input.signal ? { signal: input.signal } : {}
|
|
7483
7483
|
};
|
|
7484
|
-
const pageResult = yield* Effect.
|
|
7484
|
+
const pageResult = yield* Effect.result(readPageWithSignal(readPage, request, input.signal));
|
|
7485
7485
|
pageCount += 1;
|
|
7486
|
-
if (pageResult._tag === "
|
|
7486
|
+
if (pageResult._tag === "Failure") {
|
|
7487
7487
|
if (input.signal !== void 0 && input.signal.aborted) return yield* Effect.fail(cancelledError());
|
|
7488
7488
|
notices.push(contextNotice("unavailable", "无法读取引用消息的完整内容"));
|
|
7489
7489
|
break;
|
|
7490
7490
|
}
|
|
7491
|
-
const parsed = parsePage(pageResult.
|
|
7491
|
+
const parsed = parsePage(pageResult.success);
|
|
7492
7492
|
if (parsed === void 0) {
|
|
7493
7493
|
notices.push(contextNotice("invalid_content", "引用消息接口返回结构无效"));
|
|
7494
7494
|
break;
|
|
@@ -7530,7 +7530,7 @@ function readPageWithSignal(readPage, request, signal) {
|
|
|
7530
7530
|
return signal === void 0 ? invoked : Effect.raceFirst(invoked, waitForAbort$1(signal));
|
|
7531
7531
|
}
|
|
7532
7532
|
function waitForAbort$1(signal) {
|
|
7533
|
-
return Effect.
|
|
7533
|
+
return Effect.callback((resume) => {
|
|
7534
7534
|
const cancelled = Effect.fail(signal.reason ?? /* @__PURE__ */ new Error("Feishu message context was cancelled"));
|
|
7535
7535
|
const onAbort = () => resume(cancelled);
|
|
7536
7536
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
@@ -8591,7 +8591,7 @@ function writeExclusiveReplacing(rootDirectory, path, bytes) {
|
|
|
8591
8591
|
flag: "wx",
|
|
8592
8592
|
mode: 384
|
|
8593
8593
|
}));
|
|
8594
|
-
return Effect.tryPromise(write).pipe(Effect.
|
|
8594
|
+
return Effect.tryPromise(write).pipe(Effect.catch((error) => error.code === "EEXIST" ? Effect.tryPromise(async () => rm(await resolveSafeWorkspacePath(rootDirectory, path), { force: true })).pipe(Effect.flatMap(() => Effect.tryPromise(write))) : Effect.fail(error)));
|
|
8595
8595
|
}
|
|
8596
8596
|
function verifyStoredPath(stored, rootDirectory, additionalRootDirectory) {
|
|
8597
8597
|
return Effect.tryPromise(async () => {
|
|
@@ -8669,7 +8669,7 @@ function materializeRecoveryOutput(input) {
|
|
|
8669
8669
|
outputPath: relativePath === "" ? outputPath : relativePath,
|
|
8670
8670
|
sizeBytes: bytes.byteLength
|
|
8671
8671
|
};
|
|
8672
|
-
}).pipe(Effect.
|
|
8672
|
+
}).pipe(Effect.catch((error) => Effect.fail(attachConsumedBytes(error, input.output.sizeBytes))));
|
|
8673
8673
|
}
|
|
8674
8674
|
/** The stored record of a recovery output; the caller states where its bytes are and what they measured. */
|
|
8675
8675
|
function recoveredAttachment(grant, mimeType, path, size, digest) {
|
|
@@ -8903,13 +8903,13 @@ function createAttachmentAccess(input) {
|
|
|
8903
8903
|
output,
|
|
8904
8904
|
scope: input.scope,
|
|
8905
8905
|
workspaceDirectory: input.workspaceDirectory
|
|
8906
|
-
})), Effect.
|
|
8906
|
+
})), Effect.catch((error) => Effect.fail(attachConsumedBytes(error, output.sizeBytes))))), Effect.result, Effect.flatMap((result) => {
|
|
8907
8907
|
const activeTimeMs = Math.min(reservation.timeReservationMs, Math.max(0, Date.now() - startedAt));
|
|
8908
8908
|
return grant.ledger.complete(reservation, {
|
|
8909
8909
|
activeTimeMs,
|
|
8910
|
-
bytes: result._tag === "
|
|
8911
|
-
status: result._tag === "
|
|
8912
|
-
}).pipe(Effect.flatMap(() => result._tag === "
|
|
8910
|
+
bytes: result._tag === "Success" ? result.success.sizeBytes : consumedBytesOf(result.failure, reservation.byteReservation),
|
|
8911
|
+
status: result._tag === "Success" ? "stored" : signal.aborted ? "cancelled" : "failed"
|
|
8912
|
+
}).pipe(Effect.flatMap(() => result._tag === "Success" ? Effect.succeed(result.success) : Effect.fail(result.failure)));
|
|
8913
8913
|
}))));
|
|
8914
8914
|
} : void 0;
|
|
8915
8915
|
const readBytes = (attachmentId) => {
|
|
@@ -9080,14 +9080,14 @@ function downloadAndPublish(resource, request, reader, rootDirectory, signal, bu
|
|
|
9080
9080
|
yield* writeExclusiveReplacing(rootDirectory, metadataTempPath, new TextEncoder().encode(JSON.stringify(metadata)));
|
|
9081
9081
|
yield* Effect.tryPromise(async () => rename(await resolveSafeWorkspacePath(rootDirectory, metadataTempPath), await resolveSafeWorkspacePath(rootDirectory, metadataPath)));
|
|
9082
9082
|
return stored;
|
|
9083
|
-
}).pipe(Effect.
|
|
9084
|
-
if (publication._tag === "
|
|
9083
|
+
}).pipe(Effect.result);
|
|
9084
|
+
if (publication._tag === "Failure") return yield* failPrepared(publication.failure);
|
|
9085
9085
|
yield* ledger.complete(prepared.reservation, {
|
|
9086
9086
|
activeTimeMs: activeTimeMs(),
|
|
9087
9087
|
bytes: bytes.byteLength,
|
|
9088
9088
|
status: "stored"
|
|
9089
9089
|
});
|
|
9090
|
-
return publication.
|
|
9090
|
+
return publication.success;
|
|
9091
9091
|
}).pipe(Effect.ensuring(Effect.tryPromise(async () => rm(await resolveSafeWorkspacePath(rootDirectory, temporaryPath), { force: true })).pipe(Effect.ignore)));
|
|
9092
9092
|
}
|
|
9093
9093
|
function readWithRetries(reader, input, outerSignal, budget) {
|
|
@@ -9112,27 +9112,27 @@ function readWithRetries(reader, input, outerSignal, budget) {
|
|
|
9112
9112
|
timeReservationMs: remainingMs
|
|
9113
9113
|
});
|
|
9114
9114
|
const attemptStarted = Date.now();
|
|
9115
|
-
const result = yield* readAttempt(reader, input, outerSignal, Math.min(attemptTimeoutMs, reservation.timeReservationMs)).pipe(Effect.
|
|
9116
|
-
if (result._tag === "
|
|
9115
|
+
const result = yield* readAttempt(reader, input, outerSignal, Math.min(attemptTimeoutMs, reservation.timeReservationMs)).pipe(Effect.result);
|
|
9116
|
+
if (result._tag === "Success") {
|
|
9117
9117
|
const activeTimeMs = Math.min(reservation.timeReservationMs, Math.max(0, Date.now() - attemptStarted));
|
|
9118
|
-
if (result.
|
|
9118
|
+
if (result.success.bytes.byteLength > maxBytes) {
|
|
9119
9119
|
yield* ledger.complete(reservation, {
|
|
9120
9120
|
activeTimeMs,
|
|
9121
|
-
bytes: Math.min(result.
|
|
9121
|
+
bytes: Math.min(result.success.bytes.byteLength, reservation.byteReservation),
|
|
9122
9122
|
status: "failed"
|
|
9123
9123
|
});
|
|
9124
9124
|
return yield* Effect.fail(new FeishuAttachmentLimitExceeded("attachment byte limit exceeded"));
|
|
9125
9125
|
}
|
|
9126
9126
|
return {
|
|
9127
9127
|
activeTimeMs,
|
|
9128
|
-
read: result.
|
|
9128
|
+
read: result.success,
|
|
9129
9129
|
reservation,
|
|
9130
9130
|
startedAtMs: attemptStarted
|
|
9131
9131
|
};
|
|
9132
9132
|
}
|
|
9133
|
-
lastError = result.
|
|
9133
|
+
lastError = result.failure;
|
|
9134
9134
|
const delay = retryBackoffMs[attempt] ?? retryBackoffMs.at(-1) ?? 0;
|
|
9135
|
-
const retry = isRetryableDownloadError(result.
|
|
9135
|
+
const retry = isRetryableDownloadError(result.failure) && attempt + 1 < maxAttempts;
|
|
9136
9136
|
if (retry && delay > 0) yield* sleep(delay);
|
|
9137
9137
|
if (outerSignal.aborted) {
|
|
9138
9138
|
yield* ledger.cancel().pipe(Effect.ignore);
|
|
@@ -9140,8 +9140,8 @@ function readWithRetries(reader, input, outerSignal, budget) {
|
|
|
9140
9140
|
}
|
|
9141
9141
|
yield* ledger.complete(reservation, {
|
|
9142
9142
|
activeTimeMs: Math.min(reservation.timeReservationMs, Math.max(0, Date.now() - attemptStarted)),
|
|
9143
|
-
bytes: consumedBytesOf(result.
|
|
9144
|
-
retryableFailure: isRetryableDownloadError(result.
|
|
9143
|
+
bytes: consumedBytesOf(result.failure, reservation.byteReservation),
|
|
9144
|
+
retryableFailure: isRetryableDownloadError(result.failure),
|
|
9145
9145
|
status: "failed"
|
|
9146
9146
|
});
|
|
9147
9147
|
if (!retry) break;
|
|
@@ -9163,9 +9163,9 @@ function readAttempt(reader, input, outerSignal, timeoutMs) {
|
|
|
9163
9163
|
const result = yield* reader.read({
|
|
9164
9164
|
...input,
|
|
9165
9165
|
signal: controller.signal
|
|
9166
|
-
}).pipe(Effect.
|
|
9167
|
-
if (result._tag === "
|
|
9168
|
-
return yield* result;
|
|
9166
|
+
}).pipe(Effect.result);
|
|
9167
|
+
if (result._tag === "Failure" && timedOut) return yield* Effect.fail(attachConsumedBytes(/* @__PURE__ */ new Error("attachment download timeout"), consumedBytesOf(result.failure, input.maxBytes)));
|
|
9168
|
+
return yield* Effect.fromResult(result);
|
|
9169
9169
|
} finally {
|
|
9170
9170
|
clearTimeout(timer);
|
|
9171
9171
|
outerSignal.removeEventListener("abort", onAbort);
|
|
@@ -9377,13 +9377,13 @@ function createFeishuAttachmentPreparation(options) {
|
|
|
9377
9377
|
retryBackoffMs,
|
|
9378
9378
|
sleep,
|
|
9379
9379
|
startedAt
|
|
9380
|
-
}).pipe(Effect.
|
|
9381
|
-
if (stored._tag === "
|
|
9380
|
+
}).pipe(Effect.result);
|
|
9381
|
+
if (stored._tag === "Failure") {
|
|
9382
9382
|
if (signal.aborted) return yield* Effect.fail(new FeishuAttachmentPreparationCancelled());
|
|
9383
|
-
destination.push(yield* failureNotice(resource, fallbackMessageId, classifyFailure(stored.
|
|
9383
|
+
destination.push(yield* failureNotice(resource, fallbackMessageId, classifyFailure(stored.failure), outputPath, maxBytes));
|
|
9384
9384
|
continue;
|
|
9385
9385
|
}
|
|
9386
|
-
accept(destination, attachmentId, resource, stored.
|
|
9386
|
+
accept(destination, attachmentId, resource, stored.success);
|
|
9387
9387
|
}
|
|
9388
9388
|
});
|
|
9389
9389
|
yield* processParts(request.decoded.parts, parts, request.messageId);
|
|
@@ -9430,7 +9430,7 @@ function createFeishuAttachmentPreparation(options) {
|
|
|
9430
9430
|
}),
|
|
9431
9431
|
userInput
|
|
9432
9432
|
};
|
|
9433
|
-
}).pipe(Effect.onInterrupt(() => Effect.sync(() => controller.abort()).pipe(Effect.
|
|
9433
|
+
}).pipe(Effect.onInterrupt(() => Effect.sync(() => controller.abort()).pipe(Effect.andThen(ledger.cancel().pipe(Effect.ignore)))), Effect.ensuring(Effect.sync(() => {
|
|
9434
9434
|
unregisterPreparation(request.sessionKey, controller);
|
|
9435
9435
|
})));
|
|
9436
9436
|
}
|
|
@@ -9796,7 +9796,7 @@ function effectForCandidate(operation) {
|
|
|
9796
9796
|
return Effect.tryPromise({
|
|
9797
9797
|
try: operation,
|
|
9798
9798
|
catch: () => /* @__PURE__ */ new Error("attachment retention candidate inspection failed")
|
|
9799
|
-
}).pipe(Effect.
|
|
9799
|
+
}).pipe(Effect.catch(() => Effect.succeed("error")));
|
|
9800
9800
|
}
|
|
9801
9801
|
function inspectPreparedCandidate(input) {
|
|
9802
9802
|
return effectForCandidate(async () => {
|
|
@@ -10575,7 +10575,7 @@ function createFeishuCotPublisher(options) {
|
|
|
10575
10575
|
url: `${baseUrl}/open-apis/im/v1/message_cot/complete/${encodeURIComponent(target.cotId)}?message_id=${encodeURIComponent(target.messageId)}&reason=${reason}`
|
|
10576
10576
|
}, "Failed to complete Feishu COT message").pipe(Effect.timeout(COT_REQUEST_TIMEOUT), Effect.asVoid);
|
|
10577
10577
|
const failTarget = (runId, target) => complete(target, "error").pipe(Effect.ensuring(Effect.sync(() => targets.delete(runId))));
|
|
10578
|
-
const abandonOnError = (runId, target, operation) => operation.pipe(Effect.
|
|
10578
|
+
const abandonOnError = (runId, target, operation) => operation.pipe(Effect.catch((error) => failTarget(runId, target).pipe(Effect.catch(() => Effect.void), Effect.flatMap(() => Effect.fail(error)))));
|
|
10579
10579
|
const flushReasoning = (target, timestamp) => {
|
|
10580
10580
|
if (target.pendingReasoning.length === 0) return [];
|
|
10581
10581
|
const delta = readRedactedString(redact(target.pendingReasoning));
|
|
@@ -10987,7 +10987,7 @@ function createMessageGateway(options) {
|
|
|
10987
10987
|
case "resolve_interaction": return yield* resolveInteraction(action);
|
|
10988
10988
|
case "prompt":
|
|
10989
10989
|
markSeen(key);
|
|
10990
|
-
return yield* executePrompt(execution, observation, presentation, action).pipe(Effect.
|
|
10990
|
+
return yield* executePrompt(execution, observation, presentation, action).pipe(Effect.catch((error) => {
|
|
10991
10991
|
if (error instanceof AgentRunCancelled) return Effect.succeed({
|
|
10992
10992
|
cancelled: true,
|
|
10993
10993
|
messageId: action.messageId,
|
|
@@ -10997,7 +10997,7 @@ function createMessageGateway(options) {
|
|
|
10997
10997
|
return Effect.fail(error);
|
|
10998
10998
|
}));
|
|
10999
10999
|
}
|
|
11000
|
-
}).pipe(Effect.
|
|
11000
|
+
}).pipe(Effect.catch((error) => {
|
|
11001
11001
|
if (error instanceof AgentRunCancelled && (direct || action.type === "prompt")) return Effect.succeed({
|
|
11002
11002
|
cancelled: true,
|
|
11003
11003
|
messageId: action.messageId,
|
|
@@ -11450,7 +11450,7 @@ function parseCancelRunCommand(messageId, text) {
|
|
|
11450
11450
|
//#region src/adapters/feishu/conversation-session/feishu-session-store.ts
|
|
11451
11451
|
function createFeishuSessionStore(options = {}) {
|
|
11452
11452
|
const records = recoverFeishuSessionRecords(options.initial ?? []);
|
|
11453
|
-
const serial =
|
|
11453
|
+
const serial = Semaphore.makeUnsafe(1);
|
|
11454
11454
|
return {
|
|
11455
11455
|
current: (baseSessionKey) => {
|
|
11456
11456
|
validateFeishuBaseSessionKey(baseSessionKey);
|
|
@@ -11666,25 +11666,25 @@ function createFeishuAgentDaemon(options) {
|
|
|
11666
11666
|
replyReset: (messageId, hadActiveRun) => sideEffectsDisabled || !options.reply ? Effect.void : options.reply(messageId, hadActiveRun ? "已停止当前任务并开启新会话。请发送下一条指令。" : "已开启新会话。请发送下一条指令。"),
|
|
11667
11667
|
replySteered: (messageId) => {
|
|
11668
11668
|
if (sideEffectsDisabled) return Effect.void;
|
|
11669
|
-
if (options.acknowledgeSteering) return options.acknowledgeSteering(messageId).pipe(Effect.
|
|
11669
|
+
if (options.acknowledgeSteering) return options.acknowledgeSteering(messageId).pipe(Effect.catch(() => options.reply ? options.reply(messageId, STEERING_ACK_TEXT) : Effect.void));
|
|
11670
11670
|
return options.reply ? options.reply(messageId, STEERING_ACK_TEXT) : Effect.void;
|
|
11671
11671
|
}
|
|
11672
11672
|
}
|
|
11673
11673
|
};
|
|
11674
11674
|
};
|
|
11675
11675
|
const trySteerMessage = (payload) => Effect.gen(function* () {
|
|
11676
|
-
const resetDirective = yield* readFeishuSessionResetDirective(payload, messageIntakeOptions).pipe(Effect.
|
|
11677
|
-
if (
|
|
11678
|
-
cancelAttachmentPreparation(resetDirective.
|
|
11676
|
+
const resetDirective = yield* readFeishuSessionResetDirective(payload, messageIntakeOptions).pipe(Effect.result);
|
|
11677
|
+
if (Result.isSuccess(resetDirective) && resetDirective.success?.prompt) {
|
|
11678
|
+
cancelAttachmentPreparation(resetDirective.success.previousSessionKey);
|
|
11679
11679
|
yield* execution.cancelActiveRun({
|
|
11680
11680
|
reason: "Feishu new session command",
|
|
11681
|
-
sessionKey: resetDirective.
|
|
11681
|
+
sessionKey: resetDirective.success.previousSessionKey
|
|
11682
11682
|
});
|
|
11683
11683
|
return;
|
|
11684
11684
|
}
|
|
11685
|
-
const parsed = yield* createAgentCommandFromFeishuMessage(payload, messageIntakeOptions).pipe(Effect.
|
|
11686
|
-
if (
|
|
11687
|
-
const inbound = parsed.
|
|
11685
|
+
const parsed = yield* createAgentCommandFromFeishuMessage(payload, messageIntakeOptions).pipe(Effect.result);
|
|
11686
|
+
if (Result.isFailure(parsed)) return;
|
|
11687
|
+
const inbound = parsed.success;
|
|
11688
11688
|
const { observation, presentation, reply } = buildPorts(false);
|
|
11689
11689
|
if (inbound.type === "cancel_run") {
|
|
11690
11690
|
cancelPreparationForCommand(inbound);
|
|
@@ -11712,27 +11712,27 @@ function createFeishuAgentDaemon(options) {
|
|
|
11712
11712
|
return steered ? fromGatewayResult(steered) : void 0;
|
|
11713
11713
|
});
|
|
11714
11714
|
const prepareControlMessage = (payload, phase = "admission") => Effect.gen(function* () {
|
|
11715
|
-
const resetDirective = yield* readFeishuSessionResetDirective(payload, messageIntakeOptions).pipe(Effect.
|
|
11715
|
+
const resetDirective = yield* readFeishuSessionResetDirective(payload, messageIntakeOptions).pipe(Effect.result);
|
|
11716
11716
|
const prepared = () => ({ execute: () => trySteerMessage(payload) });
|
|
11717
|
-
if (
|
|
11718
|
-
if (
|
|
11719
|
-
if (resetDirective.
|
|
11717
|
+
if (Result.isFailure(resetDirective)) yield* failCausedIntake(resetDirective.failure);
|
|
11718
|
+
if (Result.isSuccess(resetDirective) && resetDirective.success) {
|
|
11719
|
+
if (resetDirective.success.prompt.length > 0) {
|
|
11720
11720
|
if (phase === "processing") return;
|
|
11721
|
-
const activeRunId = execution.getActiveRun ? yield* execution.getActiveRun({ sessionKey: resetDirective.
|
|
11722
|
-
const preparing = options.attachmentPreparation?.hasActive?.(resetDirective.
|
|
11721
|
+
const activeRunId = execution.getActiveRun ? yield* execution.getActiveRun({ sessionKey: resetDirective.success.previousSessionKey }) : void 0;
|
|
11722
|
+
const preparing = options.attachmentPreparation?.hasActive?.(resetDirective.success.previousSessionKey) ?? false;
|
|
11723
11723
|
return activeRunId || preparing ? prepared() : void 0;
|
|
11724
11724
|
}
|
|
11725
11725
|
return prepared();
|
|
11726
11726
|
}
|
|
11727
11727
|
if (feishuMessageRequiresWorkerPreparation(payload)) return;
|
|
11728
|
-
const intake = yield* describeFeishuMessageIntake(payload, messageIntakeOptions).pipe(Effect.
|
|
11729
|
-
if (
|
|
11730
|
-
yield* failCausedIntake(intake.
|
|
11728
|
+
const intake = yield* describeFeishuMessageIntake(payload, messageIntakeOptions).pipe(Effect.result);
|
|
11729
|
+
if (Result.isFailure(intake)) {
|
|
11730
|
+
yield* failCausedIntake(intake.failure);
|
|
11731
11731
|
return;
|
|
11732
11732
|
}
|
|
11733
|
-
if (intake.
|
|
11733
|
+
if (intake.success.commandType !== "prompt") return prepared();
|
|
11734
11734
|
if (!execution.getActiveRun) return;
|
|
11735
|
-
return (yield* execution.getActiveRun({ sessionKey: intake.
|
|
11735
|
+
return (yield* execution.getActiveRun({ sessionKey: intake.success.sessionKey })) ? prepared() : void 0;
|
|
11736
11736
|
});
|
|
11737
11737
|
return {
|
|
11738
11738
|
describeMessageIntake: (payload) => describeFeishuMessageIntake(payload, {
|
|
@@ -11815,7 +11815,7 @@ function createFeishuAgentDaemon(options) {
|
|
|
11815
11815
|
});
|
|
11816
11816
|
if (!result) return yield* Effect.fail(/* @__PURE__ */ new Error("gateway returned no result for prompt"));
|
|
11817
11817
|
return fromGatewayResult(result);
|
|
11818
|
-
}).pipe(Effect.
|
|
11818
|
+
}).pipe(Effect.catch((error) => {
|
|
11819
11819
|
if (error instanceof AgentRunCancelled) return Effect.succeed({
|
|
11820
11820
|
cancelled: true,
|
|
11821
11821
|
messageId: payload.event.message.message_id,
|
|
@@ -11975,7 +11975,7 @@ function createDurableQueue(options) {
|
|
|
11975
11975
|
const maxAttempts = positiveInteger(options.maxAttempts ?? 5, "maximum attempts");
|
|
11976
11976
|
const maxPending = positiveInteger(options.maxPending ?? 100, "capacity");
|
|
11977
11977
|
const retryDelayMs = nonNegativeInteger(options.retryDelayMs ?? 0, "retry delay");
|
|
11978
|
-
const executePreparedAction = (prepared, deliveryId, leaseId) => prepared.execute().pipe(Effect.
|
|
11978
|
+
const executePreparedAction = (prepared, deliveryId, leaseId) => prepared.execute().pipe(Effect.catch((error) => options.clock.now().pipe(Effect.flatMap((failedAt) => options.store.fail({
|
|
11979
11979
|
failedAt,
|
|
11980
11980
|
id: deliveryId,
|
|
11981
11981
|
leaseId,
|
|
@@ -12068,7 +12068,7 @@ function createDurableQueue(options) {
|
|
|
12068
12068
|
const actionResult = yield* executePreparedAction(preparedAction, delivery.id, claimedLeaseId);
|
|
12069
12069
|
if (actionResult !== void 0) return yield* completeHandled(actionResult);
|
|
12070
12070
|
}
|
|
12071
|
-
const result = yield* options.handleDelivery(delivery.payload, delivery.metadata).pipe(Effect.
|
|
12071
|
+
const result = yield* options.handleDelivery(delivery.payload, delivery.metadata).pipe(Effect.catch((error) => options.clock.now().pipe(Effect.flatMap((failedAt) => options.store.fail({
|
|
12072
12072
|
availableAt: new Date(Date.parse(failedAt) + retryDelayMs).toISOString(),
|
|
12073
12073
|
failedAt,
|
|
12074
12074
|
id: delivery.id,
|
|
@@ -12171,10 +12171,10 @@ function createDurableQueueWorker(options) {
|
|
|
12171
12171
|
const results = [];
|
|
12172
12172
|
while (options.queue.pending() > 0) {
|
|
12173
12173
|
const batchSize = Math.min(concurrency, options.queue.pending());
|
|
12174
|
-
const outcomes = yield* Effect.all(Array.from({ length: batchSize }, () => options.queue.drainOne().pipe(Effect.
|
|
12175
|
-
const failures = outcomes.filter(
|
|
12174
|
+
const outcomes = yield* Effect.all(Array.from({ length: batchSize }, () => options.queue.drainOne().pipe(Effect.result)), { concurrency: "unbounded" });
|
|
12175
|
+
const failures = outcomes.filter(Result.isFailure).map((outcome) => outcome.failure);
|
|
12176
12176
|
if (failures.length > 0) return yield* Effect.fail(failures.length === 1 ? failures[0] : new AggregateError(failures, "Inbound Delivery batch failed"));
|
|
12177
|
-
const batch = outcomes.filter(
|
|
12177
|
+
const batch = outcomes.filter(Result.isSuccess).map((outcome) => outcome.success);
|
|
12178
12178
|
if (batch.every((result) => !result.handled)) break;
|
|
12179
12179
|
for (const result of batch) if (result.handled) results.push(result);
|
|
12180
12180
|
}
|
|
@@ -12187,7 +12187,7 @@ function createDurableQueueWorker(options) {
|
|
|
12187
12187
|
function createDurableQueueWorkerLoop(options) {
|
|
12188
12188
|
if (!Number.isSafeInteger(options.intervalMs) || options.intervalMs < 0) throw new Error("Inbound Delivery worker interval must be a non-negative integer");
|
|
12189
12189
|
const report = (error) => options.onError?.(error) ?? Effect.void;
|
|
12190
|
-
const continueAfterReporting = (effect) => effect.pipe(Effect.asVoid, Effect.
|
|
12190
|
+
const continueAfterReporting = (effect) => effect.pipe(Effect.asVoid, Effect.catch(report));
|
|
12191
12191
|
return Effect.forever(Effect.suspend(() => continueAfterReporting(options.drainAvailable()).pipe(Effect.flatMap(() => continueAfterReporting(options.sleep(options.intervalMs))))));
|
|
12192
12192
|
}
|
|
12193
12193
|
//#endregion
|
|
@@ -12321,7 +12321,7 @@ function createInMemoryDurableQueueStore(options = {}) {
|
|
|
12321
12321
|
if (deliveries.has(restored.id)) throw new Error(`duplicate Inbound Delivery snapshot: ${restored.id}`);
|
|
12322
12322
|
deliveries.set(restored.id, restored);
|
|
12323
12323
|
}
|
|
12324
|
-
const serial =
|
|
12324
|
+
const serial = Semaphore.makeUnsafe(1);
|
|
12325
12325
|
let lastLaneKey;
|
|
12326
12326
|
const save = (current, delivery) => {
|
|
12327
12327
|
const snapshot = readInboundDeliverySnapshot(current === void 0 ? delivery : resolveUpdate(current, delivery));
|
|
@@ -12473,7 +12473,7 @@ function createFeishuEventHandlers(options) {
|
|
|
12473
12473
|
} };
|
|
12474
12474
|
if (options.cardActions) return {
|
|
12475
12475
|
...handlers,
|
|
12476
|
-
"card.action.trigger": (payload) => Effect.runPromise(options.cardActions.handleCardAction(payload).pipe(Effect.map(createFeishuCardActionCallbackResponse), Effect.
|
|
12476
|
+
"card.action.trigger": (payload) => Effect.runPromise(options.cardActions.handleCardAction(payload).pipe(Effect.map(createFeishuCardActionCallbackResponse), Effect.catch(() => Effect.succeed(createFeishuCardActionErrorResponse()))))
|
|
12477
12477
|
};
|
|
12478
12478
|
return handlers;
|
|
12479
12479
|
}
|
|
@@ -12530,7 +12530,7 @@ function toStandardRunResult(result) {
|
|
|
12530
12530
|
function createFeishuAgentExecutionBridge(options) {
|
|
12531
12531
|
const activeNamespacedSessions = /* @__PURE__ */ new Set();
|
|
12532
12532
|
const cancellationRequests = /* @__PURE__ */ new Map();
|
|
12533
|
-
const cancellationSerial =
|
|
12533
|
+
const cancellationSerial = Semaphore.makeUnsafe(1);
|
|
12534
12534
|
const activeHandles = /* @__PURE__ */ new Set();
|
|
12535
12535
|
const activeRuns = /* @__PURE__ */ new Map();
|
|
12536
12536
|
let stopping = false;
|
|
@@ -12543,7 +12543,7 @@ function createFeishuAgentExecutionBridge(options) {
|
|
|
12543
12543
|
if (current) return current;
|
|
12544
12544
|
const completion = yield* Deferred.make();
|
|
12545
12545
|
cancellationRequests.set(runId, completion);
|
|
12546
|
-
yield* Effect.
|
|
12546
|
+
yield* Effect.forkDetach(Effect.suspend(() => options.cancel({
|
|
12547
12547
|
reason: "endpoint_stopping",
|
|
12548
12548
|
runId,
|
|
12549
12549
|
sessionKey
|
|
@@ -12637,17 +12637,17 @@ function createFeishuAgentExecutionBridge(options) {
|
|
|
12637
12637
|
if (activeRunId) activeRuns.delete(activeRunId);
|
|
12638
12638
|
activeHandles.delete(completion);
|
|
12639
12639
|
activeNamespacedSessions.delete(sessionKey);
|
|
12640
|
-
}).pipe(Effect.
|
|
12641
|
-
yield* Effect.
|
|
12640
|
+
}).pipe(Effect.andThen(Deferred.succeed(completion, void 0)))));
|
|
12641
|
+
yield* Effect.forkDetach(restore(run).pipe(Effect.exit, Effect.flatMap((exit) => Deferred.done(outcome, exit))));
|
|
12642
12642
|
return yield* restore(Deferred.await(outcome));
|
|
12643
12643
|
}))
|
|
12644
12644
|
}
|
|
12645
12645
|
};
|
|
12646
12646
|
}
|
|
12647
12647
|
function waitUntilDeadline(effect, deadline, message) {
|
|
12648
|
-
return effect.pipe(Effect.interruptible, Effect.
|
|
12648
|
+
return effect.pipe(Effect.interruptible, Effect.timeoutOrElse({
|
|
12649
12649
|
duration: Math.max(0, deadline - Date.now()),
|
|
12650
|
-
|
|
12650
|
+
orElse: () => Effect.fail(new Error(message))
|
|
12651
12651
|
}));
|
|
12652
12652
|
}
|
|
12653
12653
|
function namespaceSessionKey(namespace, sessionKey) {
|
|
@@ -12793,7 +12793,7 @@ function createFeishuDeploymentEndpoint(options) {
|
|
|
12793
12793
|
let stopping = false;
|
|
12794
12794
|
const activeDrains = /* @__PURE__ */ new Set();
|
|
12795
12795
|
const awaitDrain = (drain) => Fiber.join(drain).pipe(Effect.onExit((exit) => Effect.sync(() => {
|
|
12796
|
-
if (exit._tag === "Success" || !Cause.
|
|
12796
|
+
if (exit._tag === "Success" || !Cause.hasInterruptsOnly(exit.cause)) activeDrains.delete(drain);
|
|
12797
12797
|
})));
|
|
12798
12798
|
const stopCardRollover = options.cardRollover ? Effect.tryPromise({
|
|
12799
12799
|
try: () => Promise.resolve(options.cardRollover.stop()),
|
|
@@ -12811,7 +12811,7 @@ function createFeishuDeploymentEndpoint(options) {
|
|
|
12811
12811
|
});
|
|
12812
12812
|
const workerLoop = createEffectLoopDriver(createDurableQueueWorkerLoop({
|
|
12813
12813
|
drainAvailable: () => Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
12814
|
-
const drain = yield* Effect.
|
|
12814
|
+
const drain = yield* Effect.forkDetach(worker.drainAvailable().pipe(Effect.interruptible));
|
|
12815
12815
|
activeDrains.add(drain);
|
|
12816
12816
|
return yield* restore(awaitDrain(drain));
|
|
12817
12817
|
})),
|
|
@@ -12825,7 +12825,7 @@ function createFeishuDeploymentEndpoint(options) {
|
|
|
12825
12825
|
handlers: createFeishuEventHandlers({
|
|
12826
12826
|
cardActions: daemon,
|
|
12827
12827
|
queue: {
|
|
12828
|
-
accept: (payload) => shouldAcceptFeishuEndpointMessage(payload, options.groupPolicy, options.botOpenId) ? inbound.accept(payload).pipe(Effect.tap((result) => result.accepted || result.reason !== "capacity" || !options.onCapacityExceeded ? Effect.void : options.onCapacityExceeded(payload).pipe(Effect.
|
|
12828
|
+
accept: (payload) => shouldAcceptFeishuEndpointMessage(payload, options.groupPolicy, options.botOpenId) ? inbound.accept(payload).pipe(Effect.tap((result) => result.accepted || result.reason !== "capacity" || !options.onCapacityExceeded ? Effect.void : options.onCapacityExceeded(payload).pipe(Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.interrupt : reportWorkerError(Cause.squash(cause)))))) : Effect.succeed({
|
|
12829
12829
|
accepted: false,
|
|
12830
12830
|
messageId: payload.event.message.message_id,
|
|
12831
12831
|
pending: queue.pending(),
|
|
@@ -12853,7 +12853,7 @@ function createFeishuDeploymentEndpoint(options) {
|
|
|
12853
12853
|
catch: (error) => error
|
|
12854
12854
|
});
|
|
12855
12855
|
workerLoop.start();
|
|
12856
|
-
}).pipe(Effect.
|
|
12856
|
+
}).pipe(Effect.catchCause((startCause) => Effect.uninterruptible(Effect.gen(function* () {
|
|
12857
12857
|
const cleanupErrors = yield* settleCleanup([
|
|
12858
12858
|
Effect.tryPromise({
|
|
12859
12859
|
try: () => websocket.stop(),
|
|
@@ -12873,11 +12873,11 @@ function createFeishuDeploymentEndpoint(options) {
|
|
|
12873
12873
|
const timeoutMs = options.shutdownTimeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
12874
12874
|
const deadline = Date.now() + timeoutMs;
|
|
12875
12875
|
let executionStopped = false;
|
|
12876
|
-
const websocketStop = yield* Effect.
|
|
12876
|
+
const websocketStop = yield* Effect.forkChild(Effect.tryPromise({
|
|
12877
12877
|
try: () => websocket.stop(),
|
|
12878
12878
|
catch: (error) => error
|
|
12879
12879
|
}));
|
|
12880
|
-
const workerStop = yield* Effect.
|
|
12880
|
+
const workerStop = yield* Effect.forkChild(Effect.tryPromise({
|
|
12881
12881
|
try: () => workerLoop.stop(),
|
|
12882
12882
|
catch: (error) => error
|
|
12883
12883
|
}));
|
|
@@ -12887,9 +12887,9 @@ function createFeishuDeploymentEndpoint(options) {
|
|
|
12887
12887
|
executionStopped = true;
|
|
12888
12888
|
}))),
|
|
12889
12889
|
Fiber.join(workerStop),
|
|
12890
|
-
Effect.suspend(() => executionStopped ? Effect.all([...activeDrains].map(awaitDrain), { concurrency: "unbounded" }).pipe(Effect.interruptible, Effect.
|
|
12890
|
+
Effect.suspend(() => executionStopped ? Effect.all([...activeDrains].map(awaitDrain), { concurrency: "unbounded" }).pipe(Effect.interruptible, Effect.timeoutOrElse({
|
|
12891
12891
|
duration: Math.max(0, deadline - Date.now()),
|
|
12892
|
-
|
|
12892
|
+
orElse: () => Effect.fail(/* @__PURE__ */ new Error(`Feishu Inbox drain did not stop within ${timeoutMs}ms`))
|
|
12893
12893
|
})) : Effect.void),
|
|
12894
12894
|
stopCardRollover
|
|
12895
12895
|
]);
|
|
@@ -12912,10 +12912,10 @@ function settleCleanup(steps) {
|
|
|
12912
12912
|
//#region src/adapters/feishu/run-presentation/feishu-presentation-preparation.ts
|
|
12913
12913
|
function createFeishuPresentationPreparation(options) {
|
|
12914
12914
|
return (run) => Effect.gen(function* () {
|
|
12915
|
-
const cotPrepared = options.cotPublisher ? yield* options.cotPublisher.prepare(run).pipe(Effect.as(true), Effect.
|
|
12915
|
+
const cotPrepared = options.cotPublisher ? yield* options.cotPublisher.prepare(run).pipe(Effect.as(true), Effect.catch((error) => options.reportCotError("create", error).pipe(Effect.as(false)))) : false;
|
|
12916
12916
|
yield* options.prepareCardTarget(run).pipe(Effect.onExit((exit) => {
|
|
12917
12917
|
if (Exit.isSuccess(exit) || !options.cotPublisher || !cotPrepared) return Effect.void;
|
|
12918
|
-
return options.cotPublisher.fail(run.runId).pipe(Effect.
|
|
12918
|
+
return options.cotPublisher.fail(run.runId).pipe(Effect.catchCause((cause) => options.reportCotError("abort", Cause.squash(cause))), Effect.catchCause(() => Effect.void));
|
|
12919
12919
|
}));
|
|
12920
12920
|
});
|
|
12921
12921
|
}
|
|
@@ -13233,7 +13233,7 @@ function replaceChain(chains, replacement) {
|
|
|
13233
13233
|
//#region src/adapters/outbound/persistence/card-presentation/in-memory-card-presentation-repository.ts
|
|
13234
13234
|
function createInMemoryCardPresentationRepository(options = {}) {
|
|
13235
13235
|
let chains = cloneAndValidate(options.initial ?? []);
|
|
13236
|
-
const semaphore =
|
|
13236
|
+
const semaphore = Semaphore.makeUnsafe(1);
|
|
13237
13237
|
return {
|
|
13238
13238
|
snapshot: () => structuredClone(chains),
|
|
13239
13239
|
transact: (decide) => semaphore.withPermits(1)(Effect.uninterruptible(Effect.gen(function* () {
|
|
@@ -13375,7 +13375,7 @@ var FeishuCardTargetRegistryStoreError = class {
|
|
|
13375
13375
|
};
|
|
13376
13376
|
function createJsonFileFeishuCardTargetRegistry(options) {
|
|
13377
13377
|
let loaded;
|
|
13378
|
-
const semaphore =
|
|
13378
|
+
const semaphore = Semaphore.makeUnsafe(1);
|
|
13379
13379
|
const ready = () => {
|
|
13380
13380
|
if (loaded) return Effect.succeed(loaded);
|
|
13381
13381
|
return semaphore.withPermits(1)(loaded ? Effect.succeed(loaded) : openJsonCardPresentationRepository(options).pipe(Effect.map(createCardPresentationService), Effect.mapError(toRegistryStoreError), Effect.tap((service) => Effect.sync(() => {
|
|
@@ -14254,7 +14254,7 @@ function createEffectSessionScheduler(options) {
|
|
|
14254
14254
|
const readySet = /* @__PURE__ */ new Set();
|
|
14255
14255
|
const activeSessions = /* @__PURE__ */ new Set();
|
|
14256
14256
|
const inFlight = /* @__PURE__ */ new Map();
|
|
14257
|
-
const serial =
|
|
14257
|
+
const serial = Semaphore.makeUnsafe(1);
|
|
14258
14258
|
let queuedRuns = 0;
|
|
14259
14259
|
let disposed = false;
|
|
14260
14260
|
const markReady = (sessionKey) => {
|
|
@@ -14275,7 +14275,7 @@ function createEffectSessionScheduler(options) {
|
|
|
14275
14275
|
readySet.delete(sessionKey);
|
|
14276
14276
|
const readyIndex = readySessions.indexOf(sessionKey);
|
|
14277
14277
|
if (readyIndex >= 0) readySessions.splice(readyIndex, 1);
|
|
14278
|
-
})).pipe(Effect.
|
|
14278
|
+
})).pipe(Effect.andThen(Deferred.succeed(scheduled.interruption, void 0)), Effect.asVoid);
|
|
14279
14279
|
const pump = () => Effect.gen(function* () {
|
|
14280
14280
|
const selected = yield* serial.withPermits(1)(Effect.gen(function* () {
|
|
14281
14281
|
const runs = [];
|
|
@@ -14300,11 +14300,11 @@ function createEffectSessionScheduler(options) {
|
|
|
14300
14300
|
}
|
|
14301
14301
|
return runs;
|
|
14302
14302
|
}));
|
|
14303
|
-
yield* Effect.forEach(selected, ({ cacheEntry, completion, scheduled }) => Effect.
|
|
14303
|
+
yield* Effect.forEach(selected, ({ cacheEntry, completion, scheduled }) => Effect.forkDetach(Effect.raceFirst(runtimes.start(cacheEntry, () => options.createRuntime(scheduled.input.sessionKey)).pipe(Effect.andThen(Deferred.await(cacheEntry.deferred)), Effect.flatMap((runtime) => serial.withPermits(1)(Effect.sync(() => !disposed && inFlight.get(scheduled.input.sessionKey)?.scheduled === scheduled)).pipe(Effect.flatMap((mayRun) => mayRun ? runtime.run(scheduled.input) : Effect.fail(new SessionRuntimeSchedulerDisposed("session scheduler was disposed")))))), Deferred.await(scheduled.interruption).pipe(Effect.andThen(Effect.interrupt))).pipe(Effect.interruptible, Effect.exit, Effect.tap((exit) => Deferred.done(scheduled.deferred, exit)), Effect.ensuring(serial.withPermits(1)(Effect.sync(() => {
|
|
14304
14304
|
activeSessions.delete(scheduled.input.sessionKey);
|
|
14305
14305
|
if (inFlight.get(scheduled.input.sessionKey)?.scheduled === scheduled) inFlight.delete(scheduled.input.sessionKey);
|
|
14306
14306
|
if ((queues.get(scheduled.input.sessionKey)?.length ?? 0) > 0) markReady(scheduled.input.sessionKey);
|
|
14307
|
-
})).pipe(Effect.
|
|
14307
|
+
})).pipe(Effect.andThen(Deferred.succeed(completion, void 0)), Effect.asVoid)), Effect.flatMap(() => pump())), { uninterruptible: "inherit" }), { discard: true });
|
|
14308
14308
|
});
|
|
14309
14309
|
const existingRuntime = (sessionKey) => Effect.gen(function* () {
|
|
14310
14310
|
const selected = yield* runtimes.getExisting(sessionKey);
|
|
@@ -14757,19 +14757,19 @@ function createAutomationScheduler(options) {
|
|
|
14757
14757
|
const mandate = mandates.activate(options.binding);
|
|
14758
14758
|
const clock = options.clock ?? systemClock;
|
|
14759
14759
|
const schedule = createDailyAutomationSchedule(options.binding.schedule, options.binding.timeZone, clock.now());
|
|
14760
|
-
const execution =
|
|
14761
|
-
const lifecycle =
|
|
14760
|
+
const execution = Semaphore.makeUnsafe(1);
|
|
14761
|
+
const lifecycle = Semaphore.makeUnsafe(1);
|
|
14762
14762
|
let loopFiber;
|
|
14763
14763
|
let running = false;
|
|
14764
14764
|
const runDue = (at) => execution.withPermits(1)(executeDue(options, schedule, at, (occurrence) => mandates.claim(mandate.id, occurrence, options.binding.servicePrincipalId)));
|
|
14765
14765
|
const start = () => lifecycle.withPermits(1)(Effect.suspend(() => {
|
|
14766
14766
|
if (running) return Effect.void;
|
|
14767
14767
|
running = true;
|
|
14768
|
-
const loop = runScheduleLoop(options, schedule, clock, runDue).pipe(Effect.
|
|
14768
|
+
const loop = runScheduleLoop(options, schedule, clock, runDue).pipe(Effect.catch((error) => notifyError(options.onError, error)), Effect.ensuring(Effect.sync(() => {
|
|
14769
14769
|
running = false;
|
|
14770
14770
|
loopFiber = void 0;
|
|
14771
14771
|
})));
|
|
14772
|
-
return Effect.
|
|
14772
|
+
return Effect.forkDetach(loop, { uninterruptible: "inherit" }).pipe(Effect.tap((fiber) => Effect.sync(() => {
|
|
14773
14773
|
if (running) loopFiber = fiber;
|
|
14774
14774
|
})), Effect.asVoid);
|
|
14775
14775
|
}));
|
|
@@ -14830,7 +14830,7 @@ function executeDue(options, schedule, at, claim) {
|
|
|
14830
14830
|
body: result.body,
|
|
14831
14831
|
...result.presentation === void 0 ? {} : { presentation: result.presentation },
|
|
14832
14832
|
runId: result.runId
|
|
14833
|
-
}))))), Effect.
|
|
14833
|
+
}))))), Effect.catch((error) => options.repository.save(running.fail(automationFailureMessage(error))).pipe(Effect.andThen(Effect.fail(error)))));
|
|
14834
14834
|
}
|
|
14835
14835
|
if (record.status === "suppressed") return record;
|
|
14836
14836
|
const snapshot = record.toSnapshot();
|
|
@@ -14864,7 +14864,7 @@ function automationFailureMessage(error) {
|
|
|
14864
14864
|
return message.trim() === "" ? "Unknown Automation run failure" : message;
|
|
14865
14865
|
}
|
|
14866
14866
|
function notifyError(onError, error) {
|
|
14867
|
-
return (onError?.(error) ?? Effect.void).pipe(Effect.
|
|
14867
|
+
return (onError?.(error) ?? Effect.void).pipe(Effect.catch(() => Effect.void));
|
|
14868
14868
|
}
|
|
14869
14869
|
const systemClock = {
|
|
14870
14870
|
now: () => /* @__PURE__ */ new Date(),
|
|
@@ -15752,7 +15752,7 @@ function listChildDirectories(parent) {
|
|
|
15752
15752
|
return Effect.tryPromise({
|
|
15753
15753
|
try: () => readdir(parent, { withFileTypes: true }),
|
|
15754
15754
|
catch: (error) => error
|
|
15755
|
-
}).pipe(Effect.map((entries) => entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => left.localeCompare(right))), Effect.
|
|
15755
|
+
}).pipe(Effect.map((entries) => entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort((left, right) => left.localeCompare(right))), Effect.catch((error) => error instanceof Error && "code" in error && error.code === "ENOENT" ? Effect.succeed([]) : Effect.fail(error)));
|
|
15756
15756
|
}
|
|
15757
15757
|
//#endregion
|
|
15758
15758
|
//#region src/bootstrap/pi/pi-session-options.ts
|
|
@@ -15852,7 +15852,7 @@ function createBackgroundSessionDeliveryQueue(options) {
|
|
|
15852
15852
|
return {
|
|
15853
15853
|
drain: () => Effect.gen(function* () {
|
|
15854
15854
|
const records = yield* fromPromise$1(() => options.deliveries.pending());
|
|
15855
|
-
yield* Effect.forEach(records, (record) => fromPromise$1(() => options.deliver(record)).pipe(Effect.flatMap(({ providerMessageId }) => fromPromise$1(() => options.deliveries.markDelivered(record.deliveryId, providerMessageId))), Effect.tap((delivered) => delivered ? Effect.sync(options.onDelivered) : Effect.void), Effect.
|
|
15855
|
+
yield* Effect.forEach(records, (record) => fromPromise$1(() => options.deliver(record)).pipe(Effect.flatMap(({ providerMessageId }) => fromPromise$1(() => options.deliveries.markDelivered(record.deliveryId, providerMessageId))), Effect.tap((delivered) => delivered ? Effect.sync(options.onDelivered) : Effect.void), Effect.catch((error) => options.onError === void 0 ? Effect.void : Effect.sync(() => options.onError?.(error))), Effect.asVoid), { discard: true });
|
|
15856
15856
|
}),
|
|
15857
15857
|
enqueue: (sessionId, kind, text, session) => {
|
|
15858
15858
|
if (text.trim() === "") return Effect.void;
|
|
@@ -15934,7 +15934,7 @@ function createBackgroundSessionSupervisor(options) {
|
|
|
15934
15934
|
const owner = `supervisor:${options.createId()}`;
|
|
15935
15935
|
const inFlight = /* @__PURE__ */ new Map();
|
|
15936
15936
|
const stepControllers = /* @__PURE__ */ new Map();
|
|
15937
|
-
const supervision =
|
|
15937
|
+
const supervision = Semaphore.makeUnsafe(1);
|
|
15938
15938
|
const counters = {
|
|
15939
15939
|
completed: 0,
|
|
15940
15940
|
deliveriesDelivered: 0,
|
|
@@ -15956,7 +15956,7 @@ function createBackgroundSessionSupervisor(options) {
|
|
|
15956
15956
|
},
|
|
15957
15957
|
...options.onError === void 0 ? {} : { onError: options.onError }
|
|
15958
15958
|
});
|
|
15959
|
-
const reportError = (error) => options.onError === void 0 ? Effect.void : Effect.sync(() => options.onError?.(error)).pipe(Effect.
|
|
15959
|
+
const reportError = (error) => options.onError === void 0 ? Effect.void : Effect.sync(() => options.onError?.(error)).pipe(Effect.catchCause(() => Effect.void));
|
|
15960
15960
|
const repositoryGet = (sessionId) => fromPromise(() => options.repository.get(sessionId));
|
|
15961
15961
|
const repositoryList = () => fromPromise(() => options.repository.list());
|
|
15962
15962
|
const persistTransition = (input) => Effect.uninterruptible(fromPromise(() => commitBackgroundSessionTransition({
|
|
@@ -16084,7 +16084,7 @@ function createBackgroundSessionSupervisor(options) {
|
|
|
16084
16084
|
wakeText: buildInterruptedBackgroundSessionWakeText(state)
|
|
16085
16085
|
})
|
|
16086
16086
|
});
|
|
16087
|
-
}).pipe(Effect.
|
|
16087
|
+
}).pipe(Effect.catch((error) => reportError(error)), Effect.asVoid);
|
|
16088
16088
|
const renewLeaseOnce = (sessionId, lease, controller) => Effect.gen(function* () {
|
|
16089
16089
|
const current = yield* repositoryGet(sessionId);
|
|
16090
16090
|
if (!current || current.lease === void 0 || current.lease.owner !== owner || current.lease.epoch !== lease.epoch) {
|
|
@@ -16111,8 +16111,8 @@ function createBackgroundSessionSupervisor(options) {
|
|
|
16111
16111
|
return true;
|
|
16112
16112
|
});
|
|
16113
16113
|
const renewLease = (sessionId, lease, controller) => {
|
|
16114
|
-
const cycle = Effect.suspend(() => options.sleep(options.config.leaseRenewalIntervalMs).pipe(Effect.flatMap(() => renewLeaseOnce(sessionId, lease, controller)), Effect.flatMap((renewed) => renewed ? cycle : Effect.void), Effect.
|
|
16115
|
-
if (Cause.
|
|
16114
|
+
const cycle = Effect.suspend(() => options.sleep(options.config.leaseRenewalIntervalMs).pipe(Effect.flatMap(() => renewLeaseOnce(sessionId, lease, controller)), Effect.flatMap((renewed) => renewed ? cycle : Effect.void), Effect.catchCause((cause) => {
|
|
16115
|
+
if (Cause.hasInterruptsOnly(cause)) return Effect.interrupt;
|
|
16116
16116
|
controller.abort(/* @__PURE__ */ new Error(`background session lease renewal failed: ${backgroundSessionErrorMessage(Cause.squash(cause))}`));
|
|
16117
16117
|
return Effect.void;
|
|
16118
16118
|
})));
|
|
@@ -16134,7 +16134,7 @@ function createBackgroundSessionSupervisor(options) {
|
|
|
16134
16134
|
wakeText: `步骤结果提交失败(${backgroundSessionErrorMessage(error)}),将重试`
|
|
16135
16135
|
})
|
|
16136
16136
|
});
|
|
16137
|
-
}).pipe(Effect.
|
|
16137
|
+
}).pipe(Effect.catch((commitError) => reportError(commitError)), Effect.asVoid);
|
|
16138
16138
|
const commitStep = (claimed, outcome, lease) => Effect.gen(function* () {
|
|
16139
16139
|
const now = options.clock.now();
|
|
16140
16140
|
const current = yield* repositoryGet(claimed.sessionId);
|
|
@@ -16239,7 +16239,7 @@ function createBackgroundSessionSupervisor(options) {
|
|
|
16239
16239
|
const controller = new AbortController();
|
|
16240
16240
|
stepControllers.set(session.sessionId, controller);
|
|
16241
16241
|
yield* Effect.gen(function* () {
|
|
16242
|
-
const outcome = yield* Effect.acquireUseRelease(Effect.
|
|
16242
|
+
const outcome = yield* Effect.acquireUseRelease(Effect.forkChild(renewLease(session.sessionId, lease, controller), { uninterruptible: false }), () => options.runStep({
|
|
16243
16243
|
session: claimed,
|
|
16244
16244
|
signal: controller.signal,
|
|
16245
16245
|
wakeText
|
|
@@ -16253,16 +16253,16 @@ function createBackgroundSessionSupervisor(options) {
|
|
|
16253
16253
|
result
|
|
16254
16254
|
})
|
|
16255
16255
|
})), (fiber) => Fiber.interrupt(fiber).pipe(Effect.asVoid));
|
|
16256
|
-
yield* Effect.uninterruptible(commitStep(claimed, outcome, lease).pipe(Effect.
|
|
16256
|
+
yield* Effect.uninterruptible(commitStep(claimed, outcome, lease).pipe(Effect.catch((error) => reportError(error).pipe(Effect.flatMap(() => requeueAfterFailedCommit(session.sessionId, lease, error))))));
|
|
16257
16257
|
}).pipe(Effect.onInterrupt(() => Effect.sync(() => controller.abort(/* @__PURE__ */ new Error("background session supervisor is stopping"))).pipe(Effect.flatMap(() => requeueAfterInterruptedFiber(session.sessionId, lease)))), Effect.ensuring(Effect.sync(() => {
|
|
16258
16258
|
stepControllers.delete(session.sessionId);
|
|
16259
16259
|
})));
|
|
16260
16260
|
});
|
|
16261
16261
|
const startStep = (session) => Effect.gen(function* () {
|
|
16262
16262
|
const gate = yield* Deferred.make();
|
|
16263
|
-
const fiber = yield* Effect.
|
|
16263
|
+
const fiber = yield* Effect.forkDetach(Deferred.await(gate).pipe(Effect.flatMap(() => runStep(session)), Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : reportError(Cause.squash(cause))), Effect.ensuring(Effect.sync(() => {
|
|
16264
16264
|
inFlight.delete(session.sessionId);
|
|
16265
|
-
}))));
|
|
16265
|
+
}))), { uninterruptible: "inherit" });
|
|
16266
16266
|
inFlight.set(session.sessionId, fiber);
|
|
16267
16267
|
yield* Deferred.succeed(gate, void 0);
|
|
16268
16268
|
}).pipe(Effect.uninterruptible);
|
|
@@ -16338,7 +16338,7 @@ function createHumanInteractionService(options) {
|
|
|
16338
16338
|
}) : (ms) => Effect.sleep(ms);
|
|
16339
16339
|
const persistAndPresent = (interaction, existing) => Effect.gen(function* () {
|
|
16340
16340
|
if (Date.parse(options.clock.now()) >= Date.parse(interaction.expiresAt)) return yield* Effect.fail(/* @__PURE__ */ new Error(`human interaction expired before presentation: ${interaction.id}`));
|
|
16341
|
-
const persisted = existing ? existing : yield* options.repository.create(interaction).pipe(Effect.as(interaction), Effect.
|
|
16341
|
+
const persisted = existing ? existing : yield* options.repository.create(interaction).pipe(Effect.as(interaction), Effect.catch((createError) => options.repository.get(interaction.id).pipe(Effect.flatMap((concurrent) => concurrent ? Effect.succeed(concurrent) : Effect.fail(createError)))));
|
|
16342
16342
|
if (!persisted.isSameRequest(interaction)) return yield* Effect.fail(/* @__PURE__ */ new Error(`human interaction id is already bound to another request: ${interaction.id}`));
|
|
16343
16343
|
yield* options.presenter.present(persisted);
|
|
16344
16344
|
return persisted;
|
|
@@ -16367,7 +16367,7 @@ function createHumanInteractionService(options) {
|
|
|
16367
16367
|
return yield* options.repository.update(input.approvalId, (interaction) => interaction.consume({
|
|
16368
16368
|
binding: input.binding,
|
|
16369
16369
|
now: options.clock.now()
|
|
16370
|
-
}).state).pipe(Effect.as(true), Effect.
|
|
16370
|
+
}).state).pipe(Effect.as(true), Effect.catch((error) => isTransitionDenied(error) ? Effect.succeed(false) : Effect.fail(error)));
|
|
16371
16371
|
}),
|
|
16372
16372
|
get: (interactionId) => options.repository.get(interactionId),
|
|
16373
16373
|
resolve: (input) => options.repository.update(input.interactionId, (interaction) => interaction.resolve({
|
|
@@ -16401,7 +16401,7 @@ function isTransitionDenied(error) {
|
|
|
16401
16401
|
return error instanceof Error && error.cause instanceof Error && error.cause.name === "HumanInteractionTransitionDenied";
|
|
16402
16402
|
}
|
|
16403
16403
|
function waitForAbort(signal) {
|
|
16404
|
-
return Effect.
|
|
16404
|
+
return Effect.callback((resume) => {
|
|
16405
16405
|
const onAbort = () => resume(Effect.fail(signal.reason ?? /* @__PURE__ */ new Error("human interaction wait was aborted")));
|
|
16406
16406
|
if (signal.aborted) {
|
|
16407
16407
|
onAbort();
|
|
@@ -16962,10 +16962,10 @@ async function createRivusDaemonProcess(context) {
|
|
|
16962
16962
|
running: () => bootstrap.process.running(),
|
|
16963
16963
|
start: () => bootstrap.process.start(),
|
|
16964
16964
|
status: () => bootstrap.status(),
|
|
16965
|
-
stop: () => bootstrap.process.stop().pipe(Effect.
|
|
16965
|
+
stop: () => bootstrap.process.stop().pipe(Effect.andThen(Effect.tryPromise({
|
|
16966
16966
|
try: () => sessionRegistry.disposeAll(),
|
|
16967
16967
|
catch: (error) => error
|
|
16968
|
-
})), Effect.
|
|
16968
|
+
})), Effect.andThen(Effect.tryPromise({
|
|
16969
16969
|
try: () => assembly.dispose(),
|
|
16970
16970
|
catch: (error) => error
|
|
16971
16971
|
})))
|
|
@@ -17354,7 +17354,7 @@ async function createRivusDeploymentAdapters(context) {
|
|
|
17354
17354
|
reply: (messageId, text) => replies.reply(messageId, text),
|
|
17355
17355
|
sessionStore,
|
|
17356
17356
|
...input.steer ? { steer: input.steer } : {},
|
|
17357
|
-
...cotPublisher ? { publishRunUpdate: (update) => cotPublisher.publish(update).pipe(Effect.
|
|
17357
|
+
...cotPublisher ? { publishRunUpdate: (update) => cotPublisher.publish(update).pipe(Effect.catch((error) => reportCotError(input.endpointId, "update", error))) } : {},
|
|
17358
17358
|
sessionNamespace: input.definition.sessionNamespace,
|
|
17359
17359
|
sleep,
|
|
17360
17360
|
websocketClient: createLazyFeishuWebSocketClient(credentials, input.definition.baseUrl),
|
|
@@ -17362,7 +17362,7 @@ async function createRivusDeploymentAdapters(context) {
|
|
|
17362
17362
|
});
|
|
17363
17363
|
interactionRegistry.register(input.endpointId, interactions);
|
|
17364
17364
|
return endpoint;
|
|
17365
|
-
}).pipe(Effect.
|
|
17365
|
+
}).pipe(Effect.catchDefect((error) => Effect.fail(error))),
|
|
17366
17366
|
createRuntime: (input) => Effect.gen(function* () {
|
|
17367
17367
|
const instanceState = join(STATE_DIR, "instances", input.instanceId);
|
|
17368
17368
|
yield* Effect.tryPromise({
|
|
@@ -17559,7 +17559,7 @@ async function createRivusDeploymentAdapters(context) {
|
|
|
17559
17559
|
concurrency: scheduler.concurrency,
|
|
17560
17560
|
run: (request) => scheduler.run(request),
|
|
17561
17561
|
steer: (request) => scheduler.steer(request),
|
|
17562
|
-
dispose: () => scheduler.dispose().pipe(Effect.
|
|
17562
|
+
dispose: () => scheduler.dispose().pipe(Effect.andThen(Effect.tryPromise({
|
|
17563
17563
|
try: () => sessionRegistry.disposeAll(),
|
|
17564
17564
|
catch: (error) => error
|
|
17565
17565
|
})), Effect.tap(() => Effect.sync(() => {
|
|
@@ -17571,7 +17571,7 @@ async function createRivusDeploymentAdapters(context) {
|
|
|
17571
17571
|
}
|
|
17572
17572
|
})))
|
|
17573
17573
|
};
|
|
17574
|
-
}).pipe(Effect.
|
|
17574
|
+
}).pipe(Effect.catchDefect((error) => Effect.fail(error)))
|
|
17575
17575
|
};
|
|
17576
17576
|
} catch (error) {
|
|
17577
17577
|
await Promise.allSettled([management?.enabled ? management.close() : Promise.resolve(), telemetry?.shutdown()]);
|