@tiangong-ai/cli 0.0.35 → 0.0.37
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 +16 -6
- package/README.md +128 -10
- package/dist/research/orchestration.js +334 -29
- package/dist/research/orchestration.js.map +1 -1
- package/dist/research/workspace/acquisition-routes.d.ts +14 -0
- package/dist/research/workspace/acquisition-routes.js +45 -0
- package/dist/research/workspace/acquisition-routes.js.map +1 -0
- package/dist/research/workspace/audit-bundle.d.ts +44 -0
- package/dist/research/workspace/audit-bundle.js +357 -0
- package/dist/research/workspace/audit-bundle.js.map +1 -0
- package/dist/research/workspace/broker.js +54 -10
- package/dist/research/workspace/broker.js.map +1 -1
- package/dist/research/workspace/downloads.d.ts +6 -0
- package/dist/research/workspace/downloads.js +32 -8
- package/dist/research/workspace/downloads.js.map +1 -1
- package/dist/research/workspace/evidence-exhaustion.d.ts +45 -0
- package/dist/research/workspace/evidence-exhaustion.js +365 -0
- package/dist/research/workspace/evidence-exhaustion.js.map +1 -0
- package/dist/research/workspace/native-activity.d.ts +6 -0
- package/dist/research/workspace/native-activity.js +24 -7
- package/dist/research/workspace/native-activity.js.map +1 -1
- package/dist/research/workspace/preflight.d.ts +34 -2
- package/dist/research/workspace/preflight.js +161 -1
- package/dist/research/workspace/preflight.js.map +1 -1
- package/dist/research/workspace/projects.d.ts +28 -4
- package/dist/research/workspace/projects.js +301 -12
- package/dist/research/workspace/projects.js.map +1 -1
- package/dist/research/workspace/publication-workflow.js +2 -0
- package/dist/research/workspace/publication-workflow.js.map +1 -1
- package/dist/research/workspace/runtime.d.ts +151 -3
- package/dist/research/workspace/runtime.js +180 -6
- package/dist/research/workspace/runtime.js.map +1 -1
- package/dist/research/workspace/sanitization.js +9 -3
- package/dist/research/workspace/sanitization.js.map +1 -1
- package/dist/research/workspace/scientific-design.d.ts +359 -0
- package/dist/research/workspace/scientific-design.js +2021 -0
- package/dist/research/workspace/scientific-design.js.map +1 -0
- package/dist/research/workspace/scientific-review.d.ts +101 -0
- package/dist/research/workspace/scientific-review.js +1167 -0
- package/dist/research/workspace/scientific-review.js.map +1 -0
- package/dist/research/workspace/setup-catalog.js +2 -2
- package/dist/research/workspace/setup.js +12 -3
- package/dist/research/workspace/setup.js.map +1 -1
- package/dist/research/workspace/types.d.ts +54 -0
- package/dist/research/workspace/workspace.js +25 -7
- package/dist/research/workspace/workspace.js.map +1 -1
- package/package.json +2 -1
|
@@ -9,6 +9,7 @@ import { stageEvidenceArtifacts } from "./artifacts.js";
|
|
|
9
9
|
import { commitDiscoveryDecisions, materializeDiscoveryEvidence } from "./discovery.js";
|
|
10
10
|
import { inspectDiscoveryProgress } from "./discovery-status.js";
|
|
11
11
|
import { downloadBindingRecordSchema } from "./downloads.js";
|
|
12
|
+
import { parseEvidenceExhaustionHandoff, validateEvidenceExhaustionHandoff, } from "./evidence-exhaustion.js";
|
|
12
13
|
import { loadProjectEvidenceReceipts, stageProjectEvidence } from "./evidence.js";
|
|
13
14
|
import { appendEvidenceLedgerEvent, evidenceLedgerPath, listEvidenceCandidates, registerProjectInputCandidates, } from "./evidence-ledger.js";
|
|
14
15
|
import { executeAgent } from "./executor.js";
|
|
@@ -19,17 +20,39 @@ import { nativeActivityRecordSchema } from "./native-activity.js";
|
|
|
19
20
|
import { calculateAgentCallTokenReservation, RESEARCH_BROKER_MAX_TURNS, RESEARCH_ESTIMATED_BYTES_PER_TOKEN, RESEARCH_MAX_REPAIR_SOURCE_BYTES, RESEARCH_REPAIR_MAX_TURNS, researchStructuredOutputMaxTurns, reservedAgentPackageCost, } from "./preflight.js";
|
|
20
21
|
import { listProjects, loadProject, nextReadyPackage, packageById, refreshProject, saveProject, } from "./projects.js";
|
|
21
22
|
import { assertResearchPolicyBinding } from "./research-policy.js";
|
|
23
|
+
import { assertScientificGateForStage } from "./scientific-review.js";
|
|
22
24
|
import { configuredResearchSecrets, sanitizeResearchRecord, sanitizeResearchText, } from "./sanitization.js";
|
|
23
25
|
import { parseEvidenceRecord, schemaForDiscoveryAssessmentBatch, parseStructuredStageOutput, schemaForStage, StructuredOutputError, } from "./schemas.js";
|
|
24
26
|
import { canonicalJson, ensureDirectory, fileRecord, isObject, pathExists, readJsonFile, regularTreeFiles, resolveContained, sha256File, sha256Text, workspacePaths, writeJsonAtomic, writeTextAtomic, } from "./storage.js";
|
|
25
27
|
import { loadWorkspaceConfig, verifyDoctorAttestation, withWorkspaceLock } from "./workspace.js";
|
|
28
|
+
function identifierSetSchema(minItems, maxItems) {
|
|
29
|
+
return {
|
|
30
|
+
type: "array",
|
|
31
|
+
minItems,
|
|
32
|
+
maxItems,
|
|
33
|
+
uniqueItems: true,
|
|
34
|
+
items: { type: "string", pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
26
37
|
export const researchHandoffRecordSchema = {
|
|
27
|
-
$id: "https://schemas.tiangong.ai/research/handoff-request-
|
|
38
|
+
$id: "https://schemas.tiangong.ai/research/handoff-request-v2.json",
|
|
28
39
|
type: "object",
|
|
29
40
|
additionalProperties: false,
|
|
30
|
-
required: [
|
|
41
|
+
required: [
|
|
42
|
+
"schemaVersion",
|
|
43
|
+
"kind",
|
|
44
|
+
"state",
|
|
45
|
+
"reasonCode",
|
|
46
|
+
"summary",
|
|
47
|
+
"requestedActions",
|
|
48
|
+
"evidenceGaps",
|
|
49
|
+
],
|
|
31
50
|
properties: {
|
|
32
|
-
schemaVersion: { type: "integer", const:
|
|
51
|
+
schemaVersion: { type: "integer", const: 2 },
|
|
52
|
+
kind: {
|
|
53
|
+
type: "string",
|
|
54
|
+
enum: ["interactive-challenge", "external-wait", "evidence-exhausted"],
|
|
55
|
+
},
|
|
33
56
|
state: {
|
|
34
57
|
type: "string",
|
|
35
58
|
enum: ["user-action-required", "external-response-required"],
|
|
@@ -50,7 +73,92 @@ export const researchHandoffRecordSchema = {
|
|
|
50
73
|
uniqueItems: true,
|
|
51
74
|
items: { type: "string", minLength: 1, maxLength: 500 },
|
|
52
75
|
},
|
|
76
|
+
exhaustion: {
|
|
77
|
+
type: "object",
|
|
78
|
+
additionalProperties: false,
|
|
79
|
+
required: ["missingEvidenceRoleIds", "routeAttempts", "remainingRouteIds"],
|
|
80
|
+
properties: {
|
|
81
|
+
missingEvidenceRoleIds: identifierSetSchema(1, 100),
|
|
82
|
+
routeAttempts: {
|
|
83
|
+
type: "array",
|
|
84
|
+
minItems: 1,
|
|
85
|
+
maxItems: 100,
|
|
86
|
+
items: {
|
|
87
|
+
type: "object",
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
required: ["routeId", "terminalEventHashes", "outcome"],
|
|
90
|
+
properties: {
|
|
91
|
+
routeId: { type: "string", pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
|
|
92
|
+
terminalEventHashes: {
|
|
93
|
+
type: "array",
|
|
94
|
+
minItems: 1,
|
|
95
|
+
maxItems: 100,
|
|
96
|
+
uniqueItems: true,
|
|
97
|
+
items: { type: "string", pattern: "^[a-f0-9]{64}$" },
|
|
98
|
+
},
|
|
99
|
+
outcome: {
|
|
100
|
+
type: "string",
|
|
101
|
+
enum: ["completed-insufficient", "access-blocked", "deterministic-unavailable"],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
remainingRouteIds: identifierSetSchema(0, 100),
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
accessRequests: {
|
|
110
|
+
type: "array",
|
|
111
|
+
minItems: 0,
|
|
112
|
+
maxItems: 100,
|
|
113
|
+
items: {
|
|
114
|
+
type: "object",
|
|
115
|
+
additionalProperties: false,
|
|
116
|
+
required: [
|
|
117
|
+
"id",
|
|
118
|
+
"routeId",
|
|
119
|
+
"resourceType",
|
|
120
|
+
"resourceName",
|
|
121
|
+
"officialLocator",
|
|
122
|
+
"evidenceRoleIds",
|
|
123
|
+
"rationale",
|
|
124
|
+
"alternativesTriedRouteIds",
|
|
125
|
+
"requestedAction",
|
|
126
|
+
"resumeCriteria",
|
|
127
|
+
"costStatus",
|
|
128
|
+
],
|
|
129
|
+
properties: {
|
|
130
|
+
id: { type: "string", pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
|
|
131
|
+
routeId: { type: "string", pattern: "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
|
|
132
|
+
resourceType: {
|
|
133
|
+
type: "string",
|
|
134
|
+
enum: [
|
|
135
|
+
"database-subscription",
|
|
136
|
+
"article-purchase",
|
|
137
|
+
"institutional-access",
|
|
138
|
+
"licensed-dataset",
|
|
139
|
+
"owner-provided-material",
|
|
140
|
+
"external-data-request",
|
|
141
|
+
"field-data-collection",
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
resourceName: { type: "string", minLength: 3, maxLength: 500 },
|
|
145
|
+
officialLocator: { type: ["string", "null"], format: "uri" },
|
|
146
|
+
evidenceRoleIds: identifierSetSchema(1, 100),
|
|
147
|
+
rationale: { type: "string", minLength: 8, maxLength: 2_000 },
|
|
148
|
+
alternativesTriedRouteIds: identifierSetSchema(1, 100),
|
|
149
|
+
requestedAction: { type: "string", minLength: 8, maxLength: 1_000 },
|
|
150
|
+
resumeCriteria: { type: "string", minLength: 8, maxLength: 1_000 },
|
|
151
|
+
costStatus: { type: "string", enum: ["unknown", "provider-quote-required"] },
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
53
155
|
},
|
|
156
|
+
allOf: [
|
|
157
|
+
{
|
|
158
|
+
if: { properties: { kind: { const: "evidence-exhausted" } } },
|
|
159
|
+
then: { required: ["exhaustion", "accessRequests"] },
|
|
160
|
+
},
|
|
161
|
+
],
|
|
54
162
|
};
|
|
55
163
|
export async function runResearchWorkspace(root, options, packageExecutor = executeAgent) {
|
|
56
164
|
return runResearchWorkspaceInternal(root, options, packageExecutor, false);
|
|
@@ -179,6 +287,7 @@ export async function prepareNativeResearchStage(input) {
|
|
|
179
287
|
const config = await loadWorkspaceConfig(input.root);
|
|
180
288
|
assertExecutionConfiguration(config);
|
|
181
289
|
const project = await loadProject(input.root, input.projectId);
|
|
290
|
+
await assertScientificGateForStage(input.root, project, input.stage);
|
|
182
291
|
await assertProjectPublicationPolicy(input.root, project);
|
|
183
292
|
if (config.producer.agent !== input.hostAgent) {
|
|
184
293
|
throw new CliError(`This workspace requires the current native ${config.producer.agent} host, not ${input.hostAgent}.`, { code: "RESEARCH_NATIVE_HOST_MISMATCH", exitCode: 3 });
|
|
@@ -297,6 +406,21 @@ export async function prepareNativeResearchStage(input) {
|
|
|
297
406
|
maxWallSeconds: config.budget.packageMaxWallSeconds[input.stage],
|
|
298
407
|
},
|
|
299
408
|
commands: {
|
|
409
|
+
inspectAccess: project.scientificDesign
|
|
410
|
+
? {
|
|
411
|
+
argv: [
|
|
412
|
+
"tiangong-ai",
|
|
413
|
+
"research",
|
|
414
|
+
"project",
|
|
415
|
+
"access",
|
|
416
|
+
"status",
|
|
417
|
+
project.id,
|
|
418
|
+
"--workspace",
|
|
419
|
+
input.root,
|
|
420
|
+
"--json",
|
|
421
|
+
],
|
|
422
|
+
}
|
|
423
|
+
: null,
|
|
300
424
|
requestHandoff: {
|
|
301
425
|
argv: [
|
|
302
426
|
"tiangong-ai",
|
|
@@ -517,6 +641,7 @@ export async function prepareNativeResearchStage(input) {
|
|
|
517
641
|
rules: [
|
|
518
642
|
"Current native host performs producer reasoning; the CLI does not spawn a producer.",
|
|
519
643
|
"Native Web/Browser activity is visible in the evidence ledger but becomes admissible only after broker/input formalization and strict assessment.",
|
|
644
|
+
"An interactive challenge pauses immediately. A material evidence-exhausted handoff is valid only after inspectAccess proves every required plan-bound agent route with exact terminal event hashes.",
|
|
520
645
|
"When the next material step requires user authorization or an external response, request a durable handoff and stop; do not keep searching low-yield substitutes.",
|
|
521
646
|
"Only broker receipts or registered immutable inputs may support discover output.",
|
|
522
647
|
"Only exact, structurally validated, content-addressed artifacts may support full-text acquisition claims.",
|
|
@@ -793,6 +918,17 @@ export async function requestResearchHandoff(input) {
|
|
|
793
918
|
details: { state: project.handoff.state },
|
|
794
919
|
});
|
|
795
920
|
}
|
|
921
|
+
const evidenceHandoff = value.kind === "evidence-exhausted"
|
|
922
|
+
? await validateEvidenceExhaustionHandoff({
|
|
923
|
+
root: input.root,
|
|
924
|
+
project,
|
|
925
|
+
state: value.state,
|
|
926
|
+
value: {
|
|
927
|
+
exhaustion: value.exhaustion,
|
|
928
|
+
accessRequests: value.accessRequests,
|
|
929
|
+
},
|
|
930
|
+
})
|
|
931
|
+
: null;
|
|
796
932
|
const activePath = nativeStageSessionPath(input.root, input.projectId);
|
|
797
933
|
const session = (await pathExists(activePath))
|
|
798
934
|
? await readNativeStageSession(input.root, input.projectId)
|
|
@@ -816,10 +952,13 @@ export async function requestResearchHandoff(input) {
|
|
|
816
952
|
const requestedAt = new Date().toISOString();
|
|
817
953
|
project.handoff = {
|
|
818
954
|
state: value.state,
|
|
955
|
+
kind: value.kind,
|
|
819
956
|
reasonCode: value.reasonCode,
|
|
820
957
|
summary: value.summary,
|
|
821
958
|
requestedActions: value.requestedActions,
|
|
822
959
|
evidenceGaps: value.evidenceGaps,
|
|
960
|
+
exhaustion: evidenceHandoff?.exhaustion ?? null,
|
|
961
|
+
accessRequests: evidenceHandoff?.accessRequests ?? [],
|
|
823
962
|
requestedAt,
|
|
824
963
|
resolvedAt: null,
|
|
825
964
|
resolutionNote: null,
|
|
@@ -828,10 +967,13 @@ export async function requestResearchHandoff(input) {
|
|
|
828
967
|
await saveProject(input.root, project);
|
|
829
968
|
const eventPayload = {
|
|
830
969
|
state: value.state,
|
|
970
|
+
kind: value.kind,
|
|
831
971
|
reasonCode: value.reasonCode,
|
|
832
972
|
summary: value.summary,
|
|
833
973
|
requestedActions: value.requestedActions,
|
|
834
974
|
evidenceGaps: value.evidenceGaps,
|
|
975
|
+
exhaustion: evidenceHandoff?.exhaustion ?? null,
|
|
976
|
+
accessRequests: evidenceHandoff?.accessRequests ?? [],
|
|
835
977
|
requestedAt,
|
|
836
978
|
interruptedSessionId: session?.packet.sessionId ?? null,
|
|
837
979
|
interruptedPackageId: session?.packet.packageId ?? null,
|
|
@@ -892,18 +1034,22 @@ function parseHandoffRequest(value) {
|
|
|
892
1034
|
const sanitized = sanitizeResearchRecord(value, configuredResearchSecrets(process.env));
|
|
893
1035
|
const allowed = new Set([
|
|
894
1036
|
"schemaVersion",
|
|
1037
|
+
"kind",
|
|
895
1038
|
"state",
|
|
896
1039
|
"reasonCode",
|
|
897
1040
|
"summary",
|
|
898
1041
|
"requestedActions",
|
|
899
1042
|
"evidenceGaps",
|
|
1043
|
+
"exhaustion",
|
|
1044
|
+
"accessRequests",
|
|
900
1045
|
]);
|
|
901
1046
|
const requestedActions = Array.isArray(sanitized.requestedActions)
|
|
902
1047
|
? sanitized.requestedActions
|
|
903
1048
|
: [];
|
|
904
1049
|
const evidenceGaps = Array.isArray(sanitized.evidenceGaps) ? sanitized.evidenceGaps : [];
|
|
905
1050
|
if (Object.keys(sanitized).some((key) => !allowed.has(key)) ||
|
|
906
|
-
sanitized.schemaVersion !==
|
|
1051
|
+
sanitized.schemaVersion !== 2 ||
|
|
1052
|
+
!["interactive-challenge", "external-wait", "evidence-exhausted"].includes(String(sanitized.kind)) ||
|
|
907
1053
|
!["user-action-required", "external-response-required"].includes(String(sanitized.state)) ||
|
|
908
1054
|
typeof sanitized.reasonCode !== "string" ||
|
|
909
1055
|
!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(sanitized.reasonCode) ||
|
|
@@ -923,18 +1069,46 @@ function parseHandoffRequest(value) {
|
|
|
923
1069
|
exitCode: 2,
|
|
924
1070
|
});
|
|
925
1071
|
}
|
|
1072
|
+
const kind = sanitized.kind;
|
|
1073
|
+
const state = sanitized.state;
|
|
1074
|
+
if ((kind === "interactive-challenge" && state !== "user-action-required") ||
|
|
1075
|
+
(kind === "external-wait" && state !== "external-response-required")) {
|
|
1076
|
+
throw new CliError("Handoff request failed validation.", {
|
|
1077
|
+
code: "RESEARCH_PROJECT_HANDOFF_INVALID",
|
|
1078
|
+
exitCode: 2,
|
|
1079
|
+
});
|
|
1080
|
+
}
|
|
1081
|
+
let exhaustion = null;
|
|
1082
|
+
let accessRequests = [];
|
|
1083
|
+
if (kind === "evidence-exhausted") {
|
|
1084
|
+
const parsed = parseEvidenceExhaustionHandoff(sanitized.exhaustion, sanitized.accessRequests);
|
|
1085
|
+
exhaustion = parsed.exhaustion;
|
|
1086
|
+
accessRequests = parsed.accessRequests;
|
|
1087
|
+
}
|
|
1088
|
+
else if (sanitized.exhaustion !== undefined ||
|
|
1089
|
+
(sanitized.accessRequests !== undefined &&
|
|
1090
|
+
(!Array.isArray(sanitized.accessRequests) || sanitized.accessRequests.length > 0))) {
|
|
1091
|
+
throw new CliError("Handoff request failed validation.", {
|
|
1092
|
+
code: "RESEARCH_PROJECT_HANDOFF_INVALID",
|
|
1093
|
+
exitCode: 2,
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
926
1096
|
return {
|
|
927
|
-
|
|
1097
|
+
kind,
|
|
1098
|
+
state,
|
|
928
1099
|
reasonCode: sanitized.reasonCode,
|
|
929
1100
|
summary: sanitized.summary.trim(),
|
|
930
1101
|
requestedActions: requestedActions,
|
|
931
1102
|
evidenceGaps: evidenceGaps,
|
|
1103
|
+
exhaustion,
|
|
1104
|
+
accessRequests,
|
|
932
1105
|
};
|
|
933
1106
|
}
|
|
934
1107
|
async function executeWorkPackage(root, projectId, packageId, config, options, requestId, packageExecutor, doctorAttestation) {
|
|
935
1108
|
const project = await loadProject(root, projectId);
|
|
936
|
-
await assertProjectPublicationPolicy(root, project);
|
|
937
1109
|
const workPackage = packageById(project, packageId);
|
|
1110
|
+
await assertScientificGateForStage(root, project, workPackage.stage);
|
|
1111
|
+
await assertProjectPublicationPolicy(root, project);
|
|
938
1112
|
const now = new Date().toISOString();
|
|
939
1113
|
workPackage.status = "running";
|
|
940
1114
|
workPackage.attempts += 1;
|