@dvmkit/sdk 0.14.0 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ITRSITFP.js → chunk-2I6NXIPG.js} +1 -1
- package/dist/{chunk-TKJBUFYY.js → chunk-33J3NQDZ.js} +1 -1
- package/dist/{chunk-7KQLPVV7.js → chunk-7NZRJPEP.js} +1 -1
- package/dist/{chunk-Z4FOPROB.js → chunk-BAHZK334.js} +2 -0
- package/dist/{chunk-D4FFS3IS.js → chunk-CRH6BMMG.js} +1 -1
- package/dist/{chunk-LDKV4UHI.js → chunk-CVT5LTAK.js} +1 -1
- package/dist/{chunk-AFV77S4C.js → chunk-FL6Q3JNJ.js} +25 -0
- package/dist/{chunk-EP7OVWI5.js → chunk-FOXGN4KQ.js} +1 -1
- package/dist/{chunk-VWIMQ5H5.js → chunk-G47UY3BK.js} +1 -1
- package/dist/{chunk-JLT2YIBS.js → chunk-GB2N4NG5.js} +2 -2
- package/dist/{chunk-E7ZBCT5U.js → chunk-I2H2XYQV.js} +1 -1
- package/dist/{chunk-3YFFZLW7.js → chunk-IUODXRQN.js} +2 -2
- package/dist/{chunk-566CFXGU.js → chunk-IVW5UMD3.js} +1 -1
- package/dist/{chunk-TVI4V7GF.js → chunk-LBMHV2DK.js} +80 -19
- package/dist/{chunk-A2YESDQM.js → chunk-LM6E4YHQ.js} +2 -2
- package/dist/{chunk-5JSPTVIK.js → chunk-LZFZGY7L.js} +1 -1
- package/dist/{chunk-FFRTAQUW.js → chunk-P5KQKLWL.js} +1 -1
- package/dist/{chunk-TWKQFIOW.js → chunk-PJAKJD2U.js} +55 -7
- package/dist/{chunk-M4NFYEEY.js → chunk-QRYGBKCR.js} +1 -1
- package/dist/{chunk-KJZVTWMX.js → chunk-R3FSW66G.js} +15 -4
- package/dist/{chunk-HNXMWHLU.js → chunk-R7FH7SHX.js} +1 -1
- package/dist/{chunk-NS2OMIU7.js → chunk-RQK7OFJO.js} +1 -1
- package/dist/{chunk-JFH34P3M.js → chunk-VG74TVFF.js} +265 -148
- package/dist/{chunk-HULU2UVM.js → chunk-ZO2ZAPG3.js} +1 -1
- package/dist/{content-retention-BcHNpP2F.d.ts → content-retention-DA2mlW31.d.ts} +1 -1
- package/dist/{credit-ledger-D3UUR2GW.js → credit-ledger-EZDZYLSK.js} +3 -3
- package/dist/{credit-menu-C-kmf61K.d.ts → credit-menu-BXHL3jHA.d.ts} +14 -7
- package/dist/{fx-hFlF4Cn8.d.ts → fx-UnO-P6Cj.d.ts} +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +13 -6
- package/dist/internal/caller.d.ts +14 -8
- package/dist/internal/caller.js +7 -7
- package/dist/internal/server.d.ts +7 -7
- package/dist/internal/server.js +21 -21
- package/dist/{job-store-DVCATwhU.d.ts → job-store-AxjHh5Gp.d.ts} +12 -2
- package/dist/{lightning-backend-DXNVlVs9.d.ts → lightning-backend-C5_GKiKR.d.ts} +1 -1
- package/dist/{memory-credit-ledger-SCXQO4HZ.js → memory-credit-ledger-REZGHPJP.js} +4 -4
- package/dist/{mpp-setup-JU3MT7QX.js → mpp-setup-RG5JDMIO.js} +3 -3
- package/dist/{payout-reporter-NXWQVKXW.js → payout-reporter-DDQ7FGRC.js} +2 -2
- package/dist/{postgres-consumed-credential-store-WXJLM6J7.js → postgres-consumed-credential-store-I4WTNVQZ.js} +1 -1
- package/dist/{postgres-job-store-ZVMAN6L2.js → postgres-job-store-VDSDXCHR.js} +3 -3
- package/dist/{postgres-replay-store-QJ4FG6AR.js → postgres-replay-store-3F5FCUXN.js} +2 -2
- package/dist/{pricing-KCLENT2C.js → pricing-HLYEGPXD.js} +3 -3
- package/dist/{revenue-reporter-HD4GMXGD.js → revenue-reporter-RIEHBKRA.js} +2 -2
- package/dist/server/index.d.ts +11 -10
- package/dist/server/index.js +29 -29
- package/dist/{step-cache-CoORQQ_Y.d.ts → step-cache-MA3hpa7F.d.ts} +25 -8
- package/dist/{tempo-charge-store-7LTUAQHQ.js → tempo-charge-store-B5SYDCBK.js} +2 -2
- package/dist/{tempo-session-store-LYAIDR2B.js → tempo-session-store-FHW7N22I.js} +3 -3
- package/dist/testing/index.d.ts +3 -3
- package/dist/testing/index.js +7 -7
- package/dist/{usd-CeXGiyTC.d.ts → usd-CLGrKw9p.d.ts} +1 -1
- package/dist/{x402-RUJ4LUKF.js → x402-AY6P5KV4.js} +3 -3
- package/package.json +1 -1
|
@@ -203,6 +203,7 @@ var diagnostic_catalogue_v1_default = {
|
|
|
203
203
|
"job_heartbeat_failed",
|
|
204
204
|
"job_id",
|
|
205
205
|
"job_message_append_failed",
|
|
206
|
+
"step_persist_failed",
|
|
206
207
|
"job_messages_listen_connect_failed",
|
|
207
208
|
"job_messages_listen_lost",
|
|
208
209
|
"job_retention_alert_failed",
|
|
@@ -368,6 +369,7 @@ var diagnostic_catalogue_v1_default = {
|
|
|
368
369
|
"spans_retention_failed",
|
|
369
370
|
"stale_job_cancelled",
|
|
370
371
|
"stale_job_failed",
|
|
372
|
+
"stale_job_local_live_skipped",
|
|
371
373
|
"stale_job_sweep_clock_skew",
|
|
372
374
|
"stale_job_sweep_failed",
|
|
373
375
|
"stripe.create_checkout_session",
|
|
@@ -138,6 +138,9 @@ function providerMessage(job, type, content) {
|
|
|
138
138
|
job.replayProviderSkip--;
|
|
139
139
|
return;
|
|
140
140
|
}
|
|
141
|
+
if (type === "prompt" || type === "payment-request") {
|
|
142
|
+
content = { ...content, expires_at_ms: Date.now() + (job.idleTimeoutMs ?? 36e5) };
|
|
143
|
+
}
|
|
141
144
|
const msg = localMessage(job, "provider", type, content);
|
|
142
145
|
if (type === "payment-request") {
|
|
143
146
|
const paymentRequest = content;
|
|
@@ -181,6 +184,26 @@ function isTerminal(status) {
|
|
|
181
184
|
function isYieldMessage(msg) {
|
|
182
185
|
return msg.type === "prompt" || msg.type === "payment-request" || msg.type === "working" || msg.type === "complete" || msg.type === "cancel";
|
|
183
186
|
}
|
|
187
|
+
function callerDeadline(job, legacyTimeoutMs) {
|
|
188
|
+
if (isTerminal(job.status)) return void 0;
|
|
189
|
+
const prompts = /* @__PURE__ */ new Map();
|
|
190
|
+
let payment;
|
|
191
|
+
for (const message of job.messages) {
|
|
192
|
+
if (message.from === "provider" && message.type === "prompt") prompts.set(message.content.id, message);
|
|
193
|
+
if (message.from === "provider" && message.type === "payment-request") payment = message;
|
|
194
|
+
if (message.from === "requester" && message.type === "response") prompts.delete(message.content.prompt_id);
|
|
195
|
+
}
|
|
196
|
+
const asks = [...prompts.values(), ...payment && (job.pendingPaymentMsats ?? 0) > 0 ? [payment] : []];
|
|
197
|
+
const deadlines = asks.map((ask) => ask.content.expires_at_ms).filter((stamp) => Number.isSafeInteger(stamp));
|
|
198
|
+
if (deadlines.length > 0) return Math.min(...deadlines);
|
|
199
|
+
if (job.status === "awaiting-input" && legacyTimeoutMs !== void 0 && (asks.length > 0 || job.messages.length === 0)) {
|
|
200
|
+
return (job.awaitingInputAtMs ?? job.lastActivityAt) + legacyTimeoutMs;
|
|
201
|
+
}
|
|
202
|
+
return void 0;
|
|
203
|
+
}
|
|
204
|
+
function hasCallerDeadline(messages) {
|
|
205
|
+
return messages.some((message) => message.from === "provider" && (message.type === "prompt" || message.type === "payment-request") && Number.isSafeInteger(message.content.expires_at_ms));
|
|
206
|
+
}
|
|
184
207
|
|
|
185
208
|
// src/sdk/server/content-retention.ts
|
|
186
209
|
import { randomUUID } from "crypto";
|
|
@@ -250,6 +273,8 @@ export {
|
|
|
250
273
|
localMessage,
|
|
251
274
|
isTerminal,
|
|
252
275
|
isYieldMessage,
|
|
276
|
+
callerDeadline,
|
|
277
|
+
hasCallerDeadline,
|
|
253
278
|
ContentHoldError,
|
|
254
279
|
isContentHoldStore,
|
|
255
280
|
contentMetadata,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loggers
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-R7FH7SHX.js";
|
|
4
4
|
import {
|
|
5
5
|
diagnosticConsole
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-BAHZK334.js";
|
|
7
7
|
|
|
8
8
|
// src/sdk/server/mpp-setup.ts
|
|
9
9
|
import { createHash, randomUUID } from "crypto";
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
createX402FacilitatorAuthHeaders,
|
|
3
3
|
settleWithFacilitator,
|
|
4
4
|
verifyWithFacilitator
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-I2H2XYQV.js";
|
|
6
6
|
import {
|
|
7
7
|
buildPaymentRequirements,
|
|
8
8
|
decodePayment,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from "./chunk-66HGCPBU.js";
|
|
16
16
|
import {
|
|
17
17
|
diagnosticConsole
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-BAHZK334.js";
|
|
19
19
|
|
|
20
20
|
// src/lib/x402/verify.ts
|
|
21
21
|
async function verifyX402Payment(paymentHeader, config, requiredUsdcMicro, resource, btcUsdRate, exactVersions = { v1: true, v2: true }) {
|
|
@@ -6,7 +6,8 @@ function envFlag(value) {
|
|
|
6
6
|
// src/sdk/server/ssrf.ts
|
|
7
7
|
import { lookup } from "dns/promises";
|
|
8
8
|
import { isIPv4, isIPv6 } from "net";
|
|
9
|
-
import {
|
|
9
|
+
import { Readable } from "stream";
|
|
10
|
+
import { Agent, getGlobalDispatcher } from "undici";
|
|
10
11
|
var SSRFError = class extends Error {
|
|
11
12
|
code = "ssrf_blocked";
|
|
12
13
|
reason;
|
|
@@ -44,25 +45,27 @@ async function createPinnedFetch(url, opts) {
|
|
|
44
45
|
const pinnedFetch = async (input, init) => {
|
|
45
46
|
let request = new Request(input, init);
|
|
46
47
|
let redirects = 0;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
request,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
try {
|
|
49
|
+
for (; ; ) {
|
|
50
|
+
const target = await targetFor(request.url);
|
|
51
|
+
const response = await fetchPinnedHop(request, target, baseFetch);
|
|
52
|
+
if (!isRedirect(response.status) || request.redirect === "manual") return response;
|
|
53
|
+
const location = response.headers.get("location");
|
|
54
|
+
if (location === null) return response;
|
|
55
|
+
await discardResponse(response);
|
|
56
|
+
if (request.redirect === "error") {
|
|
57
|
+
throw new TypeError("fetch failed: redirect mode is set to error");
|
|
58
|
+
}
|
|
59
|
+
if (redirects >= MAX_PINNED_REDIRECTS) {
|
|
60
|
+
throw new TypeError("fetch failed: maximum redirect count exceeded");
|
|
61
|
+
}
|
|
62
|
+
request = requestForRedirect(request, new URL(location, request.url), response.status);
|
|
63
|
+
redirects += 1;
|
|
64
|
+
opts?.onRedirectFollowed?.();
|
|
62
65
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
+
} catch (error) {
|
|
67
|
+
await request.body?.cancel(error).catch(() => void 0);
|
|
68
|
+
throw error;
|
|
66
69
|
}
|
|
67
70
|
};
|
|
68
71
|
return {
|
|
@@ -74,6 +77,64 @@ async function createPinnedFetch(url, opts) {
|
|
|
74
77
|
}
|
|
75
78
|
};
|
|
76
79
|
}
|
|
80
|
+
async function fetchPinnedHop(request, target, baseFetch) {
|
|
81
|
+
if (!request.body) {
|
|
82
|
+
return baseFetch(request, target.agent ? { redirect: "manual", dispatcher: target.agent } : { redirect: "manual" });
|
|
83
|
+
}
|
|
84
|
+
const body = request.body;
|
|
85
|
+
let reader;
|
|
86
|
+
let stopped = false;
|
|
87
|
+
let dispatched = false;
|
|
88
|
+
const upload = Readable.from((async function* () {
|
|
89
|
+
if (stopped) return;
|
|
90
|
+
reader = body.getReader();
|
|
91
|
+
try {
|
|
92
|
+
while (!stopped) {
|
|
93
|
+
const next = await reader.read();
|
|
94
|
+
if (next.done || stopped) return;
|
|
95
|
+
yield next.value;
|
|
96
|
+
}
|
|
97
|
+
} finally {
|
|
98
|
+
reader.releaseLock();
|
|
99
|
+
reader = void 0;
|
|
100
|
+
}
|
|
101
|
+
})(), { objectMode: false, highWaterMark: 64 * 1024 });
|
|
102
|
+
const stop = async (reason) => {
|
|
103
|
+
if (stopped) return;
|
|
104
|
+
stopped = true;
|
|
105
|
+
await (reader ? reader.cancel(reason) : body.cancel(reason)).catch(() => void 0);
|
|
106
|
+
};
|
|
107
|
+
const onAbort = () => {
|
|
108
|
+
void stop(request.signal.reason);
|
|
109
|
+
};
|
|
110
|
+
request.signal.addEventListener("abort", onAbort, { once: true });
|
|
111
|
+
const dispatcher = {
|
|
112
|
+
dispatch(options, handler) {
|
|
113
|
+
if (dispatched) throw new TypeError("fetch failed: cannot safely replay a request body");
|
|
114
|
+
dispatched = true;
|
|
115
|
+
return (target.agent ?? getGlobalDispatcher()).dispatch({
|
|
116
|
+
...options,
|
|
117
|
+
body: upload
|
|
118
|
+
}, handler);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
return await baseFetch(request, {
|
|
123
|
+
redirect: "manual",
|
|
124
|
+
// A stream also prevents native automatic body replay (e.g. on HTTP 421).
|
|
125
|
+
body: new ReadableStream({ start(controller) {
|
|
126
|
+
controller.close();
|
|
127
|
+
} }),
|
|
128
|
+
duplex: "half",
|
|
129
|
+
// Node's keepalive is a no-op, but rejects streaming request envelopes.
|
|
130
|
+
keepalive: false,
|
|
131
|
+
dispatcher
|
|
132
|
+
});
|
|
133
|
+
} finally {
|
|
134
|
+
request.signal.removeEventListener("abort", onAbort);
|
|
135
|
+
await stop();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
77
138
|
var MAX_PINNED_REDIRECTS = 20;
|
|
78
139
|
function isRedirect(status) {
|
|
79
140
|
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
@@ -10,13 +10,13 @@ import {
|
|
|
10
10
|
} from "./chunk-5UC7TOQC.js";
|
|
11
11
|
import {
|
|
12
12
|
applyRetryToPool
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FOXGN4KQ.js";
|
|
14
14
|
import {
|
|
15
15
|
x402NetworkByCaip2
|
|
16
16
|
} from "./chunk-BPYMEMQX.js";
|
|
17
17
|
import {
|
|
18
18
|
diagnosticConsole
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-BAHZK334.js";
|
|
20
20
|
|
|
21
21
|
// src/sdk/server/credit-ledger.ts
|
|
22
22
|
import { randomUUID } from "crypto";
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ContentHoldError,
|
|
3
|
-
applyContentHoldMutation
|
|
4
|
-
|
|
3
|
+
applyContentHoldMutation,
|
|
4
|
+
callerDeadline,
|
|
5
|
+
hasCallerDeadline
|
|
6
|
+
} from "./chunk-FL6Q3JNJ.js";
|
|
5
7
|
import {
|
|
6
8
|
withSdkInitLock
|
|
7
9
|
} from "./chunk-COYKJRMM.js";
|
|
8
10
|
import {
|
|
9
11
|
diagnosticConsole
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-BAHZK334.js";
|
|
11
13
|
|
|
12
14
|
// src/sdk/server/postgres-job-store.ts
|
|
13
15
|
import { createHash } from "crypto";
|
|
@@ -490,6 +492,18 @@ var PostgresJobStore = class {
|
|
|
490
492
|
}
|
|
491
493
|
held.client.release();
|
|
492
494
|
}
|
|
495
|
+
async saveStep(jobId, record) {
|
|
496
|
+
const result = await this.pool.query(
|
|
497
|
+
`UPDATE jobs SET step_cache = CASE
|
|
498
|
+
WHEN EXISTS (SELECT 1 FROM jsonb_array_elements(step_cache) AS step
|
|
499
|
+
WHERE step->>'id' = $2::jsonb->>'id') THEN step_cache
|
|
500
|
+
ELSE step_cache || jsonb_build_array($2::jsonb) END
|
|
501
|
+
WHERE id = $1 AND status NOT IN ('completed', 'failed', 'cancelled')
|
|
502
|
+
AND redacted_at IS NULL`,
|
|
503
|
+
[jobId, JSON.stringify(record)]
|
|
504
|
+
);
|
|
505
|
+
if (result.rowCount !== 1) throw new Error("Step persistence requires a live job");
|
|
506
|
+
}
|
|
493
507
|
async save(record) {
|
|
494
508
|
const dvmId = record[JOB_DVM_ID];
|
|
495
509
|
for (let attempt = 0; ; attempt++) {
|
|
@@ -588,7 +602,17 @@ var PostgresJobStore = class {
|
|
|
588
602
|
pending_x402_nonce = EXCLUDED.pending_x402_nonce,
|
|
589
603
|
pending_x402_amount_usdc_micro = EXCLUDED.pending_x402_amount_usdc_micro,
|
|
590
604
|
required_msats = EXCLUDED.required_msats,
|
|
591
|
-
|
|
605
|
+
-- A stale snapshot must not erase a step committed by saveStep.
|
|
606
|
+
-- First stored result wins for each id, matching cached replay.
|
|
607
|
+
step_cache = (
|
|
608
|
+
SELECT COALESCE(jsonb_agg(entry ORDER BY position), '[]'::jsonb)
|
|
609
|
+
FROM (
|
|
610
|
+
SELECT DISTINCT ON (entry->>'id') entry, position
|
|
611
|
+
FROM jsonb_array_elements(jobs.step_cache || EXCLUDED.step_cache)
|
|
612
|
+
WITH ORDINALITY AS steps(entry, position)
|
|
613
|
+
ORDER BY entry->>'id', position
|
|
614
|
+
) AS merged_steps
|
|
615
|
+
),
|
|
592
616
|
state = EXCLUDED.state,
|
|
593
617
|
last_activity_at = CASE WHEN jobs.status IN ('completed', 'failed', 'cancelled') THEN jobs.last_activity_at ELSE EXCLUDED.last_activity_at END
|
|
594
618
|
-- terminal is terminal. On a multi-machine DVM a DELETE can
|
|
@@ -1373,7 +1397,7 @@ var PostgresJobStore = class {
|
|
|
1373
1397
|
try {
|
|
1374
1398
|
await client.query("BEGIN");
|
|
1375
1399
|
const { rows } = await client.query(
|
|
1376
|
-
`SELECT
|
|
1400
|
+
`SELECT * FROM jobs
|
|
1377
1401
|
WHERE id = $1
|
|
1378
1402
|
AND status IN ('processing', 'working', 'awaiting-input')
|
|
1379
1403
|
${staleOnly ? "AND last_activity_at <= $2" : ""}
|
|
@@ -1384,6 +1408,22 @@ var PostgresJobStore = class {
|
|
|
1384
1408
|
await client.query("ROLLBACK");
|
|
1385
1409
|
return false;
|
|
1386
1410
|
}
|
|
1411
|
+
let terminalMessages;
|
|
1412
|
+
if (staleOnly) {
|
|
1413
|
+
const record = rowToRecord(rows[0]);
|
|
1414
|
+
const { rows: messages } = await client.query(
|
|
1415
|
+
"SELECT data FROM job_messages WHERE job_id=$1 AND status='verified' ORDER BY seq",
|
|
1416
|
+
[jobId]
|
|
1417
|
+
);
|
|
1418
|
+
const history = messages.length ? messages.map((row) => row.data) : record.messages;
|
|
1419
|
+
terminalMessages = history;
|
|
1420
|
+
const deadline = callerDeadline({ ...record, messages: history });
|
|
1421
|
+
const awaiting = deadline !== void 0 || record.status === "awaiting-input" && !hasCallerDeadline(history);
|
|
1422
|
+
if (terminalStatus === "cancelled" !== awaiting || deadline !== void 0 && Date.now() < deadline) {
|
|
1423
|
+
await client.query("ROLLBACK");
|
|
1424
|
+
return false;
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1387
1427
|
const nextSeq = rows[0].next_seq;
|
|
1388
1428
|
const now = Date.now();
|
|
1389
1429
|
const cancelMsg = {
|
|
@@ -1406,12 +1446,20 @@ var PostgresJobStore = class {
|
|
|
1406
1446
|
awaiting_input_at_ms = NULL,
|
|
1407
1447
|
status = $6,
|
|
1408
1448
|
summary = COALESCE(summary, $2),
|
|
1409
|
-
messages = COALESCE(messages, '[]'::jsonb) || $3::jsonb,
|
|
1449
|
+
messages = ${staleOnly ? "$3::jsonb" : "COALESCE(messages, '[]'::jsonb) || $3::jsonb"},
|
|
1410
1450
|
seq = $4,
|
|
1411
1451
|
next_seq = $4 + 1,
|
|
1412
1452
|
last_activity_at = $5
|
|
1413
1453
|
WHERE id = $1`,
|
|
1414
|
-
[
|
|
1454
|
+
[
|
|
1455
|
+
jobId,
|
|
1456
|
+
reason,
|
|
1457
|
+
JSON.stringify([...terminalMessages ?? [], cancelMsg]),
|
|
1458
|
+
nextSeq,
|
|
1459
|
+
now,
|
|
1460
|
+
terminalStatus,
|
|
1461
|
+
staleOnly ? terminalStatus === "cancelled" ? "caller" : "provider" : endedBy
|
|
1462
|
+
]
|
|
1415
1463
|
);
|
|
1416
1464
|
await client.query("SELECT pg_notify('job_messages', $1)", [jobId]);
|
|
1417
1465
|
await client.query("COMMIT");
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ContentHoldError,
|
|
3
3
|
applyContentHoldMutation,
|
|
4
|
+
callerDeadline,
|
|
5
|
+
hasCallerDeadline,
|
|
4
6
|
isTerminal
|
|
5
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-FL6Q3JNJ.js";
|
|
6
8
|
import {
|
|
7
9
|
redactUrl
|
|
8
10
|
} from "./chunk-FUJ36YDV.js";
|
|
9
11
|
import {
|
|
10
12
|
loggers
|
|
11
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-R7FH7SHX.js";
|
|
12
14
|
|
|
13
15
|
// src/sdk/server/job-store.ts
|
|
14
16
|
function accumulateAskedTopUp(prior, ask) {
|
|
@@ -431,6 +433,15 @@ var MemoryJobStore = class {
|
|
|
431
433
|
if (!record) return Promise.resolve(false);
|
|
432
434
|
const eligible = (record.status === "processing" || record.status === "working" || record.status === "awaiting-input") && (expectedActivityBefore === null || record.lastActivityAt <= expectedActivityBefore);
|
|
433
435
|
if (!eligible) return Promise.resolve(false);
|
|
436
|
+
let terminalMessages = record.messages;
|
|
437
|
+
if (expectedActivityBefore !== null) {
|
|
438
|
+
const messages = this.messagesFor(jobId).filter((entry) => entry.status === "verified").map((entry) => entry.message);
|
|
439
|
+
const history = messages.length ? messages : record.messages;
|
|
440
|
+
terminalMessages = history;
|
|
441
|
+
const deadline = callerDeadline({ ...record, messages: history });
|
|
442
|
+
const awaiting = deadline !== void 0 || record.status === "awaiting-input" && !hasCallerDeadline(history);
|
|
443
|
+
if (terminalStatus === "cancelled" !== awaiting || deadline !== void 0 && Date.now() < deadline) return Promise.resolve(false);
|
|
444
|
+
}
|
|
434
445
|
const seq = this.allocateSeq(jobId);
|
|
435
446
|
const cancelMsg = {
|
|
436
447
|
seq,
|
|
@@ -440,11 +451,11 @@ var MemoryJobStore = class {
|
|
|
440
451
|
content: { reason }
|
|
441
452
|
};
|
|
442
453
|
this.messagesFor(jobId).push({ message: cancelMsg, status: "verified" });
|
|
443
|
-
record.endedBy = expectedActivityBefore === null ||
|
|
454
|
+
record.endedBy = expectedActivityBefore === null || terminalStatus === "cancelled" ? "caller" : "provider";
|
|
444
455
|
applyTiming(record, structuredClone(record), Date.now(), terminalStatus);
|
|
445
456
|
record.status = terminalStatus;
|
|
446
457
|
record.summary = record.summary ?? reason;
|
|
447
|
-
record.messages = [...
|
|
458
|
+
record.messages = [...terminalMessages, cancelMsg];
|
|
448
459
|
record.seq = seq;
|
|
449
460
|
record.lastActivityAt = Date.now();
|
|
450
461
|
this.notify(jobId, cancelMsg);
|