@tiangong-ai/cli 0.0.60 → 0.0.61
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/AGENTS.md +2 -2
- package/README.md +167 -26
- package/dist/research/orchestration.js +108 -18
- package/dist/research/orchestration.js.map +1 -1
- package/dist/research/workspace/acquisition-routes.d.ts +1 -1
- package/dist/research/workspace/acquisition-routes.js +2 -11
- package/dist/research/workspace/acquisition-routes.js.map +1 -1
- package/dist/research/workspace/artifact-read-audit.d.ts +16 -0
- package/dist/research/workspace/artifact-read-audit.js +176 -0
- package/dist/research/workspace/artifact-read-audit.js.map +1 -0
- package/dist/research/workspace/artifact-trace.d.ts +12 -0
- package/dist/research/workspace/artifact-trace.js +109 -0
- package/dist/research/workspace/artifact-trace.js.map +1 -0
- package/dist/research/workspace/artifact-view-mcp.d.ts +75 -0
- package/dist/research/workspace/artifact-view-mcp.js +214 -0
- package/dist/research/workspace/artifact-view-mcp.js.map +1 -0
- package/dist/research/workspace/artifact-views.d.ts +100 -0
- package/dist/research/workspace/artifact-views.js +395 -0
- package/dist/research/workspace/artifact-views.js.map +1 -0
- package/dist/research/workspace/audit-bundle.d.ts +4 -0
- package/dist/research/workspace/audit-bundle.js +107 -8
- package/dist/research/workspace/audit-bundle.js.map +1 -1
- package/dist/research/workspace/executor.d.ts +5 -1
- package/dist/research/workspace/executor.js +106 -22
- package/dist/research/workspace/executor.js.map +1 -1
- package/dist/research/workspace/native-run.d.ts +77 -0
- package/dist/research/workspace/native-run.js +637 -0
- package/dist/research/workspace/native-run.js.map +1 -0
- package/dist/research/workspace/preflight.d.ts +8 -2
- package/dist/research/workspace/preflight.js +17 -14
- package/dist/research/workspace/preflight.js.map +1 -1
- package/dist/research/workspace/project-mutations.d.ts +1 -1
- package/dist/research/workspace/project-mutations.js +5 -3
- package/dist/research/workspace/project-mutations.js.map +1 -1
- package/dist/research/workspace/projects.js +1 -0
- package/dist/research/workspace/projects.js.map +1 -1
- package/dist/research/workspace/request-provenance.d.ts +67 -0
- package/dist/research/workspace/request-provenance.js +115 -0
- package/dist/research/workspace/request-provenance.js.map +1 -0
- package/dist/research/workspace/review-executor.js +22 -11
- package/dist/research/workspace/review-executor.js.map +1 -1
- package/dist/research/workspace/runtime.d.ts +52 -0
- package/dist/research/workspace/runtime.js +221 -98
- package/dist/research/workspace/runtime.js.map +1 -1
- package/dist/research/workspace/sanitization.js +1 -1
- package/dist/research/workspace/sanitization.js.map +1 -1
- package/dist/research/workspace/schema-compatibility.d.ts +5 -0
- package/dist/research/workspace/schema-compatibility.js +55 -0
- package/dist/research/workspace/schema-compatibility.js.map +1 -0
- package/dist/research/workspace/scientific-design.js +8 -17
- package/dist/research/workspace/scientific-design.js.map +1 -1
- package/dist/research/workspace/scientific-fulfillment-audit.d.ts +3 -0
- package/dist/research/workspace/scientific-fulfillment-audit.js +137 -0
- package/dist/research/workspace/scientific-fulfillment-audit.js.map +1 -0
- package/dist/research/workspace/scientific-fulfillment.d.ts +121 -0
- package/dist/research/workspace/scientific-fulfillment.js +539 -0
- package/dist/research/workspace/scientific-fulfillment.js.map +1 -0
- package/dist/research/workspace/scientific-review-execution.js +82 -61
- package/dist/research/workspace/scientific-review-execution.js.map +1 -1
- package/dist/research/workspace/scientific-review.d.ts +5 -1
- package/dist/research/workspace/scientific-review.js +197 -52
- package/dist/research/workspace/scientific-review.js.map +1 -1
- package/dist/research/workspace/setup-catalog.js +2 -2
- package/dist/research/workspace/task-acceptance.d.ts +10 -2
- package/dist/research/workspace/task-acceptance.js +72 -8
- package/dist/research/workspace/task-acceptance.js.map +1 -1
- package/dist/research/workspace/task-audit.js +52 -2
- package/dist/research/workspace/task-audit.js.map +1 -1
- package/dist/research/workspace/task-contract.d.ts +4 -1
- package/dist/research/workspace/task-contract.js +26 -5
- package/dist/research/workspace/task-contract.js.map +1 -1
- package/dist/research/workspace/types.d.ts +6 -3
- package/package.json +1 -1
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { cp, lstat, readFile, rm } from "node:fs/promises";
|
|
2
|
+
import { cp, lstat, readFile, realpath, rm } from "node:fs/promises";
|
|
3
3
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import { CliError } from "../../errors.js";
|
|
5
5
|
import { isConsistentAnalysisRunMetadata } from "./analysis-run.js";
|
|
6
|
+
import { artifactPromptContext, artifactReadInstructions, openArtifactViews, persistArtifactReads, persistArtifactViewIndex, writeArtifactViewIndex, verifyPersistedArtifactViewIndex, } from "./artifact-views.js";
|
|
6
7
|
import { taskContext } from "./task-contract.js";
|
|
8
|
+
import { nativeRunArtifactRecords } from "./native-run.js";
|
|
7
9
|
import { compileTaskAcceptanceContext, inspectProjectTask, taskAcceptancePrompt, validateTaskReview, } from "./task-acceptance.js";
|
|
8
|
-
import { assertProjectAuthority, projectAuthority, projectWithEffectiveAuthority, readProjectAuthorityIndex, } from "./project-authority.js";
|
|
10
|
+
import { assertProjectAuthority, projectAuthority, projectAuthorityIndex, projectWithEffectiveAuthority, readProjectAuthorityIndex, } from "./project-authority.js";
|
|
9
11
|
import { dataPublicSchemas } from "../../data/schemas.js";
|
|
10
12
|
import { loadCapabilityDeclarations, stageLockedCapabilities, verifyCapabilities, } from "./capabilities.js";
|
|
11
13
|
import { startCapabilityBroker } from "./broker.js";
|
|
@@ -23,9 +25,9 @@ import { createReviewExecutor } from "./review-executor.js";
|
|
|
23
25
|
import { requiredDiscoveryCapabilityIds } from "./external-skills.js";
|
|
24
26
|
import { renderInputLineContext } from "./input-plan.js";
|
|
25
27
|
import { freezeClaimEvidenceGraph, freezeInferenceSnapshot, loadCurrentInferenceSnapshot, } from "./inference.js";
|
|
26
|
-
import { appendJournalEvent, readJournal, verifyJournal } from "./journal.js";
|
|
28
|
+
import { appendJournalEvent, readJournal, readVerifiedJournal, verifyJournal } from "./journal.js";
|
|
27
29
|
import { nativeActivityRecordSchema } from "./native-activity.js";
|
|
28
|
-
import { calculateAgentCallTokenReservation, RESEARCH_BROKER_MAX_TURNS, RESEARCH_ESTIMATED_BYTES_PER_TOKEN, RESEARCH_MAX_REPAIR_SOURCE_BYTES, RESEARCH_REPAIR_MAX_TURNS,
|
|
30
|
+
import { calculateAgentCallTokenReservation, RESEARCH_BROKER_MAX_TURNS, RESEARCH_ESTIMATED_BYTES_PER_TOKEN, RESEARCH_MAX_REPAIR_SOURCE_BYTES, RESEARCH_REPAIR_MAX_TURNS, RESEARCH_PACKET_READ_MAX_TURNS, RESEARCH_EXPECTED_ARTIFACT_READ_TOKENS, researchStructuredOutputMaxTurns, reservedAgentPackageCost, } from "./preflight.js";
|
|
29
31
|
import { blockingScientificGate, listProjects, loadProject, nextReadyPackage, packageById, refreshProject, saveProject, scientificGateRecommendedAction, } from "./projects.js";
|
|
30
32
|
import { assertResearchPolicyBinding } from "./research-policy.js";
|
|
31
33
|
import { assertScientificGateForStage } from "./scientific-review.js";
|
|
@@ -308,6 +310,63 @@ export async function inspectNativeResearchStage(root, project) {
|
|
|
308
310
|
};
|
|
309
311
|
}
|
|
310
312
|
}
|
|
313
|
+
export async function readNativeStageArtifact(input) {
|
|
314
|
+
return withWorkspaceLock(input.root, "research.native-stage.read", async () => {
|
|
315
|
+
const project = await loadProject(input.root, input.projectId);
|
|
316
|
+
const events = await readVerifiedJournal(workspacePaths(input.root).journal);
|
|
317
|
+
assertProjectAuthority(project, projectAuthorityIndex(events));
|
|
318
|
+
const session = await readNativeStageSession(input.root, input.projectId);
|
|
319
|
+
const prepared = events.findLast((event) => event.scope === project.id &&
|
|
320
|
+
event.type === "native.stage.prepared" &&
|
|
321
|
+
event.payload.sessionId === input.sessionId);
|
|
322
|
+
const runtimeRoot = await realpath(workspacePaths(input.root).runtime);
|
|
323
|
+
const capsule = await realpath(session.capsuleProject);
|
|
324
|
+
if (session.packet.sessionId !== input.sessionId ||
|
|
325
|
+
prepared?.payload.packetSha256 !== session.packet.packetSha256 ||
|
|
326
|
+
project.handoff.state !== "agent-actionable" ||
|
|
327
|
+
relative(runtimeRoot, capsule).startsWith("..") ||
|
|
328
|
+
isAbsolute(relative(runtimeRoot, capsule)) ||
|
|
329
|
+
Date.now() - Date.parse(session.packet.preparedAt) >
|
|
330
|
+
session.packet.limits.maxWallSeconds * 1000 ||
|
|
331
|
+
packageById(project, session.packet.packageId).status !== "running" ||
|
|
332
|
+
!session.packet.artifactViews) {
|
|
333
|
+
throw new CliError("Artifact reads require the exact active native stage packet.", {
|
|
334
|
+
code: "RESEARCH_NATIVE_STAGE_SESSION_REQUIRED",
|
|
335
|
+
exitCode: 3,
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
await assertNativeStageBinding(input.root, project, session.packet);
|
|
339
|
+
const views = await openArtifactViews(session.capsuleProject, session.packet.artifactViews, session.packet.packetSha256);
|
|
340
|
+
if (views.index.projectId !== project.id)
|
|
341
|
+
throw new CliError("Artifact directory belongs to another project.", {
|
|
342
|
+
code: "RESEARCH_ARTIFACT_VIEW_INVALID",
|
|
343
|
+
exitCode: 3,
|
|
344
|
+
});
|
|
345
|
+
if (!input.selection)
|
|
346
|
+
return views.list(input.listing);
|
|
347
|
+
const result = await views.read(input.selection);
|
|
348
|
+
await persistArtifactReads(projectRoot(input.root, project.id), session.capsuleProject, session.packet.artifactViews, session.packet.packetSha256, [result.receipt]);
|
|
349
|
+
await appendJournalEvent(workspacePaths(input.root).journal, "native.artifact.read", project.id, sanitizeResearchRecord({ ...result.receipt }));
|
|
350
|
+
return result;
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
/** Called under an existing short lease; observing a calculation never opens a producer. */
|
|
354
|
+
export async function inspectNativeCalculationScope(root, project, sessionId) {
|
|
355
|
+
const session = await readNativeStageSession(root, project.id);
|
|
356
|
+
const events = await readVerifiedJournal(workspacePaths(root).journal);
|
|
357
|
+
const prepared = events.findLast((event) => event.scope === project.id &&
|
|
358
|
+
event.type === "native.stage.prepared" &&
|
|
359
|
+
event.payload.sessionId === sessionId);
|
|
360
|
+
if (session.packet.sessionId !== sessionId ||
|
|
361
|
+
!["analyze", "synthesize"].includes(session.packet.stage) ||
|
|
362
|
+
prepared?.payload.packetSha256 !== session.packet.packetSha256 ||
|
|
363
|
+
packageById(project, session.packet.packageId).status !== "running" ||
|
|
364
|
+
Date.now() - Date.parse(session.packet.preparedAt) > session.packet.limits.maxWallSeconds * 1000) {
|
|
365
|
+
throw new CliError("The calculation must bind the exact active post-acquisition native packet.", { code: "RESEARCH_NATIVE_RUN_BINDING_INVALID", exitCode: 3 });
|
|
366
|
+
}
|
|
367
|
+
await assertNativeStageBinding(root, project, session.packet);
|
|
368
|
+
return session.packet.packetSha256;
|
|
369
|
+
}
|
|
311
370
|
export async function prepareNativeResearchStage(input) {
|
|
312
371
|
return withWorkspaceLock(input.root, "research.native-stage.prepare", async () => {
|
|
313
372
|
const authority = await readProjectAuthorityIndex(input.root);
|
|
@@ -396,27 +455,23 @@ export async function prepareNativeResearchStage(input) {
|
|
|
396
455
|
let preparedStatePersisted = false;
|
|
397
456
|
try {
|
|
398
457
|
capsule = await createCapsule(input.root, project, workPackage, sessionId, config);
|
|
399
|
-
const stageContextContent = await stageContextForPackage(capsule.projectRoot, project, workPackage, config);
|
|
458
|
+
const stageContextContent = await stageContextForPackage(capsule.projectRoot, project, workPackage, capsule.artifactViews, config);
|
|
400
459
|
const declarations = await loadCapabilityDeclarations(input.root);
|
|
401
460
|
const hasBrokeredEvidence = declarations.capabilities.some((capability) => capability.permissions.includes("brokered-network"));
|
|
402
461
|
const dataCapabilities = projectResearchDataCapabilities();
|
|
403
462
|
const hasDataEvidence = dataCapabilities.capabilities.length > 0;
|
|
404
|
-
const basePrompt = packagePrompt(project, workPackage, capsule.inputManifest, capsule.stagedSkills, capsule.capabilityDocumentation, null, capsule.contextBundle, capsule.contextBundleContent, stageContextContent, discovery, await listEvidenceCandidates(input.root, project.id));
|
|
463
|
+
const basePrompt = packagePrompt(project, workPackage, capsule.inputManifest, capsule.stagedSkills, capsule.capabilityDocumentation, null, capsule.contextBundle, capsule.contextBundleContent, stageContextContent, discovery, await listEvidenceCandidates(input.root, project.id), "native-host");
|
|
405
464
|
const taskContract = await taskContext(input.root, project.id, authority.taskEvents.get(project.id) ?? []);
|
|
406
465
|
const taskPrompt = taskContract
|
|
407
466
|
? "Original task and current authorized scope (a workflow finish is not task completion):\n" +
|
|
408
|
-
|
|
467
|
+
(await artifactPromptContext(capsule.projectRoot, capsule.artifactViews, [
|
|
468
|
+
"inputs/task-context.json",
|
|
469
|
+
]))
|
|
409
470
|
: "";
|
|
410
|
-
if (taskContract &&
|
|
411
|
-
Buffer.byteLength(taskPrompt +
|
|
412
|
-
(input.stage === "discover" ? capsule.contextBundleContent : "") +
|
|
413
|
-
stageContextContent, "utf8") >
|
|
414
|
-
config.budget.maxInputContextTokens * RESEARCH_ESTIMATED_BYTES_PER_TOKEN) {
|
|
415
|
-
throw new CliError("The complete task and evidence context exceeds the reviewed input allowance. Condense representation without dropping requirements or explicitly review a larger context budget.", { code: "RESEARCH_TASK_CONTEXT_TOO_LARGE", exitCode: 3 });
|
|
416
|
-
}
|
|
417
471
|
const prompt = [
|
|
418
472
|
"Perform this producer stage in the current interactive host session. Do not launch codex exec, claude -p, or any other nested reasoning agent.",
|
|
419
473
|
capsule.publicationPolicyDocumentation,
|
|
474
|
+
artifactReadInstructions(capsule.artifactViews),
|
|
420
475
|
taskPrompt,
|
|
421
476
|
input.stage === "discover" && (hasBrokeredEvidence || hasDataEvidence)
|
|
422
477
|
? [
|
|
@@ -434,7 +489,6 @@ export async function prepareNativeResearchStage(input) {
|
|
|
434
489
|
? "Acquire the provisionally admitted sources with the installed external acquisition/document Skills or an explicitly selected user-authorized browser. Capture the exact browser/adapter Download object, save it to the planned unique staging path, and call bindDownload before registerArtifact. Record browser/download/file-inspection activity with recordActivity. Failed or cancelled downloads cannot create bindings or artifacts. Never scan a download directory or infer success from file existence."
|
|
435
490
|
: "Do not acquire additional evidence in this stage.",
|
|
436
491
|
basePrompt,
|
|
437
|
-
"Save only the final schema-conforming JSON object to a new regular file, then submit it with the packet's submit command. The CLI remains the sole authority for validation and atomic promotion.",
|
|
438
492
|
].join("\n\n");
|
|
439
493
|
const preparedAt = new Date().toISOString();
|
|
440
494
|
const bindingSha256 = await nativeStageBinding(input.root, project, workPackage);
|
|
@@ -455,6 +509,7 @@ export async function prepareNativeResearchStage(input) {
|
|
|
455
509
|
: {}),
|
|
456
510
|
publicationPolicy: capsule.publicationPolicy,
|
|
457
511
|
taskContract,
|
|
512
|
+
artifactViews: capsule.artifactViews,
|
|
458
513
|
discovery,
|
|
459
514
|
limits: {
|
|
460
515
|
maxOutputBytes: config.budget.maxBytesPerPackage,
|
|
@@ -465,6 +520,42 @@ export async function prepareNativeResearchStage(input) {
|
|
|
465
520
|
maxWallSeconds: config.budget.packageMaxWallSeconds[input.stage],
|
|
466
521
|
},
|
|
467
522
|
commands: {
|
|
523
|
+
listArtifacts: {
|
|
524
|
+
argv: [
|
|
525
|
+
"tiangong-ai",
|
|
526
|
+
"research",
|
|
527
|
+
"project",
|
|
528
|
+
"stage",
|
|
529
|
+
"artifacts",
|
|
530
|
+
project.id,
|
|
531
|
+
"--session",
|
|
532
|
+
sessionId,
|
|
533
|
+
"--workspace",
|
|
534
|
+
input.root,
|
|
535
|
+
"--json",
|
|
536
|
+
],
|
|
537
|
+
},
|
|
538
|
+
readArtifact: {
|
|
539
|
+
argv: [
|
|
540
|
+
"tiangong-ai",
|
|
541
|
+
"research",
|
|
542
|
+
"project",
|
|
543
|
+
"stage",
|
|
544
|
+
"read",
|
|
545
|
+
project.id,
|
|
546
|
+
"--session",
|
|
547
|
+
sessionId,
|
|
548
|
+
"--artifact",
|
|
549
|
+
"<objectId-from-directory>",
|
|
550
|
+
"--offset",
|
|
551
|
+
"<byte-offset>",
|
|
552
|
+
"--length",
|
|
553
|
+
"<bytes-or-all>",
|
|
554
|
+
"--workspace",
|
|
555
|
+
input.root,
|
|
556
|
+
"--json",
|
|
557
|
+
],
|
|
558
|
+
},
|
|
468
559
|
inspectAccess: project.scientificDesign
|
|
469
560
|
? {
|
|
470
561
|
argv: [
|
|
@@ -764,6 +855,7 @@ export async function prepareNativeResearchStage(input) {
|
|
|
764
855
|
await appendJournalEvent(workspacePaths(input.root).journal, "native.stage.prepared", project.id, {
|
|
765
856
|
sessionId,
|
|
766
857
|
packetSha256: packet.packetSha256,
|
|
858
|
+
artifactViewIndexSha256: packet.artifactViews.sha256,
|
|
767
859
|
bindingSha256,
|
|
768
860
|
projectId: project.id,
|
|
769
861
|
packageId: workPackage.id,
|
|
@@ -1303,7 +1395,7 @@ async function executeWorkPackage(root, projectId, packageId, config, options, r
|
|
|
1303
1395
|
packet: capsule.reviewPacketRecord,
|
|
1304
1396
|
});
|
|
1305
1397
|
}
|
|
1306
|
-
const stageContextContent = await stageContextForPackage(capsule.projectRoot, project, workPackage, config);
|
|
1398
|
+
const stageContextContent = await stageContextForPackage(capsule.projectRoot, project, workPackage, capsule.artifactViews, config);
|
|
1307
1399
|
const route = workPackage.executor === "reviewer" ? config.reviewer : config.producer;
|
|
1308
1400
|
const selectedPackageExecutor = workPackage.executor === "reviewer" && reviewerPackageExecutor
|
|
1309
1401
|
? reviewerPackageExecutor
|
|
@@ -1325,11 +1417,14 @@ async function executeWorkPackage(root, projectId, packageId, config, options, r
|
|
|
1325
1417
|
options,
|
|
1326
1418
|
requestId,
|
|
1327
1419
|
purpose: "primary",
|
|
1328
|
-
prompt: packagePrompt(project, workPackage, capsule.inputManifest, capsule.stagedSkills, capsule.capabilityDocumentation, capsule.reviewPacketSha256, capsule.contextBundle, capsule.contextBundleContent, stageContextContent, discovery, await listEvidenceCandidates(root, project.id)) +
|
|
1420
|
+
prompt: packagePrompt(project, workPackage, capsule.inputManifest, capsule.stagedSkills, capsule.capabilityDocumentation, capsule.reviewPacketSha256, capsule.contextBundle, capsule.contextBundleContent, stageContextContent, discovery, await listEvidenceCandidates(root, project.id), "headless-cli") +
|
|
1329
1421
|
(capsule.publicationPolicyDocumentation
|
|
1330
1422
|
? `\n\n${capsule.publicationPolicyDocumentation}`
|
|
1331
1423
|
: "") +
|
|
1332
|
-
(capsule.taskAcceptancePrompt ? `\n\n${capsule.taskAcceptancePrompt}` : "")
|
|
1424
|
+
(capsule.taskAcceptancePrompt ? `\n\n${capsule.taskAcceptancePrompt}` : "") +
|
|
1425
|
+
(workPackage.stage === "review"
|
|
1426
|
+
? `\n\n${artifactReadInstructions(capsule.artifactViews)}`
|
|
1427
|
+
: ""),
|
|
1333
1428
|
brokerUrl: primaryBrokerUrl,
|
|
1334
1429
|
inputOnlyProvenance,
|
|
1335
1430
|
maxOutputTokens: Math.min(stageOutputTokens, reservation.tokens),
|
|
@@ -1340,6 +1435,15 @@ async function executeWorkPackage(root, projectId, packageId, config, options, r
|
|
|
1340
1435
|
assertPreCallTokenReservation(project, workPackage, config, primaryRequest, 0, true);
|
|
1341
1436
|
result = await withHeartbeat(selectedPackageExecutor(primaryRequest), options, requestId, project, workPackage, config);
|
|
1342
1437
|
accountedResult = result;
|
|
1438
|
+
if (primaryRequest.artifactViews && result.artifactReads?.length) {
|
|
1439
|
+
await persistArtifactReads(projectRoot(root, project.id), capsule.projectRoot, capsule.artifactViews, primaryRequest.artifactViews.packetSha256, result.artifactReads);
|
|
1440
|
+
await appendJournalEvent(workspacePaths(root).journal, "review.artifacts.read", project.id, sanitizeResearchRecord({
|
|
1441
|
+
requestId,
|
|
1442
|
+
packetSha256: primaryRequest.artifactViews.packetSha256,
|
|
1443
|
+
indexSha256: capsule.artifactViews.sha256,
|
|
1444
|
+
receipts: result.artifactReads.map((receipt) => receipt.receiptSha256),
|
|
1445
|
+
}));
|
|
1446
|
+
}
|
|
1343
1447
|
assertExecutorSucceeded(result);
|
|
1344
1448
|
assertActualPackageBudget(project, workPackage, config, result, stageOutputTokens);
|
|
1345
1449
|
let acceptedRaw = result.stdout;
|
|
@@ -1580,7 +1684,14 @@ async function stagePublicationPolicy(root, project, capsuleProject) {
|
|
|
1580
1684
|
manifestPath: resolveContained(capsuleProject, manifestPath),
|
|
1581
1685
|
documents,
|
|
1582
1686
|
};
|
|
1583
|
-
await writeJsonAtomic(staged.manifestPath,
|
|
1687
|
+
await writeJsonAtomic(staged.manifestPath, {
|
|
1688
|
+
...staged,
|
|
1689
|
+
manifestPath,
|
|
1690
|
+
documents: documents.map((document) => ({
|
|
1691
|
+
...document,
|
|
1692
|
+
path: relative(capsuleProject, document.path).replaceAll("\\", "/"),
|
|
1693
|
+
})),
|
|
1694
|
+
});
|
|
1584
1695
|
return staged;
|
|
1585
1696
|
}
|
|
1586
1697
|
async function createCapsule(root, project, workPackage, runId, config, taskAcceptance = null) {
|
|
@@ -1689,35 +1800,65 @@ async function createCapsule(root, project, workPackage, runId, config, taskAcce
|
|
|
1689
1800
|
"Approved Research Policy (mandatory for every producer and reviewer decision):",
|
|
1690
1801
|
`resolvedPolicySha256=${publicationPolicy.resolvedPolicySha256}`,
|
|
1691
1802
|
`verdictCeiling=${publicationPolicy.verdictCeiling}`,
|
|
1692
|
-
...publicationPolicy.documents.map((document) => `- ${document.kind}:${document.id} sha256=${document.sha256} path=${document.path}`),
|
|
1803
|
+
...publicationPolicy.documents.map((document) => `- ${document.kind}:${document.id} sha256=${document.sha256} path=${relative(capsuleProject, document.path).replaceAll("\\", "/")}`),
|
|
1693
1804
|
"Read every listed policy document before reasoning. Generic defaults are explicit constraints, not evidence that a target journal will accept the manuscript.",
|
|
1694
1805
|
].join("\n")
|
|
1695
1806
|
: "";
|
|
1696
1807
|
const stagedSkills = await stageLockedCapabilities(root, join(capsuleProject, "skills"));
|
|
1697
|
-
const capabilityDocumentation = await buildCapabilityDocumentation(capsuleProject, stagedSkills
|
|
1808
|
+
const capabilityDocumentation = await buildCapabilityDocumentation(capsuleProject, stagedSkills);
|
|
1809
|
+
await writeTextAtomic(join(capsuleProject, "inputs/capability-documentation.txt"), capabilityDocumentation);
|
|
1698
1810
|
const reviewEvidenceContext = workPackage.stage === "review"
|
|
1699
1811
|
? await writeReviewEvidenceContext(root, project.id, capsuleProject, contextBundleContent, evidenceReceipts, contextualEvidenceArtifacts, config.budget.maxInputContextTokens * RESEARCH_ESTIMATED_BYTES_PER_TOKEN)
|
|
1700
1812
|
: null;
|
|
1813
|
+
const task = taskAcceptance ?? (await taskContext(root, project.id));
|
|
1814
|
+
if (task) {
|
|
1815
|
+
await writeJsonAtomic(join(capsuleProject, "inputs/task-context.json"), task);
|
|
1816
|
+
const source = task.requestProvenance.source;
|
|
1817
|
+
if (source) {
|
|
1818
|
+
const logical = `task/request-sources/${source.objectSha256}.json`;
|
|
1819
|
+
await ensureDirectory(dirname(resolveContained(capsuleProject, logical)));
|
|
1820
|
+
await cp(resolveContained(projectRoot(root, project.id), logical), resolveContained(capsuleProject, logical), { force: false });
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
const taskArtifacts = new Map((taskAcceptance?.results ?? []).map((record) => [record.path, record]));
|
|
1824
|
+
if (task)
|
|
1825
|
+
for (const record of await nativeRunArtifactRecords(root, project.id))
|
|
1826
|
+
taskArtifacts.set(record.path, record);
|
|
1827
|
+
for (const result of taskArtifacts.values()) {
|
|
1828
|
+
await ensureDirectory(dirname(resolveContained(capsuleProject, result.path)));
|
|
1829
|
+
await cp(resolveContained(projectRoot(root, project.id), result.path), resolveContained(capsuleProject, result.path), { force: false });
|
|
1830
|
+
if ((await sha256File(resolveContained(capsuleProject, result.path))) !== result.sha256)
|
|
1831
|
+
throw new CliError("Native run/check artifact changed while staging the packet.", {
|
|
1832
|
+
code: "RESEARCH_TASK_ARTIFACT_DRIFT",
|
|
1833
|
+
exitCode: 3,
|
|
1834
|
+
});
|
|
1835
|
+
}
|
|
1701
1836
|
const reviewPacket = reviewEvidenceContext
|
|
1702
1837
|
? await writeReviewPacket(root, capsuleProject, project, inputManifest, evidenceReceipts, evidenceArtifacts, reviewEvidenceContext.persistent, taskAcceptance)
|
|
1703
1838
|
: null;
|
|
1839
|
+
const artifactViews = reviewPacket?.artifactViews ?? (await writeArtifactViewIndex(capsuleProject, project.id));
|
|
1704
1840
|
return {
|
|
1705
1841
|
capsuleRoot,
|
|
1706
1842
|
projectRoot: capsuleProject,
|
|
1707
1843
|
inputManifest,
|
|
1708
1844
|
contextBundle,
|
|
1709
|
-
contextBundleContent,
|
|
1845
|
+
contextBundleContent: await artifactPromptContext(capsuleProject, artifactViews, [
|
|
1846
|
+
"inputs/context-bundle.txt",
|
|
1847
|
+
]),
|
|
1710
1848
|
stagedSkills,
|
|
1711
|
-
capabilityDocumentation,
|
|
1849
|
+
capabilityDocumentation: await artifactPromptContext(capsuleProject, artifactViews, [
|
|
1850
|
+
"inputs/capability-documentation.txt",
|
|
1851
|
+
]),
|
|
1712
1852
|
publicationPolicy,
|
|
1713
1853
|
publicationPolicyDocumentation,
|
|
1714
1854
|
reviewPacketSha256: reviewPacket?.sha256 ?? null,
|
|
1715
1855
|
reviewPacketRecord: reviewPacket?.record ?? null,
|
|
1716
1856
|
taskAcceptance,
|
|
1717
|
-
taskAcceptancePrompt: await taskAcceptancePrompt(
|
|
1857
|
+
taskAcceptancePrompt: await taskAcceptancePrompt(taskAcceptance, capsuleProject, artifactViews),
|
|
1858
|
+
artifactViews,
|
|
1718
1859
|
};
|
|
1719
1860
|
}
|
|
1720
|
-
async function buildCapabilityDocumentation(capsuleProject, stagedSkills
|
|
1861
|
+
async function buildCapabilityDocumentation(capsuleProject, stagedSkills) {
|
|
1721
1862
|
const documents = [
|
|
1722
1863
|
{
|
|
1723
1864
|
path: "skills/manifest.json",
|
|
@@ -1733,14 +1874,6 @@ async function buildCapabilityDocumentation(capsuleProject, stagedSkills, maxByt
|
|
|
1733
1874
|
const bundle = documents
|
|
1734
1875
|
.map((document) => `--- ${document.path} ---\n${document.content.trimEnd()}`)
|
|
1735
1876
|
.join("\n\n");
|
|
1736
|
-
const bytes = Buffer.byteLength(bundle, "utf8");
|
|
1737
|
-
if (bytes > maxBytes) {
|
|
1738
|
-
throw new CliError("Staged external Skill documentation exceeds the input context budget.", {
|
|
1739
|
-
code: "RESEARCH_CAPABILITY_CONTEXT_BUDGET_EXCEEDED",
|
|
1740
|
-
exitCode: 3,
|
|
1741
|
-
details: { bytes, maxBytes, skills: stagedSkills.map((path) => basename(path)) },
|
|
1742
|
-
});
|
|
1743
|
-
}
|
|
1744
1877
|
return bundle;
|
|
1745
1878
|
}
|
|
1746
1879
|
async function buildInputContextBundle(capsuleProject, inputManifest) {
|
|
@@ -1806,6 +1939,8 @@ async function writeReviewPacket(root, capsuleProject, project, inputManifest, e
|
|
|
1806
1939
|
}
|
|
1807
1940
|
}
|
|
1808
1941
|
await writeJsonAtomic(join(capsuleProject, "inputs", "runtime-fingerprint.json"), environment);
|
|
1942
|
+
const artifactViews = await writeArtifactViewIndex(capsuleProject, project.id);
|
|
1943
|
+
const persistedViews = await persistArtifactViewIndex(projectRoot(root, project.id), capsuleProject, artifactViews);
|
|
1809
1944
|
const packet = {
|
|
1810
1945
|
schemaVersion: 1,
|
|
1811
1946
|
projectId: project.id,
|
|
@@ -1819,6 +1954,7 @@ async function writeReviewPacket(root, capsuleProject, project, inputManifest, e
|
|
|
1819
1954
|
},
|
|
1820
1955
|
snapshotChain,
|
|
1821
1956
|
taskAcceptance,
|
|
1957
|
+
artifactViews: persistedViews,
|
|
1822
1958
|
inputs: inputManifest,
|
|
1823
1959
|
reviewEvidenceContext,
|
|
1824
1960
|
inputFiles: [...inputFiles.values()].sort((left, right) => left.path.localeCompare(right.path)),
|
|
@@ -1838,7 +1974,7 @@ async function writeReviewPacket(root, capsuleProject, project, inputManifest, e
|
|
|
1838
1974
|
};
|
|
1839
1975
|
await writeJsonAtomic(join(capsuleProject, "inputs", "review-packet.json"), completePacket);
|
|
1840
1976
|
const record = await persistReviewPacket(root, project.id, completePacket, packetSha256);
|
|
1841
|
-
return { sha256: packetSha256, record };
|
|
1977
|
+
return { sha256: packetSha256, record, artifactViews };
|
|
1842
1978
|
}
|
|
1843
1979
|
async function writeReviewEvidenceContext(root, projectId, capsuleProject, inputContextBundle, evidenceReceipts, evidenceArtifacts, maxBytes) {
|
|
1844
1980
|
const header = [
|
|
@@ -1920,15 +2056,10 @@ async function writeReviewEvidenceContext(root, projectId, capsuleProject, input
|
|
|
1920
2056
|
...views.map((view) => `${view.prefix}${view.active ? "" : view.content}${view.suffix}`),
|
|
1921
2057
|
].join("\n\n");
|
|
1922
2058
|
const fixedBytes = Buffer.byteLength(`${fixedContent}\n`, "utf8");
|
|
1923
|
-
if (fixedBytes > maxBytes) {
|
|
1924
|
-
throw new CliError("Review evidence metadata exceeds the configured context budget.", {
|
|
1925
|
-
code: "RESEARCH_REVIEW_CONTEXT_BUDGET_EXCEEDED",
|
|
1926
|
-
exitCode: 3,
|
|
1927
|
-
details: { fixedBytes, maxBytes, views: views.length },
|
|
1928
|
-
});
|
|
1929
|
-
}
|
|
1930
2059
|
const activeViews = views.filter((view) => view.active).length;
|
|
1931
|
-
const contentBudgetPerView = activeViews
|
|
2060
|
+
const contentBudgetPerView = activeViews
|
|
2061
|
+
? Math.max(0, Math.floor((maxBytes - fixedBytes) / activeViews))
|
|
2062
|
+
: 0;
|
|
1932
2063
|
const sections = [
|
|
1933
2064
|
header,
|
|
1934
2065
|
...views.map((view) => `${view.prefix}${view.active ? boundedUtf8ReviewExcerpt(view.content, contentBudgetPerView) : view.content}${view.suffix}`),
|
|
@@ -1936,14 +2067,6 @@ async function writeReviewEvidenceContext(root, projectId, capsuleProject, input
|
|
|
1936
2067
|
const logicalPath = "inputs/review-evidence-context.txt";
|
|
1937
2068
|
const path = resolveContained(capsuleProject, logicalPath);
|
|
1938
2069
|
const content = `${sections.join("\n\n")}\n`;
|
|
1939
|
-
const actualBytes = Buffer.byteLength(content, "utf8");
|
|
1940
|
-
if (actualBytes > maxBytes) {
|
|
1941
|
-
throw new CliError("Review evidence context exceeded its deterministic byte budget.", {
|
|
1942
|
-
code: "RESEARCH_REVIEW_CONTEXT_BUDGET_EXCEEDED",
|
|
1943
|
-
exitCode: 3,
|
|
1944
|
-
details: { actualBytes, maxBytes },
|
|
1945
|
-
});
|
|
1946
|
-
}
|
|
1947
2070
|
await writeTextAtomic(path, content);
|
|
1948
2071
|
const capsule = await fileRecord(path, logicalPath);
|
|
1949
2072
|
const persistentLogicalPath = `review/contexts/${capsule.sha256}.txt`;
|
|
@@ -1995,15 +2118,8 @@ async function writeProducerArtifactContext(capsuleProject, evidenceArtifacts, m
|
|
|
1995
2118
|
.map((view) => `${view.prefix}${view.active ? "" : view.content}${view.suffix}`)
|
|
1996
2119
|
.join("\n\n")}\n`;
|
|
1997
2120
|
const fixedBytes = Buffer.byteLength(fixed, "utf8");
|
|
1998
|
-
if (fixedBytes > maxBytes) {
|
|
1999
|
-
throw new CliError("Producer artifact metadata exceeds the configured context budget.", {
|
|
2000
|
-
code: "RESEARCH_INPUT_CONTEXT_BUDGET_EXCEEDED",
|
|
2001
|
-
exitCode: 3,
|
|
2002
|
-
details: { fixedBytes, maxBytes, artifacts: views.length },
|
|
2003
|
-
});
|
|
2004
|
-
}
|
|
2005
2121
|
const activeViews = views.filter((view) => view.active).length;
|
|
2006
|
-
const perView = activeViews ? Math.floor((maxBytes - fixedBytes) / activeViews) : 0;
|
|
2122
|
+
const perView = activeViews ? Math.max(0, Math.floor((maxBytes - fixedBytes) / activeViews)) : 0;
|
|
2007
2123
|
const content = `${header}\n\n${views
|
|
2008
2124
|
.map((view) => `${view.prefix}${view.active ? boundedUtf8ReviewExcerpt(view.content, perView) : view.content}${view.suffix}`)
|
|
2009
2125
|
.join("\n\n")}\n`;
|
|
@@ -2164,6 +2280,13 @@ export async function loadVerifiedReviewPacket(root, projectId, packetSha256) {
|
|
|
2164
2280
|
const path = resolveContained(projectRoot(root, projectId), logicalPath);
|
|
2165
2281
|
const packet = await readJsonFile(path, "Research review packet");
|
|
2166
2282
|
verifyReviewPacketValue(packet, packetSha256);
|
|
2283
|
+
if (packet.projectId !== projectId)
|
|
2284
|
+
throw new CliError("Review packet belongs to another project.", {
|
|
2285
|
+
code: "RESEARCH_REVIEW_PACKET_DRIFT",
|
|
2286
|
+
exitCode: 3,
|
|
2287
|
+
});
|
|
2288
|
+
if (packet.artifactViews !== undefined)
|
|
2289
|
+
await verifyPersistedArtifactViewIndex(projectRoot(root, projectId), projectId, packet.artifactViews);
|
|
2167
2290
|
const context = packet.reviewEvidenceContext;
|
|
2168
2291
|
if (!isObject(context) ||
|
|
2169
2292
|
typeof context.path !== "string" ||
|
|
@@ -2315,12 +2438,17 @@ function reviewSafeReceipt(receipt) {
|
|
|
2315
2438
|
};
|
|
2316
2439
|
}
|
|
2317
2440
|
function agentRequest(input) {
|
|
2318
|
-
const
|
|
2441
|
+
const packetRead = input.purpose === "primary" &&
|
|
2442
|
+
input.workPackage.stage === "review" &&
|
|
2443
|
+
input.capsule.reviewPacketSha256 !== null;
|
|
2444
|
+
const toolPolicy = packetRead ? "packet-read" : "none";
|
|
2319
2445
|
const maxTurns = input.purpose === "repair"
|
|
2320
2446
|
? RESEARCH_REPAIR_MAX_TURNS
|
|
2321
|
-
:
|
|
2322
|
-
?
|
|
2323
|
-
:
|
|
2447
|
+
: packetRead
|
|
2448
|
+
? RESEARCH_PACKET_READ_MAX_TURNS
|
|
2449
|
+
: input.brokerUrl
|
|
2450
|
+
? RESEARCH_BROKER_MAX_TURNS
|
|
2451
|
+
: researchStructuredOutputMaxTurns(input.route);
|
|
2324
2452
|
return {
|
|
2325
2453
|
route: input.route,
|
|
2326
2454
|
prompt: input.prompt,
|
|
@@ -2345,11 +2473,22 @@ function agentRequest(input) {
|
|
|
2345
2473
|
timeoutSeconds: Math.min(remainingWallSeconds(input.project, input.config), input.maxWallSeconds ??
|
|
2346
2474
|
input.config.budget.packageMaxWallSeconds[input.workPackage.stage]),
|
|
2347
2475
|
maxTurns,
|
|
2476
|
+
...(packetRead
|
|
2477
|
+
? {
|
|
2478
|
+
reservationTurns: researchStructuredOutputMaxTurns(input.route),
|
|
2479
|
+
artifactViews: {
|
|
2480
|
+
index: input.capsule.artifactViews,
|
|
2481
|
+
packetSha256: input.capsule.reviewPacketSha256,
|
|
2482
|
+
},
|
|
2483
|
+
}
|
|
2484
|
+
: {}),
|
|
2348
2485
|
maxOutputTokens: input.maxOutputTokens,
|
|
2349
2486
|
maxToolContextTokens: input.brokerUrl
|
|
2350
2487
|
? input.config.budget.maxBrokerContextTokens *
|
|
2351
2488
|
(input.brokerCallBudget ?? input.config.budget.maxBrokerCalls)
|
|
2352
|
-
:
|
|
2489
|
+
: packetRead
|
|
2490
|
+
? RESEARCH_EXPECTED_ARTIFACT_READ_TOKENS
|
|
2491
|
+
: 0,
|
|
2353
2492
|
maxCostUsd: input.maxCostUsd,
|
|
2354
2493
|
expectedRuntime: input.expectedRuntime,
|
|
2355
2494
|
toolPolicy,
|
|
@@ -3066,7 +3205,7 @@ async function verifyProjectInputBindings(project) {
|
|
|
3066
3205
|
async function outputRecords(root, project, logicalPaths) {
|
|
3067
3206
|
return Promise.all(logicalPaths.map((logicalPath) => fileRecord(resolveContained(projectRoot(root, project.id), logicalPath), logicalPath)));
|
|
3068
3207
|
}
|
|
3069
|
-
async function stageContextForPackage(capsuleProject, project, workPackage, config) {
|
|
3208
|
+
async function stageContextForPackage(capsuleProject, project, workPackage, index, config) {
|
|
3070
3209
|
let analyzeFallbackContext = [];
|
|
3071
3210
|
if (workPackage.stage === "analyze") {
|
|
3072
3211
|
const inference = JSON.parse(await readFile(resolveContained(capsuleProject, "outputs/inference-snapshot.json"), "utf8"));
|
|
@@ -3101,41 +3240,21 @@ async function stageContextForPackage(capsuleProject, project, workPackage, conf
|
|
|
3101
3240
|
"outputs/report.md",
|
|
3102
3241
|
]
|
|
3103
3242
|
: [];
|
|
3104
|
-
|
|
3105
|
-
for (const logicalPath of logicalPaths) {
|
|
3106
|
-
const content = await readFile(resolveContained(capsuleProject, logicalPath), "utf8");
|
|
3107
|
-
sections.push(`### ${logicalPath}\n${content.trimEnd()}`);
|
|
3108
|
-
}
|
|
3109
|
-
const bundled = sections.join("\n\n");
|
|
3110
|
-
const estimatedTokens = Math.ceil(Buffer.byteLength(bundled, "utf8") / RESEARCH_ESTIMATED_BYTES_PER_TOKEN);
|
|
3111
|
-
const maxStageContextTokens = researchStageContextTokenLimit(config, workPackage.stage, project.lineage.kind === "addendum");
|
|
3112
|
-
if (estimatedTokens > maxStageContextTokens) {
|
|
3113
|
-
throw new CliError(`Admitted stage context exceeds the configured input context limit for ${workPackage.id}.`, {
|
|
3114
|
-
code: "RESEARCH_INPUT_CONTEXT_BUDGET_EXCEEDED",
|
|
3115
|
-
exitCode: 3,
|
|
3116
|
-
details: {
|
|
3117
|
-
packageId: workPackage.id,
|
|
3118
|
-
estimatedTokens,
|
|
3119
|
-
maxStageContextTokens,
|
|
3120
|
-
limitField: "budget.maxInputContextTokens",
|
|
3121
|
-
contextPaths: logicalPaths,
|
|
3122
|
-
recommendedAction: "Keep frozen evidence unchanged. Use research project fork to regenerate a bounded context with concise metadata, or explicitly review budget.maxInputContextTokens in .tiangong-research/config.json and rerun project preflight plus workspace doctor before preparing this stage again. Do not raise output limits to accommodate input context.",
|
|
3123
|
-
},
|
|
3124
|
-
});
|
|
3125
|
-
}
|
|
3126
|
-
return bundled;
|
|
3243
|
+
return artifactPromptContext(capsuleProject, index, logicalPaths, Math.min(8_000, config.budget.maxInputContextTokens) * RESEARCH_ESTIMATED_BYTES_PER_TOKEN);
|
|
3127
3244
|
}
|
|
3128
|
-
function packagePrompt(project, workPackage, inputs, stagedSkills, capabilityDocumentation, reviewPacketSha256, contextBundle, contextBundleContent, stageContextContent, discovery, evidenceCandidates) {
|
|
3245
|
+
function packagePrompt(project, workPackage, inputs, stagedSkills, capabilityDocumentation, reviewPacketSha256, contextBundle, contextBundleContent, stageContextContent, discovery, evidenceCandidates, executionMode) {
|
|
3129
3246
|
const stageInstructions = {
|
|
3130
3247
|
discover: "Assess candidates incrementally through the packet's recordAssessment command; do not accumulate a source-sized final response. The control plane has already assigned every immutable input, broker result, and structured data result a candidateId and retains its title, URL, DOI, dates, receipt, locator, JSON Pointer, hashes, and retrieval metadata. Reference candidateId; never repeat or invent those deterministic fields. Give each admitted candidate a concise sourceId plus source type, relevance, quality, applicability, coverage dimensions, and limitations. Record meaningful explicit rejections; omitted candidates remain unassessed for later gap filling. Native Web or Browser discoveries are supplemental candidates only and cannot be admitted until an immutable broker receipt is attached to the same canonical URL or DOI. After broad search, strict assessment, and focused gap filling, return only the small closeout object with one judgment for every reviewed dimension plus limitations and remaining gaps. The CLI mechanically joins the latest recorded assessments to provenance, derives counts/date range/coverage, and rejects unknown or unformalized candidates.",
|
|
3131
3248
|
acquire: "Audit every provisionally admitted source exactly once. For each source, bind its ledger candidateId, list only artifactIds returned by the exact artifact registration command, and choose accepted, limited, or rejected with a concise rationale and explicit limitations. A broker receipt is an immutable discovery record but is not full text. Use an empty artifactIds array only when intentionally retaining a source as metadata/abstract evidence or when the source is an already registered local input. Put unresolved blocking acquisition or coverage deficiencies in gaps; put honest non-blocking scope constraints in limitations. Do not invent file paths, hashes, URLs, artifact IDs, or successful downloads.",
|
|
3132
|
-
analyze: "Use only the
|
|
3133
|
-
synthesize: "Use only the
|
|
3134
|
-
review: `Independently inspect the
|
|
3249
|
+
analyze: "Use only the admitted inference snapshot and its packet-bound on-demand artifacts; return analysis schema v2. Bind the exact inference snapshot hash and one reproducible analysisRun. Every finding must cite admitted source IDs and exact evidenceAtomIds; a top-journal finding must also bind design claimIds. State uncertainty and applicability. Never promote a source-level citation when no exact atom supports the statement.",
|
|
3250
|
+
synthesize: "Use only the admitted inference snapshot, analysis, and Claim–Evidence Graph, reading their complete packet-bound objects on demand. Return the schema-defined object whose reportMarkdown separates supported conclusions, uncertainty, limitations, and next actions. Every material statement must remain within a graph-bound finding. Use real Markdown line breaks encoded exactly once for JSON; never place literal /n or double-escaped \\n markers in reportMarkdown.",
|
|
3251
|
+
review: `Independently inspect the supplied excerpts and use the packet-only artifact tools for further material, including failed checks and counterevidence. Every full object's size and SHA-256 is bound; metadata or a digest is not proof that you read it. Return the schema-defined review bound to packetSha256 ${reviewPacketSha256 ?? "unavailable"}. Use pass only after sufficient inspection supports every material claim and its stated limitations.`,
|
|
3135
3252
|
close: "No agent action is allowed for mechanical closure.",
|
|
3136
3253
|
};
|
|
3137
3254
|
const prompt = [
|
|
3138
|
-
|
|
3255
|
+
executionMode === "native-host"
|
|
3256
|
+
? "Operate in the current native host with this project's authorized inputs and packet operations; host permissions still apply."
|
|
3257
|
+
: "Operate only inside this isolated research capsule.",
|
|
3139
3258
|
`Project: ${project.id}`,
|
|
3140
3259
|
`Question: ${project.question}`,
|
|
3141
3260
|
`Stage: ${workPackage.stage}`,
|
|
@@ -3144,15 +3263,19 @@ function packagePrompt(project, workPackage, inputs, stagedSkills, capabilityDoc
|
|
|
3144
3263
|
`Bounded input context bundle: ${JSON.stringify(contextBundle)}`,
|
|
3145
3264
|
`Staged capability directories: ${JSON.stringify(stagedSkills.map((path) => `skills/${basename(path)}`))}`,
|
|
3146
3265
|
workPackage.stage === "discover"
|
|
3147
|
-
? "The exact capability manifest and each staged external SKILL.md are
|
|
3266
|
+
? "The exact capability manifest and each staged external SKILL.md are supplied inline or through the native packet's artifact read commands. Read the required documentation; do not launch its standalone commands for broker work."
|
|
3148
3267
|
: workPackage.stage === "acquire"
|
|
3149
3268
|
? "Use the installed external acquisition/document Skills in the current native host, but treat the CLI artifact registry and acquisition schema as the only authority for durable evidence."
|
|
3150
3269
|
: "Capability files are provenance-bound but are not available as execution tools in this stage.",
|
|
3151
3270
|
workPackage.stage === "discover"
|
|
3152
3271
|
? `Follow the reviewed discovery plan: ${JSON.stringify(discovery)}. The plan's max evidence-call count is a hard working ceiling, not a target to exhaust. Execute required first-pass channels before supplemental channels, prefer broad high-yield queries, assess registered candidates between batches, and use the next gap-fill batch only for explicit uncovered dimensions, source types, date ranges, full text, limitations, or counterevidence. Stop fetching as soon as the declared coverage minimums are supportable. Native Web/Browser may broaden lead discovery, but every such action must be recorded through recordActivity, every useful result must be registered as a candidate, and the same URL/DOI must then be formalized through the broker before admission. A broker receipt, structured data-runtime receipt, or immutable registered input is an admissible evidence path. Do not execute a staged Skill's curl/CLI examples or read provider environment variables. For generic broker capabilities, invoke fetch_candidate_source with the manifest capability ID and obey its exact declared HTTP method. For structured data capabilities, use the packet's dynamic catalog and describe command, then invoke runDataCapability; never call standalone data run for project evidence. Never place API keys, tokens, authorization data, cookies, or other credential-like fields in request files. The Research control plane injects declared logical credentials and persists only safe hash-bound results. Exercise every manifest capability with requiredForDiscovery=true and every project-required data capability ID, or the mechanical coverage gate will stop downstream work.`
|
|
3153
|
-
:
|
|
3272
|
+
: executionMode === "native-host" && workPackage.stage === "acquire"
|
|
3273
|
+
? "Acquire files and readable derivatives only for provisionally admitted sources using the packet's bindDownload and registerArtifact commands. Do not reopen discovery, admit new sources, or access unrelated host files."
|
|
3274
|
+
: "Use only admitted stage context and this packet's read-only artifact channel. No new evidence acquisition or arbitrary host-file access is authorized.",
|
|
3154
3275
|
stageInstructions[workPackage.stage],
|
|
3155
|
-
|
|
3276
|
+
executionMode === "native-host"
|
|
3277
|
+
? "Do not write admitted output paths or control-plane files directly. Save only the final schema-conforming JSON object to a new regular file, then submit it with the packet's submit command. The CLI remains the sole authority for validation and atomic promotion."
|
|
3278
|
+
: "Do not write stage output files directly. Your final response must be only the JSON object required by the supplied output schema; the CLI will validate and atomically materialize it.",
|
|
3156
3279
|
"Do not edit project.json, input manifests, prior outputs, evidence objects, or staged capability files.",
|
|
3157
3280
|
];
|
|
3158
3281
|
if (workPackage.stage === "discover") {
|
|
@@ -3164,10 +3287,10 @@ function packagePrompt(project, workPackage, inputs, stagedSkills, capabilityDoc
|
|
|
3164
3287
|
publicationDate: candidate.publicationDate,
|
|
3165
3288
|
excerpt: candidate.excerpt,
|
|
3166
3289
|
originKind: candidate.origin.kind,
|
|
3167
|
-
})))}`, "
|
|
3290
|
+
})))}`, "External capability documentation (inline or exact on-demand reference):", capabilityDocumentation, "Authorized local-input context (inline or exact on-demand reference). Full evidence files are intentionally withheld from producer packages when fullTextStaged=false; the read channel does not widen that authorization.", contextBundleContent);
|
|
3168
3291
|
}
|
|
3169
3292
|
if (stageContextContent) {
|
|
3170
|
-
prompt.push("
|
|
3293
|
+
prompt.push("Admitted stage context (inline or exact on-demand reference; no material is discarded to meet an embedding preference):", stageContextContent);
|
|
3171
3294
|
}
|
|
3172
3295
|
return prompt.join("\n\n");
|
|
3173
3296
|
}
|
|
@@ -3188,7 +3311,7 @@ function assertPreCallTokenReservation(project, workPackage, config, request, al
|
|
|
3188
3311
|
route: request.route,
|
|
3189
3312
|
primaryPayloadTokens: Math.ceil((schemaBytes + promptBytes) / RESEARCH_ESTIMATED_BYTES_PER_TOKEN),
|
|
3190
3313
|
repairPayloadTokens: Math.ceil((schemaBytes + RESEARCH_MAX_REPAIR_SOURCE_BYTES + 2_048) / RESEARCH_ESTIMATED_BYTES_PER_TOKEN),
|
|
3191
|
-
maxTurns: request.maxTurns,
|
|
3314
|
+
maxTurns: request.reservationTurns ?? request.maxTurns,
|
|
3192
3315
|
maxOutputTokens: request.maxOutputTokens,
|
|
3193
3316
|
maxToolContextTokens: request.maxToolContextTokens ?? 0,
|
|
3194
3317
|
maxRepairTokens: config.budget.maxRepairTokens,
|