@rei-standard/amsg-server 2.6.0-next.31 → 2.6.0-next.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/{chunk-PG54W6B5.mjs → chunk-INNZZFGJ.mjs} +62 -10
- package/dist/{chunk-7TM3MH3Q.cjs → chunk-KZT3YC62.cjs} +64 -12
- package/dist/cloudflare.cjs +2 -2
- package/dist/cloudflare.mjs +1 -1
- package/dist/index.cjs +25 -25
- package/dist/index.mjs +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -940,3 +940,30 @@ VERCEL_PROTECTION_BYPASS=YOUR_BYPASS_KEY
|
|
|
940
940
|
- [SW 包 README](https://github.com/Tosd0/ReiStandard/blob/main/packages/rei-standard-amsg/sw/README.md)
|
|
941
941
|
- [API 技术规范](https://github.com/Tosd0/ReiStandard/blob/main/standards/active-messaging-api.md)
|
|
942
942
|
- [Service Worker 规范](https://github.com/Tosd0/ReiStandard/blob/main/standards/service-worker-specification.md)
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
## 取消正在执行的生成与工具
|
|
946
|
+
|
|
947
|
+
任务被 `DELETE /cancel-message` 取消或被新任务顶替后,租约心跳发现任务已经失效,会中断正在等待的模型请求,阻止新的模型轮次、工具阶段和推送。`leaseHeartbeatMs` 默认仍为 30000;需要及时停止的交互应用可配置为 1000(每个正在执行的任务每秒续租一次)。这是跨请求的数据库检测,延迟取决于心跳和数据库响应,不承诺瞬时中断。自定义适配器需要支持 `claimTask` / `renewTaskLease`;关掉心跳时也关掉了这条主动检测路径。
|
|
948
|
+
|
|
949
|
+
`onBeforeFire`、`onLLMOutput`、`executeToolCalls` 的 context 以及 `onFireSettled` 回执新增:
|
|
950
|
+
|
|
951
|
+
- `signal: AbortSignal`:传给工具内部的 `fetch`,与工具自己的超时信号合并。
|
|
952
|
+
- `isCancelled(): boolean`:当前是否已收到取消信号。
|
|
953
|
+
- `throwIfCancelled(): void`:已取消时抛出 `code: 'TASK_CANCELLED'` 的错误。每个副作用开始前检查,工具 catch 中也要先调用它,以免取消被转成普通工具失败后继续执行。
|
|
954
|
+
|
|
955
|
+
```js
|
|
956
|
+
async function executeToolCalls(calls, ctx) {
|
|
957
|
+
const results = [];
|
|
958
|
+
for (const call of calls) {
|
|
959
|
+
ctx.throwIfCancelled();
|
|
960
|
+
const response = await fetch(toolUrl(call), { signal: ctx.signal });
|
|
961
|
+
results.push({ tool_call_id: call.id, role: 'tool', content: await response.text() });
|
|
962
|
+
}
|
|
963
|
+
return results;
|
|
964
|
+
}
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
取消收尾使用 `onFireSettled({ status: 'cancelled', willRetry: false, error, ... })`,不是生成失败。应用应在这里释放资源、结算已发生的用量,避免发出失败提示或把未送达内容记为已回复。取消时已经开始写入的 outbox 批次会在写完后检查信号并撤掉未投递部分;已经发到客户端的消息仍由客户端处理。应用需要记录停止的任务身份,拦住迟到推送、补收以及尚未显示的本地内容。已完成的外部副作用无法撤销;不支持 AbortSignal 的工具也需要自己在执行步骤之间检查取消。
|
|
968
|
+
|
|
969
|
+
执行阶段的 `ctx.writeState`、`scheduleTask`、`cancelTask`、`renewTask` 和 `emitResult` 会拒绝取消后新发起的操作。`onFireSettled` 的 `info.writeState` 特意仍可用,供宿主释放锁、保存账单等收尾;它不能用于继续生成阶段的业务动作。已经开始的数据库写入不支持回滚,宿主仍需处理并发状态版本。
|
|
@@ -1707,6 +1707,17 @@ function firstPositiveNumber(values, fallback) {
|
|
|
1707
1707
|
}
|
|
1708
1708
|
async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
1709
1709
|
const hooks = ctx.hooks;
|
|
1710
|
+
const signal = ctx.signal || new AbortController().signal;
|
|
1711
|
+
const isCancelled = () => signal.aborted || ctx.isTaskCancelled?.() === true;
|
|
1712
|
+
const throwIfCancelled = () => {
|
|
1713
|
+
if (!isCancelled()) return;
|
|
1714
|
+
if (isTaskCancelledError(signal.reason)) throw signal.reason;
|
|
1715
|
+
const error = new Error("Task was cancelled or superseded");
|
|
1716
|
+
error.code = "TASK_CANCELLED";
|
|
1717
|
+
throw error;
|
|
1718
|
+
};
|
|
1719
|
+
const cancellation = { signal, isCancelled, throwIfCancelled };
|
|
1720
|
+
ctx = { ...ctx, ...cancellation };
|
|
1710
1721
|
if (typeof hooks.onLLMOutput !== "function") {
|
|
1711
1722
|
throw new DeploymentConfigError(
|
|
1712
1723
|
"AGENTIC_CONFIG_ERROR: hooks.onBeforeFire requires hooks.onLLMOutput to classify LLM rounds",
|
|
@@ -1715,13 +1726,17 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1715
1726
|
}
|
|
1716
1727
|
const nowFn = typeof ctx._agenticNow === "function" ? ctx._agenticNow : Date.now;
|
|
1717
1728
|
const sleep = typeof ctx._agenticSleep === "function" ? ctx._agenticSleep : defaultSleep;
|
|
1718
|
-
const { readState, writeState } = createStateAccessors({
|
|
1729
|
+
const { readState, writeState: writeSettledState } = createStateAccessors({
|
|
1719
1730
|
db: ctx.db,
|
|
1720
1731
|
userId: task.user_id,
|
|
1721
1732
|
userKey,
|
|
1722
1733
|
maxStateValueBytes: ctx.maxStateValueBytes,
|
|
1723
1734
|
now: nowFn
|
|
1724
1735
|
});
|
|
1736
|
+
const writeState = async (namespace, entries) => {
|
|
1737
|
+
throwIfCancelled();
|
|
1738
|
+
return writeSettledState(namespace, entries);
|
|
1739
|
+
};
|
|
1725
1740
|
const sessionId = task.id != null ? `sess_task_${task.id}${occurrenceSuffix(task)}` : `sess_${randomUUID()}`;
|
|
1726
1741
|
const messageIdBase = task.id != null ? `msg_task_${task.id}${occurrenceSuffix(task)}` : `msg_${randomUUID()}`;
|
|
1727
1742
|
const occurrenceMs = occurrenceMsOf(task);
|
|
@@ -1737,7 +1752,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1737
1752
|
now: nowFn,
|
|
1738
1753
|
// run-tick 在投递 ctx 上挂的取消信号(与 guardWebpushWithLease 读的是同一
|
|
1739
1754
|
// 个租约状态),emitResult 不发推送的那条路要靠它拦下已取消任务的落行。
|
|
1740
|
-
isCancelled
|
|
1755
|
+
isCancelled
|
|
1741
1756
|
});
|
|
1742
1757
|
const maxScheduledTasksPerFire = Number.isInteger(ctx.maxScheduledTasksPerFire) && ctx.maxScheduledTasksPerFire >= 0 ? ctx.maxScheduledTasksPerFire : DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE;
|
|
1743
1758
|
let scheduledTaskCount = 0;
|
|
@@ -1754,6 +1769,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1754
1769
|
}
|
|
1755
1770
|
}
|
|
1756
1771
|
const scheduleTask = async (options) => {
|
|
1772
|
+
throwIfCancelled();
|
|
1757
1773
|
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1758
1774
|
throw new TypeError("scheduleTask(options) \u9700\u8981\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u81F3\u5C11\u5305\u542B { firstSendTime }");
|
|
1759
1775
|
}
|
|
@@ -1874,6 +1890,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1874
1890
|
}
|
|
1875
1891
|
scheduledTaskCount++;
|
|
1876
1892
|
const encryptedPayload = await encryptForStorage(serializedTaskData, userKey);
|
|
1893
|
+
throwIfCancelled();
|
|
1877
1894
|
let created;
|
|
1878
1895
|
try {
|
|
1879
1896
|
created = await ctx.db.createTask({
|
|
@@ -1908,6 +1925,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1908
1925
|
};
|
|
1909
1926
|
};
|
|
1910
1927
|
const cancelTask = async (uuid) => {
|
|
1928
|
+
throwIfCancelled();
|
|
1911
1929
|
if (typeof uuid !== "string" || !uuid.trim()) {
|
|
1912
1930
|
throw new TypeError("cancelTask(uuid) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
|
|
1913
1931
|
}
|
|
@@ -1922,6 +1940,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1922
1940
|
{ code: "AGENTIC_CANCEL_UNSUPPORTED" }
|
|
1923
1941
|
);
|
|
1924
1942
|
}
|
|
1943
|
+
throwIfCancelled();
|
|
1925
1944
|
const cancelled = await ctx.db.deleteTaskByUuid(uuid, task.user_id);
|
|
1926
1945
|
if (cancelled) {
|
|
1927
1946
|
await discardUndeliveredPushesForTask({ db: ctx.db, userId: task.user_id, taskUuid: uuid });
|
|
@@ -1929,6 +1948,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1929
1948
|
return { cancelled: !!cancelled };
|
|
1930
1949
|
};
|
|
1931
1950
|
const renewTask = async (uuid, nextSendAt) => {
|
|
1951
|
+
throwIfCancelled();
|
|
1932
1952
|
if (typeof uuid !== "string" || !uuid.trim()) {
|
|
1933
1953
|
throw new TypeError("renewTask(uuid, nextSendAt) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
|
|
1934
1954
|
}
|
|
@@ -1959,6 +1979,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1959
1979
|
const payload = JSON.parse(await decryptFromStorage(row.encrypted_payload, userKey));
|
|
1960
1980
|
const nextSendAtIso = sendAt.toISOString();
|
|
1961
1981
|
const encrypted = await encryptForStorage(JSON.stringify({ ...payload, firstSendTime: nextSendAtIso }), userKey);
|
|
1982
|
+
throwIfCancelled();
|
|
1962
1983
|
const updated = await ctx.db.updateTaskByUuid(uuid, task.user_id, encrypted, {
|
|
1963
1984
|
next_send_at: nextSendAtIso,
|
|
1964
1985
|
retry_count: 0,
|
|
@@ -1979,6 +2000,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1979
2000
|
};
|
|
1980
2001
|
const scratch = {};
|
|
1981
2002
|
const fireCtx = Object.freeze({
|
|
2003
|
+
...cancellation,
|
|
1982
2004
|
task: buildHookTask(task, decryptedPayload),
|
|
1983
2005
|
userId: task.user_id,
|
|
1984
2006
|
readState,
|
|
@@ -2027,16 +2049,26 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
2027
2049
|
messageIdBase,
|
|
2028
2050
|
occurrenceMs
|
|
2029
2051
|
});
|
|
2052
|
+
throwIfCancelled();
|
|
2030
2053
|
settledStatus = !outcome.handled ? "not-handled" : outcome.result.status === "skipped" ? "skipped" : "sent";
|
|
2031
2054
|
return outcome;
|
|
2032
2055
|
} catch (error) {
|
|
2056
|
+
if (isCancelled() && !isTaskCancelledError(error)) {
|
|
2057
|
+
try {
|
|
2058
|
+
throwIfCancelled();
|
|
2059
|
+
} catch (cancelled) {
|
|
2060
|
+
error = cancelled;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
if (isTaskCancelledError(error)) settledStatus = "cancelled";
|
|
2033
2064
|
settledError = error;
|
|
2034
2065
|
throw error;
|
|
2035
2066
|
} finally {
|
|
2036
2067
|
await notifyFireSettled(ctx, {
|
|
2037
2068
|
task,
|
|
2069
|
+
...cancellation,
|
|
2038
2070
|
status: settledStatus,
|
|
2039
|
-
...settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
|
|
2071
|
+
...settledStatus === "cancelled" ? { willRetry: false, failureStage: null } : settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
|
|
2040
2072
|
skipReason: settledStatus === "skipped" ? progress.skipReason : null,
|
|
2041
2073
|
sentCount: progress.sentCount,
|
|
2042
2074
|
pushedCount: progress.pushedCount,
|
|
@@ -2060,7 +2092,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
2060
2092
|
outboxed: progress.outboxed,
|
|
2061
2093
|
scratch,
|
|
2062
2094
|
readState,
|
|
2063
|
-
writeState,
|
|
2095
|
+
writeState: writeSettledState,
|
|
2064
2096
|
emitResult
|
|
2065
2097
|
});
|
|
2066
2098
|
}
|
|
@@ -2087,7 +2119,9 @@ async function runFireChain({
|
|
|
2087
2119
|
messageIdBase,
|
|
2088
2120
|
occurrenceMs
|
|
2089
2121
|
}) {
|
|
2122
|
+
ctx.throwIfCancelled();
|
|
2090
2123
|
const before = await hooks.onBeforeFire(fireCtx);
|
|
2124
|
+
ctx.throwIfCancelled();
|
|
2091
2125
|
if (before == null) return { handled: false };
|
|
2092
2126
|
if (typeof before === "object" && before.skip === true) {
|
|
2093
2127
|
progress.skipReason = "before-fire";
|
|
@@ -2111,6 +2145,7 @@ async function runFireChain({
|
|
|
2111
2145
|
decryptedPayload
|
|
2112
2146
|
});
|
|
2113
2147
|
for (let iteration = 0; iteration < maxToolIterations; iteration++) {
|
|
2148
|
+
ctx.throwIfCancelled();
|
|
2114
2149
|
if (nowFn() >= deadline) {
|
|
2115
2150
|
throw new Error(`AGENTIC_TOTAL_TIMEOUT: fire chain exceeded ${totalTimeoutMs}ms after ${iteration} LLM round(s)`);
|
|
2116
2151
|
}
|
|
@@ -2124,13 +2159,17 @@ async function runFireChain({
|
|
|
2124
2159
|
messages,
|
|
2125
2160
|
...normalized.tools ? { tools: normalized.tools, toolChoice: normalized.toolChoice } : {}
|
|
2126
2161
|
},
|
|
2127
|
-
{ requireContent: false, timeoutMs: roundTimeoutMs }
|
|
2162
|
+
{ requireContent: false, timeoutMs: roundTimeoutMs, signal: ctx.signal }
|
|
2128
2163
|
);
|
|
2129
2164
|
const assistantMessage = extractAssistantMessage(llmResponse);
|
|
2130
2165
|
messages = [...messages, assistantMessage];
|
|
2131
2166
|
progress.usage = llmResponse && typeof llmResponse === "object" && llmResponse.usage || null;
|
|
2132
2167
|
progress.usageTotal = accumulateUsage(progress.usageTotal, progress.usage);
|
|
2168
|
+
ctx.throwIfCancelled();
|
|
2133
2169
|
const sessionCtx = Object.freeze({
|
|
2170
|
+
signal: ctx.signal,
|
|
2171
|
+
isCancelled: ctx.isCancelled,
|
|
2172
|
+
throwIfCancelled: ctx.throwIfCancelled,
|
|
2134
2173
|
...buildSessionContext({
|
|
2135
2174
|
sessionId,
|
|
2136
2175
|
messages,
|
|
@@ -2154,6 +2193,7 @@ async function runFireChain({
|
|
|
2154
2193
|
resolveLlmCredential: resolveLlmCredential2
|
|
2155
2194
|
});
|
|
2156
2195
|
const decision = await hooks.onLLMOutput(sessionCtx);
|
|
2196
|
+
ctx.throwIfCancelled();
|
|
2157
2197
|
try {
|
|
2158
2198
|
assertValidDecision(decision, { inlineToolCalls: true });
|
|
2159
2199
|
} catch (error) {
|
|
@@ -2204,11 +2244,15 @@ async function runFireChain({
|
|
|
2204
2244
|
}
|
|
2205
2245
|
let toolResults;
|
|
2206
2246
|
try {
|
|
2247
|
+
ctx.throwIfCancelled();
|
|
2207
2248
|
toolResults = await hooks.executeToolCalls(toolCalls, sessionCtx);
|
|
2249
|
+
ctx.throwIfCancelled();
|
|
2208
2250
|
if (!Array.isArray(toolResults)) {
|
|
2209
2251
|
throw new TypeError('executeToolCalls must resolve to an array of { tool_call_id, role: "tool", content }');
|
|
2210
2252
|
}
|
|
2211
2253
|
} catch (error) {
|
|
2254
|
+
ctx.throwIfCancelled();
|
|
2255
|
+
if (isTaskCancelledError(error)) throw error;
|
|
2212
2256
|
toolResults = toolCalls.map((toolCall) => ({
|
|
2213
2257
|
tool_call_id: toolCall && typeof toolCall === "object" && typeof toolCall.id === "string" ? toolCall.id : "",
|
|
2214
2258
|
role: "tool",
|
|
@@ -2298,9 +2342,11 @@ async function sendHookPushPayloads({
|
|
|
2298
2342
|
stampTaskIdentity(push, task, decryptedPayload, occurrenceMs);
|
|
2299
2343
|
finalized.push(push);
|
|
2300
2344
|
}
|
|
2345
|
+
ctx.throwIfCancelled();
|
|
2301
2346
|
outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
|
|
2302
2347
|
progress.outboxed = outboxed;
|
|
2303
2348
|
if (ctx._deliveryState) ctx._deliveryState.outboxed = outboxed;
|
|
2349
|
+
ctx.throwIfCancelled();
|
|
2304
2350
|
if (!ctx.vapid || !ctx.vapid.email || !ctx.vapid.publicKey || !ctx.vapid.privateKey) {
|
|
2305
2351
|
throw new Error("VAPID configuration missing - push notifications cannot be sent");
|
|
2306
2352
|
}
|
|
@@ -2314,6 +2360,7 @@ async function sendHookPushPayloads({
|
|
|
2314
2360
|
const willPush = finalized.map((push) => shouldSendPush(push, pushGate));
|
|
2315
2361
|
const lastPushIndex = willPush.lastIndexOf(true);
|
|
2316
2362
|
for (let i = 0; i < total; i++) {
|
|
2363
|
+
ctx.throwIfCancelled();
|
|
2317
2364
|
if (willPush[i]) {
|
|
2318
2365
|
await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
|
|
2319
2366
|
pushedCount++;
|
|
@@ -2577,7 +2624,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
|
|
|
2577
2624
|
const hasChatSource = hasChatCredRef(decryptedPayload) || !!(decryptedPayload.apiUrl && decryptedPayload.apiKey && decryptedPayload.primaryModel);
|
|
2578
2625
|
if (hasPrompt && hasChatSource) {
|
|
2579
2626
|
const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
|
|
2580
|
-
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
|
|
2627
|
+
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
|
|
2581
2628
|
messageContent = aiResult.content;
|
|
2582
2629
|
llmResponse = aiResult.response;
|
|
2583
2630
|
} else if (decryptedPayload.userMessage) {
|
|
@@ -2587,7 +2634,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
|
|
|
2587
2634
|
}
|
|
2588
2635
|
} else if (decryptedPayload.messageType === "prompted" || decryptedPayload.messageType === "auto") {
|
|
2589
2636
|
const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
|
|
2590
|
-
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
|
|
2637
|
+
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
|
|
2591
2638
|
messageContent = aiResult.content;
|
|
2592
2639
|
llmResponse = aiResult.response;
|
|
2593
2640
|
} else {
|
|
@@ -3208,7 +3255,8 @@ async function deliverTasks(ctx, tasks) {
|
|
|
3208
3255
|
return !!await db.claimTask(task.id, task.next_send_at, leaseUntil, serializeGroup);
|
|
3209
3256
|
}
|
|
3210
3257
|
function startLeaseHeartbeat(task) {
|
|
3211
|
-
const
|
|
3258
|
+
const controller = new AbortController();
|
|
3259
|
+
const lease = { lost: false, released: false, signal: controller.signal, stop: () => {
|
|
3212
3260
|
} };
|
|
3213
3261
|
if (!heartbeatEnabled) return lease;
|
|
3214
3262
|
let stopped = false;
|
|
@@ -3224,6 +3272,9 @@ async function deliverTasks(ctx, tasks) {
|
|
|
3224
3272
|
if (renewed === false) {
|
|
3225
3273
|
if (stopped || lease.released) return;
|
|
3226
3274
|
lease.lost = true;
|
|
3275
|
+
const error = new Error("Task was cancelled or superseded");
|
|
3276
|
+
error.code = TASK_CANCELLED_CODE;
|
|
3277
|
+
controller.abort(error);
|
|
3227
3278
|
console.warn(`[amsg-server] \u4EFB\u52A1 ${task.id} \u7684\u79DF\u7EA6\u5DF2\u5931\u6548\uFF08\u884C\u88AB\u53D6\u6D88\u6216\u9876\u66FF\uFF09\uFF0C\u5269\u4F59\u63A8\u9001\u5C06\u4E2D\u6B62`);
|
|
3228
3279
|
return;
|
|
3229
3280
|
}
|
|
@@ -3553,7 +3604,8 @@ async function deliverTasks(ctx, tasks) {
|
|
|
3553
3604
|
db,
|
|
3554
3605
|
masterKey,
|
|
3555
3606
|
webpush: guardWebpushWithLease(ctx.webpush, lease),
|
|
3556
|
-
isTaskCancelled: () => lease.lost
|
|
3607
|
+
isTaskCancelled: () => lease.lost,
|
|
3608
|
+
signal: lease.signal
|
|
3557
3609
|
},
|
|
3558
3610
|
masterKey,
|
|
3559
3611
|
{ userKey, payload: decryptedPayload }
|
|
@@ -5960,7 +6012,7 @@ function createClientStateNamespacesHandler(ctx) {
|
|
|
5960
6012
|
}
|
|
5961
6013
|
|
|
5962
6014
|
// src/server/lib/version.js
|
|
5963
|
-
var SERVER_VERSION = true ? "2.6.0-next.
|
|
6015
|
+
var SERVER_VERSION = true ? "2.6.0-next.32" : "0.0.0-dev";
|
|
5964
6016
|
|
|
5965
6017
|
// src/server/handlers/capabilities.js
|
|
5966
6018
|
var SERVER_FEATURES = Object.freeze([
|
|
@@ -1707,6 +1707,17 @@ function firstPositiveNumber(values, fallback) {
|
|
|
1707
1707
|
}
|
|
1708
1708
|
async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
1709
1709
|
const hooks = ctx.hooks;
|
|
1710
|
+
const signal = ctx.signal || new AbortController().signal;
|
|
1711
|
+
const isCancelled = () => signal.aborted || _optionalChain([ctx, 'access', _5 => _5.isTaskCancelled, 'optionalCall', _6 => _6()]) === true;
|
|
1712
|
+
const throwIfCancelled = () => {
|
|
1713
|
+
if (!isCancelled()) return;
|
|
1714
|
+
if (isTaskCancelledError(signal.reason)) throw signal.reason;
|
|
1715
|
+
const error = new Error("Task was cancelled or superseded");
|
|
1716
|
+
error.code = "TASK_CANCELLED";
|
|
1717
|
+
throw error;
|
|
1718
|
+
};
|
|
1719
|
+
const cancellation = { signal, isCancelled, throwIfCancelled };
|
|
1720
|
+
ctx = { ...ctx, ...cancellation };
|
|
1710
1721
|
if (typeof hooks.onLLMOutput !== "function") {
|
|
1711
1722
|
throw new DeploymentConfigError(
|
|
1712
1723
|
"AGENTIC_CONFIG_ERROR: hooks.onBeforeFire requires hooks.onLLMOutput to classify LLM rounds",
|
|
@@ -1715,13 +1726,17 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1715
1726
|
}
|
|
1716
1727
|
const nowFn = typeof ctx._agenticNow === "function" ? ctx._agenticNow : Date.now;
|
|
1717
1728
|
const sleep = typeof ctx._agenticSleep === "function" ? ctx._agenticSleep : defaultSleep;
|
|
1718
|
-
const { readState, writeState } = createStateAccessors({
|
|
1729
|
+
const { readState, writeState: writeSettledState } = createStateAccessors({
|
|
1719
1730
|
db: ctx.db,
|
|
1720
1731
|
userId: task.user_id,
|
|
1721
1732
|
userKey,
|
|
1722
1733
|
maxStateValueBytes: ctx.maxStateValueBytes,
|
|
1723
1734
|
now: nowFn
|
|
1724
1735
|
});
|
|
1736
|
+
const writeState = async (namespace, entries) => {
|
|
1737
|
+
throwIfCancelled();
|
|
1738
|
+
return writeSettledState(namespace, entries);
|
|
1739
|
+
};
|
|
1725
1740
|
const sessionId = task.id != null ? `sess_task_${task.id}${occurrenceSuffix(task)}` : `sess_${_amsgshared.randomUUID.call(void 0, )}`;
|
|
1726
1741
|
const messageIdBase = task.id != null ? `msg_task_${task.id}${occurrenceSuffix(task)}` : `msg_${_amsgshared.randomUUID.call(void 0, )}`;
|
|
1727
1742
|
const occurrenceMs = occurrenceMsOf(task);
|
|
@@ -1737,7 +1752,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1737
1752
|
now: nowFn,
|
|
1738
1753
|
// run-tick 在投递 ctx 上挂的取消信号(与 guardWebpushWithLease 读的是同一
|
|
1739
1754
|
// 个租约状态),emitResult 不发推送的那条路要靠它拦下已取消任务的落行。
|
|
1740
|
-
isCancelled
|
|
1755
|
+
isCancelled
|
|
1741
1756
|
});
|
|
1742
1757
|
const maxScheduledTasksPerFire = Number.isInteger(ctx.maxScheduledTasksPerFire) && ctx.maxScheduledTasksPerFire >= 0 ? ctx.maxScheduledTasksPerFire : DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE;
|
|
1743
1758
|
let scheduledTaskCount = 0;
|
|
@@ -1754,6 +1769,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1754
1769
|
}
|
|
1755
1770
|
}
|
|
1756
1771
|
const scheduleTask = async (options) => {
|
|
1772
|
+
throwIfCancelled();
|
|
1757
1773
|
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
1758
1774
|
throw new TypeError("scheduleTask(options) \u9700\u8981\u4E00\u4E2A\u5BF9\u8C61\uFF0C\u81F3\u5C11\u5305\u542B { firstSendTime }");
|
|
1759
1775
|
}
|
|
@@ -1874,6 +1890,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1874
1890
|
}
|
|
1875
1891
|
scheduledTaskCount++;
|
|
1876
1892
|
const encryptedPayload = await encryptForStorage(serializedTaskData, userKey);
|
|
1893
|
+
throwIfCancelled();
|
|
1877
1894
|
let created;
|
|
1878
1895
|
try {
|
|
1879
1896
|
created = await ctx.db.createTask({
|
|
@@ -1908,6 +1925,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1908
1925
|
};
|
|
1909
1926
|
};
|
|
1910
1927
|
const cancelTask = async (uuid) => {
|
|
1928
|
+
throwIfCancelled();
|
|
1911
1929
|
if (typeof uuid !== "string" || !uuid.trim()) {
|
|
1912
1930
|
throw new TypeError("cancelTask(uuid) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
|
|
1913
1931
|
}
|
|
@@ -1922,6 +1940,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1922
1940
|
{ code: "AGENTIC_CANCEL_UNSUPPORTED" }
|
|
1923
1941
|
);
|
|
1924
1942
|
}
|
|
1943
|
+
throwIfCancelled();
|
|
1925
1944
|
const cancelled = await ctx.db.deleteTaskByUuid(uuid, task.user_id);
|
|
1926
1945
|
if (cancelled) {
|
|
1927
1946
|
await discardUndeliveredPushesForTask({ db: ctx.db, userId: task.user_id, taskUuid: uuid });
|
|
@@ -1929,6 +1948,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1929
1948
|
return { cancelled: !!cancelled };
|
|
1930
1949
|
};
|
|
1931
1950
|
const renewTask = async (uuid, nextSendAt) => {
|
|
1951
|
+
throwIfCancelled();
|
|
1932
1952
|
if (typeof uuid !== "string" || !uuid.trim()) {
|
|
1933
1953
|
throw new TypeError("renewTask(uuid, nextSendAt) \u9700\u8981\u975E\u7A7A\u5B57\u7B26\u4E32 uuid");
|
|
1934
1954
|
}
|
|
@@ -1959,6 +1979,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1959
1979
|
const payload = JSON.parse(await decryptFromStorage(row.encrypted_payload, userKey));
|
|
1960
1980
|
const nextSendAtIso = sendAt.toISOString();
|
|
1961
1981
|
const encrypted = await encryptForStorage(JSON.stringify({ ...payload, firstSendTime: nextSendAtIso }), userKey);
|
|
1982
|
+
throwIfCancelled();
|
|
1962
1983
|
const updated = await ctx.db.updateTaskByUuid(uuid, task.user_id, encrypted, {
|
|
1963
1984
|
next_send_at: nextSendAtIso,
|
|
1964
1985
|
retry_count: 0,
|
|
@@ -1979,6 +2000,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
1979
2000
|
};
|
|
1980
2001
|
const scratch = {};
|
|
1981
2002
|
const fireCtx = Object.freeze({
|
|
2003
|
+
...cancellation,
|
|
1982
2004
|
task: buildHookTask(task, decryptedPayload),
|
|
1983
2005
|
userId: task.user_id,
|
|
1984
2006
|
readState,
|
|
@@ -2027,16 +2049,26 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
2027
2049
|
messageIdBase,
|
|
2028
2050
|
occurrenceMs
|
|
2029
2051
|
});
|
|
2052
|
+
throwIfCancelled();
|
|
2030
2053
|
settledStatus = !outcome.handled ? "not-handled" : outcome.result.status === "skipped" ? "skipped" : "sent";
|
|
2031
2054
|
return outcome;
|
|
2032
2055
|
} catch (error) {
|
|
2056
|
+
if (isCancelled() && !isTaskCancelledError(error)) {
|
|
2057
|
+
try {
|
|
2058
|
+
throwIfCancelled();
|
|
2059
|
+
} catch (cancelled) {
|
|
2060
|
+
error = cancelled;
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
if (isTaskCancelledError(error)) settledStatus = "cancelled";
|
|
2033
2064
|
settledError = error;
|
|
2034
2065
|
throw error;
|
|
2035
2066
|
} finally {
|
|
2036
2067
|
await notifyFireSettled(ctx, {
|
|
2037
2068
|
task,
|
|
2069
|
+
...cancellation,
|
|
2038
2070
|
status: settledStatus,
|
|
2039
|
-
...settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
|
|
2071
|
+
...settledStatus === "cancelled" ? { willRetry: false, failureStage: null } : settledStatus === "failed" && ctx._deliveryState ? failureRetryDecision(ctx._deliveryState, settledError) : { willRetry: null, failureStage: null },
|
|
2040
2072
|
skipReason: settledStatus === "skipped" ? progress.skipReason : null,
|
|
2041
2073
|
sentCount: progress.sentCount,
|
|
2042
2074
|
pushedCount: progress.pushedCount,
|
|
@@ -2060,7 +2092,7 @@ async function runAgenticFire({ task, decryptedPayload, userKey, ctx }) {
|
|
|
2060
2092
|
outboxed: progress.outboxed,
|
|
2061
2093
|
scratch,
|
|
2062
2094
|
readState,
|
|
2063
|
-
writeState,
|
|
2095
|
+
writeState: writeSettledState,
|
|
2064
2096
|
emitResult
|
|
2065
2097
|
});
|
|
2066
2098
|
}
|
|
@@ -2087,7 +2119,9 @@ async function runFireChain({
|
|
|
2087
2119
|
messageIdBase,
|
|
2088
2120
|
occurrenceMs
|
|
2089
2121
|
}) {
|
|
2122
|
+
ctx.throwIfCancelled();
|
|
2090
2123
|
const before = await hooks.onBeforeFire(fireCtx);
|
|
2124
|
+
ctx.throwIfCancelled();
|
|
2091
2125
|
if (before == null) return { handled: false };
|
|
2092
2126
|
if (typeof before === "object" && before.skip === true) {
|
|
2093
2127
|
progress.skipReason = "before-fire";
|
|
@@ -2111,6 +2145,7 @@ async function runFireChain({
|
|
|
2111
2145
|
decryptedPayload
|
|
2112
2146
|
});
|
|
2113
2147
|
for (let iteration = 0; iteration < maxToolIterations; iteration++) {
|
|
2148
|
+
ctx.throwIfCancelled();
|
|
2114
2149
|
if (nowFn() >= deadline) {
|
|
2115
2150
|
throw new Error(`AGENTIC_TOTAL_TIMEOUT: fire chain exceeded ${totalTimeoutMs}ms after ${iteration} LLM round(s)`);
|
|
2116
2151
|
}
|
|
@@ -2124,13 +2159,17 @@ async function runFireChain({
|
|
|
2124
2159
|
messages,
|
|
2125
2160
|
...normalized.tools ? { tools: normalized.tools, toolChoice: normalized.toolChoice } : {}
|
|
2126
2161
|
},
|
|
2127
|
-
{ requireContent: false, timeoutMs: roundTimeoutMs }
|
|
2162
|
+
{ requireContent: false, timeoutMs: roundTimeoutMs, signal: ctx.signal }
|
|
2128
2163
|
);
|
|
2129
2164
|
const assistantMessage = _amsgshared.extractAssistantMessage.call(void 0, llmResponse);
|
|
2130
2165
|
messages = [...messages, assistantMessage];
|
|
2131
2166
|
progress.usage = llmResponse && typeof llmResponse === "object" && llmResponse.usage || null;
|
|
2132
2167
|
progress.usageTotal = accumulateUsage(progress.usageTotal, progress.usage);
|
|
2168
|
+
ctx.throwIfCancelled();
|
|
2133
2169
|
const sessionCtx = Object.freeze({
|
|
2170
|
+
signal: ctx.signal,
|
|
2171
|
+
isCancelled: ctx.isCancelled,
|
|
2172
|
+
throwIfCancelled: ctx.throwIfCancelled,
|
|
2134
2173
|
..._amsgshared.buildSessionContext.call(void 0, {
|
|
2135
2174
|
sessionId,
|
|
2136
2175
|
messages,
|
|
@@ -2154,6 +2193,7 @@ async function runFireChain({
|
|
|
2154
2193
|
resolveLlmCredential: resolveLlmCredential2
|
|
2155
2194
|
});
|
|
2156
2195
|
const decision = await hooks.onLLMOutput(sessionCtx);
|
|
2196
|
+
ctx.throwIfCancelled();
|
|
2157
2197
|
try {
|
|
2158
2198
|
_amsgshared.assertValidDecision.call(void 0, decision, { inlineToolCalls: true });
|
|
2159
2199
|
} catch (error) {
|
|
@@ -2204,15 +2244,19 @@ async function runFireChain({
|
|
|
2204
2244
|
}
|
|
2205
2245
|
let toolResults;
|
|
2206
2246
|
try {
|
|
2247
|
+
ctx.throwIfCancelled();
|
|
2207
2248
|
toolResults = await hooks.executeToolCalls(toolCalls, sessionCtx);
|
|
2249
|
+
ctx.throwIfCancelled();
|
|
2208
2250
|
if (!Array.isArray(toolResults)) {
|
|
2209
2251
|
throw new TypeError('executeToolCalls must resolve to an array of { tool_call_id, role: "tool", content }');
|
|
2210
2252
|
}
|
|
2211
2253
|
} catch (error) {
|
|
2254
|
+
ctx.throwIfCancelled();
|
|
2255
|
+
if (isTaskCancelledError(error)) throw error;
|
|
2212
2256
|
toolResults = toolCalls.map((toolCall) => ({
|
|
2213
2257
|
tool_call_id: toolCall && typeof toolCall === "object" && typeof toolCall.id === "string" ? toolCall.id : "",
|
|
2214
2258
|
role: "tool",
|
|
2215
|
-
content: `Tool execution failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess',
|
|
2259
|
+
content: `Tool execution failed: ${_nullishCoalesce(_optionalChain([error, 'optionalAccess', _7 => _7.message]), () => ( String(error)))}`
|
|
2216
2260
|
}));
|
|
2217
2261
|
}
|
|
2218
2262
|
const nativeCalls = Array.isArray(assistantMessage.tool_calls) ? assistantMessage.tool_calls : [];
|
|
@@ -2298,9 +2342,11 @@ async function sendHookPushPayloads({
|
|
|
2298
2342
|
stampTaskIdentity(push, task, decryptedPayload, occurrenceMs);
|
|
2299
2343
|
finalized.push(push);
|
|
2300
2344
|
}
|
|
2345
|
+
ctx.throwIfCancelled();
|
|
2301
2346
|
outboxed = await appendPushesToOutbox({ db: ctx.db, userId: task.user_id, userKey, pushes: finalized });
|
|
2302
2347
|
progress.outboxed = outboxed;
|
|
2303
2348
|
if (ctx._deliveryState) ctx._deliveryState.outboxed = outboxed;
|
|
2349
|
+
ctx.throwIfCancelled();
|
|
2304
2350
|
if (!ctx.vapid || !ctx.vapid.email || !ctx.vapid.publicKey || !ctx.vapid.privateKey) {
|
|
2305
2351
|
throw new Error("VAPID configuration missing - push notifications cannot be sent");
|
|
2306
2352
|
}
|
|
@@ -2314,6 +2360,7 @@ async function sendHookPushPayloads({
|
|
|
2314
2360
|
const willPush = finalized.map((push) => shouldSendPush(push, pushGate));
|
|
2315
2361
|
const lastPushIndex = willPush.lastIndexOf(true);
|
|
2316
2362
|
for (let i = 0; i < total; i++) {
|
|
2363
|
+
ctx.throwIfCancelled();
|
|
2317
2364
|
if (willPush[i]) {
|
|
2318
2365
|
await sendTaggedPush(ctx.webpush, pushSubscription, JSON.stringify(finalized[i]));
|
|
2319
2366
|
pushedCount++;
|
|
@@ -2577,7 +2624,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
|
|
|
2577
2624
|
const hasChatSource = hasChatCredRef(decryptedPayload) || !!(decryptedPayload.apiUrl && decryptedPayload.apiKey && decryptedPayload.primaryModel);
|
|
2578
2625
|
if (hasPrompt && hasChatSource) {
|
|
2579
2626
|
const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
|
|
2580
|
-
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
|
|
2627
|
+
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
|
|
2581
2628
|
messageContent = aiResult.content;
|
|
2582
2629
|
llmResponse = aiResult.response;
|
|
2583
2630
|
} else if (decryptedPayload.userMessage) {
|
|
@@ -2587,7 +2634,7 @@ async function processSingleMessage(task, ctx, providedMasterKey, predecrypted =
|
|
|
2587
2634
|
}
|
|
2588
2635
|
} else if (decryptedPayload.messageType === "prompted" || decryptedPayload.messageType === "auto") {
|
|
2589
2636
|
const chatCred = await resolveFireCredentials({ db: ctx.db, userId: task.user_id, userKey, decryptedPayload });
|
|
2590
|
-
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload);
|
|
2637
|
+
const aiResult = await callLlm(chatCred ? { ...decryptedPayload, ...chatCred } : decryptedPayload, { signal: ctx.signal });
|
|
2591
2638
|
messageContent = aiResult.content;
|
|
2592
2639
|
llmResponse = aiResult.response;
|
|
2593
2640
|
} else {
|
|
@@ -3208,7 +3255,8 @@ async function deliverTasks(ctx, tasks) {
|
|
|
3208
3255
|
return !!await db.claimTask(task.id, task.next_send_at, leaseUntil, serializeGroup);
|
|
3209
3256
|
}
|
|
3210
3257
|
function startLeaseHeartbeat(task) {
|
|
3211
|
-
const
|
|
3258
|
+
const controller = new AbortController();
|
|
3259
|
+
const lease = { lost: false, released: false, signal: controller.signal, stop: () => {
|
|
3212
3260
|
} };
|
|
3213
3261
|
if (!heartbeatEnabled) return lease;
|
|
3214
3262
|
let stopped = false;
|
|
@@ -3224,6 +3272,9 @@ async function deliverTasks(ctx, tasks) {
|
|
|
3224
3272
|
if (renewed === false) {
|
|
3225
3273
|
if (stopped || lease.released) return;
|
|
3226
3274
|
lease.lost = true;
|
|
3275
|
+
const error = new Error("Task was cancelled or superseded");
|
|
3276
|
+
error.code = TASK_CANCELLED_CODE;
|
|
3277
|
+
controller.abort(error);
|
|
3227
3278
|
console.warn(`[amsg-server] \u4EFB\u52A1 ${task.id} \u7684\u79DF\u7EA6\u5DF2\u5931\u6548\uFF08\u884C\u88AB\u53D6\u6D88\u6216\u9876\u66FF\uFF09\uFF0C\u5269\u4F59\u63A8\u9001\u5C06\u4E2D\u6B62`);
|
|
3228
3279
|
return;
|
|
3229
3280
|
}
|
|
@@ -3553,7 +3604,8 @@ async function deliverTasks(ctx, tasks) {
|
|
|
3553
3604
|
db,
|
|
3554
3605
|
masterKey,
|
|
3555
3606
|
webpush: guardWebpushWithLease(ctx.webpush, lease),
|
|
3556
|
-
isTaskCancelled: () => lease.lost
|
|
3607
|
+
isTaskCancelled: () => lease.lost,
|
|
3608
|
+
signal: lease.signal
|
|
3557
3609
|
},
|
|
3558
3610
|
masterKey,
|
|
3559
3611
|
{ userKey, payload: decryptedPayload }
|
|
@@ -5099,7 +5151,7 @@ var D1Adapter = class {
|
|
|
5099
5151
|
result.cleanupOutcomes = probeIndexes.map((probeAt) => {
|
|
5100
5152
|
if (probeAt === null) return null;
|
|
5101
5153
|
const row = results[probeAt] && Array.isArray(results[probeAt].results) ? results[probeAt].results[0] : null;
|
|
5102
|
-
return Number(_nullishCoalesce(_optionalChain([row, 'optionalAccess',
|
|
5154
|
+
return Number(_nullishCoalesce(_optionalChain([row, 'optionalAccess', _8 => _8.n]), () => ( 0))) === 0;
|
|
5103
5155
|
});
|
|
5104
5156
|
}
|
|
5105
5157
|
return result;
|
|
@@ -5960,7 +6012,7 @@ function createClientStateNamespacesHandler(ctx) {
|
|
|
5960
6012
|
}
|
|
5961
6013
|
|
|
5962
6014
|
// src/server/lib/version.js
|
|
5963
|
-
var SERVER_VERSION = true ? "2.6.0-next.
|
|
6015
|
+
var SERVER_VERSION = true ? "2.6.0-next.32" : "0.0.0-dev";
|
|
5964
6016
|
|
|
5965
6017
|
// src/server/handlers/capabilities.js
|
|
5966
6018
|
var SERVER_FEATURES = Object.freeze([
|
package/dist/cloudflare.cjs
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
var
|
|
30
|
+
var _chunkKZT3YC62cjs = require('./chunk-KZT3YC62.cjs');
|
|
31
31
|
require('./chunk-7NMQFTDJ.cjs');
|
|
32
32
|
|
|
33
33
|
|
|
@@ -58,4 +58,4 @@ require('./chunk-7NMQFTDJ.cjs');
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
|
|
61
|
-
exports.DEFAULT_MAX_DELIVERY_RETRIES =
|
|
61
|
+
exports.DEFAULT_MAX_DELIVERY_RETRIES = _chunkKZT3YC62cjs.DEFAULT_MAX_DELIVERY_RETRIES; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkKZT3YC62cjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkKZT3YC62cjs.MAX_PUSH_PAYLOAD_BYTES; exports.NonRetryableError = _chunkKZT3YC62cjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkKZT3YC62cjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkKZT3YC62cjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkKZT3YC62cjs.advanceOccurrence; exports.createD1Adapter = _chunkKZT3YC62cjs.createD1Adapter; exports.createSingleUserCloudflareWorker = _chunkKZT3YC62cjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkKZT3YC62cjs.createSingleUserServer; exports.createWebCryptoWebPush = _chunkKZT3YC62cjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkKZT3YC62cjs.decryptFromStorage; exports.decryptPayload = _chunkKZT3YC62cjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkKZT3YC62cjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkKZT3YC62cjs.encryptForStorage; exports.ensureSchema = _chunkKZT3YC62cjs.ensureSchema; exports.getSchemaVersion = _chunkKZT3YC62cjs.getSchemaVersion; exports.isNonRetryableError = _chunkKZT3YC62cjs.isNonRetryableError; exports.isValidTimeZoneId = _chunkKZT3YC62cjs.isValidTimeZoneId; exports.measurePushPayload = _chunkKZT3YC62cjs.measurePushPayload; exports.nextFutureOccurrence = _chunkKZT3YC62cjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkKZT3YC62cjs.planNextOccurrence; exports.readRequestBody = _chunkKZT3YC62cjs.readRequestBody; exports.runScheduledTick = _chunkKZT3YC62cjs.runScheduledTick; exports.runTask = _chunkKZT3YC62cjs.runTask; exports.summarizeErrorCause = _chunkKZT3YC62cjs.summarizeErrorCause;
|
package/dist/cloudflare.mjs
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
var
|
|
75
|
+
var _chunkKZT3YC62cjs = require('./chunk-KZT3YC62.cjs');
|
|
76
76
|
require('./chunk-7NMQFTDJ.cjs');
|
|
77
77
|
|
|
78
78
|
// src/server/adapters/factory.js
|
|
@@ -106,7 +106,7 @@ async function createAdapter(config) {
|
|
|
106
106
|
// src/server/handlers/init-tenant.js
|
|
107
107
|
function createInitTenantHandler(ctx) {
|
|
108
108
|
async function POST(headers, body) {
|
|
109
|
-
const initSecret =
|
|
109
|
+
const initSecret = _chunkKZT3YC62cjs.getHeader.call(void 0, headers, "x-init-secret");
|
|
110
110
|
if (ctx.tenant.initSecret && initSecret !== ctx.tenant.initSecret) {
|
|
111
111
|
return {
|
|
112
112
|
status: 401,
|
|
@@ -119,7 +119,7 @@ function createInitTenantHandler(ctx) {
|
|
|
119
119
|
}
|
|
120
120
|
};
|
|
121
121
|
}
|
|
122
|
-
const parsed =
|
|
122
|
+
const parsed = _chunkKZT3YC62cjs.parseJsonBody.call(void 0, body);
|
|
123
123
|
if (!parsed.ok) {
|
|
124
124
|
return {
|
|
125
125
|
status: 400,
|
|
@@ -133,7 +133,7 @@ function createInitTenantHandler(ctx) {
|
|
|
133
133
|
const tenantId = payload.tenantId || void 0;
|
|
134
134
|
const driver = payload.driver;
|
|
135
135
|
const databaseUrl = payload.databaseUrl || payload.connectionString;
|
|
136
|
-
if (tenantId && !
|
|
136
|
+
if (tenantId && !_chunkKZT3YC62cjs.isValidUUIDv4.call(void 0, tenantId)) {
|
|
137
137
|
return {
|
|
138
138
|
status: 400,
|
|
139
139
|
body: {
|
|
@@ -253,7 +253,7 @@ function createSendNotificationsHandler(ctx) {
|
|
|
253
253
|
}
|
|
254
254
|
};
|
|
255
255
|
}
|
|
256
|
-
const data = await
|
|
256
|
+
const data = await _chunkKZT3YC62cjs.runScheduledTick.call(void 0, { ...ctx, db, masterKey });
|
|
257
257
|
return { status: 200, body: { success: true, data } };
|
|
258
258
|
}
|
|
259
259
|
return { POST };
|
|
@@ -275,16 +275,16 @@ function encryptConfig(config, kekBuffer) {
|
|
|
275
275
|
const plaintext = Buffer.from(JSON.stringify(config), "utf8");
|
|
276
276
|
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
277
277
|
const authTag = cipher.getAuthTag();
|
|
278
|
-
return `v1.${
|
|
278
|
+
return `v1.${_chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, iv)}.${_chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, authTag)}.${_chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, ciphertext)}`;
|
|
279
279
|
}
|
|
280
280
|
function decryptConfig(encrypted, kekBuffer) {
|
|
281
281
|
const parts = String(encrypted || "").split(".");
|
|
282
282
|
if (parts.length !== 4 || parts[0] !== "v1") {
|
|
283
283
|
throw new Error("INVALID_TENANT_CONFIG");
|
|
284
284
|
}
|
|
285
|
-
const iv =
|
|
286
|
-
const authTag =
|
|
287
|
-
const ciphertext =
|
|
285
|
+
const iv = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, parts[1]);
|
|
286
|
+
const authTag = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, parts[2]);
|
|
287
|
+
const ciphertext = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, parts[3]);
|
|
288
288
|
const decipher = _crypto.createDecipheriv.call(void 0, "aes-256-gcm", kekBuffer, iv);
|
|
289
289
|
decipher.setAuthTag(authTag);
|
|
290
290
|
const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]).toString("utf8");
|
|
@@ -352,7 +352,7 @@ function createTenantBlobStore(options) {
|
|
|
352
352
|
// src/server/tenant/token.js
|
|
353
353
|
|
|
354
354
|
function sign(input, secret) {
|
|
355
|
-
return
|
|
355
|
+
return _chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, _crypto.createHmac.call(void 0, "sha256", secret).update(input).digest());
|
|
356
356
|
}
|
|
357
357
|
function nowEpochSeconds() {
|
|
358
358
|
return Math.floor(Date.now() / 1e3);
|
|
@@ -368,8 +368,8 @@ function createTenantToken(params, secret) {
|
|
|
368
368
|
v: 1
|
|
369
369
|
};
|
|
370
370
|
const header = { alg: "HS256", typ: "JWT" };
|
|
371
|
-
const encodedHeader =
|
|
372
|
-
const encodedPayload =
|
|
371
|
+
const encodedHeader = _chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, _chunkKZT3YC62cjs.utf8.call(void 0, JSON.stringify(header)));
|
|
372
|
+
const encodedPayload = _chunkKZT3YC62cjs.bytesToBase64Url.call(void 0, _chunkKZT3YC62cjs.utf8.call(void 0, JSON.stringify(payload)));
|
|
373
373
|
const signingInput = `${encodedHeader}.${encodedPayload}`;
|
|
374
374
|
const signature = sign(signingInput, secret);
|
|
375
375
|
return `${signingInput}.${signature}`;
|
|
@@ -388,17 +388,17 @@ function verifyTenantToken(token, secret, options = {}) {
|
|
|
388
388
|
let receivedBytes;
|
|
389
389
|
let expectedBytes;
|
|
390
390
|
try {
|
|
391
|
-
receivedBytes =
|
|
392
|
-
expectedBytes =
|
|
391
|
+
receivedBytes = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, receivedSignature);
|
|
392
|
+
expectedBytes = _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, expectedSignature);
|
|
393
393
|
} catch (e) {
|
|
394
394
|
throw new Error("INVALID_TENANT_AUTH");
|
|
395
395
|
}
|
|
396
|
-
if (!
|
|
396
|
+
if (!_chunkKZT3YC62cjs.timingSafeEqualBytes.call(void 0, receivedBytes, expectedBytes)) {
|
|
397
397
|
throw new Error("INVALID_TENANT_AUTH");
|
|
398
398
|
}
|
|
399
399
|
let payload;
|
|
400
400
|
try {
|
|
401
|
-
payload = JSON.parse(
|
|
401
|
+
payload = JSON.parse(_chunkKZT3YC62cjs.utf8Decode.call(void 0, _chunkKZT3YC62cjs.base64UrlToBytes.call(void 0, encodedPayload)));
|
|
402
402
|
} catch (e2) {
|
|
403
403
|
throw new Error("INVALID_TENANT_AUTH");
|
|
404
404
|
}
|
|
@@ -626,15 +626,15 @@ async function createReiServer(config) {
|
|
|
626
626
|
return {
|
|
627
627
|
handlers: {
|
|
628
628
|
initTenant: createInitTenantHandler(ctx),
|
|
629
|
-
getUserKey:
|
|
630
|
-
scheduleMessage:
|
|
629
|
+
getUserKey: _chunkKZT3YC62cjs.createGetUserKeyHandler.call(void 0, ctx),
|
|
630
|
+
scheduleMessage: _chunkKZT3YC62cjs.createScheduleMessageHandler.call(void 0, ctx),
|
|
631
631
|
sendNotifications: createSendNotificationsHandler(ctx),
|
|
632
|
-
updateMessage:
|
|
633
|
-
cancelMessage:
|
|
634
|
-
messages:
|
|
635
|
-
getMessage:
|
|
636
|
-
pushSubscription:
|
|
637
|
-
llmCredentials:
|
|
632
|
+
updateMessage: _chunkKZT3YC62cjs.createUpdateMessageHandler.call(void 0, ctx),
|
|
633
|
+
cancelMessage: _chunkKZT3YC62cjs.createCancelMessageHandler.call(void 0, ctx),
|
|
634
|
+
messages: _chunkKZT3YC62cjs.createMessagesHandler.call(void 0, ctx),
|
|
635
|
+
getMessage: _chunkKZT3YC62cjs.createGetMessageHandler.call(void 0, ctx),
|
|
636
|
+
pushSubscription: _chunkKZT3YC62cjs.createPushSubscriptionHandler.call(void 0, ctx),
|
|
637
|
+
llmCredentials: _chunkKZT3YC62cjs.createLlmCredentialsHandler.call(void 0, ctx)
|
|
638
638
|
}
|
|
639
639
|
};
|
|
640
640
|
}
|
|
@@ -701,4 +701,4 @@ async function createReiServer(config) {
|
|
|
701
701
|
|
|
702
702
|
|
|
703
703
|
|
|
704
|
-
exports.CORS_ALLOW_HEADERS =
|
|
704
|
+
exports.CORS_ALLOW_HEADERS = _chunkKZT3YC62cjs.CORS_ALLOW_HEADERS; exports.CORS_ALLOW_METHODS = _chunkKZT3YC62cjs.CORS_ALLOW_METHODS; exports.CRED_ID_MAX_LENGTH = _chunkKZT3YC62cjs.CRED_ID_MAX_LENGTH; exports.CRED_PUT_BATCH_MAX = _chunkKZT3YC62cjs.CRED_PUT_BATCH_MAX; exports.CRED_REFS_MAX_ENTRIES = _chunkKZT3YC62cjs.CRED_REFS_MAX_ENTRIES; exports.CRED_ROWS_PER_USER_MAX = _chunkKZT3YC62cjs.CRED_ROWS_PER_USER_MAX; exports.DEFAULT_CLAIM_LEASE_MS = _chunkKZT3YC62cjs.DEFAULT_CLAIM_LEASE_MS; exports.DEFAULT_HEARTBEAT_LEASE_TTL_MS = _chunkKZT3YC62cjs.DEFAULT_HEARTBEAT_LEASE_TTL_MS; exports.DEFAULT_LEASE_HEARTBEAT_MS = _chunkKZT3YC62cjs.DEFAULT_LEASE_HEARTBEAT_MS; exports.DEFAULT_MAX_DELIVERY_RETRIES = _chunkKZT3YC62cjs.DEFAULT_MAX_DELIVERY_RETRIES; exports.DEFAULT_MAX_REQUEST_BODY_BYTES = _chunkKZT3YC62cjs.DEFAULT_MAX_REQUEST_BODY_BYTES; exports.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE = _chunkKZT3YC62cjs.DEFAULT_MAX_SCHEDULED_TASKS_PER_FIRE; exports.DEFAULT_MAX_TOOL_ITERATIONS = _chunkKZT3YC62cjs.DEFAULT_MAX_TOOL_ITERATIONS; exports.DEFAULT_TOTAL_TIMEOUT_MS = _chunkKZT3YC62cjs.DEFAULT_TOTAL_TIMEOUT_MS; exports.DeploymentConfigError = _chunkKZT3YC62cjs.DeploymentConfigError; exports.MAX_PUSH_PAYLOAD_BYTES = _chunkKZT3YC62cjs.MAX_PUSH_PAYLOAD_BYTES; exports.MAX_TASK_PAYLOAD_BYTES = _chunkKZT3YC62cjs.MAX_TASK_PAYLOAD_BYTES; exports.MIN_SCHEDULE_LEAD_MS = _chunkKZT3YC62cjs.MIN_SCHEDULE_LEAD_MS; exports.NonRetryableError = _chunkKZT3YC62cjs.NonRetryableError; exports.PUSH_ENVELOPE_RESERVED_BYTES = _chunkKZT3YC62cjs.PUSH_ENVELOPE_RESERVED_BYTES; exports.SCHEMA_VERSION = _chunkKZT3YC62cjs.SCHEMA_VERSION; exports.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_ENCRYPTION_OVERHEAD_BYTES; exports.WEB_PUSH_MAX_BODY_BYTES = _chunkKZT3YC62cjs.WEB_PUSH_MAX_BODY_BYTES; exports.advanceOccurrence = _chunkKZT3YC62cjs.advanceOccurrence; exports.createAdapter = createAdapter; exports.createD1Adapter = _chunkKZT3YC62cjs.createD1Adapter; exports.createReiServer = createReiServer; exports.createSingleUserCloudflareWorker = _chunkKZT3YC62cjs.createSingleUserCloudflareWorker; exports.createSingleUserServer = _chunkKZT3YC62cjs.createSingleUserServer; exports.createTenantToken = createTenantToken; exports.createWebCryptoWebPush = _chunkKZT3YC62cjs.createWebCryptoWebPush; exports.decryptFromStorage = _chunkKZT3YC62cjs.decryptFromStorage; exports.decryptPayload = _chunkKZT3YC62cjs.decryptPayload; exports.deriveUserEncryptionKey = _chunkKZT3YC62cjs.deriveUserEncryptionKey; exports.encryptForStorage = _chunkKZT3YC62cjs.encryptForStorage; exports.ensureSchema = _chunkKZT3YC62cjs.ensureSchema; exports.getSchemaVersion = _chunkKZT3YC62cjs.getSchemaVersion; exports.hasChatCredRef = _chunkKZT3YC62cjs.hasChatCredRef; exports.isNonRetryableError = _chunkKZT3YC62cjs.isNonRetryableError; exports.isValidCredId = _chunkKZT3YC62cjs.isValidCredId; exports.isValidISO8601 = _chunkKZT3YC62cjs.isValidISO8601; exports.isValidTimeZoneId = _chunkKZT3YC62cjs.isValidTimeZoneId; exports.isValidUUID = _chunkKZT3YC62cjs.isValidUUID; exports.isValidUUIDv4 = _chunkKZT3YC62cjs.isValidUUIDv4; exports.isValidUrl = _chunkKZT3YC62cjs.isValidUrl; exports.measurePushPayload = _chunkKZT3YC62cjs.measurePushPayload; exports.nextFutureOccurrence = _chunkKZT3YC62cjs.nextFutureOccurrence; exports.planNextOccurrence = _chunkKZT3YC62cjs.planNextOccurrence; exports.readRequestBody = _chunkKZT3YC62cjs.readRequestBody; exports.resolveLlmCredential = _chunkKZT3YC62cjs.resolveLlmCredential; exports.runScheduledTick = _chunkKZT3YC62cjs.runScheduledTick; exports.runTask = _chunkKZT3YC62cjs.runTask; exports.sanitizeErrorSummary = _chunkKZT3YC62cjs.sanitizeErrorSummary; exports.summarizeErrorCause = _chunkKZT3YC62cjs.summarizeErrorCause; exports.supportsLlmCredentialsStore = _chunkKZT3YC62cjs.supportsLlmCredentialsStore; exports.validateAvatarUrl = _chunkKZT3YC62cjs.validateAvatarUrl; exports.validateCredRefs = _chunkKZT3YC62cjs.validateCredRefs; exports.validateCredValue = _chunkKZT3YC62cjs.validateCredValue; exports.validateLlmMessagesArray = _chunkKZT3YC62cjs.validateLlmMessagesArray; exports.validateScheduleMessagePayload = _chunkKZT3YC62cjs.validateScheduleMessagePayload; exports.validateSplitPattern = _chunkKZT3YC62cjs.validateSplitPattern; exports.verifyTenantToken = verifyTenantToken;
|
package/dist/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rei-standard/amsg-server",
|
|
3
|
-
"version": "2.6.0-next.
|
|
3
|
+
"version": "2.6.0-next.32",
|
|
4
4
|
"description": "ReiStandard Active Messaging server SDK with pluggable database adapters. Three-axis push schema (messageKind / messageType / messageSubtype) from @rei-standard/amsg-shared. Auto-emits ReasoningPush when the LLM response carries reasoning_content.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@netlify/blobs": "^8.1.0",
|
|
42
|
-
"@rei-standard/amsg-shared": "^0.4.0-next.
|
|
42
|
+
"@rei-standard/amsg-shared": "^0.4.0-next.11",
|
|
43
43
|
"web-push": "^3.6.7"
|
|
44
44
|
},
|
|
45
45
|
"peerDependencies": {
|