openworkgraph 0.2.12
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 +64 -0
- package/dist/api-image-agent.d.ts +32 -0
- package/dist/api-image-agent.js +132 -0
- package/dist/api-image-output.d.ts +8 -0
- package/dist/api-image-output.js +41 -0
- package/dist/api.d.ts +35 -0
- package/dist/api.js +153 -0
- package/dist/auth.d.ts +58 -0
- package/dist/auth.js +273 -0
- package/dist/backend/adapter.d.ts +35 -0
- package/dist/backend/adapter.js +439 -0
- package/dist/backend/capabilities.d.ts +23 -0
- package/dist/backend/capabilities.js +75 -0
- package/dist/backend/diagnostics.d.ts +9 -0
- package/dist/backend/diagnostics.js +80 -0
- package/dist/backend/index.d.ts +6 -0
- package/dist/backend/index.js +7 -0
- package/dist/backend/models.d.ts +15 -0
- package/dist/backend/models.js +43 -0
- package/dist/backend/paths.d.ts +6 -0
- package/dist/backend/paths.js +69 -0
- package/dist/backend/stdio.d.ts +66 -0
- package/dist/backend/stdio.js +172 -0
- package/dist/backend/types.d.ts +90 -0
- package/dist/backend/types.js +11 -0
- package/dist/backup-api.d.ts +10 -0
- package/dist/backup-api.js +40 -0
- package/dist/blob-store.d.ts +40 -0
- package/dist/blob-store.js +218 -0
- package/dist/cli-help.d.ts +1 -0
- package/dist/cli-help.js +63 -0
- package/dist/cli-output.d.ts +4 -0
- package/dist/cli-output.js +130 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +284 -0
- package/dist/client-pairing.d.ts +8 -0
- package/dist/client-pairing.js +30 -0
- package/dist/directories.d.ts +14 -0
- package/dist/directories.js +34 -0
- package/dist/errors.d.ts +12 -0
- package/dist/errors.js +7 -0
- package/dist/events.d.ts +22 -0
- package/dist/events.js +155 -0
- package/dist/execution-chains.d.ts +24 -0
- package/dist/execution-chains.js +231 -0
- package/dist/execution-settings.d.ts +10 -0
- package/dist/execution-settings.js +38 -0
- package/dist/graph-document-history.d.ts +43 -0
- package/dist/graph-document-history.js +275 -0
- package/dist/graph-files.d.ts +14 -0
- package/dist/graph-files.js +59 -0
- package/dist/graph-transfer.d.ts +53 -0
- package/dist/graph-transfer.js +501 -0
- package/dist/graphs.d.ts +68 -0
- package/dist/graphs.js +771 -0
- package/dist/history.d.ts +20 -0
- package/dist/history.js +61 -0
- package/dist/http.d.ts +2 -0
- package/dist/http.js +42 -0
- package/dist/image-credentials.d.ts +11 -0
- package/dist/image-credentials.js +130 -0
- package/dist/image-providers.d.ts +51 -0
- package/dist/image-providers.js +271 -0
- package/dist/input-materialization.d.ts +17 -0
- package/dist/input-materialization.js +95 -0
- package/dist/inputs.d.ts +74 -0
- package/dist/inputs.js +301 -0
- package/dist/local-control.d.ts +13 -0
- package/dist/local-control.js +37 -0
- package/dist/network.d.ts +11 -0
- package/dist/network.js +48 -0
- package/dist/openai-image-driver.d.ts +42 -0
- package/dist/openai-image-driver.js +368 -0
- package/dist/operations/backups.d.ts +40 -0
- package/dist/operations/backups.js +391 -0
- package/dist/operations/capacity.d.ts +7 -0
- package/dist/operations/capacity.js +35 -0
- package/dist/operations/cli-context.d.ts +7 -0
- package/dist/operations/cli-context.js +58 -0
- package/dist/operations/daemon.d.ts +36 -0
- package/dist/operations/daemon.js +159 -0
- package/dist/operations/files.d.ts +12 -0
- package/dist/operations/files.js +84 -0
- package/dist/operations/lifecycle.d.ts +28 -0
- package/dist/operations/lifecycle.js +155 -0
- package/dist/operations/local-admin.d.ts +6 -0
- package/dist/operations/local-admin.js +38 -0
- package/dist/operations/logs.d.ts +16 -0
- package/dist/operations/logs.js +37 -0
- package/dist/operations/plugins.d.ts +10 -0
- package/dist/operations/plugins.js +11 -0
- package/dist/operations/snapshot-worker.d.ts +1 -0
- package/dist/operations/snapshot-worker.js +18 -0
- package/dist/operations/snapshot.d.ts +1 -0
- package/dist/operations/snapshot.js +14 -0
- package/dist/operations/update.d.ts +26 -0
- package/dist/operations/update.js +216 -0
- package/dist/persistence/asset-business-schema.d.ts +2 -0
- package/dist/persistence/asset-business-schema.js +36 -0
- package/dist/persistence/database.d.ts +7 -0
- package/dist/persistence/database.js +91 -0
- package/dist/persistence/plugin-schema.d.ts +9 -0
- package/dist/persistence/plugin-schema.js +38 -0
- package/dist/persistence/repositories.d.ts +20 -0
- package/dist/persistence/repositories.js +106 -0
- package/dist/persistence/resource-schema.d.ts +2 -0
- package/dist/persistence/resource-schema.js +44 -0
- package/dist/persistence/schema.d.ts +6 -0
- package/dist/persistence/schema.js +236 -0
- package/dist/persistence/workflow-schema.d.ts +2 -0
- package/dist/persistence/workflow-schema.js +19 -0
- package/dist/plugin-api.d.ts +10 -0
- package/dist/plugin-api.js +40 -0
- package/dist/plugin-management.d.ts +36 -0
- package/dist/plugin-management.js +112 -0
- package/dist/plugins.d.ts +55 -0
- package/dist/plugins.js +239 -0
- package/dist/project-discovery.d.ts +3 -0
- package/dist/project-discovery.js +57 -0
- package/dist/project-files-api.d.ts +16 -0
- package/dist/project-files-api.js +243 -0
- package/dist/project-files.d.ts +97 -0
- package/dist/project-files.js +557 -0
- package/dist/project-lock.d.ts +4 -0
- package/dist/project-lock.js +35 -0
- package/dist/project-probe-worker.d.ts +1 -0
- package/dist/project-probe-worker.js +17 -0
- package/dist/project-probe.d.ts +22 -0
- package/dist/project-probe.js +67 -0
- package/dist/projects.d.ts +29 -0
- package/dist/projects.js +219 -0
- package/dist/publication.d.ts +31 -0
- package/dist/publication.js +642 -0
- package/dist/resource-api.d.ts +15 -0
- package/dist/resource-api.js +256 -0
- package/dist/resources-orphans.d.ts +41 -0
- package/dist/resources-orphans.js +235 -0
- package/dist/resources.d.ts +246 -0
- package/dist/resources.js +714 -0
- package/dist/run-api.d.ts +10 -0
- package/dist/run-api.js +308 -0
- package/dist/run-context.d.ts +54 -0
- package/dist/run-context.js +137 -0
- package/dist/runs.d.ts +82 -0
- package/dist/runs.js +506 -0
- package/dist/runtime-backend.d.ts +24 -0
- package/dist/runtime-backend.js +214 -0
- package/dist/runtime.d.ts +97 -0
- package/dist/runtime.js +553 -0
- package/dist/scheduler.d.ts +85 -0
- package/dist/scheduler.js +344 -0
- package/dist/service.d.ts +29 -0
- package/dist/service.js +515 -0
- package/dist/skills-api.d.ts +18 -0
- package/dist/skills-api.js +120 -0
- package/dist/storage-api.d.ts +21 -0
- package/dist/storage-api.js +92 -0
- package/dist/transfer-api.d.ts +10 -0
- package/dist/transfer-api.js +60 -0
- package/dist/vendor/protocol/contracts.typecheck.d.ts +1 -0
- package/dist/vendor/protocol/contracts.typecheck.js +35 -0
- package/dist/vendor/protocol/execution-chain.d.ts +6 -0
- package/dist/vendor/protocol/execution-chain.js +26 -0
- package/dist/vendor/protocol/graph-binary.d.ts +15 -0
- package/dist/vendor/protocol/graph-binary.js +121 -0
- package/dist/vendor/protocol/graph-title.d.ts +2 -0
- package/dist/vendor/protocol/graph-title.js +23 -0
- package/dist/vendor/protocol/index.d.ts +617 -0
- package/dist/vendor/protocol/index.js +20 -0
- package/dist/vendor/protocol/pairing.d.ts +29 -0
- package/dist/vendor/protocol/pairing.js +71 -0
- package/dist/vendor/protocol/preview.d.ts +2 -0
- package/dist/vendor/protocol/preview.js +9 -0
- package/dist/vendor/protocol/resource-mime.d.ts +2 -0
- package/dist/vendor/protocol/resource-mime.js +35 -0
- package/dist/video-thumbnail.d.ts +2 -0
- package/dist/video-thumbnail.js +34 -0
- package/package.json +9 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { open } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { Runs } from './runs.js';
|
|
4
|
+
import { ProjectProbe } from './project-probe.js';
|
|
5
|
+
import { materializeInputs } from './input-materialization.js';
|
|
6
|
+
import { runDirectories } from './directories.js';
|
|
7
|
+
import { ServiceError } from './errors.js';
|
|
8
|
+
import { publicProgressText } from './backend/adapter.js';
|
|
9
|
+
import { sandboxMode } from './execution-settings.js';
|
|
10
|
+
import { ProjectFiles } from './project-files.js';
|
|
11
|
+
import { RunContexts } from './run-context.js';
|
|
12
|
+
export function backendReply(interaction, answer) {
|
|
13
|
+
const payload = interaction.payload;
|
|
14
|
+
if (interaction.kind === 'approval') {
|
|
15
|
+
const decision = typeof answer === 'boolean' ? (answer ? 'accept' : 'decline') : answer && typeof answer === 'object' && !Array.isArray(answer) && answer.kind === 'approval' ? answer.decision : null;
|
|
16
|
+
if (!['accept', 'decline'].includes(String(decision)) || (decision === 'accept' && !payload?.canApprove))
|
|
17
|
+
throw new ServiceError('INVALID_REQUEST', 'Approval is not permitted for this action');
|
|
18
|
+
return { kind: 'approval', decision: decision };
|
|
19
|
+
}
|
|
20
|
+
const ids = payload?.questions?.map(question => question.id) ?? [];
|
|
21
|
+
const answers = typeof answer === 'string' && ids.length === 1 ? { [ids[0]]: [answer] } : answer && typeof answer === 'object' && !Array.isArray(answer) && answer.kind === 'question' ? answer.answers : null;
|
|
22
|
+
if (!ids.length || !answers || typeof answers !== 'object' || Array.isArray(answers) || Object.keys(answers).length !== ids.length || ids.some(id => !Array.isArray(answers[id]) || !answers[id].length || answers[id].some(value => typeof value !== 'string' || !value.trim() || value.length > 16000)))
|
|
23
|
+
throw new ServiceError('INVALID_REQUEST', 'Answer each requested question exactly once');
|
|
24
|
+
return { kind: 'question', answers: answers };
|
|
25
|
+
}
|
|
26
|
+
/** Trusted host bridge. Never accepts browser paths or creates isolation evidence. */
|
|
27
|
+
export class RuntimeBackend {
|
|
28
|
+
runs;
|
|
29
|
+
dirs;
|
|
30
|
+
adapter;
|
|
31
|
+
probe;
|
|
32
|
+
contexts = new Map();
|
|
33
|
+
runContexts;
|
|
34
|
+
constructor(runs, dirs, adapter, probe = new ProjectProbe()) {
|
|
35
|
+
this.runs = runs;
|
|
36
|
+
this.dirs = dirs;
|
|
37
|
+
this.adapter = adapter;
|
|
38
|
+
this.probe = probe;
|
|
39
|
+
this.runContexts = new RunContexts(runs, dirs);
|
|
40
|
+
}
|
|
41
|
+
snapshot(snapshot, context, expectedRunId) {
|
|
42
|
+
if (snapshot.runId !== expectedRunId)
|
|
43
|
+
return;
|
|
44
|
+
if (!this.runs.db.prepare('SELECT 1 FROM runs WHERE id=?').get(expectedRunId))
|
|
45
|
+
return;
|
|
46
|
+
const run = this.runs.get(snapshot.runId);
|
|
47
|
+
const token = this.runs.runtime(run.id);
|
|
48
|
+
if (token.epoch !== context.epoch)
|
|
49
|
+
return;
|
|
50
|
+
if (snapshot.state === 'starting')
|
|
51
|
+
return;
|
|
52
|
+
if (run.status === 'preparing')
|
|
53
|
+
context.emit({ type: 'started', identity: { threadId: snapshot.threadId, turnId: snapshot.turnId } });
|
|
54
|
+
const progress = snapshot.progress;
|
|
55
|
+
const content = progress && publicProgressText(progress.text);
|
|
56
|
+
// Persistent identity deduplication also covers start/respond return snapshots and reconciliation.
|
|
57
|
+
const duplicate = progress && this.runs.db.prepare("SELECT 1 FROM run_process_records WHERE run_id=? AND kind='backend.progress' AND json_extract(payload,'$.threadId')=? AND json_extract(payload,'$.turnId')=? AND json_extract(payload,'$.summary.itemId')=? LIMIT 1").get(run.id, snapshot.threadId, snapshot.turnId, progress.itemId);
|
|
58
|
+
const summary = content && !duplicate && snapshot.threadId && snapshot.turnId && progress && typeof progress.itemId === 'string' && progress.itemId.length > 0 && progress.itemId.length <= 200 && ['commentary', 'final_answer'].includes(progress.phase)
|
|
59
|
+
? { source: 'agentMessage', itemId: progress.itemId, phase: progress.phase, text: content } : null;
|
|
60
|
+
context.emit({ type: 'progress', payload: { state: snapshot.state, threadId: snapshot.threadId, turnId: snapshot.turnId, observedAt: snapshot.observedAt, ...(summary ? { summary } : {}), ...(snapshot.transportFailure ? { transportFailure: { kind: snapshot.transportFailure.kind, ...(snapshot.transportFailure.exitCode !== undefined ? { exitCode: snapshot.transportFailure.exitCode } : {}), ...(snapshot.transportFailure.exitSignal !== undefined ? { exitSignal: snapshot.transportFailure.exitSignal } : {}), ...(snapshot.transportFailure.observedFrameBytes !== undefined ? { observedFrameBytes: snapshot.transportFailure.observedFrameBytes } : {}) } } : {}) } });
|
|
61
|
+
if (snapshot.state === 'completed')
|
|
62
|
+
context.emit({ type: 'completed', result: { answer: snapshot.answer } });
|
|
63
|
+
else if (snapshot.state === 'failed')
|
|
64
|
+
context.emit({ type: 'failed', error: snapshot.reason ?? 'Backend confirmed failure' });
|
|
65
|
+
else if (snapshot.state === 'cancelled')
|
|
66
|
+
context.emit({ type: 'stopped' });
|
|
67
|
+
else if (snapshot.state === 'unknown') {
|
|
68
|
+
const current = this.runs.get(run.id);
|
|
69
|
+
if (['preparing', 'running', 'waiting_answer', 'waiting_approval', 'cancelling'].includes(current.status))
|
|
70
|
+
this.runs.transition(run.id, this.runs.runtime(run.id), 'reconciling', { uncertainty: snapshot.reason ?? 'Backend outcome unknown' });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async start(run, snapshot, context) {
|
|
74
|
+
if (this.runs.db.isTransaction)
|
|
75
|
+
throw new ServiceError('CONFLICT', 'Backend preparation must run outside transactions');
|
|
76
|
+
if (snapshot.imageRoute?.type === 'api' || !snapshot.model)
|
|
77
|
+
throw new ServiceError('INVALID_REQUEST', 'Codex backend cannot execute an API image snapshot');
|
|
78
|
+
this.contexts.set(run.id, context);
|
|
79
|
+
const runtime = this.runs.runtime(run.id);
|
|
80
|
+
const path = String(runtime.details.canonicalPath);
|
|
81
|
+
// All checks before adapter.start are known not to have spawned a backend.
|
|
82
|
+
let directories;
|
|
83
|
+
let inputFiles;
|
|
84
|
+
let upstreamContext;
|
|
85
|
+
try {
|
|
86
|
+
if (runtime.details.kind === 'execution')
|
|
87
|
+
upstreamContext = this.runContexts.lineage(run.id);
|
|
88
|
+
const inspect = await this.probe.inspect([path]);
|
|
89
|
+
if (inspect(path).canonicalPath !== path)
|
|
90
|
+
throw new ServiceError('PROJECT_UNAVAILABLE', 'Project canonical path changed');
|
|
91
|
+
const projectFiles = snapshot.projectFiles ?? [];
|
|
92
|
+
if (projectFiles.length) {
|
|
93
|
+
const states = await new ProjectFiles(this.runs.db).stat(run.projectId, projectFiles.map(item => item.relativePath));
|
|
94
|
+
const unavailable = states.find(item => item.state !== 'available');
|
|
95
|
+
if (unavailable)
|
|
96
|
+
throw new ServiceError(unavailable.state === 'missing' ? 'INPUT_BLOCKED' : 'PROJECT_UNAVAILABLE', '项目文件引用当前不可读:' + unavailable.path);
|
|
97
|
+
}
|
|
98
|
+
directories = runDirectories(this.dirs, run.id);
|
|
99
|
+
const inputs = await materializeInputs(snapshot, { inputDirectory: directories.input, blobDirectory: this.dirs.blobs, resolveBlobPath: sha256 => {
|
|
100
|
+
const row = this.runs.db.prepare('SELECT path FROM resource_blob_files WHERE sha256=?').get(sha256);
|
|
101
|
+
if (!row)
|
|
102
|
+
throw new ServiceError('INPUT_BLOCKED', 'Frozen blob file not registered');
|
|
103
|
+
return String(row.path);
|
|
104
|
+
} });
|
|
105
|
+
inputFiles = inputs.files;
|
|
106
|
+
// Keep the materialized snapshot self-contained. Agents are told to inspect
|
|
107
|
+
// this file, so omitting the frozen prompt makes an input with no references
|
|
108
|
+
// look like an empty task even though the prompt is supplied to turn/start.
|
|
109
|
+
const manifest = JSON.stringify({ ...snapshot, projectFiles: snapshot.projectFiles ?? [], files: inputs.files }, null, 2);
|
|
110
|
+
const file = await open(join(directories.input, 'snapshot.json'), 'wx', 0o400);
|
|
111
|
+
try {
|
|
112
|
+
await file.writeFile(manifest);
|
|
113
|
+
await file.sync();
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await file.close();
|
|
117
|
+
}
|
|
118
|
+
if (upstreamContext) {
|
|
119
|
+
const lineageFile = await open(join(directories.input, 'upstream-context.json'), 'wx', 0o400);
|
|
120
|
+
try {
|
|
121
|
+
await lineageFile.writeFile(JSON.stringify(upstreamContext, null, 2));
|
|
122
|
+
await lineageFile.sync();
|
|
123
|
+
}
|
|
124
|
+
finally {
|
|
125
|
+
await lineageFile.close();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Recheck immediately before actual spawn, after asynchronous materialization.
|
|
129
|
+
const finalInspect = await this.probe.inspect([path]);
|
|
130
|
+
const currentPath = this.runs.db.prepare('SELECT canonical_path,state FROM projects WHERE id=?').get(run.projectId);
|
|
131
|
+
if (finalInspect(path).canonicalPath !== path || currentPath?.canonical_path !== path || currentPath.state !== 'active')
|
|
132
|
+
throw new ServiceError('PROJECT_UNAVAILABLE', 'Project path/state changed before launch');
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (this.runs.get(run.id).status === 'cancelling')
|
|
136
|
+
context.emit({ type: 'stopped' });
|
|
137
|
+
else
|
|
138
|
+
context.emit({ type: 'failed', error: error instanceof Error ? error.message : 'Input preflight failed' });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (this.runs.runtime(run.id).epoch !== context.epoch)
|
|
142
|
+
return;
|
|
143
|
+
if (this.runs.get(run.id).status === 'cancelling') {
|
|
144
|
+
context.emit({ type: 'stopped' });
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const result = await this.adapter.start({ runId: run.id, kind: runtime.details.kind, projectPath: path, inputPath: directories.input, outputPath: directories.output, serviceRoot: this.dirs.root, prompt: snapshot.prompt, resources: snapshot.resources, projectFiles: snapshot.projectFiles ?? [], files: inputFiles, model: snapshot.model, ...(upstreamContext ? { upstreamContext } : {}), ...(snapshot.imageRoute?.type === 'codex' && snapshot.imageRoute.options ? { imageOptions: snapshot.imageRoute.options } : {}), sandboxMode: sandboxMode(runtime.details.sandboxMode ?? 'read-only') }, {
|
|
148
|
+
onSnapshot: value => this.snapshot(value, context, run.id),
|
|
149
|
+
onInteraction: value => {
|
|
150
|
+
if (!this.runs.db.prepare('SELECT 1 FROM runs WHERE id=?').get(run.id))
|
|
151
|
+
return;
|
|
152
|
+
const token = this.runs.runtime(run.id);
|
|
153
|
+
if (token.epoch !== context.epoch || token.details.cancelRequested === true)
|
|
154
|
+
return;
|
|
155
|
+
if (this.runs.db.prepare('SELECT 1 FROM interactions WHERE id=? AND run_id=?').get(value.id, run.id))
|
|
156
|
+
return;
|
|
157
|
+
if (this.runs.get(run.id).status === 'preparing')
|
|
158
|
+
context.emit({ type: 'started' });
|
|
159
|
+
context.emit({ type: value.kind, id: value.id, payload: JSON.parse(JSON.stringify(value)) });
|
|
160
|
+
},
|
|
161
|
+
queryHistory: async (query) => this.queryHistory(run.id, query),
|
|
162
|
+
readRunContext: async (request) => this.runContexts.read(run.id, request),
|
|
163
|
+
});
|
|
164
|
+
this.snapshot(result, context, run.id);
|
|
165
|
+
}
|
|
166
|
+
queryHistory(runId, query) {
|
|
167
|
+
if (typeof query !== 'string' || !query.trim() || query.length > 2000)
|
|
168
|
+
throw new ServiceError('INVALID_REQUEST', 'Bounded history query required');
|
|
169
|
+
const run = this.runs.get(runId);
|
|
170
|
+
// Project scope is derived from the accepted Run, never from tool arguments.
|
|
171
|
+
const rows = this.runs.db.prepare("SELECT id,node_id,status,created_at,history_state FROM runs WHERE project_id=? AND (id=? OR node_id=? OR EXISTS(SELECT 1 FROM run_process_records p WHERE p.run_id=runs.id AND instr(p.payload,?)>0)) ORDER BY sequence DESC LIMIT 10").all(run.projectId, query, query, query);
|
|
172
|
+
return JSON.stringify(rows.map(row => ({ runId: row.id, nodeId: row.node_id, status: row.status, createdAt: row.created_at, historyState: row.history_state, records: row.history_state === 'cleared' ? [] : this.runs.db.prepare('SELECT kind,payload FROM run_process_records WHERE run_id=? AND instr(payload,?)>0 ORDER BY id DESC LIMIT 10').all(String(row.id), query).map(record => ({ kind: record.kind, payload: String(record.payload).slice(0, 1600) })) }))).slice(0, 30000);
|
|
173
|
+
}
|
|
174
|
+
async cancel(run, context) {
|
|
175
|
+
const result = await this.adapter.cancel(run.id);
|
|
176
|
+
if (result.runId !== run.id)
|
|
177
|
+
return 'unknown';
|
|
178
|
+
this.snapshot(result, context, run.id);
|
|
179
|
+
return ['cancelled', 'failed', 'completed'].includes(result.state) ? 'confirmed' : 'unknown';
|
|
180
|
+
}
|
|
181
|
+
async reply(run, interaction, answer, context) {
|
|
182
|
+
const result = await this.adapter.respond(run.id, interaction.id, backendReply(interaction, answer));
|
|
183
|
+
if (result.runId !== run.id || result.state === 'unknown')
|
|
184
|
+
throw new ServiceError('CONFLICT', 'Reply delivery outcome unknown');
|
|
185
|
+
this.snapshot(result, context, run.id);
|
|
186
|
+
}
|
|
187
|
+
async reconcile(run, context) {
|
|
188
|
+
try {
|
|
189
|
+
const result = await this.adapter.reconcile(run.id);
|
|
190
|
+
if (result.runId !== run.id)
|
|
191
|
+
return 'unknown';
|
|
192
|
+
if (result.state === 'cancelled' || result.state === 'failed' || result.state === 'interrupted')
|
|
193
|
+
return 'interrupted';
|
|
194
|
+
if (result.state === 'completed') {
|
|
195
|
+
const token = this.runs.runtime(run.id);
|
|
196
|
+
if (token.details.unresolvedCompletion === true && token.details.cancelRequested !== true)
|
|
197
|
+
return 'unknown';
|
|
198
|
+
if (token.epoch === context.epoch && this.runs.get(run.id).status === 'reconciling' && token.details.cancelRequested !== true)
|
|
199
|
+
this.runs.transition(run.id, token, 'agent_completed', { result: { answer: result.answer } });
|
|
200
|
+
else if (token.details.cancelRequested === true)
|
|
201
|
+
return 'interrupted';
|
|
202
|
+
return 'unknown';
|
|
203
|
+
}
|
|
204
|
+
// Only an adapter attached by THIS bridge has an original responder.
|
|
205
|
+
if (result.state === 'running' && this.contexts.get(run.id)?.epoch === context.epoch)
|
|
206
|
+
return 'resumed';
|
|
207
|
+
return 'unknown';
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return 'unknown';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=runtime-backend.js.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { Capability, Run, ServiceInfo, SubmitRun } from "./vendor/protocol/index.js";
|
|
3
|
+
import { BlobStore } from './blob-store.js';
|
|
4
|
+
import { Graphs } from './graphs.js';
|
|
5
|
+
import { GraphFiles } from './graph-files.js';
|
|
6
|
+
import { Resources } from './resources.js';
|
|
7
|
+
import { PluginRegistry } from './plugins.js';
|
|
8
|
+
import { InputPreparation } from './inputs.js';
|
|
9
|
+
import { ModelDefaultsStore, type BackendModel } from './backend/models.js';
|
|
10
|
+
import { type AdapterOptions } from './backend/adapter.js';
|
|
11
|
+
import { Runs } from './runs.js';
|
|
12
|
+
import { ExecutionChains } from './execution-chains.js';
|
|
13
|
+
import { History } from './history.js';
|
|
14
|
+
import { Scheduler, type SchedulerBackend } from './scheduler.js';
|
|
15
|
+
import { Publication } from './publication.js';
|
|
16
|
+
import type { DataDirectories } from './directories.js';
|
|
17
|
+
import { ExecutionSettingsStore } from './execution-settings.js';
|
|
18
|
+
import { ImageProviders } from './image-providers.js';
|
|
19
|
+
import { ImageCredentials } from './image-credentials.js';
|
|
20
|
+
export interface WorkflowRuntimeOptions {
|
|
21
|
+
backend?: SchedulerBackend;
|
|
22
|
+
models?: BackendModel[];
|
|
23
|
+
/** Default: discover on model reads/submission. True also probes at startup; false disables execution and discovery. */
|
|
24
|
+
enableBackend?: boolean;
|
|
25
|
+
backendOptions?: AdapterOptions;
|
|
26
|
+
}
|
|
27
|
+
export declare class WorkflowRuntime {
|
|
28
|
+
readonly db: DatabaseSync;
|
|
29
|
+
readonly serviceId: string;
|
|
30
|
+
readonly directories: DataDirectories;
|
|
31
|
+
readonly options: WorkflowRuntimeOptions;
|
|
32
|
+
readonly blobs: BlobStore;
|
|
33
|
+
readonly graphs: Graphs;
|
|
34
|
+
readonly resources: Resources;
|
|
35
|
+
readonly plugins: PluginRegistry;
|
|
36
|
+
readonly inputs: InputPreparation;
|
|
37
|
+
readonly models: ModelDefaultsStore;
|
|
38
|
+
readonly runs: Runs;
|
|
39
|
+
readonly history: History;
|
|
40
|
+
readonly scheduler: Scheduler;
|
|
41
|
+
readonly publication: Publication;
|
|
42
|
+
readonly executionChains: ExecutionChains;
|
|
43
|
+
readonly graphFiles: GraphFiles;
|
|
44
|
+
readonly executionSettings: ExecutionSettingsStore;
|
|
45
|
+
readonly imageProviders: ImageProviders;
|
|
46
|
+
readonly imageCredentials: ImageCredentials;
|
|
47
|
+
private readonly probe;
|
|
48
|
+
private readonly adapter;
|
|
49
|
+
private availableModels;
|
|
50
|
+
private timer;
|
|
51
|
+
private starting;
|
|
52
|
+
private catalogRefresh;
|
|
53
|
+
private catalogRpc;
|
|
54
|
+
private recovering;
|
|
55
|
+
private closed;
|
|
56
|
+
private closing;
|
|
57
|
+
private stopping;
|
|
58
|
+
constructor(db: DatabaseSync, serviceId: string, directories: DataDirectories, options?: WorkflowRuntimeOptions);
|
|
59
|
+
get catalog(): BackendModel[];
|
|
60
|
+
/** Catalog reads require only the wire handshake, never login or execution self-checks. */
|
|
61
|
+
refreshModels(): Promise<void>;
|
|
62
|
+
get executionCapability(): Capability;
|
|
63
|
+
get imageGenerationCapability(): Capability;
|
|
64
|
+
get capabilities(): ServiceInfo['capabilities'];
|
|
65
|
+
get serviceInfo(): ServiceInfo;
|
|
66
|
+
/** An explicitly initiated, potentially billable request. No catalog probe or fixture marks availability. */
|
|
67
|
+
discoverImageModels(providerId: string, expectedRevision: number): Promise<{
|
|
68
|
+
models: {
|
|
69
|
+
id: string;
|
|
70
|
+
name: string;
|
|
71
|
+
selected: boolean;
|
|
72
|
+
}[];
|
|
73
|
+
revision: number;
|
|
74
|
+
}>;
|
|
75
|
+
private requireAvailable;
|
|
76
|
+
/** Returns a request-scoped synchronous commit closure; no shared mutable cache. */
|
|
77
|
+
prepareSubmission(input: SubmitRun): Promise<(principal: string) => Run>;
|
|
78
|
+
prepareExecutionStart(id: string, nodeIds: string[], expectedExecutionRevision: number): Promise<(principal: string, key: string) => Run>;
|
|
79
|
+
private prepareSingleSubmission;
|
|
80
|
+
prepareContinuation(id: string): Promise<(principal: string, idempotencyKey: string) => Run>;
|
|
81
|
+
get ready(): Promise<void>;
|
|
82
|
+
private active;
|
|
83
|
+
private pump;
|
|
84
|
+
start(): Promise<void>;
|
|
85
|
+
/** Host must hold its service-root instance lock before transferring epochs. */
|
|
86
|
+
recover(): Promise<void>;
|
|
87
|
+
/** Bind/startup failure only: never drain or mutate persisted service state. */
|
|
88
|
+
disposeUnstarted(): void;
|
|
89
|
+
stopAccepting(): void;
|
|
90
|
+
/** A host shutdown cancels durable queued work as well as active responders. */
|
|
91
|
+
stopRuns(): void;
|
|
92
|
+
drain(options?: {
|
|
93
|
+
interrupt?: boolean;
|
|
94
|
+
}): Promise<void>;
|
|
95
|
+
private finishClose;
|
|
96
|
+
close(): void;
|
|
97
|
+
}
|