@workerdeck/queue 2.10.0 → 2.12.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.
- package/build/index.mjs +8 -2
- package/build/index.mjs.map +1 -1
- package/package.json +3 -3
package/build/index.mjs
CHANGED
|
@@ -59,6 +59,10 @@ var InMemoryQueueAdapter = class {
|
|
|
59
59
|
function dayKey(epochMs) {
|
|
60
60
|
return new Date(epochMs).toISOString().slice(0, 10);
|
|
61
61
|
}
|
|
62
|
+
function addOptionalCost(prior, attempt) {
|
|
63
|
+
if (prior === void 0 && attempt === void 0) return;
|
|
64
|
+
return (prior ?? 0) + (attempt ?? 0);
|
|
65
|
+
}
|
|
62
66
|
function sumUsage(usage) {
|
|
63
67
|
if (typeof usage !== "object" || usage === null) return 0;
|
|
64
68
|
const u = usage;
|
|
@@ -405,7 +409,8 @@ var JobQueue = class {
|
|
|
405
409
|
usage: {
|
|
406
410
|
tokens,
|
|
407
411
|
totalCostUsd: event.totalCostUsd,
|
|
408
|
-
numTurns: event.numTurns
|
|
412
|
+
numTurns: event.numTurns,
|
|
413
|
+
costUsd: event.costUsd
|
|
409
414
|
},
|
|
410
415
|
result: {
|
|
411
416
|
subtype: event.subtype,
|
|
@@ -459,7 +464,8 @@ var JobQueue = class {
|
|
|
459
464
|
const usage = {
|
|
460
465
|
tokens: prior.tokens + attemptUsage.tokens,
|
|
461
466
|
totalCostUsd: prior.totalCostUsd + attemptUsage.totalCostUsd,
|
|
462
|
-
numTurns: prior.numTurns + attemptUsage.numTurns
|
|
467
|
+
numTurns: prior.numTurns + attemptUsage.numTurns,
|
|
468
|
+
costUsd: addOptionalCost(prior.costUsd, attemptUsage.costUsd)
|
|
463
469
|
};
|
|
464
470
|
const attempt = job.record.info.attempt ?? 1;
|
|
465
471
|
const maxAttempts = job.record.request.attempts ?? 1;
|
package/build/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/adapter.ts","../src/queue.ts"],"sourcesContent":["import type { CreateJobRequest, JobInfo } from '@workerdeck/protocol'\n\nexport type JobRecord = {\n info: JobInfo\n request: CreateJobRequest\n}\n\nexport interface QueueAdapter {\n add(job: JobRecord): Promise<void>\n claimNext(): Promise<JobRecord | null>\n get(id: string): Promise<JobRecord | null>\n list(): Promise<JobRecord[]>\n update(id: string, patch: Partial<JobInfo>): Promise<JobRecord | null>\n prune(olderThanMs: number): Promise<number>\n addDailyTokens(dayKey: string, tokens: number): Promise<number>\n dailyTokens(dayKey: string): Promise<number>\n onWork?(listener: () => void): () => void\n}\n\nexport class InMemoryQueueAdapter implements QueueAdapter {\n #jobs = new Map<string, JobRecord>()\n #dailyTokens = new Map<string, number>()\n\n add(job: JobRecord): Promise<void> {\n this.#jobs.set(job.info.id, job)\n return Promise.resolve()\n }\n\n claimNext(): Promise<JobRecord | null> {\n const now = Date.now()\n for (const job of this.#jobs.values()) {\n if (job.info.status === 'queued' && (job.info.nextRunAt === undefined || job.info.nextRunAt <= now)) {\n job.info = { ...job.info, status: 'running' }\n return Promise.resolve(job)\n }\n }\n return Promise.resolve(null)\n }\n\n get(id: string): Promise<JobRecord | null> {\n return Promise.resolve(this.#jobs.get(id) ?? null)\n }\n\n list(): Promise<JobRecord[]> {\n return Promise.resolve([...this.#jobs.values()])\n }\n\n update(id: string, patch: Partial<JobInfo>): Promise<JobRecord | null> {\n const job = this.#jobs.get(id)\n if (!job) {\n return Promise.resolve(null)\n }\n job.info = { ...job.info, ...patch }\n return Promise.resolve(job)\n }\n\n prune(olderThanMs: number): Promise<number> {\n const cutoff = Date.now() - olderThanMs\n let removed = 0\n for (const [id, job] of this.#jobs) {\n const { status, finishedAt } = job.info\n const terminal = status === 'succeeded' || status === 'failed' || status === 'canceled'\n if (terminal && (finishedAt ?? 0) <= cutoff) {\n this.#jobs.delete(id)\n removed++\n }\n }\n return Promise.resolve(removed)\n }\n\n addDailyTokens(dayKey: string, tokens: number): Promise<number> {\n const next = (this.#dailyTokens.get(dayKey) ?? 0) + tokens\n this.#dailyTokens.set(dayKey, next)\n return Promise.resolve(next)\n }\n\n dailyTokens(dayKey: string): Promise<number> {\n return Promise.resolve(this.#dailyTokens.get(dayKey) ?? 0)\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { Runner, SessionRunnerConfig } from '@workerdeck/core'\nimport type {\n ApiMessage,\n CreateJobRequest,\n CreateSessionRequest,\n JobEvent,\n JobInfo,\n JobProgress,\n QueueStats,\n SessionEvent,\n} from '@workerdeck/protocol'\nimport { InMemoryQueueAdapter, type JobRecord, type QueueAdapter } from './adapter.ts'\n\nexport type JobQueueOptions = {\n createRunner: (config: SessionRunnerConfig) => Runner | Promise<Runner>\n adapter?: QueueAdapter\n maxConcurrency?: number\n sessionTokenLimit?: number\n dailyTokenLimit?: number\n maxJobDurationMs?: number\n maxParkedDurationMs?: number\n killGraceMs?: number\n retention?: { maxAgeMs: number; sweepIntervalMs?: number }\n buildRunnerConfig?: (req: CreateSessionRequest) => SessionRunnerConfig\n discardSession?: (sessionId: string) => void | Promise<void>\n fetchImpl?: typeof fetch\n webhookAttempts?: number\n webhookRetryDelayMs?: number\n onEvent?: (event: JobEvent) => void\n}\n\ntype RunningJob = {\n record: JobRecord\n runner: Runner\n unsubscribe: () => void\n lastSeq: number\n estimatedTokens: number\n killReason?: string\n canceled: boolean\n finalized: boolean\n deliveries: Promise<void>\n durationTimer?: ReturnType<typeof setTimeout>\n forceTimer?: ReturnType<typeof setTimeout>\n runningMs: number\n legStartedAt: number\n parkedAt?: number\n parkedExecutionId?: string\n parkTimer?: ReturnType<typeof setTimeout>\n parkedMs: number\n}\n\nfunction dayKey(epochMs: number): string {\n return new Date(epochMs).toISOString().slice(0, 10)\n}\n\nfunction sumUsage(usage: unknown): number {\n if (typeof usage !== 'object' || usage === null) {\n return 0\n }\n const u = usage as Record<string, unknown>\n return (\n (typeof u.input_tokens === 'number' ? u.input_tokens : 0) +\n (typeof u.output_tokens === 'number' ? u.output_tokens : 0) +\n (typeof u.cache_creation_input_tokens === 'number' ? u.cache_creation_input_tokens : 0) +\n (typeof u.cache_read_input_tokens === 'number' ? u.cache_read_input_tokens : 0)\n )\n}\n\nfunction textPreview(message: ApiMessage, max = 140): JobProgress | null {\n const blocks = typeof message.content === 'string' ? [{ type: 'text', text: message.content }] : message.content\n for (const block of blocks) {\n if (block.type === 'tool_use') {\n return { kind: 'tool_use', preview: (block as { name?: string }).name }\n }\n if (block.type === 'text') {\n const text = (block as { text?: string }).text ?? ''\n if (text.trim()) {\n return {\n kind: 'assistant_text',\n preview: text.length > max ? text.slice(0, max - 1) + '…' : text,\n }\n }\n }\n }\n return null\n}\n\nexport class JobQueue {\n #options: JobQueueOptions\n #adapter: QueueAdapter\n #running = new Map<string, RunningJob>()\n #parked = new Map<string, RunningJob>()\n #pumping = false\n #closed = false\n #offWork: (() => void) | undefined\n #sweepTimer: ReturnType<typeof setInterval> | undefined\n #retryTimers = new Set<ReturnType<typeof setTimeout>>()\n\n constructor(options: JobQueueOptions) {\n this.#options = options\n this.#adapter = options.adapter ?? new InMemoryQueueAdapter()\n this.#offWork = this.#adapter.onWork?.(() => void this.#pump())\n const retention = options.retention\n if (retention) {\n const interval = retention.sweepIntervalMs ?? Math.min(retention.maxAgeMs, 60_000)\n this.#sweepTimer = setInterval(() => this.#sweep(), interval)\n this.#sweepTimer.unref?.()\n }\n }\n\n async submit(request: CreateJobRequest): Promise<JobInfo> {\n if (this.#closed) {\n throw new Error('queue is closed')\n }\n if (!request.session?.prompt?.trim()) {\n throw new Error('session.prompt is required')\n }\n if (request.session.resume || request.session.forkSession) {\n throw new Error('resume/forkSession are not supported for queued jobs')\n }\n const attempts = request.attempts ?? 1\n if (!Number.isInteger(attempts) || attempts < 1) {\n throw new Error('attempts must be a positive integer')\n }\n if (request.retryDelayMs !== undefined && !(request.retryDelayMs >= 0)) {\n throw new Error('retryDelayMs must be >= 0')\n }\n const info: JobInfo = {\n id: randomUUID(),\n status: 'queued',\n cwd: request.session.cwd ?? '',\n profile: request.session.profile,\n prompt: request.session.prompt,\n createdAt: Date.now(),\n attempt: 1,\n maxAttempts: attempts,\n usage: { tokens: 0, totalCostUsd: 0, numTurns: 0 },\n meta: request.meta,\n scope: request.session.scope,\n }\n const record: JobRecord = { info, request }\n await this.#adapter.add(record)\n this.#emit(record, { type: 'job_submitted', job: info, ts: Date.now() }, undefined, {\n skipWebhook: true,\n })\n void this.#pump()\n return info\n }\n\n async get(id: string): Promise<JobInfo | null> {\n return (await this.#adapter.get(id))?.info ?? null\n }\n\n async list(): Promise<JobInfo[]> {\n return (await this.#adapter.list()).map((j) => j.info)\n }\n\n onSessionParking(sessionId: string, executionId: string): boolean {\n const job = this.#bySession(this.#running, sessionId)\n if (!job) {\n return true\n }\n if (job.finalized || job.killReason) {\n return false\n }\n const now = Date.now()\n job.unsubscribe()\n job.runningMs += now - job.legStartedAt\n clearTimeout(job.durationTimer)\n job.durationTimer = undefined\n job.parkedAt = now\n job.parkedExecutionId = executionId\n this.#running.delete(job.record.info.id)\n this.#parked.set(job.record.info.id, job)\n const parkedLimit = this.#options.maxParkedDurationMs\n if (parkedLimit !== undefined) {\n job.parkTimer = setTimeout(\n () => this.#kill(job, `job exceeded max parked duration (${parkedLimit}ms)`),\n Math.max(0, parkedLimit - job.parkedMs),\n )\n job.parkTimer.unref?.()\n }\n void this.#recordPark(job, executionId)\n return true\n }\n\n async #recordPark(job: RunningJob, executionId: string): Promise<void> {\n const updated = await this.#adapter.update(job.record.info.id, {\n status: 'parked',\n parkedAt: job.parkedAt,\n parkedExecutionId: executionId,\n })\n if (updated) {\n job.record = updated\n }\n this.#emit(job.record, { type: 'job_parked', job: job.record.info, executionId, ts: Date.now() }, job)\n void this.#pump()\n }\n\n onSessionResumed(sessionId: string, runner: Runner): void {\n const job = this.#bySession(this.#parked, sessionId)\n if (!job || job.finalized) {\n return\n }\n const now = Date.now()\n const executionId = job.parkedExecutionId ?? ''\n clearTimeout(job.parkTimer)\n job.parkTimer = undefined\n job.parkedMs += now - (job.parkedAt ?? now)\n job.parkedAt = undefined\n job.parkedExecutionId = undefined\n job.legStartedAt = now\n job.runner = runner\n this.#parked.delete(job.record.info.id)\n this.#running.set(job.record.info.id, job)\n const durationLimit = this.#effectiveDurationLimit(job.record.request)\n if (durationLimit !== undefined) {\n job.durationTimer = setTimeout(\n () => this.#kill(job, `job exceeded max duration (${durationLimit}ms)`),\n Math.max(0, durationLimit - job.runningMs),\n )\n job.durationTimer.unref?.()\n }\n job.unsubscribe = runner.subscribe((event) => void this.#handleEvent(job, event), job.lastSeq)\n void this.#recordResume(job, executionId)\n }\n\n async #recordResume(job: RunningJob, executionId: string): Promise<void> {\n const updated = await this.#adapter.update(job.record.info.id, {\n status: 'running',\n parkedAt: undefined,\n parkedExecutionId: undefined,\n })\n if (updated) {\n job.record = updated\n }\n this.#emit(job.record, { type: 'job_resumed', job: job.record.info, executionId, ts: Date.now() }, job)\n }\n\n #bySession(jobs: Map<string, RunningJob>, sessionId: string): RunningJob | undefined {\n for (const job of jobs.values()) {\n if (job.record.info.sessionId === sessionId) {\n return job\n }\n }\n return undefined\n }\n\n async cancel(id: string): Promise<JobInfo | null> {\n const record = await this.#adapter.get(id)\n if (!record) {\n return null\n }\n const running = this.#running.get(id) ?? this.#parked.get(id)\n if (running) {\n running.canceled = true\n running.killReason = 'canceled'\n await this.#finalize(running, this.#abortPatch(running, 'canceled'))\n return running.record.info\n }\n if (record.info.status !== 'queued') {\n return record.info\n }\n const updated = await this.#adapter.update(id, {\n status: 'canceled',\n finishedAt: Date.now(),\n error: 'canceled',\n })\n if (updated) {\n this.#emit(updated, { type: 'job_completed', job: updated.info, ts: Date.now() })\n }\n return updated?.info ?? null\n }\n\n async stats(): Promise<QueueStats> {\n const jobs = await this.#adapter.list()\n const dailyTokensUsed = await this.#adapter.dailyTokens(dayKey(Date.now()))\n const dailyTokenLimit = this.#options.dailyTokenLimit\n return {\n maxConcurrency: this.#options.maxConcurrency ?? 1,\n running: this.#running.size,\n parked: this.#parked.size,\n queued: jobs.filter((j) => j.info.status === 'queued').length,\n sessionTokenLimit: this.#options.sessionTokenLimit,\n dailyTokenLimit,\n dailyTokensUsed,\n paused: dailyTokenLimit !== undefined && dailyTokensUsed >= dailyTokenLimit,\n }\n }\n\n close(): void {\n this.#closed = true\n this.#offWork?.()\n clearInterval(this.#sweepTimer)\n for (const timer of this.#retryTimers) {\n clearTimeout(timer)\n }\n this.#retryTimers.clear()\n }\n\n #sweep(): void {\n const retention = this.#options.retention\n if (!retention) {\n return\n }\n this.#adapter.prune(retention.maxAgeMs).catch(() => {})\n }\n\n async #pump(): Promise<void> {\n if (this.#pumping || this.#closed) {\n return\n }\n this.#pumping = true\n try {\n const maxConcurrency = this.#options.maxConcurrency ?? 1\n while (this.#running.size < maxConcurrency) {\n const limit = this.#options.dailyTokenLimit\n if (limit !== undefined && (await this.#adapter.dailyTokens(dayKey(Date.now()))) >= limit) {\n return\n }\n const record = await this.#adapter.claimNext()\n if (!record) {\n return\n }\n await this.#start(record)\n }\n } finally {\n this.#pumping = false\n }\n }\n\n async #start(record: JobRecord): Promise<void> {\n const id = record.info.id\n const build = this.#options.buildRunnerConfig ?? ((req: CreateSessionRequest) => req)\n let runner: Runner\n try {\n const request: CreateSessionRequest = {\n ...record.request.session,\n meta: { ...record.request.session.meta, jobId: id },\n }\n runner = await this.#options.createRunner(build(request))\n } catch (error) {\n const failed = await this.#adapter.update(id, {\n status: 'failed',\n finishedAt: Date.now(),\n error: error instanceof Error ? error.message : String(error),\n })\n if (failed) {\n this.#emit(failed, { type: 'job_completed', job: failed.info, ts: Date.now() })\n }\n return\n }\n const job: RunningJob = {\n record,\n runner,\n unsubscribe: () => {},\n lastSeq: 0,\n estimatedTokens: 0,\n canceled: false,\n finalized: false,\n deliveries: Promise.resolve(),\n runningMs: 0,\n legStartedAt: Date.now(),\n parkedMs: 0,\n }\n this.#running.set(id, job)\n const updated = await this.#adapter.update(id, {\n startedAt: Date.now(),\n sessionId: runner.id,\n })\n if (updated) {\n job.record = updated\n }\n this.#emit(job.record, { type: 'job_started', job: job.record.info, ts: Date.now() })\n const durationLimit = this.#effectiveDurationLimit(record.request)\n if (durationLimit !== undefined) {\n job.durationTimer = setTimeout(() => this.#kill(job, `job exceeded max duration (${durationLimit}ms)`), durationLimit)\n job.durationTimer.unref?.()\n }\n job.unsubscribe = runner.subscribe((event) => void this.#handleEvent(job, event))\n }\n\n // How a run that never produced a `turn_result` is written down. There is no authoritative\n // usage for such a run, so it reports the tokens counted from the message stream, no cost\n // and no turns. `turn_result` is the one path that does NOT come through here - it has real\n // numbers - which is exactly the distinction five inline copies of this used to hide.\n #abortPatch(job: RunningJob, error: string): Partial<JobInfo> {\n return {\n usage: { tokens: job.estimatedTokens, totalCostUsd: 0, numTurns: 0 },\n status: job.canceled ? 'canceled' : 'failed',\n error,\n }\n }\n\n #kill(job: RunningJob, reason: string): void {\n if (job.finalized || job.killReason) {\n return\n }\n job.killReason = reason\n if (job.parkedAt !== undefined) {\n void this.#finalize(job, this.#abortPatch(job, reason))\n return\n }\n void job.runner.interrupt().catch(() => {})\n job.forceTimer = setTimeout(() => {\n void this.#finalize(job, this.#abortPatch(job, reason))\n }, this.#options.killGraceMs ?? 5000)\n job.forceTimer.unref?.()\n }\n\n async #handleEvent(job: RunningJob, event: SessionEvent): Promise<void> {\n if (job.finalized) {\n return\n }\n job.lastSeq = Math.max(job.lastSeq, event.seq)\n switch (event.type) {\n case 'system_init': {\n await this.#adapter.update(job.record.info.id, { sdkSessionId: event.sdkSessionId })\n return\n }\n case 'assistant_message': {\n if (event.replay) {\n return\n }\n job.estimatedTokens += sumUsage(event.message.usage)\n const limit = this.#effectiveTokenLimit(job.record.request)\n if (limit !== undefined && job.estimatedTokens > limit) {\n this.#kill(job, `session token limit exceeded (${job.estimatedTokens} > ${limit})`)\n }\n const progress = textPreview(event.message)\n if (progress) {\n this.#progress(job, progress)\n }\n return\n }\n case 'permission_requested': {\n this.#progress(job, {\n kind: 'permission_requested',\n preview: event.request.title ?? event.request.toolName,\n request: event.request,\n })\n return\n }\n case 'permission_resolved': {\n this.#progress(job, { kind: 'permission_resolved', preview: event.behavior })\n return\n }\n case 'turn_result': {\n const tokens = sumUsage(event.usage) || job.estimatedTokens\n await this.#finalize(job, {\n usage: {\n tokens,\n totalCostUsd: event.totalCostUsd,\n numTurns: event.numTurns,\n },\n result: {\n subtype: event.subtype,\n isError: event.isError,\n result: event.result,\n errors: event.errors,\n durationMs: event.durationMs,\n },\n status: job.killReason ? (job.canceled ? 'canceled' : 'failed') : event.isError ? 'failed' : 'succeeded',\n error: job.killReason ?? (event.isError ? event.errors?.join('; ') || event.subtype : undefined),\n })\n return\n }\n case 'session_error': {\n await this.#finalize(job, this.#abortPatch(job, job.killReason ?? event.message))\n return\n }\n case 'session_closed': {\n await this.#finalize(job, this.#abortPatch(job, job.killReason ?? 'session closed before completing'))\n return\n }\n default: {\n return\n }\n }\n }\n\n #effectiveTokenLimit(request: CreateJobRequest): number | undefined {\n const limits = [request.maxTokens, this.#options.sessionTokenLimit].filter((n): n is number => typeof n === 'number')\n return limits.length > 0 ? Math.min(...limits) : undefined\n }\n\n #effectiveDurationLimit(request: CreateJobRequest): number | undefined {\n const limits = [request.maxDurationMs, this.#options.maxJobDurationMs].filter((n): n is number => typeof n === 'number')\n return limits.length > 0 ? Math.min(...limits) : undefined\n }\n\n async #finalize(job: RunningJob, patch: Partial<JobInfo>): Promise<void> {\n if (job.finalized) {\n return\n }\n job.finalized = true\n job.unsubscribe()\n clearTimeout(job.durationTimer)\n clearTimeout(job.forceTimer)\n clearTimeout(job.parkTimer)\n this.#running.delete(job.record.info.id)\n const wasParked = this.#parked.delete(job.record.info.id)\n job.runner.close('server')\n if (wasParked && job.record.info.sessionId) {\n try {\n void Promise.resolve(this.#options.discardSession?.(job.record.info.sessionId)).catch(() => {})\n } catch {}\n }\n const attemptUsage = patch.usage ?? { tokens: 0, totalCostUsd: 0, numTurns: 0 }\n if (attemptUsage.tokens > 0) {\n await this.#adapter.addDailyTokens(dayKey(Date.now()), attemptUsage.tokens)\n }\n const prior = job.record.info.usage\n const usage = {\n tokens: prior.tokens + attemptUsage.tokens,\n totalCostUsd: prior.totalCostUsd + attemptUsage.totalCostUsd,\n numTurns: prior.numTurns + attemptUsage.numTurns,\n }\n const attempt = job.record.info.attempt ?? 1\n const maxAttempts = job.record.request.attempts ?? 1\n if (patch.status === 'failed' && attempt < maxAttempts && !this.#closed) {\n const baseDelay = job.record.request.retryDelayMs ?? 5000\n const delay = baseDelay * 2 ** (attempt - 1)\n const updated = await this.#adapter.update(job.record.info.id, {\n status: 'queued',\n attempt: attempt + 1,\n nextRunAt: Date.now() + delay,\n error: patch.error,\n usage,\n sessionId: undefined,\n sdkSessionId: undefined,\n startedAt: undefined,\n result: undefined,\n })\n if (updated) {\n job.record = updated\n this.#emit(updated, { type: 'job_retrying', job: updated.info, ts: Date.now() }, job)\n const timer = setTimeout(() => {\n this.#retryTimers.delete(timer)\n void this.#pump()\n }, delay)\n timer.unref?.()\n this.#retryTimers.add(timer)\n }\n void this.#pump()\n return\n }\n const updated = await this.#adapter.update(job.record.info.id, {\n ...patch,\n usage,\n nextRunAt: undefined,\n finishedAt: Date.now(),\n })\n if (updated) {\n job.record = updated\n this.#emit(job.record, { type: 'job_completed', job: updated.info, ts: Date.now() }, job)\n }\n this.#sweep()\n void this.#pump()\n }\n\n #progress(job: RunningJob, progress: JobProgress): void {\n const event: JobEvent = { type: 'job_progress', job: job.record.info, progress, ts: Date.now() }\n if (job.record.request.webhook?.progress === 'completion') {\n try {\n this.#options.onEvent?.(event)\n } catch {}\n return\n }\n this.#emit(job.record, event, job)\n }\n\n #emit(record: JobRecord, event: JobEvent, chainOwner?: RunningJob, { skipWebhook = false }: { skipWebhook?: boolean } = {}): void {\n try {\n this.#options.onEvent?.(event)\n } catch {}\n const webhook = record.request.webhook\n if (!webhook || skipWebhook) {\n return\n }\n const running = chainOwner ?? this.#running.get(record.info.id)\n const deliver = () => this.#deliver(webhook.url, webhook.headers, event)\n if (running) {\n running.deliveries = running.deliveries.then(deliver)\n } else {\n void deliver()\n }\n }\n\n async #deliver(url: string, headers: Record<string, string> | undefined, event: JobEvent): Promise<void> {\n const fetchImpl = this.#options.fetchImpl ?? fetch\n const attempts = this.#options.webhookAttempts ?? 3\n const baseDelay = this.#options.webhookRetryDelayMs ?? 500\n for (let attempt = 0; attempt < attempts; attempt++) {\n try {\n const res = await fetchImpl(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...headers },\n body: JSON.stringify(event),\n })\n if (res.ok) {\n return\n }\n } catch {}\n if (attempt < attempts - 1) {\n await new Promise((resolve) => setTimeout(resolve, baseDelay * 2 ** attempt))\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/adapter.ts","../src/queue.ts"],"sourcesContent":["import type { CreateJobRequest, JobInfo } from '@workerdeck/protocol'\n\nexport type JobRecord = {\n info: JobInfo\n request: CreateJobRequest\n}\n\nexport interface QueueAdapter {\n add(job: JobRecord): Promise<void>\n claimNext(): Promise<JobRecord | null>\n get(id: string): Promise<JobRecord | null>\n list(): Promise<JobRecord[]>\n update(id: string, patch: Partial<JobInfo>): Promise<JobRecord | null>\n prune(olderThanMs: number): Promise<number>\n addDailyTokens(dayKey: string, tokens: number): Promise<number>\n dailyTokens(dayKey: string): Promise<number>\n onWork?(listener: () => void): () => void\n}\n\nexport class InMemoryQueueAdapter implements QueueAdapter {\n #jobs = new Map<string, JobRecord>()\n #dailyTokens = new Map<string, number>()\n\n add(job: JobRecord): Promise<void> {\n this.#jobs.set(job.info.id, job)\n return Promise.resolve()\n }\n\n claimNext(): Promise<JobRecord | null> {\n const now = Date.now()\n for (const job of this.#jobs.values()) {\n if (job.info.status === 'queued' && (job.info.nextRunAt === undefined || job.info.nextRunAt <= now)) {\n job.info = { ...job.info, status: 'running' }\n return Promise.resolve(job)\n }\n }\n return Promise.resolve(null)\n }\n\n get(id: string): Promise<JobRecord | null> {\n return Promise.resolve(this.#jobs.get(id) ?? null)\n }\n\n list(): Promise<JobRecord[]> {\n return Promise.resolve([...this.#jobs.values()])\n }\n\n update(id: string, patch: Partial<JobInfo>): Promise<JobRecord | null> {\n const job = this.#jobs.get(id)\n if (!job) {\n return Promise.resolve(null)\n }\n job.info = { ...job.info, ...patch }\n return Promise.resolve(job)\n }\n\n prune(olderThanMs: number): Promise<number> {\n const cutoff = Date.now() - olderThanMs\n let removed = 0\n for (const [id, job] of this.#jobs) {\n const { status, finishedAt } = job.info\n const terminal = status === 'succeeded' || status === 'failed' || status === 'canceled'\n if (terminal && (finishedAt ?? 0) <= cutoff) {\n this.#jobs.delete(id)\n removed++\n }\n }\n return Promise.resolve(removed)\n }\n\n addDailyTokens(dayKey: string, tokens: number): Promise<number> {\n const next = (this.#dailyTokens.get(dayKey) ?? 0) + tokens\n this.#dailyTokens.set(dayKey, next)\n return Promise.resolve(next)\n }\n\n dailyTokens(dayKey: string): Promise<number> {\n return Promise.resolve(this.#dailyTokens.get(dayKey) ?? 0)\n }\n}\n","import { randomUUID } from 'node:crypto'\nimport type { Runner, SessionRunnerConfig } from '@workerdeck/core'\nimport type {\n ApiMessage,\n CreateJobRequest,\n CreateSessionRequest,\n JobEvent,\n JobInfo,\n JobProgress,\n JobUsage,\n QueueStats,\n SessionEvent,\n} from '@workerdeck/protocol'\nimport { InMemoryQueueAdapter, type JobRecord, type QueueAdapter } from './adapter.ts'\n\nexport type JobQueueOptions = {\n createRunner: (config: SessionRunnerConfig) => Runner | Promise<Runner>\n adapter?: QueueAdapter\n maxConcurrency?: number\n sessionTokenLimit?: number\n dailyTokenLimit?: number\n maxJobDurationMs?: number\n maxParkedDurationMs?: number\n killGraceMs?: number\n retention?: { maxAgeMs: number; sweepIntervalMs?: number }\n buildRunnerConfig?: (req: CreateSessionRequest) => SessionRunnerConfig\n discardSession?: (sessionId: string) => void | Promise<void>\n fetchImpl?: typeof fetch\n webhookAttempts?: number\n webhookRetryDelayMs?: number\n onEvent?: (event: JobEvent) => void\n}\n\ntype RunningJob = {\n record: JobRecord\n runner: Runner\n unsubscribe: () => void\n lastSeq: number\n estimatedTokens: number\n killReason?: string\n canceled: boolean\n finalized: boolean\n deliveries: Promise<void>\n durationTimer?: ReturnType<typeof setTimeout>\n forceTimer?: ReturnType<typeof setTimeout>\n runningMs: number\n legStartedAt: number\n parkedAt?: number\n parkedExecutionId?: string\n parkTimer?: ReturnType<typeof setTimeout>\n parkedMs: number\n}\n\nfunction dayKey(epochMs: number): string {\n return new Date(epochMs).toISOString().slice(0, 10)\n}\n\n// An attempt that reported no priced figure at all stays unknown rather than banking a zero:\n// only the claude engine reports a cost of its own, and `$0.00` is a claim.\nfunction addOptionalCost(prior: number | undefined, attempt: number | undefined): number | undefined {\n if (prior === undefined && attempt === undefined) {\n return undefined\n }\n return (prior ?? 0) + (attempt ?? 0)\n}\n\nfunction sumUsage(usage: unknown): number {\n if (typeof usage !== 'object' || usage === null) {\n return 0\n }\n const u = usage as Record<string, unknown>\n return (\n (typeof u.input_tokens === 'number' ? u.input_tokens : 0) +\n (typeof u.output_tokens === 'number' ? u.output_tokens : 0) +\n (typeof u.cache_creation_input_tokens === 'number' ? u.cache_creation_input_tokens : 0) +\n (typeof u.cache_read_input_tokens === 'number' ? u.cache_read_input_tokens : 0)\n )\n}\n\nfunction textPreview(message: ApiMessage, max = 140): JobProgress | null {\n const blocks = typeof message.content === 'string' ? [{ type: 'text', text: message.content }] : message.content\n for (const block of blocks) {\n if (block.type === 'tool_use') {\n return { kind: 'tool_use', preview: (block as { name?: string }).name }\n }\n if (block.type === 'text') {\n const text = (block as { text?: string }).text ?? ''\n if (text.trim()) {\n return {\n kind: 'assistant_text',\n preview: text.length > max ? text.slice(0, max - 1) + '…' : text,\n }\n }\n }\n }\n return null\n}\n\nexport class JobQueue {\n #options: JobQueueOptions\n #adapter: QueueAdapter\n #running = new Map<string, RunningJob>()\n #parked = new Map<string, RunningJob>()\n #pumping = false\n #closed = false\n #offWork: (() => void) | undefined\n #sweepTimer: ReturnType<typeof setInterval> | undefined\n #retryTimers = new Set<ReturnType<typeof setTimeout>>()\n\n constructor(options: JobQueueOptions) {\n this.#options = options\n this.#adapter = options.adapter ?? new InMemoryQueueAdapter()\n this.#offWork = this.#adapter.onWork?.(() => void this.#pump())\n const retention = options.retention\n if (retention) {\n const interval = retention.sweepIntervalMs ?? Math.min(retention.maxAgeMs, 60_000)\n this.#sweepTimer = setInterval(() => this.#sweep(), interval)\n this.#sweepTimer.unref?.()\n }\n }\n\n async submit(request: CreateJobRequest): Promise<JobInfo> {\n if (this.#closed) {\n throw new Error('queue is closed')\n }\n if (!request.session?.prompt?.trim()) {\n throw new Error('session.prompt is required')\n }\n if (request.session.resume || request.session.forkSession) {\n throw new Error('resume/forkSession are not supported for queued jobs')\n }\n const attempts = request.attempts ?? 1\n if (!Number.isInteger(attempts) || attempts < 1) {\n throw new Error('attempts must be a positive integer')\n }\n if (request.retryDelayMs !== undefined && !(request.retryDelayMs >= 0)) {\n throw new Error('retryDelayMs must be >= 0')\n }\n const info: JobInfo = {\n id: randomUUID(),\n status: 'queued',\n cwd: request.session.cwd ?? '',\n profile: request.session.profile,\n prompt: request.session.prompt,\n createdAt: Date.now(),\n attempt: 1,\n maxAttempts: attempts,\n usage: { tokens: 0, totalCostUsd: 0, numTurns: 0 },\n meta: request.meta,\n scope: request.session.scope,\n }\n const record: JobRecord = { info, request }\n await this.#adapter.add(record)\n this.#emit(record, { type: 'job_submitted', job: info, ts: Date.now() }, undefined, {\n skipWebhook: true,\n })\n void this.#pump()\n return info\n }\n\n async get(id: string): Promise<JobInfo | null> {\n return (await this.#adapter.get(id))?.info ?? null\n }\n\n async list(): Promise<JobInfo[]> {\n return (await this.#adapter.list()).map((j) => j.info)\n }\n\n onSessionParking(sessionId: string, executionId: string): boolean {\n const job = this.#bySession(this.#running, sessionId)\n if (!job) {\n return true\n }\n if (job.finalized || job.killReason) {\n return false\n }\n const now = Date.now()\n job.unsubscribe()\n job.runningMs += now - job.legStartedAt\n clearTimeout(job.durationTimer)\n job.durationTimer = undefined\n job.parkedAt = now\n job.parkedExecutionId = executionId\n this.#running.delete(job.record.info.id)\n this.#parked.set(job.record.info.id, job)\n const parkedLimit = this.#options.maxParkedDurationMs\n if (parkedLimit !== undefined) {\n job.parkTimer = setTimeout(\n () => this.#kill(job, `job exceeded max parked duration (${parkedLimit}ms)`),\n Math.max(0, parkedLimit - job.parkedMs),\n )\n job.parkTimer.unref?.()\n }\n void this.#recordPark(job, executionId)\n return true\n }\n\n async #recordPark(job: RunningJob, executionId: string): Promise<void> {\n const updated = await this.#adapter.update(job.record.info.id, {\n status: 'parked',\n parkedAt: job.parkedAt,\n parkedExecutionId: executionId,\n })\n if (updated) {\n job.record = updated\n }\n this.#emit(job.record, { type: 'job_parked', job: job.record.info, executionId, ts: Date.now() }, job)\n void this.#pump()\n }\n\n onSessionResumed(sessionId: string, runner: Runner): void {\n const job = this.#bySession(this.#parked, sessionId)\n if (!job || job.finalized) {\n return\n }\n const now = Date.now()\n const executionId = job.parkedExecutionId ?? ''\n clearTimeout(job.parkTimer)\n job.parkTimer = undefined\n job.parkedMs += now - (job.parkedAt ?? now)\n job.parkedAt = undefined\n job.parkedExecutionId = undefined\n job.legStartedAt = now\n job.runner = runner\n this.#parked.delete(job.record.info.id)\n this.#running.set(job.record.info.id, job)\n const durationLimit = this.#effectiveDurationLimit(job.record.request)\n if (durationLimit !== undefined) {\n job.durationTimer = setTimeout(\n () => this.#kill(job, `job exceeded max duration (${durationLimit}ms)`),\n Math.max(0, durationLimit - job.runningMs),\n )\n job.durationTimer.unref?.()\n }\n job.unsubscribe = runner.subscribe((event) => void this.#handleEvent(job, event), job.lastSeq)\n void this.#recordResume(job, executionId)\n }\n\n async #recordResume(job: RunningJob, executionId: string): Promise<void> {\n const updated = await this.#adapter.update(job.record.info.id, {\n status: 'running',\n parkedAt: undefined,\n parkedExecutionId: undefined,\n })\n if (updated) {\n job.record = updated\n }\n this.#emit(job.record, { type: 'job_resumed', job: job.record.info, executionId, ts: Date.now() }, job)\n }\n\n #bySession(jobs: Map<string, RunningJob>, sessionId: string): RunningJob | undefined {\n for (const job of jobs.values()) {\n if (job.record.info.sessionId === sessionId) {\n return job\n }\n }\n return undefined\n }\n\n async cancel(id: string): Promise<JobInfo | null> {\n const record = await this.#adapter.get(id)\n if (!record) {\n return null\n }\n const running = this.#running.get(id) ?? this.#parked.get(id)\n if (running) {\n running.canceled = true\n running.killReason = 'canceled'\n await this.#finalize(running, this.#abortPatch(running, 'canceled'))\n return running.record.info\n }\n if (record.info.status !== 'queued') {\n return record.info\n }\n const updated = await this.#adapter.update(id, {\n status: 'canceled',\n finishedAt: Date.now(),\n error: 'canceled',\n })\n if (updated) {\n this.#emit(updated, { type: 'job_completed', job: updated.info, ts: Date.now() })\n }\n return updated?.info ?? null\n }\n\n async stats(): Promise<QueueStats> {\n const jobs = await this.#adapter.list()\n const dailyTokensUsed = await this.#adapter.dailyTokens(dayKey(Date.now()))\n const dailyTokenLimit = this.#options.dailyTokenLimit\n return {\n maxConcurrency: this.#options.maxConcurrency ?? 1,\n running: this.#running.size,\n parked: this.#parked.size,\n queued: jobs.filter((j) => j.info.status === 'queued').length,\n sessionTokenLimit: this.#options.sessionTokenLimit,\n dailyTokenLimit,\n dailyTokensUsed,\n paused: dailyTokenLimit !== undefined && dailyTokensUsed >= dailyTokenLimit,\n }\n }\n\n close(): void {\n this.#closed = true\n this.#offWork?.()\n clearInterval(this.#sweepTimer)\n for (const timer of this.#retryTimers) {\n clearTimeout(timer)\n }\n this.#retryTimers.clear()\n }\n\n #sweep(): void {\n const retention = this.#options.retention\n if (!retention) {\n return\n }\n this.#adapter.prune(retention.maxAgeMs).catch(() => {})\n }\n\n async #pump(): Promise<void> {\n if (this.#pumping || this.#closed) {\n return\n }\n this.#pumping = true\n try {\n const maxConcurrency = this.#options.maxConcurrency ?? 1\n while (this.#running.size < maxConcurrency) {\n const limit = this.#options.dailyTokenLimit\n if (limit !== undefined && (await this.#adapter.dailyTokens(dayKey(Date.now()))) >= limit) {\n return\n }\n const record = await this.#adapter.claimNext()\n if (!record) {\n return\n }\n await this.#start(record)\n }\n } finally {\n this.#pumping = false\n }\n }\n\n async #start(record: JobRecord): Promise<void> {\n const id = record.info.id\n const build = this.#options.buildRunnerConfig ?? ((req: CreateSessionRequest) => req)\n let runner: Runner\n try {\n const request: CreateSessionRequest = {\n ...record.request.session,\n meta: { ...record.request.session.meta, jobId: id },\n }\n runner = await this.#options.createRunner(build(request))\n } catch (error) {\n const failed = await this.#adapter.update(id, {\n status: 'failed',\n finishedAt: Date.now(),\n error: error instanceof Error ? error.message : String(error),\n })\n if (failed) {\n this.#emit(failed, { type: 'job_completed', job: failed.info, ts: Date.now() })\n }\n return\n }\n const job: RunningJob = {\n record,\n runner,\n unsubscribe: () => {},\n lastSeq: 0,\n estimatedTokens: 0,\n canceled: false,\n finalized: false,\n deliveries: Promise.resolve(),\n runningMs: 0,\n legStartedAt: Date.now(),\n parkedMs: 0,\n }\n this.#running.set(id, job)\n const updated = await this.#adapter.update(id, {\n startedAt: Date.now(),\n sessionId: runner.id,\n })\n if (updated) {\n job.record = updated\n }\n this.#emit(job.record, { type: 'job_started', job: job.record.info, ts: Date.now() })\n const durationLimit = this.#effectiveDurationLimit(record.request)\n if (durationLimit !== undefined) {\n job.durationTimer = setTimeout(() => this.#kill(job, `job exceeded max duration (${durationLimit}ms)`), durationLimit)\n job.durationTimer.unref?.()\n }\n job.unsubscribe = runner.subscribe((event) => void this.#handleEvent(job, event))\n }\n\n // How a run that never produced a `turn_result` is written down. There is no authoritative\n // usage for such a run, so it reports the tokens counted from the message stream, no cost\n // and no turns. `turn_result` is the one path that does NOT come through here - it has real\n // numbers - which is exactly the distinction five inline copies of this used to hide.\n #abortPatch(job: RunningJob, error: string): Partial<JobInfo> {\n return {\n usage: { tokens: job.estimatedTokens, totalCostUsd: 0, numTurns: 0 },\n status: job.canceled ? 'canceled' : 'failed',\n error,\n }\n }\n\n #kill(job: RunningJob, reason: string): void {\n if (job.finalized || job.killReason) {\n return\n }\n job.killReason = reason\n if (job.parkedAt !== undefined) {\n void this.#finalize(job, this.#abortPatch(job, reason))\n return\n }\n void job.runner.interrupt().catch(() => {})\n job.forceTimer = setTimeout(() => {\n void this.#finalize(job, this.#abortPatch(job, reason))\n }, this.#options.killGraceMs ?? 5000)\n job.forceTimer.unref?.()\n }\n\n async #handleEvent(job: RunningJob, event: SessionEvent): Promise<void> {\n if (job.finalized) {\n return\n }\n job.lastSeq = Math.max(job.lastSeq, event.seq)\n switch (event.type) {\n case 'system_init': {\n await this.#adapter.update(job.record.info.id, { sdkSessionId: event.sdkSessionId })\n return\n }\n case 'assistant_message': {\n if (event.replay) {\n return\n }\n job.estimatedTokens += sumUsage(event.message.usage)\n const limit = this.#effectiveTokenLimit(job.record.request)\n if (limit !== undefined && job.estimatedTokens > limit) {\n this.#kill(job, `session token limit exceeded (${job.estimatedTokens} > ${limit})`)\n }\n const progress = textPreview(event.message)\n if (progress) {\n this.#progress(job, progress)\n }\n return\n }\n case 'permission_requested': {\n this.#progress(job, {\n kind: 'permission_requested',\n preview: event.request.title ?? event.request.toolName,\n request: event.request,\n })\n return\n }\n case 'permission_resolved': {\n this.#progress(job, { kind: 'permission_resolved', preview: event.behavior })\n return\n }\n case 'turn_result': {\n const tokens = sumUsage(event.usage) || job.estimatedTokens\n await this.#finalize(job, {\n usage: {\n tokens,\n totalCostUsd: event.totalCostUsd,\n numTurns: event.numTurns,\n costUsd: event.costUsd,\n },\n result: {\n subtype: event.subtype,\n isError: event.isError,\n result: event.result,\n errors: event.errors,\n durationMs: event.durationMs,\n },\n status: job.killReason ? (job.canceled ? 'canceled' : 'failed') : event.isError ? 'failed' : 'succeeded',\n error: job.killReason ?? (event.isError ? event.errors?.join('; ') || event.subtype : undefined),\n })\n return\n }\n case 'session_error': {\n await this.#finalize(job, this.#abortPatch(job, job.killReason ?? event.message))\n return\n }\n case 'session_closed': {\n await this.#finalize(job, this.#abortPatch(job, job.killReason ?? 'session closed before completing'))\n return\n }\n default: {\n return\n }\n }\n }\n\n #effectiveTokenLimit(request: CreateJobRequest): number | undefined {\n const limits = [request.maxTokens, this.#options.sessionTokenLimit].filter((n): n is number => typeof n === 'number')\n return limits.length > 0 ? Math.min(...limits) : undefined\n }\n\n #effectiveDurationLimit(request: CreateJobRequest): number | undefined {\n const limits = [request.maxDurationMs, this.#options.maxJobDurationMs].filter((n): n is number => typeof n === 'number')\n return limits.length > 0 ? Math.min(...limits) : undefined\n }\n\n async #finalize(job: RunningJob, patch: Partial<JobInfo>): Promise<void> {\n if (job.finalized) {\n return\n }\n job.finalized = true\n job.unsubscribe()\n clearTimeout(job.durationTimer)\n clearTimeout(job.forceTimer)\n clearTimeout(job.parkTimer)\n this.#running.delete(job.record.info.id)\n const wasParked = this.#parked.delete(job.record.info.id)\n job.runner.close('server')\n if (wasParked && job.record.info.sessionId) {\n try {\n void Promise.resolve(this.#options.discardSession?.(job.record.info.sessionId)).catch(() => {})\n } catch {}\n }\n const attemptUsage = patch.usage ?? { tokens: 0, totalCostUsd: 0, numTurns: 0 }\n if (attemptUsage.tokens > 0) {\n await this.#adapter.addDailyTokens(dayKey(Date.now()), attemptUsage.tokens)\n }\n const prior = job.record.info.usage\n const usage: JobUsage = {\n tokens: prior.tokens + attemptUsage.tokens,\n totalCostUsd: prior.totalCostUsd + attemptUsage.totalCostUsd,\n numTurns: prior.numTurns + attemptUsage.numTurns,\n costUsd: addOptionalCost(prior.costUsd, attemptUsage.costUsd),\n }\n const attempt = job.record.info.attempt ?? 1\n const maxAttempts = job.record.request.attempts ?? 1\n if (patch.status === 'failed' && attempt < maxAttempts && !this.#closed) {\n const baseDelay = job.record.request.retryDelayMs ?? 5000\n const delay = baseDelay * 2 ** (attempt - 1)\n const updated = await this.#adapter.update(job.record.info.id, {\n status: 'queued',\n attempt: attempt + 1,\n nextRunAt: Date.now() + delay,\n error: patch.error,\n usage,\n sessionId: undefined,\n sdkSessionId: undefined,\n startedAt: undefined,\n result: undefined,\n })\n if (updated) {\n job.record = updated\n this.#emit(updated, { type: 'job_retrying', job: updated.info, ts: Date.now() }, job)\n const timer = setTimeout(() => {\n this.#retryTimers.delete(timer)\n void this.#pump()\n }, delay)\n timer.unref?.()\n this.#retryTimers.add(timer)\n }\n void this.#pump()\n return\n }\n const updated = await this.#adapter.update(job.record.info.id, {\n ...patch,\n usage,\n nextRunAt: undefined,\n finishedAt: Date.now(),\n })\n if (updated) {\n job.record = updated\n this.#emit(job.record, { type: 'job_completed', job: updated.info, ts: Date.now() }, job)\n }\n this.#sweep()\n void this.#pump()\n }\n\n #progress(job: RunningJob, progress: JobProgress): void {\n const event: JobEvent = { type: 'job_progress', job: job.record.info, progress, ts: Date.now() }\n if (job.record.request.webhook?.progress === 'completion') {\n try {\n this.#options.onEvent?.(event)\n } catch {}\n return\n }\n this.#emit(job.record, event, job)\n }\n\n #emit(record: JobRecord, event: JobEvent, chainOwner?: RunningJob, { skipWebhook = false }: { skipWebhook?: boolean } = {}): void {\n try {\n this.#options.onEvent?.(event)\n } catch {}\n const webhook = record.request.webhook\n if (!webhook || skipWebhook) {\n return\n }\n const running = chainOwner ?? this.#running.get(record.info.id)\n const deliver = () => this.#deliver(webhook.url, webhook.headers, event)\n if (running) {\n running.deliveries = running.deliveries.then(deliver)\n } else {\n void deliver()\n }\n }\n\n async #deliver(url: string, headers: Record<string, string> | undefined, event: JobEvent): Promise<void> {\n const fetchImpl = this.#options.fetchImpl ?? fetch\n const attempts = this.#options.webhookAttempts ?? 3\n const baseDelay = this.#options.webhookRetryDelayMs ?? 500\n for (let attempt = 0; attempt < attempts; attempt++) {\n try {\n const res = await fetchImpl(url, {\n method: 'POST',\n headers: { 'content-type': 'application/json', ...headers },\n body: JSON.stringify(event),\n })\n if (res.ok) {\n return\n }\n } catch {}\n if (attempt < attempts - 1) {\n await new Promise((resolve) => setTimeout(resolve, baseDelay * 2 ** attempt))\n }\n }\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workerdeck/queue",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Job queue over the WorkerDeck session runner: remote services schedule one-shot runs; the queue executes them as sessions with bounded concurrency and token budgets, delivering progress and completion via webhooks. Pluggable adapter interface (in-memory bundled; redis/bullmq/pubsub adapters can implement the same contract).",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@workerdeck/core": "2.
|
|
21
|
-
"@workerdeck/protocol": "2.
|
|
20
|
+
"@workerdeck/core": "2.12.0",
|
|
21
|
+
"@workerdeck/protocol": "2.12.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@anthropic-ai/claude-agent-sdk": "^0.3.278",
|