@citeark/agent 0.3.20
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/LICENSE +202 -0
- package/README.md +128 -0
- package/data/dataset-source-registry.v1.json +300 -0
- package/dist/arkgraph/boot.js +6 -0
- package/dist/arkgraph/index.html +1 -0
- package/dist/arkgraph/viewer.css +1 -0
- package/dist/arkgraph/viewer.en.css +1 -0
- package/dist/arkgraph/viewer.en.js +49 -0
- package/dist/arkgraph/viewer.en.js.LEGAL.txt +56 -0
- package/dist/arkgraph/viewer.js +49 -0
- package/dist/arkgraph/viewer.js.LEGAL.txt +56 -0
- package/docker/claude-code/Dockerfile +97 -0
- package/docker/claude-code/codex-pro-relay.mjs +466 -0
- package/docker/claude-code/runtime-contract-check.mjs +79 -0
- package/docs/arkgraph-reading.md +79 -0
- package/docs/configuration.md +100 -0
- package/docs/integration.md +92 -0
- package/docs/maturity-plan.md +27 -0
- package/docs/npm-release.md +44 -0
- package/docs/paper-reading.md +40 -0
- package/docs/research-plan-granularity.md +27 -0
- package/docs/terminal.md +49 -0
- package/examples/toy-evaluation/compile-task.json +27 -0
- package/examples/toy-evaluation/paper.md +5 -0
- package/examples/toy-evaluation/repository/README.md +9 -0
- package/examples/toy-evaluation/repository/checkpoint.json +4 -0
- package/examples/toy-evaluation/repository/evaluate.py +17 -0
- package/examples/toy-evaluation/task.json +81 -0
- package/package.json +59 -0
- package/prompts/compile-research.md +58 -0
- package/prompts/execute-contract.md +72 -0
- package/prompts/execute-workspace-simple.md +51 -0
- package/prompts/execute-workspace.md +34 -0
- package/prompts/prepare-reproduction.md +82 -0
- package/prompts/repair-research.md +45 -0
- package/protocol/CAP.md +129 -0
- package/protocol/LICENSE +12 -0
- package/protocol/MAPPINGS.md +72 -0
- package/protocol/README.md +38 -0
- package/protocol/conformance-v2.0-alpha.1.json +36 -0
- package/protocol/examples/arkgraph/checkpoint-evaluation.json +309 -0
- package/protocol/examples/arkgraph/fixtures.mjs +49 -0
- package/protocol/examples/arkgraph/paper-free.json +291 -0
- package/protocol/examples/arkgraph/partial-failure.json +344 -0
- package/protocol/examples/arkgraph/training-evaluation.json +443 -0
- package/protocol/profiles/agent-trace.md +16 -0
- package/protocol/profiles/computational-run.md +16 -0
- package/protocol/profiles/core.md +15 -0
- package/protocol/profiles/public-bundle.md +18 -0
- package/protocol/profiles/reproduction.md +29 -0
- package/protocol/profiles/research-compilation.md +44 -0
- package/protocol/profiles/research-plan.md +39 -0
- package/protocol/profiles/restricted-evidence.md +15 -0
- package/runtime/bootstrap-autodl-runtime.sh +314 -0
- package/runtime/create-runtime-venv.sh +41 -0
- package/runtime/install-local-cpu-runtime.sh +23 -0
- package/runtime/install-scientific-runtime.sh +153 -0
- package/runtime/mineru/parse.py +62 -0
- package/runtime/mineru/requirements.txt +4 -0
- package/runtime/requirements-baseline.txt +38 -0
- package/schemas/cap/v2/activity.schema.json +47 -0
- package/schemas/cap/v2/agent.schema.json +32 -0
- package/schemas/cap/v2/assertion.schema.json +110 -0
- package/schemas/cap/v2/descriptor.schema.json +243 -0
- package/schemas/cap/v2/entity.schema.json +64 -0
- package/schemas/cap/v2/manifest.schema.json +67 -0
- package/schemas/cap/v2/relation.schema.json +82 -0
- package/schemas/compute-catalog.schema.json +63 -0
- package/schemas/compute-decision.schema.json +27 -0
- package/schemas/execution-contract.schema.json +1024 -0
- package/schemas/research-card.schema.json +30 -0
- package/schemas/research-inventory-draft.schema.json +366 -0
- package/schemas/research.schema.json +1044 -0
- package/schemas/result.schema.json +173 -0
- package/schemas/verification-policy.schema.json +47 -0
- package/schemas/verified-conclusion.schema.json +58 -0
- package/schemas/workspace-summary.schema.json +24 -0
- package/scripts/build-arkgraph-view.mjs +12 -0
- package/scripts/check-execution-feasibility.mjs +24 -0
- package/scripts/check-syntax.mjs +15 -0
- package/scripts/deterministic-asset-preparation.py +438 -0
- package/scripts/package-cap.mjs +23 -0
- package/scripts/package-local-agent.mjs +23 -0
- package/scripts/preview-arkgraph.mjs +25 -0
- package/scripts/replay-research-compiler-candidate.mjs +134 -0
- package/scripts/review-compiler-sources.mjs +44 -0
- package/scripts/run-asset-preparation.sh +17 -0
- package/scripts/run-research-plan.mjs +98 -0
- package/scripts/validate-asset-preparation.py +290 -0
- package/scripts/verify-local-runtime.mjs +57 -0
- package/scripts/verify-npm-package.mjs +57 -0
- package/src/adapters/paper2agent.mjs +107 -0
- package/src/assets/cache.mjs +159 -0
- package/src/assets/compute.mjs +98 -0
- package/src/assets/executor.mjs +145 -0
- package/src/assets/lifecycle.mjs +213 -0
- package/src/assets/manifest.mjs +242 -0
- package/src/assets/opportunistic-preparation.mjs +81 -0
- package/src/assets/plan.mjs +411 -0
- package/src/assets/prompts.mjs +29 -0
- package/src/assets/public-asset-probe.mjs +525 -0
- package/src/assets/qualification.mjs +119 -0
- package/src/assets/readiness.mjs +130 -0
- package/src/assets/reproduction-admission.mjs +355 -0
- package/src/assets/requirements.mjs +152 -0
- package/src/assets/source-grounding.mjs +341 -0
- package/src/assets/source-policy.mjs +118 -0
- package/src/autodl/client.mjs +260 -0
- package/src/autodl/ssh.mjs +380 -0
- package/src/autodl/tools.mjs +129 -0
- package/src/cap/redaction.mjs +38 -0
- package/src/cap/v2/archive.mjs +152 -0
- package/src/cap/v2/attestation.mjs +204 -0
- package/src/cap/v2/canonical-json.mjs +114 -0
- package/src/cap/v2/compilation-artifact.mjs +240 -0
- package/src/cap/v2/core.mjs +282 -0
- package/src/cap/v2/measurement-assessment-records.mjs +23 -0
- package/src/cap/v2/pipeline-artifact.mjs +922 -0
- package/src/cap/v2/read.mjs +41 -0
- package/src/cap/v2/reassessment-artifact.mjs +383 -0
- package/src/cap/v2/research-artifact.mjs +231 -0
- package/src/cap/v2/research-map-records.mjs +46 -0
- package/src/cap/v2/research-object-records.mjs +163 -0
- package/src/cap/v2/research-records.mjs +187 -0
- package/src/cap/v2/verify.mjs +642 -0
- package/src/cli.mjs +1146 -0
- package/src/compute/autodl-pro-compiler.mjs +347 -0
- package/src/compute/autodl-pro-executor.mjs +459 -0
- package/src/compute/autodl-pro-job.mjs +843 -0
- package/src/compute/autodl-pro-network.mjs +295 -0
- package/src/compute/autodl-pro-remote.mjs +810 -0
- package/src/compute/autodl-pro-staging.mjs +117 -0
- package/src/compute/campaign.mjs +110 -0
- package/src/compute/catalog.mjs +123 -0
- package/src/compute/checkpoint-protocol.mjs +154 -0
- package/src/compute/codex-account-lock.mjs +111 -0
- package/src/compute/codex-account-session.mjs +107 -0
- package/src/compute/compiler-profile.mjs +38 -0
- package/src/compute/compiler-router.mjs +23 -0
- package/src/compute/coordinator-recovery.mjs +210 -0
- package/src/compute/executor-router.mjs +29 -0
- package/src/compute/gcp-batch-compiler.mjs +685 -0
- package/src/compute/gcp-batch-executor.mjs +1215 -0
- package/src/compute/gcp-batch-failure.mjs +92 -0
- package/src/compute/gcp-batch-job.mjs +527 -0
- package/src/compute/gcp-batch-lifecycle.mjs +81 -0
- package/src/compute/gcp-checkpoint-worker.mjs +1633 -0
- package/src/compute/local-codex-compiler.mjs +52 -0
- package/src/compute/measurement-hardware.mjs +128 -0
- package/src/compute/remote-attempt.mjs +226 -0
- package/src/compute/requirements.mjs +124 -0
- package/src/compute/research-phases.mjs +48 -0
- package/src/compute/scheduler.mjs +452 -0
- package/src/compute/shared-workloads.mjs +26 -0
- package/src/compute/stage-archive.mjs +79 -0
- package/src/contracts/campaign-contract.mjs +52 -0
- package/src/contracts/execution-contract.mjs +819 -0
- package/src/contracts/execution-mode.mjs +19 -0
- package/src/contracts/execution-timeouts.mjs +45 -0
- package/src/contracts/execution-workload.mjs +68 -0
- package/src/contracts/preflight-schema.mjs +25 -0
- package/src/contracts/public-contract.mjs +63 -0
- package/src/contracts/subject-tags.mjs +31 -0
- package/src/dashboard/data.mjs +898 -0
- package/src/dashboard/server.mjs +79 -0
- package/src/dashboard/static/dashboard.css +366 -0
- package/src/dashboard/static/dashboard.js +560 -0
- package/src/dashboard/static/index.html +85 -0
- package/src/deployment/community-policy.mjs +9 -0
- package/src/deployment/environment.mjs +112 -0
- package/src/deployment/guided.mjs +98 -0
- package/src/deployment/handoff.mjs +102 -0
- package/src/deployment/local-contract.mjs +31 -0
- package/src/deployment/local.mjs +100 -0
- package/src/deployment/prepare.mjs +46 -0
- package/src/deployment/recipe.mjs +108 -0
- package/src/deployment/supplement.mjs +51 -0
- package/src/deployment/terminal.mjs +43 -0
- package/src/diagnosis/renderer.mjs +75 -0
- package/src/diagnosis/target-failure.mjs +46 -0
- package/src/evidence/parser-registry.mjs +54 -0
- package/src/evidence/parsers/fasttext-classification.mjs +82 -0
- package/src/evidence/parsers/json-scalar.mjs +96 -0
- package/src/evidence/parsers/simcse-senteval.mjs +104 -0
- package/src/evidence/parsers/starspace-classification.mjs +78 -0
- package/src/evidence/registry.mjs +147 -0
- package/src/execution/runner-audit.mjs +473 -0
- package/src/gcp/auth.mjs +106 -0
- package/src/gcp/batch-client.mjs +120 -0
- package/src/gcp/resource-discovery.mjs +177 -0
- package/src/gcp/rest.mjs +82 -0
- package/src/gcp/secret-manager.mjs +34 -0
- package/src/gcp/signed-url.mjs +133 -0
- package/src/gcp/storage.mjs +220 -0
- package/src/graph/command.mjs +41 -0
- package/src/graph/execution.mjs +97 -0
- package/src/graph/model.mjs +37 -0
- package/src/graph/presentation.mjs +110 -0
- package/src/graph/query.mjs +159 -0
- package/src/graph/research-relations.mjs +69 -0
- package/src/graph/source-page.mjs +12 -0
- package/src/graph/source-preview.mjs +34 -0
- package/src/graph/validate.mjs +76 -0
- package/src/job.mjs +496 -0
- package/src/network/autodl-routing-proxy.mjs +462 -0
- package/src/network/egress-proxy.mjs +158 -0
- package/src/observability/event-contract.mjs +230 -0
- package/src/observability/pipeline-monitor.mjs +166 -0
- package/src/pipeline/orchestrator.mjs +1281 -0
- package/src/pipeline/recovery-error.mjs +11 -0
- package/src/pipeline/replay.mjs +304 -0
- package/src/pipeline/shared-execution.mjs +115 -0
- package/src/pipeline/stage-checkpoint.mjs +86 -0
- package/src/pipeline/stage-recovery.mjs +101 -0
- package/src/pipeline/targets.mjs +110 -0
- package/src/process.mjs +143 -0
- package/src/protocol.mjs +312 -0
- package/src/provider/codex-account.mjs +44 -0
- package/src/provider/codex-completion.mjs +49 -0
- package/src/provider/completion.mjs +292 -0
- package/src/provider/model-client.mjs +44 -0
- package/src/provider/model-route.mjs +29 -0
- package/src/provider/openrouter-readiness.mjs +189 -0
- package/src/provider/reader-bridge.mjs +35 -0
- package/src/provider/relay.mjs +263 -0
- package/src/provider/runtime-auth.mjs +40 -0
- package/src/public/cap.d.mts +90 -0
- package/src/public/cap.mjs +12 -0
- package/src/public/contracts.d.mts +2 -0
- package/src/public/host.mjs +171 -0
- package/src/public/operations.d.mts +11 -0
- package/src/public/presentation.d.mts +4 -0
- package/src/records/views.mjs +26 -0
- package/src/remote/command.mjs +178 -0
- package/src/remote/ssh.mjs +59 -0
- package/src/repository-origin.mjs +81 -0
- package/src/reproduction/evidence-feedback.mjs +96 -0
- package/src/reproduction/incomplete-initialization.mjs +25 -0
- package/src/reproduction/lifecycle.mjs +253 -0
- package/src/reproduction/plan.mjs +132 -0
- package/src/reproduction/prompts.mjs +70 -0
- package/src/reproduction/runner.mjs +188 -0
- package/src/reproduction/summary.mjs +130 -0
- package/src/reproduction/workspace-mode.mjs +7 -0
- package/src/research/automatic-admission.mjs +156 -0
- package/src/research/compiler-coverage.mjs +85 -0
- package/src/research/compiler-failure.mjs +24 -0
- package/src/research/compiler-normalization-guards.mjs +112 -0
- package/src/research/compiler-repair.mjs +3 -0
- package/src/research/compiler.mjs +853 -0
- package/src/research/continuation-selection.mjs +26 -0
- package/src/research/execution-graph-context.mjs +43 -0
- package/src/research/experiment-importance.mjs +15 -0
- package/src/research/inventory-handoff.mjs +104 -0
- package/src/research/inventory-revisions.mjs +32 -0
- package/src/research/mineru-local.mjs +73 -0
- package/src/research/paper-command.mjs +19 -0
- package/src/research/paper-markdown.mjs +180 -0
- package/src/research/paper-source-map.mjs +69 -0
- package/src/research/planning-policy.mjs +88 -0
- package/src/research/reference-materials.mjs +11 -0
- package/src/research/reproduction-scope.mjs +30 -0
- package/src/research/research-map.mjs +94 -0
- package/src/research/research-objects.mjs +88 -0
- package/src/research/source-discovery.mjs +646 -0
- package/src/research/source-observations.mjs +75 -0
- package/src/research/source-review-cli-mcp.mjs +26 -0
- package/src/research/source-review-input.mjs +209 -0
- package/src/research/source-review-local-codex.mjs +36 -0
- package/src/research/source-review-model.mjs +70 -0
- package/src/research/source-review.mjs +173 -0
- package/src/research/structure.mjs +3163 -0
- package/src/research-card/renderer.mjs +277 -0
- package/src/research-card/verified-conclusion.mjs +143 -0
- package/src/results/output-registry.mjs +183 -0
- package/src/runtime/claude-code.mjs +52 -0
- package/src/runtime/codex-capacity-retry.mjs +87 -0
- package/src/runtime/codex.mjs +64 -0
- package/src/runtime/config.mjs +157 -0
- package/src/runtime/final-output.mjs +40 -0
- package/src/runtime/index.mjs +21 -0
- package/src/runtime/local-codex.mjs +74 -0
- package/src/runtime/opencode.mjs +95 -0
- package/src/runtime/prompt.mjs +13 -0
- package/src/sandbox/docker.mjs +363 -0
- package/src/settings/command.mjs +297 -0
- package/src/settings/store.mjs +119 -0
- package/src/telemetry/pricing.mjs +68 -0
- package/src/telemetry/usage.mjs +265 -0
- package/src/terminal/events.mjs +97 -0
- package/src/terminal/input.mjs +40 -0
- package/src/terminal/plain.mjs +40 -0
- package/src/terminal/remote-stream.mjs +22 -0
- package/src/terminal/screen.mjs +214 -0
- package/src/terminal/transcript.mjs +69 -0
- package/src/util.mjs +107 -0
- package/src/verification/ai-assessor.mjs +534 -0
- package/src/verification/claim-evaluator.mjs +242 -0
- package/src/verification/evidence-context.mjs +165 -0
- package/src/verification/evidence-reader.mjs +95 -0
- package/src/verification/integrity.mjs +570 -0
- package/src/verification/tolerance.mjs +32 -0
- package/src/workloads/cpu-research-preparation.mjs +56 -0
- package/src/workloads/definition.mjs +74 -0
- package/src/workloads/phase-aware-reproduction.mjs +46 -0
- package/src/workloads/reproduction.mjs +85 -0
- package/src/workspace/command.mjs +242 -0
- package/src/workspace/control.mjs +49 -0
- package/src/workspace/entry.mjs +28 -0
- package/src/workspace/input.mjs +93 -0
- package/src/workspace/interactive.mjs +94 -0
- package/src/workspace/jobs.mjs +418 -0
- package/src/workspace/session.mjs +97 -0
- package/src/workspace/worker.mjs +137 -0
- package/ui/arkgraph/ambient-motion.mjs +10 -0
- package/ui/arkgraph/app.jsx +153 -0
- package/ui/arkgraph/boot.js +6 -0
- package/ui/arkgraph/camera-motion.mjs +20 -0
- package/ui/arkgraph/context-reveal.mjs +39 -0
- package/ui/arkgraph/details.css +3 -0
- package/ui/arkgraph/entry.jsx +28 -0
- package/ui/arkgraph/experiment-curves.mjs +17 -0
- package/ui/arkgraph/experiment-selection.mjs +15 -0
- package/ui/arkgraph/experiment-style.css +26 -0
- package/ui/arkgraph/experiment-ui.jsx +32 -0
- package/ui/arkgraph/frame.html +1 -0
- package/ui/arkgraph/graph-gestures.mjs +62 -0
- package/ui/arkgraph/label-layout.mjs +57 -0
- package/ui/arkgraph/locales/en.json +229 -0
- package/ui/arkgraph/locales/source-types.json +15 -0
- package/ui/arkgraph/localization-build.mjs +27 -0
- package/ui/arkgraph/material-build.mjs +23 -0
- package/ui/arkgraph/material-colors.mjs +39 -0
- package/ui/arkgraph/material-style.css +15 -0
- package/ui/arkgraph/open-graph.jsx +326 -0
- package/ui/arkgraph/outline.jsx +49 -0
- package/ui/arkgraph/package-lock.json +888 -0
- package/ui/arkgraph/package.json +17 -0
- package/ui/arkgraph/reading-layout.mjs +130 -0
- package/ui/arkgraph/reading-presentation.mjs +73 -0
- package/ui/arkgraph/record-detail.css +51 -0
- package/ui/arkgraph/record-details.jsx +29 -0
- package/ui/arkgraph/research-types.mjs +31 -0
- package/ui/arkgraph/selection-mark.jsx +6 -0
- package/ui/arkgraph/soft-spine.mjs +26 -0
- package/ui/arkgraph/steering-style.css +187 -0
- package/ui/arkgraph/style.css +272 -0
|
@@ -0,0 +1,685 @@
|
|
|
1
|
+
import { hasSessionEvents } from '../terminal/events.mjs';
|
|
2
|
+
import { needsCompilerRepairGeneration } from "../research/compiler-repair.mjs";
|
|
3
|
+
import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { createHash } from "node:crypto";
|
|
7
|
+
|
|
8
|
+
import { restoreRunRecovery, saveRunRecovery, saveRemoteRecovery, restoreRemoteRecovery } from "./coordinator-recovery.mjs";
|
|
9
|
+
import { GcpBatchClient } from "../gcp/batch-client.mjs";
|
|
10
|
+
import { GoogleAccessTokenProvider } from "../gcp/auth.mjs";
|
|
11
|
+
import { GcsStagingClient } from "../gcp/storage.mjs";
|
|
12
|
+
import {
|
|
13
|
+
ensureFinalWorkspaceCapture,
|
|
14
|
+
updateRunState,
|
|
15
|
+
} from "../job.mjs";
|
|
16
|
+
import { captureProcess } from "../process.mjs";
|
|
17
|
+
import { createRemoteStageArchive } from "./stage-archive.mjs";
|
|
18
|
+
import {
|
|
19
|
+
acceptCompilerDraft,
|
|
20
|
+
compilerPrompt,
|
|
21
|
+
normalizeCompilationTask,
|
|
22
|
+
prepareCompilationBundle,
|
|
23
|
+
} from "../research/compiler.mjs";
|
|
24
|
+
import { researchCompilationFailure } from "../research/compiler-failure.mjs";
|
|
25
|
+
import { agentInvocationPromptArgument, buildAgentInvocation } from "../runtime/index.mjs";
|
|
26
|
+
import { publicAgentRuntime, resolveAgentRuntime } from "../runtime/config.mjs";
|
|
27
|
+
import {
|
|
28
|
+
CODEX_FINAL_MESSAGE_PATH,
|
|
29
|
+
recoverJsonFromFinalMessage,
|
|
30
|
+
} from "../runtime/final-output.mjs";
|
|
31
|
+
import { readAgentUsage } from "../telemetry/usage.mjs";
|
|
32
|
+
import {
|
|
33
|
+
CiteArkError,
|
|
34
|
+
createRunId,
|
|
35
|
+
pathExists,
|
|
36
|
+
readJson,
|
|
37
|
+
writeJson,
|
|
38
|
+
} from "../util.mjs";
|
|
39
|
+
import {
|
|
40
|
+
buildGcpBatchJob,
|
|
41
|
+
remoteProviderSession,
|
|
42
|
+
resolveCheckpointObjects,
|
|
43
|
+
resolveGcpBatchConfig,
|
|
44
|
+
} from "./gcp-batch-job.mjs";
|
|
45
|
+
import { assertSuccessfulGcpBatchTerminal } from "./gcp-batch-failure.mjs";
|
|
46
|
+
import {
|
|
47
|
+
createLockedBatchJob,
|
|
48
|
+
deleteBatchJob,
|
|
49
|
+
releaseBatchJobAccountLock,
|
|
50
|
+
} from "./gcp-batch-lifecycle.mjs";
|
|
51
|
+
import {
|
|
52
|
+
classifyProviderActionRequired,
|
|
53
|
+
describeRemoteAgentFailure,
|
|
54
|
+
} from "./remote-attempt.mjs";
|
|
55
|
+
|
|
56
|
+
const COMPILER_ACTIVITY_WAITING_SECONDS = 2 * 60;
|
|
57
|
+
|
|
58
|
+
export async function executeGcpBatchCompilation({
|
|
59
|
+
taskPath,
|
|
60
|
+
runsDirectory,
|
|
61
|
+
runId = createRunId(),
|
|
62
|
+
agentRuntime,
|
|
63
|
+
computeProfile,
|
|
64
|
+
executorOptions = {},
|
|
65
|
+
dryRun = false,
|
|
66
|
+
progress = () => {},
|
|
67
|
+
sourceReviewer,
|
|
68
|
+
prepareMarkdown,
|
|
69
|
+
validateResearch = async () => [],
|
|
70
|
+
}) {
|
|
71
|
+
const absoluteTaskPath = path.resolve(taskPath);
|
|
72
|
+
const taskDirectory = path.dirname(absoluteTaskPath);
|
|
73
|
+
const task = normalizeCompilationTask(await readJson(absoluteTaskPath));
|
|
74
|
+
const runtimeAgent = resolveAgentRuntime({
|
|
75
|
+
taskAgent: task.agent,
|
|
76
|
+
...agentRuntime,
|
|
77
|
+
requireApi: false,
|
|
78
|
+
});
|
|
79
|
+
assertCompilerProfile(computeProfile);
|
|
80
|
+
task.environment = {
|
|
81
|
+
...task.environment,
|
|
82
|
+
image: computeProfile.image,
|
|
83
|
+
cpus: computeProfile.cpuCores,
|
|
84
|
+
memoryGb: computeProfile.memoryGb,
|
|
85
|
+
gpu: computeProfile.accelerator === "gpu" ? "all" : "none",
|
|
86
|
+
};
|
|
87
|
+
const bundle = await restoreRunRecovery({ runsDirectory, runId }) ?? await prepareCompilationBundle({
|
|
88
|
+
task,
|
|
89
|
+
taskDirectory,
|
|
90
|
+
runsDirectory,
|
|
91
|
+
runId,
|
|
92
|
+
prepareMarkdown,
|
|
93
|
+
});
|
|
94
|
+
bundle.runtimeAgent = { ...runtimeAgent, paperBudgetEnforced: Boolean(executorOptions.gcpBatch?.paperBudget) };
|
|
95
|
+
bundle.paperBudget = executorOptions.gcpBatch?.paperBudget;
|
|
96
|
+
bundle.computeDecision = {
|
|
97
|
+
schemaVersion: "0.1",
|
|
98
|
+
selectedProfile: structuredClone(computeProfile),
|
|
99
|
+
};
|
|
100
|
+
bundle.executionEnvironment = structuredClone(task.environment);
|
|
101
|
+
bundle.sandboxProvider = "gcp-batch";
|
|
102
|
+
await updateRunState(bundle, {
|
|
103
|
+
runtime: runtimeAgent.runtime,
|
|
104
|
+
agent: publicAgentRuntime(runtimeAgent),
|
|
105
|
+
sandbox: "gcp-batch",
|
|
106
|
+
image: task.environment.image,
|
|
107
|
+
executionEnvironment: bundle.executionEnvironment,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const instructions = await readFile(
|
|
111
|
+
path.join(bundle.directories.input, "agent-instructions.md"),
|
|
112
|
+
"utf8",
|
|
113
|
+
);
|
|
114
|
+
const gcpOptions = executorOptions.gcpBatch ?? {};
|
|
115
|
+
const config = resolveGcpBatchConfig({ bundle, options: gcpOptions });
|
|
116
|
+
bundle.sourceReviewProviderSecret = config.providerSecret;
|
|
117
|
+
const clients = createClients(config, gcpOptions.clients);
|
|
118
|
+
const temporaryDirectory = await mkdtemp(
|
|
119
|
+
path.join(os.tmpdir(), "citeark-gcp-compiler-"),
|
|
120
|
+
);
|
|
121
|
+
const jobs = bundle.restored ? [...(bundle.state.cloudExecution?.jobs ?? [])] : [];
|
|
122
|
+
const stagedObjects = new Set();
|
|
123
|
+
let validationIssues = ["research.json 尚未生成"];
|
|
124
|
+
let normalizedResearch = null;
|
|
125
|
+
let normalizationWarnings = [];
|
|
126
|
+
let blockingFailure = null;
|
|
127
|
+
let successful = false;
|
|
128
|
+
let processingLeaseLost = false;
|
|
129
|
+
await mkdir(path.join(bundle.directories.execution, "prompts"), { recursive: true });
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
if (bundle.restored && bundle.state.status === "completed" && await pathExists(path.join(bundle.directories.output, "research.normalized.json"))) {
|
|
133
|
+
const research = await readJson(path.join(bundle.directories.output, bundle.sourceInventory ? "research.json" : "research.normalized.json"));
|
|
134
|
+
const accepted = await acceptCompilerDraft({ bundle, draft: research, validateResearch, sourceReviewer })
|
|
135
|
+
.catch((error) => { throw researchCompilationFailure([error.message], error.failureCode === "compiler.source_review_unavailable" ? { code: error.failureCode, retryable: false } : null); });
|
|
136
|
+
successful = true;
|
|
137
|
+
progress("复用已完成的 Research Compiler 输出,不创建计算任务");
|
|
138
|
+
return { dryRun: false, bundle, research: accepted.research, normalizationWarnings: accepted.normalizationWarnings, jobs };
|
|
139
|
+
}
|
|
140
|
+
let resumedJob = null;
|
|
141
|
+
const previous = jobs.at(-1) ?? bundle.state.recoveryPendingJob;
|
|
142
|
+
if (bundle.restored && previous?.name && typeof clients.batch.findJob === "function") {
|
|
143
|
+
resumedJob = await clients.batch.findJob(previous.name);
|
|
144
|
+
if (resumedJob && new Set(["FAILED", "CANCELLED"]).has(resumedJob.status?.state)) {
|
|
145
|
+
await updateCompilerCloudObservation({ bundle, config, jobs, record: previous, job: resumedJob, state: resumedJob.status.state,
|
|
146
|
+
checkpointStatus: previous.checkpointStatus, storage: clients.storage, progress });
|
|
147
|
+
await saveRemoteRecovery({ bundle, storage: clients.storage, bucket: config.stagingBucket, record: previous, persist: gcpOptions.onCheckpoint, recoveryBucket: gcpOptions.recoveryBucket, recoveryNamespace: gcpOptions.recoveryNamespace });
|
|
148
|
+
await clients.batch.deleteJob(previous.name);
|
|
149
|
+
await releaseCompilerAccountLock({ bundle, config, clients, record: previous });
|
|
150
|
+
resumedJob = null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// A transport-successful VM can still contain a failed Agent process.
|
|
154
|
+
// Preserve its accounting, but resume the workspace in a new generation
|
|
155
|
+
// instead of repeatedly importing the same failed archive. Source-review
|
|
156
|
+
// recovery without a process failure retains its independent reuse path.
|
|
157
|
+
const rejectedAgentOutput = bundle.state.status === "invalid_result"
|
|
158
|
+
? await describeRemoteAgentFailure(bundle, previous?.attempt ?? 1) : null;
|
|
159
|
+
if (needsCompilerRepairGeneration(gcpOptions.compilerRepair, bundle.state.status, resumedJob?.status?.state)
|
|
160
|
+
|| (rejectedAgentOutput && resumedJob?.status?.state === "SUCCEEDED")) resumedJob = null;
|
|
161
|
+
if (bundle.restored && !resumedJob) {
|
|
162
|
+
const restored = await restoreRemoteRecovery({ bundle, storage: clients.storage, bucket: config.stagingBucket });
|
|
163
|
+
if (restored) { config.restoreCheckpointPrefix = restored.checkpointPrefix; config.restoreCheckpointBucket = restored.bucket; }
|
|
164
|
+
bundle.state.recoveryGeneration = (bundle.state.recoveryGeneration ?? 0) + 1;
|
|
165
|
+
config.stagingPrefix += `-r${bundle.state.recoveryGeneration}`;
|
|
166
|
+
}
|
|
167
|
+
const maxAttempts = 1 + runtimeAgent.validationRetries;
|
|
168
|
+
const checkpointAttempt = 1;
|
|
169
|
+
for (let attempt = bundle.restored ? previous?.attempt ?? 1 : 1; attempt <= maxAttempts; attempt += 1) {
|
|
170
|
+
const invocation = await buildAgentInvocation({
|
|
171
|
+
bundle,
|
|
172
|
+
attempt,
|
|
173
|
+
prompt: compilerPrompt(attempt, validationIssues, {
|
|
174
|
+
continuation: bundle.runtimeTask?.continuation,
|
|
175
|
+
repairBaseline: bundle.repairBaselineResearch,
|
|
176
|
+
}),
|
|
177
|
+
instructions,
|
|
178
|
+
providerSession: remoteProviderSession(bundle.runtimeAgent),
|
|
179
|
+
});
|
|
180
|
+
const resumeInvocation = await buildAgentInvocation({
|
|
181
|
+
bundle,
|
|
182
|
+
attempt: 2,
|
|
183
|
+
prompt: [
|
|
184
|
+
"Continue from the restored compilation workspace. Inspect preserved artifacts and apply the current task below; a prior research.json may still contain the rejected draft.",
|
|
185
|
+
compilerPrompt(attempt, validationIssues, {
|
|
186
|
+
continuation: bundle.runtimeTask?.continuation,
|
|
187
|
+
repairBaseline: bundle.repairBaselineResearch,
|
|
188
|
+
}),
|
|
189
|
+
].join("\n\n"),
|
|
190
|
+
instructions,
|
|
191
|
+
providerSession: remoteProviderSession(bundle.runtimeAgent),
|
|
192
|
+
});
|
|
193
|
+
await writeFile(
|
|
194
|
+
path.join(bundle.directories.execution, "prompts", `attempt-${attempt}.txt`),
|
|
195
|
+
`${agentInvocationPromptArgument(invocation)}\n`,
|
|
196
|
+
);
|
|
197
|
+
await writeFile(
|
|
198
|
+
path.join(bundle.directories.execution, "prompts", `attempt-${attempt}-resume.txt`),
|
|
199
|
+
`${agentInvocationPromptArgument(resumeInvocation)}\n`,
|
|
200
|
+
);
|
|
201
|
+
const preview = compilerJobPreview({
|
|
202
|
+
bundle,
|
|
203
|
+
invocation,
|
|
204
|
+
resumeInvocation,
|
|
205
|
+
attempt,
|
|
206
|
+
config,
|
|
207
|
+
checkpointAttempt,
|
|
208
|
+
restoreCheckpointOnStart: attempt > 1 || Boolean(config.restoreCheckpointPrefix),
|
|
209
|
+
reuseCompletedResultOnRestore: attempt === 1 && !rejectedAgentOutput && !gcpOptions.compilerRepair,
|
|
210
|
+
});
|
|
211
|
+
await writeJson(
|
|
212
|
+
path.join(bundle.directories.execution, `gcp-batch-job-a${attempt}.json`),
|
|
213
|
+
{ schemaVersion: "0.1", executor: "gcp-batch", jobId: preview.jobId, job: sanitizeJob(preview.job) },
|
|
214
|
+
);
|
|
215
|
+
if (dryRun) {
|
|
216
|
+
await updateRunState(bundle, { status: "prepared" });
|
|
217
|
+
return { dryRun: true, bundle, invocation, jobSpec: preview.job };
|
|
218
|
+
}
|
|
219
|
+
if (attempt === 1) {
|
|
220
|
+
await updateRunState(bundle, {
|
|
221
|
+
status: "running",
|
|
222
|
+
startedAt: new Date().toISOString(),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
const stageArchive = path.join(temporaryDirectory, preview.stageFilename);
|
|
226
|
+
const resultArchive = path.join(temporaryDirectory, preview.resultFilename);
|
|
227
|
+
if (!resumedJob) await createStageArchive(bundle, stageArchive);
|
|
228
|
+
stagedObjects.add(preview.stageObject);
|
|
229
|
+
stagedObjects.add(preview.resultObject);
|
|
230
|
+
if (hasSessionEvents()) stagedObjects.add(`${preview.resultObject}.trace.jsonl`);
|
|
231
|
+
stagedObjects.add(preview.checkpointStatus);
|
|
232
|
+
progress(`GCP Batch ${bundle.runId}: 上传 Research Compiler 输入`);
|
|
233
|
+
if (!resumedJob) await clients.storage.uploadFile({
|
|
234
|
+
bucket: config.stagingBucket,
|
|
235
|
+
object: preview.stageObject,
|
|
236
|
+
filePath: stageArchive,
|
|
237
|
+
});
|
|
238
|
+
try {
|
|
239
|
+
await gcpOptions.assertActive?.();
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (error?.processingLeaseLost === true) processingLeaseLost = true;
|
|
242
|
+
throw error;
|
|
243
|
+
}
|
|
244
|
+
progress(`GCP Batch ${bundle.runId}: 创建 Research Compiler Job ${preview.jobId}`);
|
|
245
|
+
bundle.state.recoveryPendingJob = { jobId: preview.jobId, name: clients.batch.jobName(preview.jobId), attempt,
|
|
246
|
+
resultObject: preview.resultObject, checkpointPrefix: resolveCheckpointObjects(config, checkpointAttempt).prefix,
|
|
247
|
+
checkpointStatus: preview.checkpointStatus };
|
|
248
|
+
await saveRunRecovery(bundle, gcpOptions.onCheckpoint);
|
|
249
|
+
const created = resumedJob ?? await createLockedBatchJob({
|
|
250
|
+
storage: clients.storage,
|
|
251
|
+
batch: clients.batch,
|
|
252
|
+
bucket: config.stagingBucket,
|
|
253
|
+
accountId: bundle.runtimeAgent.codexAccountId,
|
|
254
|
+
owner: `${bundle.runId}-${attempt}`,
|
|
255
|
+
jobId: preview.jobId,
|
|
256
|
+
job: preview.job,
|
|
257
|
+
});
|
|
258
|
+
const jobName = created?.name ?? clients.batch.jobName(preview.jobId);
|
|
259
|
+
const record = resumedJob ? previous : {
|
|
260
|
+
attempt,
|
|
261
|
+
jobId: preview.jobId,
|
|
262
|
+
name: jobName,
|
|
263
|
+
state: "QUEUED",
|
|
264
|
+
startedAt: new Date().toISOString(),
|
|
265
|
+
checkpointStatus: preview.checkpointStatus,
|
|
266
|
+
checkpointPrefix: resolveCheckpointObjects(config, checkpointAttempt).prefix,
|
|
267
|
+
resultObject: preview.resultObject,
|
|
268
|
+
checkpoint: null,
|
|
269
|
+
activity: null,
|
|
270
|
+
codexAccountLockOwner: `${bundle.runId}-${attempt}`,
|
|
271
|
+
};
|
|
272
|
+
if (!jobs.includes(record)) jobs.push(record);
|
|
273
|
+
await saveRunRecovery(bundle, gcpOptions.onCheckpoint);
|
|
274
|
+
const terminal = await clients.batch.waitForTerminal(jobName, {
|
|
275
|
+
liveOutput: { storage: clients.storage, bucket: config.stagingBucket, object: `${record.resultObject}.trace.jsonl`, source: `${bundle.runId}:${attempt}`, runtime: bundle.runtimeAgent.runtime },
|
|
276
|
+
timeoutMs: config.waitTimeoutMinutes * 60_000,
|
|
277
|
+
pollIntervalMs: config.pollIntervalMs,
|
|
278
|
+
onState: (state) => {
|
|
279
|
+
progress(`GCP Batch ${preview.jobId}: ${state}`);
|
|
280
|
+
},
|
|
281
|
+
onPoll: async (observedJob, state) => {
|
|
282
|
+
try {
|
|
283
|
+
await gcpOptions.assertActive?.();
|
|
284
|
+
} catch (error) {
|
|
285
|
+
if (error?.processingLeaseLost === true) processingLeaseLost = true;
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
const previousRecovery = `${record.state}:${record.checkpoint?.sequence ?? ""}`;
|
|
289
|
+
await updateCompilerCloudObservation({
|
|
290
|
+
bundle,
|
|
291
|
+
config,
|
|
292
|
+
jobs,
|
|
293
|
+
record,
|
|
294
|
+
job: observedJob,
|
|
295
|
+
state,
|
|
296
|
+
checkpointStatus: record.checkpointStatus,
|
|
297
|
+
storage: clients.storage,
|
|
298
|
+
progress,
|
|
299
|
+
});
|
|
300
|
+
if (previousRecovery !== `${record.state}:${record.checkpoint?.sequence ?? ""}`) await saveRemoteRecovery({ bundle,
|
|
301
|
+
storage: clients.storage, bucket: config.stagingBucket, record, persist: gcpOptions.onCheckpoint, recoveryBucket: gcpOptions.recoveryBucket, recoveryNamespace: gcpOptions.recoveryNamespace });
|
|
302
|
+
},
|
|
303
|
+
});
|
|
304
|
+
await updateCompilerCloudObservation({
|
|
305
|
+
bundle,
|
|
306
|
+
config,
|
|
307
|
+
jobs,
|
|
308
|
+
record,
|
|
309
|
+
job: terminal,
|
|
310
|
+
state: terminal?.status?.state ?? record.state,
|
|
311
|
+
checkpointStatus: preview.checkpointStatus,
|
|
312
|
+
storage: clients.storage,
|
|
313
|
+
progress,
|
|
314
|
+
});
|
|
315
|
+
await saveRemoteRecovery({ bundle, storage: clients.storage, bucket: config.stagingBucket, record, persist: gcpOptions.onCheckpoint, recoveryBucket: gcpOptions.recoveryBucket, recoveryNamespace: gcpOptions.recoveryNamespace });
|
|
316
|
+
record.state = terminal?.status?.state ?? record.state;
|
|
317
|
+
record.finishedAt = new Date().toISOString();
|
|
318
|
+
await releaseCompilerAccountLock({ bundle, config, clients, record });
|
|
319
|
+
await writeJson(
|
|
320
|
+
path.join(bundle.directories.execution, `gcp-batch-result-a${attempt}.json`),
|
|
321
|
+
sanitizeJob(terminal),
|
|
322
|
+
);
|
|
323
|
+
assertSuccessfulGcpBatchTerminal({
|
|
324
|
+
job: terminal,
|
|
325
|
+
jobId: preview.jobId,
|
|
326
|
+
workload: "Research Compiler",
|
|
327
|
+
});
|
|
328
|
+
await clients.storage.downloadFile({
|
|
329
|
+
bucket: config.stagingBucket,
|
|
330
|
+
object: record.resultObject ?? preview.resultObject,
|
|
331
|
+
filePath: resultArchive,
|
|
332
|
+
});
|
|
333
|
+
await extractResultArchive(bundle, resultArchive);
|
|
334
|
+
resumedJob = null;
|
|
335
|
+
await saveRunRecovery(bundle, gcpOptions.onCheckpoint);
|
|
336
|
+
|
|
337
|
+
const researchPath = path.join(bundle.directories.output, "research.json");
|
|
338
|
+
await recoverJsonFromFinalMessage({
|
|
339
|
+
finalMessagePath: hostRuntimePath(bundle, CODEX_FINAL_MESSAGE_PATH),
|
|
340
|
+
outputPath: researchPath,
|
|
341
|
+
});
|
|
342
|
+
const remoteFailure = await describeRemoteAgentFailure(bundle, attempt);
|
|
343
|
+
if (remoteFailure?.failureCode === "agent.effective_progress_stalled") {
|
|
344
|
+
blockingFailure = {
|
|
345
|
+
code: remoteFailure.failureCode,
|
|
346
|
+
failureCategory: "timeout",
|
|
347
|
+
retryable: false,
|
|
348
|
+
message: remoteFailure.message,
|
|
349
|
+
recoveryAction: "保留编译现场并停止自动重跑;检查模型请求与编译任务书后创建显式续跑任务",
|
|
350
|
+
};
|
|
351
|
+
validationIssues = [remoteFailure.message];
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
const providerFailure = remoteFailure?.failureCategory === "provider" && remoteFailure.retryable === false
|
|
355
|
+
? { code: remoteFailure.failureCode, failureCategory: "provider", retryable: false, message: remoteFailure.message, recoveryAction: remoteFailure.recoveryAction }
|
|
356
|
+
: classifyProviderActionRequired(remoteFailure?.message);
|
|
357
|
+
if (providerFailure) {
|
|
358
|
+
blockingFailure = providerFailure;
|
|
359
|
+
validationIssues = [providerFailure.message];
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
// A syntactically valid compiler file can still be an unfinished draft.
|
|
363
|
+
// Transport publication errors retain their independent recovery path.
|
|
364
|
+
if (remoteFailure && remoteFailure.failureCategory !== "publication") {
|
|
365
|
+
blockingFailure = { code: remoteFailure.failureCode ?? "compiler.agent_incomplete",
|
|
366
|
+
failureCategory: remoteFailure.failureCategory, retryable: remoteFailure.retryable };
|
|
367
|
+
validationIssues = [remoteFailure.message];
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
try {
|
|
371
|
+
if (!(await pathExists(researchPath))) {
|
|
372
|
+
throw new CiteArkError("缺少 /job/output/research.json");
|
|
373
|
+
}
|
|
374
|
+
const accepted = await acceptCompilerDraft({ bundle, draft: await readJson(researchPath), validateResearch, sourceReviewer });
|
|
375
|
+
normalizedResearch = accepted.research;
|
|
376
|
+
normalizationWarnings = accepted.normalizationWarnings;
|
|
377
|
+
validationIssues = [];
|
|
378
|
+
break;
|
|
379
|
+
} catch (error) {
|
|
380
|
+
validationIssues = [
|
|
381
|
+
...(remoteFailure ? [remoteFailure.message] : []),
|
|
382
|
+
error instanceof Error ? error.message : String(error),
|
|
383
|
+
];
|
|
384
|
+
if (error.failureCode === "compiler.source_review_unavailable") { blockingFailure = { code: error.failureCode, retryable: false }; break; }
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
await ensureFinalWorkspaceCapture(bundle);
|
|
389
|
+
const usage = await readAgentUsage(
|
|
390
|
+
path.join(bundle.directories.execution, "trace.jsonl"),
|
|
391
|
+
{ runtimeHome: bundle.directories.runtimeHome, model: runtimeAgent.model },
|
|
392
|
+
);
|
|
393
|
+
const status = validationIssues.length ? "invalid_result" : "completed";
|
|
394
|
+
await updateRunState(bundle, {
|
|
395
|
+
status,
|
|
396
|
+
finishedAt: new Date().toISOString(),
|
|
397
|
+
validationIssues,
|
|
398
|
+
normalizationWarnings,
|
|
399
|
+
output: normalizedResearch ? "output/research.normalized.json" : null,
|
|
400
|
+
sandboxImageIdentity: remoteImageIdentity(task.environment.image),
|
|
401
|
+
cloudExecution: compilerCloudExecution(config, jobs),
|
|
402
|
+
usage,
|
|
403
|
+
});
|
|
404
|
+
await saveRunRecovery(bundle, gcpOptions.onCheckpoint);
|
|
405
|
+
if (validationIssues.length || !normalizedResearch) {
|
|
406
|
+
throw researchCompilationFailure(validationIssues, blockingFailure);
|
|
407
|
+
}
|
|
408
|
+
const result = {
|
|
409
|
+
dryRun: false,
|
|
410
|
+
bundle,
|
|
411
|
+
research: normalizedResearch,
|
|
412
|
+
normalizationWarnings,
|
|
413
|
+
jobs,
|
|
414
|
+
};
|
|
415
|
+
successful = true;
|
|
416
|
+
return result;
|
|
417
|
+
} finally {
|
|
418
|
+
if (!config.keepJob && (successful || processingLeaseLost)) {
|
|
419
|
+
for (const job of jobs) {
|
|
420
|
+
await deleteBatchJob({ batch: clients.batch, record: job });
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
for (const job of jobs) {
|
|
424
|
+
if (job.jobDeletionRequested || new Set(["SUCCEEDED", "FAILED", "CANCELLED"]).has(job.state)) {
|
|
425
|
+
await releaseCompilerAccountLock({ bundle, config, clients, record: job });
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (!config.keepStaging && (successful || processingLeaseLost)) {
|
|
429
|
+
const checkpointObjects = typeof clients.storage.listObjects === "function"
|
|
430
|
+
? await clients.storage.listObjects({
|
|
431
|
+
bucket: config.stagingBucket,
|
|
432
|
+
prefix: `${config.stagingPrefix.replaceAll(/[^a-zA-Z0-9_.-]/g, "-")}-checkpoint-`,
|
|
433
|
+
}).catch(() => [])
|
|
434
|
+
: [];
|
|
435
|
+
for (const object of checkpointObjects) stagedObjects.add(object);
|
|
436
|
+
await Promise.all(
|
|
437
|
+
[...stagedObjects].map((object) =>
|
|
438
|
+
clients.storage.deleteObject({ bucket: config.stagingBucket, object }).catch(() => undefined),
|
|
439
|
+
),
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
await rm(temporaryDirectory, { recursive: true, force: true });
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
async function releaseCompilerAccountLock({ bundle, config, clients, record }) {
|
|
447
|
+
await releaseBatchJobAccountLock({
|
|
448
|
+
storage: clients.storage,
|
|
449
|
+
bucket: config.stagingBucket,
|
|
450
|
+
accountId: bundle.runtimeAgent?.codexAccountId,
|
|
451
|
+
owner: record?.codexAccountLockOwner ?? `${bundle.runId}-${record?.attempt ?? 1}`,
|
|
452
|
+
jobName: record?.name,
|
|
453
|
+
record,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function hostRuntimePath(bundle, containerPath) {
|
|
458
|
+
return path.join(bundle.directories.run, containerPath.replace(/^\/job\//, ""));
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export function compilerBatchJobId(runId, attempt, recoveryGeneration = 0) {
|
|
462
|
+
const stem = runId.toLowerCase().replaceAll(/[^a-z0-9-]/g, "-").replaceAll(/^-+|-+$/g, "");
|
|
463
|
+
const suffix = `-compile-a${attempt}${recoveryGeneration ? `-r${recoveryGeneration}` : ""}`;
|
|
464
|
+
if (stem.length + suffix.length <= 63) return `${stem}${suffix}`;
|
|
465
|
+
const digest = createHash("sha256").update(runId).digest("hex").slice(0, 10);
|
|
466
|
+
return `${stem.slice(0, 63 - suffix.length - digest.length - 1)}-${digest}${suffix}`;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function compilerJobPreview({
|
|
470
|
+
bundle,
|
|
471
|
+
invocation,
|
|
472
|
+
resumeInvocation,
|
|
473
|
+
attempt,
|
|
474
|
+
config,
|
|
475
|
+
checkpointAttempt = attempt,
|
|
476
|
+
restoreCheckpointOnStart = false,
|
|
477
|
+
reuseCompletedResultOnRestore = true,
|
|
478
|
+
}) {
|
|
479
|
+
const jobId = compilerBatchJobId(bundle.runId, attempt, bundle.state.recoveryGeneration);
|
|
480
|
+
const stageFilename = `compile-stage-a${attempt}.tar.gz`;
|
|
481
|
+
const resultFilename = `compile-result-a${attempt}.tar.gz`;
|
|
482
|
+
const objectPrefix = config.stagingPrefix.replaceAll(/[^a-zA-Z0-9_.-]/g, "-");
|
|
483
|
+
const stageObject = `${objectPrefix}-${stageFilename}`;
|
|
484
|
+
const resultObject = `${objectPrefix}-${resultFilename}`;
|
|
485
|
+
const checkpoint = resolveCheckpointObjects(config, checkpointAttempt);
|
|
486
|
+
return {
|
|
487
|
+
jobId,
|
|
488
|
+
stageFilename,
|
|
489
|
+
resultFilename,
|
|
490
|
+
stageObject,
|
|
491
|
+
resultObject,
|
|
492
|
+
checkpointStatus: checkpoint.status,
|
|
493
|
+
job: buildGcpBatchJob({
|
|
494
|
+
bundle,
|
|
495
|
+
invocation,
|
|
496
|
+
resumeInvocation,
|
|
497
|
+
attempt,
|
|
498
|
+
config,
|
|
499
|
+
stageObject,
|
|
500
|
+
resultObject,
|
|
501
|
+
checkpointPrefix: checkpoint.prefix,
|
|
502
|
+
checkpointStatus: checkpoint.status,
|
|
503
|
+
completionRelativePath: "output/research.json",
|
|
504
|
+
completionHasEvidence: false,
|
|
505
|
+
workload: "compilation",
|
|
506
|
+
restoreCheckpointOnStart,
|
|
507
|
+
restoreCheckpointPrefix: config.restoreCheckpointPrefix,
|
|
508
|
+
reuseCompletedResultOnRestore,
|
|
509
|
+
}),
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function createClients(config, injected = {}) {
|
|
514
|
+
if (injected.batch && injected.storage) return injected;
|
|
515
|
+
const auth = injected.auth ?? new GoogleAccessTokenProvider(injected.authOptions);
|
|
516
|
+
return {
|
|
517
|
+
batch: injected.batch ?? new GcpBatchClient({
|
|
518
|
+
projectId: config.projectId,
|
|
519
|
+
region: config.region,
|
|
520
|
+
auth,
|
|
521
|
+
...injected.batchOptions,
|
|
522
|
+
}),
|
|
523
|
+
storage: injected.storage ?? new GcsStagingClient({
|
|
524
|
+
auth,
|
|
525
|
+
...injected.storageOptions,
|
|
526
|
+
}),
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async function updateCompilerCloudObservation({
|
|
531
|
+
bundle,
|
|
532
|
+
config,
|
|
533
|
+
jobs,
|
|
534
|
+
record,
|
|
535
|
+
job,
|
|
536
|
+
state,
|
|
537
|
+
checkpointStatus,
|
|
538
|
+
storage,
|
|
539
|
+
progress,
|
|
540
|
+
}) {
|
|
541
|
+
const previousState = record.state;
|
|
542
|
+
const previousDigest = record.activity?.traceDigest ?? null;
|
|
543
|
+
const previousEffectiveAt = record.activity?.lastEffectiveAt ?? null;
|
|
544
|
+
const previousHealth = record.activity?.status ?? null;
|
|
545
|
+
record.state = state;
|
|
546
|
+
record.runDuration = job?.status?.runDuration ?? record.runDuration ?? null;
|
|
547
|
+
|
|
548
|
+
if (config.checkpointing.enabled && typeof storage.readJsonObject === "function") {
|
|
549
|
+
const checkpoint = await storage.readJsonObject({
|
|
550
|
+
bucket: config.stagingBucket,
|
|
551
|
+
object: checkpointStatus,
|
|
552
|
+
missing: null,
|
|
553
|
+
}).catch(() => null);
|
|
554
|
+
if (
|
|
555
|
+
checkpoint?.schemaVersion === "0.1"
|
|
556
|
+
&& typeof checkpoint.sequence === "string"
|
|
557
|
+
&& typeof checkpoint.object === "string"
|
|
558
|
+
) {
|
|
559
|
+
const activity = checkpoint.activity && typeof checkpoint.activity === "object"
|
|
560
|
+
? checkpoint.activity
|
|
561
|
+
: {};
|
|
562
|
+
const { activity: _privateActivity, ...checkpointRecord } = checkpoint;
|
|
563
|
+
record.checkpoint = checkpointRecord;
|
|
564
|
+
if (typeof activity.traceDigest === "string") {
|
|
565
|
+
const traceTail = Array.isArray(activity.traceTail) ? activity.traceTail.slice(-24) : [];
|
|
566
|
+
const lastEffectiveAt = validIso(activity.lastEffectiveAt);
|
|
567
|
+
const idleSeconds = lastEffectiveAt
|
|
568
|
+
? Math.max(0, Math.floor((Date.now() - Date.parse(lastEffectiveAt)) / 1_000))
|
|
569
|
+
: null;
|
|
570
|
+
const attemptStart = traceTail.findLastIndex((event) =>
|
|
571
|
+
event && typeof event === "object" && event.type === "citeark.attempt_started");
|
|
572
|
+
const stalled = traceTail.slice(attemptStart + 1).some((event) =>
|
|
573
|
+
event && typeof event === "object" && event.type === "citeark.agent_stalled");
|
|
574
|
+
const status = stalled
|
|
575
|
+
? "stalled"
|
|
576
|
+
: idleSeconds !== null && idleSeconds >= COMPILER_ACTIVITY_WAITING_SECONDS
|
|
577
|
+
? "waiting_for_model"
|
|
578
|
+
: "active";
|
|
579
|
+
record.activity = {
|
|
580
|
+
traceDigest: activity.traceDigest,
|
|
581
|
+
traceTail,
|
|
582
|
+
lastEffectiveAt,
|
|
583
|
+
observedAt: validIso(activity.observedAt) ?? validIso(checkpoint.createdAt),
|
|
584
|
+
idleSeconds,
|
|
585
|
+
status,
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const activityChanged = (record.activity?.traceDigest ?? null) !== previousDigest
|
|
592
|
+
|| (record.activity?.lastEffectiveAt ?? null) !== previousEffectiveAt;
|
|
593
|
+
const healthChanged = record.activity?.status !== previousHealth;
|
|
594
|
+
const stateChanged = record.state !== previousState;
|
|
595
|
+
if (!activityChanged && !healthChanged && !stateChanged) return;
|
|
596
|
+
|
|
597
|
+
if (record.activity?.status === "stalled" && (activityChanged || healthChanged)) {
|
|
598
|
+
progress(
|
|
599
|
+
"Research Compiler 已因长时间无有效进展而停止,正在保存诊断现场",
|
|
600
|
+
{ agentActivity: { ...record.activity, traceTail: undefined } },
|
|
601
|
+
);
|
|
602
|
+
} else if (activityChanged && record.activity?.lastEffectiveAt) {
|
|
603
|
+
progress(
|
|
604
|
+
`Research Compiler 有效进展更新:${record.activity.lastEffectiveAt}`,
|
|
605
|
+
{ agentActivity: { ...record.activity, traceTail: undefined } },
|
|
606
|
+
);
|
|
607
|
+
} else if (healthChanged && record.activity?.status === "waiting_for_model") {
|
|
608
|
+
progress(
|
|
609
|
+
`Research Compiler 正在等待模型响应;最近有效进展为 ${record.activity.lastEffectiveAt ?? "未知"}`,
|
|
610
|
+
{ agentActivity: { ...record.activity, traceTail: undefined } },
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
await updateRunState(bundle, {
|
|
614
|
+
cloudExecution: compilerCloudExecution(config, jobs),
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function compilerCloudExecution(config, jobs) {
|
|
619
|
+
return {
|
|
620
|
+
provider: "gcp",
|
|
621
|
+
service: "batch",
|
|
622
|
+
projectId: config.projectId,
|
|
623
|
+
region: config.region,
|
|
624
|
+
machineType: config.machineType,
|
|
625
|
+
provisioningModel: config.provisioningModel,
|
|
626
|
+
jobs,
|
|
627
|
+
};
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function validIso(value) {
|
|
631
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value))
|
|
632
|
+
? new Date(value).toISOString()
|
|
633
|
+
: null;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
async function createStageArchive(bundle, destination) {
|
|
637
|
+
await createRemoteStageArchive({
|
|
638
|
+
runDirectory: bundle.directories.run,
|
|
639
|
+
destination,
|
|
640
|
+
label: "Research Compiler",
|
|
641
|
+
paperBudget: bundle.paperBudget,
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
async function extractResultArchive(bundle, source) {
|
|
646
|
+
const result = await captureProcess(
|
|
647
|
+
"tar",
|
|
648
|
+
["-xzf", source, "-C", bundle.directories.run],
|
|
649
|
+
);
|
|
650
|
+
if (result.code !== 0) {
|
|
651
|
+
throw new CiteArkError(`解压 Research Compiler 结果失败:\n${result.stderr.trim()}`);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
function sanitizeJob(value) {
|
|
656
|
+
const clone = structuredClone(value);
|
|
657
|
+
for (const group of clone?.taskGroups ?? []) {
|
|
658
|
+
const variables = group?.taskSpec?.environment?.variables;
|
|
659
|
+
if (variables?.CITEARK_PROVIDER_SECRET_RESOURCE) {
|
|
660
|
+
variables.CITEARK_PROVIDER_SECRET_RESOURCE = "<secret-manager-version>";
|
|
661
|
+
}
|
|
662
|
+
if (variables?.CITEARK_PROVIDER_CREDENTIAL_TOKEN) {
|
|
663
|
+
variables.CITEARK_PROVIDER_CREDENTIAL_TOKEN = "<short-lived-credential-token>";
|
|
664
|
+
}
|
|
665
|
+
const secrets = group?.taskSpec?.environment?.secretVariables;
|
|
666
|
+
if (secrets) {
|
|
667
|
+
for (const key of Object.keys(secrets)) secrets[key] = "<secret-manager-version>";
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
return clone;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
function remoteImageIdentity(image) {
|
|
674
|
+
const digest = image.match(/@sha256:[0-9a-f]{64}$/)?.[0]?.slice(1) ?? null;
|
|
675
|
+
return { id: digest, repositoryDigests: digest ? [image] : [] };
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
function assertCompilerProfile(profile) {
|
|
679
|
+
if (!profile || profile.executor !== "gcp-batch") {
|
|
680
|
+
throw new CiteArkError("Research Compiler 必须使用 gcp-batch 资源规格");
|
|
681
|
+
}
|
|
682
|
+
if (typeof profile.image !== "string" || !profile.image.includes("@sha256:")) {
|
|
683
|
+
throw new CiteArkError("Research Compiler 运行镜像必须固定不可变摘要");
|
|
684
|
+
}
|
|
685
|
+
}
|