imprint-mcp 0.6.6 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/README.md +278 -16
- package/package.json +2 -2
- package/prompts/audit-agent.md +25 -4
- package/prompts/auth-compile-agent.md +28 -12
- package/prompts/build-planning.md +3 -3
- package/prompts/compile-agent.md +895 -180
- package/prompts/live-verifier-agent.md +10 -3
- package/prompts/master-teach-api-researcher.md +813 -0
- package/prompts/master-teach-baseline-mvp-review.md +217 -0
- package/prompts/master-teach-completion-review.md +188 -0
- package/prompts/master-teach-decision.md +885 -0
- package/prompts/master-teach-focused-planner.md +764 -0
- package/prompts/master-teach-parameter-advisor.md +58 -0
- package/prompts/master-teach-recording-evidence.md +19 -0
- package/prompts/master-teach-refine-plan.md +7 -0
- package/prompts/master-teach-tool-advisor.md +130 -0
- package/prompts/playbook-compilation.md +45 -54
- package/prompts/prereq-builder.md +28 -6
- package/prompts/prereq-planner.md +2 -2
- package/prompts/tool-candidate-detection.md +70 -39
- package/prompts/tool-planning.md +3 -3
- package/src/cli.ts +190 -150
- package/src/imprint/agent.ts +47 -33
- package/src/imprint/api-research-agent.ts +933 -0
- package/src/imprint/audit.ts +49 -2
- package/src/imprint/auth-compile-agent.ts +125 -55
- package/src/imprint/auth-compile-tools.ts +20 -48
- package/src/imprint/auth-verifier.ts +8 -19
- package/src/imprint/backend-ladder.ts +499 -367
- package/src/imprint/body-structure.ts +656 -0
- package/src/imprint/build-plan.ts +33 -323
- package/src/imprint/cdp-browser-fetch.ts +734 -29
- package/src/imprint/cdp-jar-cache.ts +7 -12
- package/src/imprint/claude-cli-compile.ts +276 -320
- package/src/imprint/codex-cli-compile.ts +476 -350
- package/src/imprint/codex-sdk-turn.ts +102 -0
- package/src/imprint/compile-agent-types.ts +49 -10
- package/src/imprint/compile-agent.ts +189 -274
- package/src/imprint/compile-done-sentinel.ts +211 -0
- package/src/imprint/compile-provider-control.ts +401 -0
- package/src/imprint/compile-provider-recovery.ts +142 -0
- package/src/imprint/compile-strategy.ts +5 -0
- package/src/imprint/compile-tools.ts +1695 -3097
- package/src/imprint/compile-verification.ts +9 -1
- package/src/imprint/compile.ts +107 -29
- package/src/imprint/compiler-log.ts +12 -0
- package/src/imprint/compiler-process.ts +440 -0
- package/src/imprint/concurrency.ts +43 -58
- package/src/imprint/credential-extract.ts +1 -88
- package/src/imprint/emit.ts +18 -2
- package/src/imprint/evidence-inspection.ts +55 -0
- package/src/imprint/freeform-redact.ts +34 -234
- package/src/imprint/import-module-fresh.ts +30 -0
- package/src/imprint/live-finesse-runner.ts +299 -0
- package/src/imprint/live-verifier.ts +299 -358
- package/src/imprint/llm.ts +466 -422
- package/src/imprint/log.ts +1 -9
- package/src/imprint/master-teach-agent-contracts.ts +875 -0
- package/src/imprint/master-teach-agents.ts +2850 -0
- package/src/imprint/master-teach-checks.ts +341 -0
- package/src/imprint/master-teach-controller.ts +7159 -0
- package/src/imprint/master-teach-plan.ts +1410 -0
- package/src/imprint/master-teach-prompt-projections.ts +347 -0
- package/src/imprint/master-teach-store.ts +961 -0
- package/src/imprint/mcp-cdp-sessions.ts +60 -0
- package/src/imprint/mcp-compile-server.ts +519 -668
- package/src/imprint/mcp-live-verifier-server.ts +246 -190
- package/src/imprint/mcp-server.ts +46 -57
- package/src/imprint/native-agent-pass.ts +260 -0
- package/src/imprint/native-agent-usage.ts +141 -0
- package/src/imprint/native-teach-agents.ts +495 -0
- package/src/imprint/param-grounding.ts +488 -347
- package/src/imprint/playbook-runner.ts +254 -63
- package/src/imprint/prereq-builder.ts +55 -543
- package/src/imprint/private-file.ts +18 -0
- package/src/imprint/probe-backends.ts +129 -33
- package/src/imprint/provider-retry.ts +501 -0
- package/src/imprint/provider-terminal.ts +214 -0
- package/src/imprint/recording-request.ts +290 -1
- package/src/imprint/recording-verification.ts +444 -0
- package/src/imprint/redact.ts +33 -749
- package/src/imprint/refine-worker.ts +326 -0
- package/src/imprint/refine.ts +241 -0
- package/src/imprint/replay-capture.ts +41 -12
- package/src/imprint/replay-evidence.ts +1007 -0
- package/src/imprint/research-response-evidence.ts +45 -0
- package/src/imprint/runtime.ts +514 -106
- package/src/imprint/sensitive-keys.ts +0 -6
- package/src/imprint/session-merge.ts +103 -7
- package/src/imprint/stealth-fetch.ts +25 -8
- package/src/imprint/stealth-token-cache.ts +16 -16
- package/src/imprint/teach-plan.ts +0 -242
- package/src/imprint/teach-research-memory.ts +229 -0
- package/src/imprint/teach-state.ts +47 -625
- package/src/imprint/teach.ts +12 -3699
- package/src/imprint/tool-candidates.ts +58 -210
- package/src/imprint/tool-loader.ts +3 -0
- package/src/imprint/tool-plan.ts +1 -134
- package/src/imprint/tracing.ts +24 -7
- package/src/imprint/types.ts +68 -4
- package/src/imprint/endpoint-key.ts +0 -23
|
@@ -0,0 +1,875 @@
|
|
|
1
|
+
/** Strict wire contracts for bounded, one-shot semantic roles. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { BackendAttemptFact } from './backend-ladder.ts';
|
|
4
|
+
import type { BodyComparison } from './body-structure.ts';
|
|
5
|
+
import {
|
|
6
|
+
ChainEdgeSchema,
|
|
7
|
+
ConcreteTeachingParameterSchema,
|
|
8
|
+
ContentAddressedRefSchema,
|
|
9
|
+
DesiredTeachingPlanSchema,
|
|
10
|
+
EditableTeachingPlanSchema,
|
|
11
|
+
EditableTeachingToolSchema,
|
|
12
|
+
ImplementationPlanPayloadSchema,
|
|
13
|
+
ImplementationPlanRefSchema,
|
|
14
|
+
TeachingCompileContextSchema,
|
|
15
|
+
TeachingParameterSchema,
|
|
16
|
+
TeachingToolCandidateSchema,
|
|
17
|
+
TeachingToolStrategySchema,
|
|
18
|
+
teachingPlanContentSha256 as digest,
|
|
19
|
+
implementationPlanRequestProvenanceSha256,
|
|
20
|
+
} from './master-teach-plan.ts';
|
|
21
|
+
import {
|
|
22
|
+
CurrentExecutionSnapshotSchema,
|
|
23
|
+
PromptEvidenceProjectionSchema,
|
|
24
|
+
PromptIdSchema,
|
|
25
|
+
PromptShaSchema,
|
|
26
|
+
PromptToolIdSchema,
|
|
27
|
+
ReceiptHistoryProjectionSchema,
|
|
28
|
+
RecordingIndexSchema,
|
|
29
|
+
RunIdentitySchema,
|
|
30
|
+
ToolVerificationPayloadSchema,
|
|
31
|
+
contentProjection,
|
|
32
|
+
schemaIssue,
|
|
33
|
+
utf8Text,
|
|
34
|
+
} from './master-teach-prompt-projections.ts';
|
|
35
|
+
import { RESPONSE_OBSERVATIONS_MAX, RESPONSE_OBSERVATION_PREVIEW_BYTES } from './runtime.ts';
|
|
36
|
+
import { WorkflowSchema } from './types.ts';
|
|
37
|
+
const Reason = utf8Text(1, 4_000);
|
|
38
|
+
const Short = utf8Text(1, 1_000);
|
|
39
|
+
export { schemaIssue };
|
|
40
|
+
const strictObject = <Shape extends z.ZodRawShape>(shape: Shape) => z.object(shape).strict();
|
|
41
|
+
export const SemanticToolCandidateSchema = TeachingToolCandidateSchema;
|
|
42
|
+
export type SemanticToolCandidate = z.infer<typeof SemanticToolCandidateSchema>;
|
|
43
|
+
const ToolBoundaryProposalSchema = SemanticToolCandidateSchema.omit({
|
|
44
|
+
likelyParams: true,
|
|
45
|
+
}).strict();
|
|
46
|
+
export const CurrentPlanProjectionSchema = contentProjection(EditableTeachingPlanSchema);
|
|
47
|
+
export type CurrentPlanProjection = z.infer<typeof CurrentPlanProjectionSchema>;
|
|
48
|
+
export const CurrentPlanBindingSchema = RunIdentitySchema.extend({
|
|
49
|
+
planRevision: z.number().int().positive(),
|
|
50
|
+
planSha256: PromptShaSchema,
|
|
51
|
+
}).strict();
|
|
52
|
+
export type CurrentPlanBinding = z.infer<typeof CurrentPlanBindingSchema>;
|
|
53
|
+
const FocusedPlannerBindingSchema = RunIdentitySchema.extend({
|
|
54
|
+
toolId: PromptToolIdSchema,
|
|
55
|
+
}).strict();
|
|
56
|
+
const PlannerProposalBindingSchema = FocusedPlannerBindingSchema.extend({
|
|
57
|
+
compileInputsSha256: PromptShaSchema,
|
|
58
|
+
}).strict();
|
|
59
|
+
export const PlannableTeachingToolSchema = EditableTeachingToolSchema.omit({
|
|
60
|
+
implementationPlan: true,
|
|
61
|
+
}).strict();
|
|
62
|
+
export type PlannableTeachingTool = z.infer<typeof PlannableTeachingToolSchema>;
|
|
63
|
+
const PlannedTeachingToolSchema = PlannableTeachingToolSchema.extend({
|
|
64
|
+
candidate: TeachingToolCandidateSchema.extend({
|
|
65
|
+
likelyParams: z.array(ConcreteTeachingParameterSchema).max(64),
|
|
66
|
+
}).strict(),
|
|
67
|
+
strategy: TeachingToolStrategySchema,
|
|
68
|
+
}).strict();
|
|
69
|
+
const AvailableProducerSchema = strictObject({
|
|
70
|
+
toolId: PromptToolIdSchema,
|
|
71
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
72
|
+
expectedOutput: SemanticToolCandidateSchema.shape.expectedOutput,
|
|
73
|
+
});
|
|
74
|
+
/** Input-only context from the other tools in the master's current plan.
|
|
75
|
+
* This lets a focused planner reuse already-grounded transport/bootstrap
|
|
76
|
+
* evidence without turning that evidence into a runtime policy. */
|
|
77
|
+
const SiblingToolEvidenceSchema = strictObject({
|
|
78
|
+
toolId: PromptToolIdSchema,
|
|
79
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
80
|
+
supportRequestSeqs: SemanticToolCandidateSchema.shape.dependencySeqs,
|
|
81
|
+
compileContext: TeachingCompileContextSchema,
|
|
82
|
+
strategy: TeachingToolStrategySchema.optional(),
|
|
83
|
+
});
|
|
84
|
+
export const FocusedPlannerRevisionContextSchema = strictObject({
|
|
85
|
+
/** The exact older plan/build being revised. The failure facts are the
|
|
86
|
+
* latest reason the master recalled this tool and may describe a direct
|
|
87
|
+
* failure or a dependency failure involving it. */
|
|
88
|
+
sourcePlanRevision: z.number().int().positive(),
|
|
89
|
+
sourcePlanRef: ContentAddressedRefSchema,
|
|
90
|
+
sourceBuildRef: ContentAddressedRefSchema.optional(),
|
|
91
|
+
previousImplementationPlan: strictObject({
|
|
92
|
+
ref: ImplementationPlanRefSchema,
|
|
93
|
+
payload: ImplementationPlanPayloadSchema,
|
|
94
|
+
})
|
|
95
|
+
.superRefine((implementation, ctx) => {
|
|
96
|
+
if (digest(implementation.payload) !== implementation.ref.sha256)
|
|
97
|
+
schemaIssue(ctx, ['ref', 'sha256'], 'previous implementation plan hash mismatch');
|
|
98
|
+
})
|
|
99
|
+
.optional(),
|
|
100
|
+
latestFailureFacts: PromptEvidenceProjectionSchema,
|
|
101
|
+
});
|
|
102
|
+
export type FocusedPlannerRevisionContext = z.infer<typeof FocusedPlannerRevisionContextSchema>;
|
|
103
|
+
export const FocusedPlannerInputSchema = strictObject({
|
|
104
|
+
run: RunIdentitySchema,
|
|
105
|
+
recordingIndex: RecordingIndexSchema,
|
|
106
|
+
/** Captured bodies available for offline parser fixtures. Omitted only by
|
|
107
|
+
* older callers; request existence alone does not establish body availability. */
|
|
108
|
+
recordingResponseBodySeqs: z.array(z.number().int().nonnegative()).optional(),
|
|
109
|
+
/** The master's latest accepted/rejected/revised reasoning for this plan. */
|
|
110
|
+
masterGuidance: Reason,
|
|
111
|
+
tool: PlannableTeachingToolSchema,
|
|
112
|
+
availableProducers: z.array(AvailableProducerSchema),
|
|
113
|
+
siblingToolEvidence: z.array(SiblingToolEvidenceSchema),
|
|
114
|
+
incomingChainEdges: z.array(ChainEdgeSchema),
|
|
115
|
+
outgoingChainEdges: z.array(ChainEdgeSchema),
|
|
116
|
+
/** Completed request research for every selected operation. Planning runs
|
|
117
|
+
* only after these handoffs exist so cross-tool dependencies can be chosen
|
|
118
|
+
* from tested calls and response shapes rather than guesses. */
|
|
119
|
+
apiResearch: z.array(z.lazy(() => ApiResearchHandoffSchema)).default([]),
|
|
120
|
+
evidence: PromptEvidenceProjectionSchema,
|
|
121
|
+
/** Optional input-only handoff from the immediately preceding failed
|
|
122
|
+
* attempt. The planner never echoes this object. */
|
|
123
|
+
revisionContext: FocusedPlannerRevisionContextSchema.optional(),
|
|
124
|
+
});
|
|
125
|
+
export type FocusedPlannerInput = z.input<typeof FocusedPlannerInputSchema>;
|
|
126
|
+
export const FocusedPlannerOutputSchema = strictObject({
|
|
127
|
+
binding: FocusedPlannerBindingSchema,
|
|
128
|
+
tool: PlannedTeachingToolSchema,
|
|
129
|
+
chainEdges: z.array(ChainEdgeSchema),
|
|
130
|
+
implementationPlan: ImplementationPlanPayloadSchema,
|
|
131
|
+
reason: Reason,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const ScalarParameterValuesSchema = z.record(z.union([z.string(), z.number(), z.boolean()]));
|
|
135
|
+
export const ApiResearchCandidateSchema = strictObject({
|
|
136
|
+
workflow: WorkflowSchema,
|
|
137
|
+
requestTransformSource: utf8Text(1, 100_000).optional(),
|
|
138
|
+
parameterValues: ScalarParameterValuesSchema,
|
|
139
|
+
testBackend: z
|
|
140
|
+
.enum(['auto', 'fetch', 'fetch-bootstrap', 'cdp-replay', 'stealth-fetch'])
|
|
141
|
+
.optional(),
|
|
142
|
+
});
|
|
143
|
+
export type ApiResearchCandidate = z.infer<typeof ApiResearchCandidateSchema>;
|
|
144
|
+
const BackendResponseObservationSchema = strictObject({
|
|
145
|
+
backend: z.enum(['fetch', 'fetch-bootstrap', 'cdp-replay', 'stealth-fetch', 'playbook']),
|
|
146
|
+
requestIndex: z.number().int().nonnegative(),
|
|
147
|
+
status: z.number().int().min(0).max(999),
|
|
148
|
+
bodyByteLength: z.number().int().nonnegative(),
|
|
149
|
+
redactedBodyPreview: utf8Text(0, RESPONSE_OBSERVATION_PREVIEW_BYTES).optional(),
|
|
150
|
+
contentType: utf8Text(0, 200).optional(),
|
|
151
|
+
valueType: z.enum(['null', 'array', 'object', 'string', 'number', 'boolean']),
|
|
152
|
+
topLevelKeys: z.array(utf8Text(0, 200)).max(32).optional(),
|
|
153
|
+
arrayLength: z.number().int().nonnegative().optional(),
|
|
154
|
+
});
|
|
155
|
+
const PreparedRequestComparisonSchema = strictObject({
|
|
156
|
+
backend: z.enum(['fetch', 'fetch-bootstrap', 'cdp-replay', 'stealth-fetch', 'playbook']),
|
|
157
|
+
requestIndex: z.number().int().nonnegative(),
|
|
158
|
+
recordingRequestSeq: z.number().int().nonnegative().optional(),
|
|
159
|
+
status: z.enum(['checked', 'not_checked']),
|
|
160
|
+
reason: utf8Text(1, 500).optional(),
|
|
161
|
+
methodEqual: z.boolean().optional(),
|
|
162
|
+
originPathEqual: z.boolean().optional(),
|
|
163
|
+
recordedQueryKeyCount: z.number().int().nonnegative().optional(),
|
|
164
|
+
preparedQueryKeyCount: z.number().int().nonnegative().optional(),
|
|
165
|
+
recordedOnlyQueryKeys: z.array(utf8Text(0, 200)).max(32).optional(),
|
|
166
|
+
preparedOnlyQueryKeys: z.array(utf8Text(0, 200)).max(32).optional(),
|
|
167
|
+
queryKeyDifferencesTruncated: z.boolean().optional(),
|
|
168
|
+
sharedHeaderNameCount: z.number().int().nonnegative().optional(),
|
|
169
|
+
recordedOnlyHeaderNames: z.array(utf8Text(0, 200)).max(32).optional(),
|
|
170
|
+
preparedOnlyHeaderNames: z.array(utf8Text(0, 200)).max(32).optional(),
|
|
171
|
+
headerNameDifferencesTruncated: z.boolean().optional(),
|
|
172
|
+
recordedUrlBytes: z.number().int().nonnegative().optional(),
|
|
173
|
+
preparedUrlBytes: z.number().int().nonnegative().optional(),
|
|
174
|
+
urlFirstMismatchByte: z.number().int().nonnegative().optional(),
|
|
175
|
+
recordedBodyBytes: z.number().int().nonnegative().optional(),
|
|
176
|
+
preparedBodyBytes: z.number().int().nonnegative().optional(),
|
|
177
|
+
bodyFirstMismatchByte: z.number().int().nonnegative().optional(),
|
|
178
|
+
bodyStructureComparison: z.custom<BodyComparison>().optional(),
|
|
179
|
+
});
|
|
180
|
+
export const RetainedResponseEvidenceSchema = strictObject({
|
|
181
|
+
evidenceRef: PromptIdSchema,
|
|
182
|
+
attemptId: PromptIdSchema,
|
|
183
|
+
backend: z.enum(['fetch', 'fetch-bootstrap', 'cdp-replay', 'stealth-fetch', 'playbook']),
|
|
184
|
+
requestIndex: z.number().int().nonnegative(),
|
|
185
|
+
recordingRequestSeq: z.number().int().nonnegative().optional(),
|
|
186
|
+
receivedAt: z.string().datetime(),
|
|
187
|
+
status: z.number().int(),
|
|
188
|
+
contentType: utf8Text(0, 200).optional(),
|
|
189
|
+
textLength: z.number().int().nonnegative().optional(),
|
|
190
|
+
readError: utf8Text(0, 4_000).optional(),
|
|
191
|
+
});
|
|
192
|
+
export type RetainedResponseEvidence = z.infer<typeof RetainedResponseEvidenceSchema>;
|
|
193
|
+
const EvidenceProjectionSchema = strictObject({
|
|
194
|
+
source: utf8Text(1, 8_000),
|
|
195
|
+
outputCharacters: z.number().int().nonnegative(),
|
|
196
|
+
error: utf8Text(1, 8_000).optional(),
|
|
197
|
+
});
|
|
198
|
+
export const ApiResearchObservationSchema = strictObject({
|
|
199
|
+
id: PromptIdSchema,
|
|
200
|
+
producerToolName: SemanticToolCandidateSchema.shape.toolName.optional(),
|
|
201
|
+
invocationParameters: ScalarParameterValuesSchema.optional(),
|
|
202
|
+
resultTextLength: z.number().int().nonnegative().optional(),
|
|
203
|
+
responseEvidence: z
|
|
204
|
+
.array(RetainedResponseEvidenceSchema)
|
|
205
|
+
.max(RESPONSE_OBSERVATIONS_MAX)
|
|
206
|
+
.optional(),
|
|
207
|
+
resultInspections: z
|
|
208
|
+
.array(
|
|
209
|
+
strictObject({
|
|
210
|
+
offset: z.number().int().nonnegative(),
|
|
211
|
+
text: utf8Text(0, 8_000),
|
|
212
|
+
projection: EvidenceProjectionSchema.optional(),
|
|
213
|
+
evidenceRef: PromptIdSchema.optional(),
|
|
214
|
+
}),
|
|
215
|
+
)
|
|
216
|
+
.max(8)
|
|
217
|
+
.optional(),
|
|
218
|
+
candidateSha256: PromptShaSchema,
|
|
219
|
+
requestDefinitionSha256: PromptShaSchema.optional(),
|
|
220
|
+
executionMechanism: utf8Text(1, 128),
|
|
221
|
+
backendAttempts: z.custom<BackendAttemptFact[]>().default([]),
|
|
222
|
+
responseObservations: z
|
|
223
|
+
.array(BackendResponseObservationSchema)
|
|
224
|
+
.max(RESPONSE_OBSERVATIONS_MAX)
|
|
225
|
+
.default([]),
|
|
226
|
+
/** Advisory only: artifact-prepared requests reduced immediately to names,
|
|
227
|
+
* lengths, mismatch positions and bounded structural differences. No request
|
|
228
|
+
* scalar values reach the agent. */
|
|
229
|
+
requestComparisons: z.array(PreparedRequestComparisonSchema).max(32).optional(),
|
|
230
|
+
result: strictObject({
|
|
231
|
+
ok: z.boolean(),
|
|
232
|
+
error: utf8Text(1, 256).optional(),
|
|
233
|
+
message: utf8Text(1, 4_000).optional(),
|
|
234
|
+
preview: utf8Text(0, 12_000),
|
|
235
|
+
pageDiagnostic: strictObject({
|
|
236
|
+
url: z.string().max(300),
|
|
237
|
+
title: z.string().max(300),
|
|
238
|
+
bodyText: z.string().max(3_000),
|
|
239
|
+
truncated: z.boolean(),
|
|
240
|
+
}).optional(),
|
|
241
|
+
}),
|
|
242
|
+
});
|
|
243
|
+
export type ApiResearchObservation = z.infer<typeof ApiResearchObservationSchema>;
|
|
244
|
+
export const ApiResearchRequestCatalogEntrySchema = strictObject({
|
|
245
|
+
recordingRequestSeq: z.number().int().nonnegative(),
|
|
246
|
+
method: utf8Text(1, 32),
|
|
247
|
+
urlShape: utf8Text(1, 1_000),
|
|
248
|
+
resourceType: utf8Text(0, 128),
|
|
249
|
+
responseStatus: z.number().int().nullable(),
|
|
250
|
+
responseMimeType: utf8Text(0, 256).nullable(),
|
|
251
|
+
requestBodyBytes: z.number().int().nonnegative(),
|
|
252
|
+
responseBodyBytes: z.number().int().nonnegative(),
|
|
253
|
+
});
|
|
254
|
+
export type ApiResearchRequestCatalogEntry = z.infer<typeof ApiResearchRequestCatalogEntrySchema>;
|
|
255
|
+
export const ApiResearchRequiredLinkSchema = z.discriminatedUnion('role', [
|
|
256
|
+
strictObject({
|
|
257
|
+
role: z.literal('producer'),
|
|
258
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
259
|
+
resultPath: utf8Text(1, 512),
|
|
260
|
+
}),
|
|
261
|
+
strictObject({
|
|
262
|
+
role: z.literal('consumer'),
|
|
263
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
264
|
+
parameter: utf8Text(1, 128),
|
|
265
|
+
}),
|
|
266
|
+
]);
|
|
267
|
+
export type ApiResearchRequiredLink = z.infer<typeof ApiResearchRequiredLinkSchema>;
|
|
268
|
+
const ApiResearchMissingProofSchema = z.array(Short).min(1).max(32);
|
|
269
|
+
const ApiResearchRequestedSeqsSchema = z
|
|
270
|
+
.array(z.number().int().nonnegative())
|
|
271
|
+
.min(1)
|
|
272
|
+
.max(32)
|
|
273
|
+
.refine((seqs) => new Set(seqs).size === seqs.length, 'request sequences must be unique');
|
|
274
|
+
export const ApiResearchInputSchema = strictObject({
|
|
275
|
+
run: RunIdentitySchema,
|
|
276
|
+
recordingIndex: RecordingIndexSchema,
|
|
277
|
+
tool: PlannableTeachingToolSchema,
|
|
278
|
+
evidence: PromptEvidenceProjectionSchema,
|
|
279
|
+
/** Research iteration is bounded by the shared run deadline/cancellation,
|
|
280
|
+
* not an arbitrary attempt count. Retained Codex turns receive only the
|
|
281
|
+
* newest observation while other providers receive the factual history. */
|
|
282
|
+
observations: z.array(ApiResearchObservationSchema),
|
|
283
|
+
availableProducers: z
|
|
284
|
+
.array(
|
|
285
|
+
strictObject({
|
|
286
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
287
|
+
parameters: WorkflowSchema.shape.parameters,
|
|
288
|
+
summary: Reason,
|
|
289
|
+
}),
|
|
290
|
+
)
|
|
291
|
+
.optional(),
|
|
292
|
+
/** A payload-free discovery index. Exact URL/body/response evidence remains
|
|
293
|
+
* absent until the researcher explicitly asks to inspect a listed seq. */
|
|
294
|
+
requestCatalog: z
|
|
295
|
+
.array(ApiResearchRequestCatalogEntrySchema)
|
|
296
|
+
.max(256)
|
|
297
|
+
.refine(
|
|
298
|
+
(entries) =>
|
|
299
|
+
new Set(entries.map(({ recordingRequestSeq }) => recordingRequestSeq)).size ===
|
|
300
|
+
entries.length,
|
|
301
|
+
'request catalog sequences must be unique',
|
|
302
|
+
)
|
|
303
|
+
.optional(),
|
|
304
|
+
requestCatalogTruncated: z.boolean().optional(),
|
|
305
|
+
/** Position of the current bounded catalog page. Bodies are never included;
|
|
306
|
+
* `hasMore` lets the retained researcher walk every compact entry. */
|
|
307
|
+
requestCatalogPage: strictObject({
|
|
308
|
+
offset: z.number().int().nonnegative(),
|
|
309
|
+
totalEntries: z.number().int().nonnegative(),
|
|
310
|
+
hasMore: z.boolean(),
|
|
311
|
+
}).optional(),
|
|
312
|
+
/** Only this public tool's side of each required producer-consumer promise.
|
|
313
|
+
* Counterpart wiring and edge ids do not invalidate independent proof. */
|
|
314
|
+
requiredLinks: z.array(ApiResearchRequiredLinkSchema).max(128).optional(),
|
|
315
|
+
inspectedRequestSeqs: z
|
|
316
|
+
.array(z.number().int().nonnegative())
|
|
317
|
+
.max(256)
|
|
318
|
+
.refine((seqs) => new Set(seqs).size === seqs.length, 'request sequences must be unique')
|
|
319
|
+
.optional(),
|
|
320
|
+
researchPhase: z.enum(['mvp', 'follow_up']).optional(),
|
|
321
|
+
/** A bounded master-authored follow-up. The named sibling handoffs and
|
|
322
|
+
* request sequences are selected facts, not a dump of the whole recording. */
|
|
323
|
+
followUp: strictObject({
|
|
324
|
+
masterDirection: Reason,
|
|
325
|
+
missingProof: ApiResearchMissingProofSchema,
|
|
326
|
+
relevantRequestSeqs: z
|
|
327
|
+
.array(z.number().int().nonnegative())
|
|
328
|
+
.max(256)
|
|
329
|
+
.refine((seqs) => new Set(seqs).size === seqs.length, 'request sequences must be unique'),
|
|
330
|
+
siblingResearch: z.array(z.lazy(() => ApiResearchHandoffSchema)).max(64),
|
|
331
|
+
}).optional(),
|
|
332
|
+
/** The exact preceding handoff keeps follow-ups factual even when a provider
|
|
333
|
+
* cannot retain the live conversation. It may be hash-stale after an
|
|
334
|
+
* intentional same-name boundary revision, so the current tool remains the
|
|
335
|
+
* authority for the next candidate. */
|
|
336
|
+
previousProgress: z.lazy(() => ApiResearchHandoffSchema).optional(),
|
|
337
|
+
blockReview: strictObject({ proposedReason: Reason }).optional(),
|
|
338
|
+
resultInspection: strictObject({
|
|
339
|
+
observationId: PromptIdSchema,
|
|
340
|
+
evidenceRef: PromptIdSchema.optional(),
|
|
341
|
+
offset: z.number().int().nonnegative(),
|
|
342
|
+
totalCharacters: z.number().int().nonnegative(),
|
|
343
|
+
text: utf8Text(0, 8_000),
|
|
344
|
+
nextOffset: z.number().int().nonnegative().nullable(),
|
|
345
|
+
matchFound: z.boolean().optional(),
|
|
346
|
+
projection: EvidenceProjectionSchema.optional(),
|
|
347
|
+
}).optional(),
|
|
348
|
+
});
|
|
349
|
+
export type ApiResearchInput = z.infer<typeof ApiResearchInputSchema>;
|
|
350
|
+
const ApiResearchBindingSchema = strictObject({
|
|
351
|
+
runId: PromptIdSchema,
|
|
352
|
+
recordingSha256: PromptShaSchema,
|
|
353
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
354
|
+
compileInputsSha256: PromptShaSchema,
|
|
355
|
+
});
|
|
356
|
+
export const RecordingReferenceChangeSchema = strictObject({
|
|
357
|
+
selectedRequestSeqs: z.array(z.number().int().nonnegative()).min(1).max(32),
|
|
358
|
+
comparability: utf8Text(1, 2_000),
|
|
359
|
+
remainingUncertainty: utf8Text(1, 2_000),
|
|
360
|
+
});
|
|
361
|
+
export const ApiResearchOutputSchema = strictObject({
|
|
362
|
+
binding: ApiResearchBindingSchema,
|
|
363
|
+
action: z.enum([
|
|
364
|
+
'catalog',
|
|
365
|
+
'inspect',
|
|
366
|
+
'inspect_result',
|
|
367
|
+
'call_producer',
|
|
368
|
+
'test',
|
|
369
|
+
'proven',
|
|
370
|
+
'partial',
|
|
371
|
+
'blocked',
|
|
372
|
+
]),
|
|
373
|
+
producerCall: strictObject({
|
|
374
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
375
|
+
parameters: ScalarParameterValuesSchema,
|
|
376
|
+
}).optional(),
|
|
377
|
+
resultQuery: strictObject({
|
|
378
|
+
observationId: PromptIdSchema,
|
|
379
|
+
evidenceRef: PromptIdSchema.optional(),
|
|
380
|
+
offset: z.number().int().nonnegative().default(0),
|
|
381
|
+
length: z.number().int().min(1).max(2_000).default(2_000),
|
|
382
|
+
search: utf8Text(1, 256).optional(),
|
|
383
|
+
project: utf8Text(1, 8_000).optional(),
|
|
384
|
+
}).optional(),
|
|
385
|
+
candidate: ApiResearchCandidateSchema.optional(),
|
|
386
|
+
/** Reuse an exact candidate from this tool's retained test observation. */
|
|
387
|
+
candidateRef: strictObject({
|
|
388
|
+
observationId: PromptIdSchema,
|
|
389
|
+
parameterValues: ScalarParameterValuesSchema,
|
|
390
|
+
testBackend: z
|
|
391
|
+
.enum(['auto', 'fetch', 'fetch-bootstrap', 'cdp-replay', 'stealth-fetch'])
|
|
392
|
+
.optional(),
|
|
393
|
+
}).optional(),
|
|
394
|
+
/** Agent explanation when its executable request references differ from the
|
|
395
|
+
* selected tool's recorded requests. The host checks identity, not purpose. */
|
|
396
|
+
recordingReferenceChange: RecordingReferenceChangeSchema.optional(),
|
|
397
|
+
testCases: z
|
|
398
|
+
.array(
|
|
399
|
+
strictObject({
|
|
400
|
+
parameterValues: ScalarParameterValuesSchema,
|
|
401
|
+
recordingRequestSeqs: z.array(z.number().int().nonnegative()).min(1).max(32),
|
|
402
|
+
freshnessChanges: utf8Text(1, 2_000),
|
|
403
|
+
}),
|
|
404
|
+
)
|
|
405
|
+
.min(1)
|
|
406
|
+
.max(3)
|
|
407
|
+
.optional(),
|
|
408
|
+
basedOnObservationId: PromptIdSchema.optional(),
|
|
409
|
+
missingProof: ApiResearchMissingProofSchema.optional(),
|
|
410
|
+
requestedRequestSeqs: ApiResearchRequestedSeqsSchema.optional(),
|
|
411
|
+
reason: Reason,
|
|
412
|
+
});
|
|
413
|
+
export const ApiResearchHandoffSchema = strictObject({
|
|
414
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
415
|
+
researchInputsSha256: PromptShaSchema,
|
|
416
|
+
status: z.enum(['proven', 'partial', 'blocked']),
|
|
417
|
+
summary: Reason,
|
|
418
|
+
candidate: ApiResearchCandidateSchema.optional(),
|
|
419
|
+
observation: ApiResearchObservationSchema.optional(),
|
|
420
|
+
/** Actual research history, including successful contrasts. Oldest-to-newest,
|
|
421
|
+
* bounded by the host; retained across follow-ups and final handoffs. */
|
|
422
|
+
observations: z.array(ApiResearchObservationSchema).max(64).optional(),
|
|
423
|
+
missingProof: ApiResearchMissingProofSchema.optional(),
|
|
424
|
+
}).superRefine((handoff, ctx) => {
|
|
425
|
+
if (handoff.status === 'proven' && (!handoff.candidate || !handoff.observation)) {
|
|
426
|
+
schemaIssue(ctx, [], 'proven API research requires the exact candidate and observation');
|
|
427
|
+
}
|
|
428
|
+
if (handoff.status === 'proven' && handoff.observation && !handoff.observation.result.ok) {
|
|
429
|
+
schemaIssue(
|
|
430
|
+
ctx,
|
|
431
|
+
['observation', 'result', 'ok'],
|
|
432
|
+
'proven API research requires a successful candidate',
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
if (
|
|
436
|
+
handoff.status === 'partial' &&
|
|
437
|
+
(!handoff.candidate || !handoff.observation || !handoff.missingProof)
|
|
438
|
+
) {
|
|
439
|
+
schemaIssue(
|
|
440
|
+
ctx,
|
|
441
|
+
[],
|
|
442
|
+
'partial API research requires its best tested candidate, observation, and missing proof',
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
if (handoff.status === 'partial' && handoff.observation && !handoff.observation.result.ok) {
|
|
446
|
+
schemaIssue(
|
|
447
|
+
ctx,
|
|
448
|
+
['observation', 'result', 'ok'],
|
|
449
|
+
'partial API research must preserve a working candidate',
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
if (
|
|
453
|
+
handoff.status === 'blocked' &&
|
|
454
|
+
(handoff.candidate || handoff.observation || handoff.missingProof)
|
|
455
|
+
) {
|
|
456
|
+
schemaIssue(ctx, [], 'blocked API research cannot claim a proven candidate');
|
|
457
|
+
}
|
|
458
|
+
if (handoff.status === 'proven' && handoff.missingProof) {
|
|
459
|
+
schemaIssue(ctx, ['missingProof'], 'proven API research cannot have missing proof');
|
|
460
|
+
}
|
|
461
|
+
if (
|
|
462
|
+
handoff.candidate &&
|
|
463
|
+
handoff.observation &&
|
|
464
|
+
digest(handoff.candidate) !== handoff.observation.candidateSha256
|
|
465
|
+
) {
|
|
466
|
+
schemaIssue(ctx, ['candidate'], 'research handoff candidate differs from its observation');
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
export type ApiResearchHandoff = z.infer<typeof ApiResearchHandoffSchema>;
|
|
470
|
+
|
|
471
|
+
export const ApiResearchFollowUpDirectiveSchema = strictObject({
|
|
472
|
+
/** Agent-facing coordination uses the public name, never a journal identity. */
|
|
473
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
474
|
+
instruction: Reason,
|
|
475
|
+
missingProof: ApiResearchMissingProofSchema,
|
|
476
|
+
relevantToolNames: z
|
|
477
|
+
.array(SemanticToolCandidateSchema.shape.toolName)
|
|
478
|
+
.max(64)
|
|
479
|
+
.refine((names) => new Set(names).size === names.length, 'tool names must be unique'),
|
|
480
|
+
relevantRequestSeqs: z
|
|
481
|
+
.array(z.number().int().nonnegative())
|
|
482
|
+
.max(256)
|
|
483
|
+
.refine((seqs) => new Set(seqs).size === seqs.length, 'request sequences must be unique'),
|
|
484
|
+
});
|
|
485
|
+
export type ApiResearchFollowUpDirective = z.infer<typeof ApiResearchFollowUpDirectiveSchema>;
|
|
486
|
+
export const ApiResearchNoProgressSchema = strictObject({
|
|
487
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
488
|
+
/** Digest of the exact partial handoff that was reviewed. */
|
|
489
|
+
partialHandoffSha256: PromptShaSchema,
|
|
490
|
+
/** Digest of tool boundary, partial handoff, directive, and relevant sibling identities. */
|
|
491
|
+
followUpStateSha256: PromptShaSchema,
|
|
492
|
+
reason: Reason,
|
|
493
|
+
});
|
|
494
|
+
export type ApiResearchNoProgress = z.infer<typeof ApiResearchNoProgressSchema>;
|
|
495
|
+
const HostedImplementationPlanSchema = strictObject({
|
|
496
|
+
ref: ImplementationPlanRefSchema,
|
|
497
|
+
payload: ImplementationPlanPayloadSchema,
|
|
498
|
+
}).superRefine((implementation, ctx) => {
|
|
499
|
+
if (digest(implementation.payload) !== implementation.ref.sha256)
|
|
500
|
+
schemaIssue(ctx, ['ref', 'sha256'], 'implementation plan payload hash mismatch');
|
|
501
|
+
if (
|
|
502
|
+
implementationPlanRequestProvenanceSha256(implementation.payload) !==
|
|
503
|
+
implementation.ref.requestProvenanceSha256
|
|
504
|
+
)
|
|
505
|
+
schemaIssue(ctx, ['ref', 'requestProvenanceSha256'], 'request provenance hash mismatch');
|
|
506
|
+
});
|
|
507
|
+
const FocusedPlannerProposalPayloadSchema = strictObject({
|
|
508
|
+
binding: PlannerProposalBindingSchema,
|
|
509
|
+
tool: EditableTeachingToolSchema,
|
|
510
|
+
chainEdges: z.array(ChainEdgeSchema),
|
|
511
|
+
implementationPlan: HostedImplementationPlanSchema,
|
|
512
|
+
reason: Reason,
|
|
513
|
+
}).superRefine((proposal, ctx) => {
|
|
514
|
+
if (
|
|
515
|
+
proposal.binding.toolId !== proposal.tool.id ||
|
|
516
|
+
proposal.binding.compileInputsSha256 !==
|
|
517
|
+
proposal.implementationPlan.ref.basedOnCompileInputsSha256
|
|
518
|
+
)
|
|
519
|
+
schemaIssue(ctx, ['binding'], 'planner proposal compile binding is stale');
|
|
520
|
+
if (
|
|
521
|
+
!proposal.tool.implementationPlan ||
|
|
522
|
+
digest(proposal.tool.implementationPlan) !== digest(proposal.implementationPlan.ref) ||
|
|
523
|
+
proposal.implementationPlan.ref.basedOnCompileInputsSha256 !==
|
|
524
|
+
proposal.binding.compileInputsSha256
|
|
525
|
+
)
|
|
526
|
+
schemaIssue(
|
|
527
|
+
ctx,
|
|
528
|
+
['implementationPlan', 'ref'],
|
|
529
|
+
'hosted implementation plan does not bind the proposed tool',
|
|
530
|
+
);
|
|
531
|
+
if (
|
|
532
|
+
proposal.implementationPlan.payload.toolId !== proposal.tool.id ||
|
|
533
|
+
proposal.implementationPlan.payload.strategyKind !== proposal.tool.strategy?.kind
|
|
534
|
+
)
|
|
535
|
+
schemaIssue(
|
|
536
|
+
ctx,
|
|
537
|
+
['implementationPlan', 'payload'],
|
|
538
|
+
'implementation plan identity or strategy does not match the proposed tool',
|
|
539
|
+
);
|
|
540
|
+
const proposedParameters = proposal.tool.candidate.likelyParams.map(({ name }) => name).sort();
|
|
541
|
+
const mappedParameters = proposal.implementationPlan.payload.parameterMappings
|
|
542
|
+
.map(({ parameterName }) => parameterName)
|
|
543
|
+
.sort();
|
|
544
|
+
if (digest(proposedParameters) !== digest(mappedParameters))
|
|
545
|
+
schemaIssue(
|
|
546
|
+
ctx,
|
|
547
|
+
['implementationPlan', 'payload', 'parameterMappings'],
|
|
548
|
+
'implementation plan parameter mappings do not match the proposed tool',
|
|
549
|
+
);
|
|
550
|
+
proposal.chainEdges.forEach((edge, index) => {
|
|
551
|
+
if (edge.consumerToolId !== proposal.tool.id)
|
|
552
|
+
schemaIssue(ctx, ['chainEdges', index], 'planner proposal edge belongs to another consumer');
|
|
553
|
+
});
|
|
554
|
+
});
|
|
555
|
+
export const FocusedPlannerProposalSchema = contentProjection(FocusedPlannerProposalPayloadSchema);
|
|
556
|
+
const DiscoveryInputFields = {
|
|
557
|
+
/** Human scope is guidance, never recording evidence. */
|
|
558
|
+
userGuidance: utf8Text(1, 4_000).optional(),
|
|
559
|
+
selectedRecordingEvidence: PromptEvidenceProjectionSchema.optional(),
|
|
560
|
+
recordingResponseBodySeqs: z.array(z.number().int().nonnegative()).optional(),
|
|
561
|
+
run: RunIdentitySchema,
|
|
562
|
+
recordingIndex: RecordingIndexSchema,
|
|
563
|
+
detectorSharedContext: TeachingCompileContextSchema,
|
|
564
|
+
discoveryCandidates: z.array(SemanticToolCandidateSchema),
|
|
565
|
+
evidence: PromptEvidenceProjectionSchema,
|
|
566
|
+
};
|
|
567
|
+
export const ToolSelectionAdvisorInputSchema = strictObject(DiscoveryInputFields);
|
|
568
|
+
export type ToolSelectionAdvisorInput = z.infer<typeof ToolSelectionAdvisorInputSchema>;
|
|
569
|
+
/** Narrow analyzer view. The full detector input remains the host validation boundary. */
|
|
570
|
+
export const ToolSelectionAdvisorPromptInputSchema = strictObject({
|
|
571
|
+
userGuidance: DiscoveryInputFields.userGuidance,
|
|
572
|
+
recordingResponseBodySeqs: DiscoveryInputFields.recordingResponseBodySeqs,
|
|
573
|
+
run: RunIdentitySchema,
|
|
574
|
+
recordingIndex: RecordingIndexSchema,
|
|
575
|
+
discoveryCandidates: z.array(ToolBoundaryProposalSchema),
|
|
576
|
+
evidence: PromptEvidenceProjectionSchema,
|
|
577
|
+
});
|
|
578
|
+
export const ToolSelectionAdvisorOutputSchema = strictObject({
|
|
579
|
+
binding: RunIdentitySchema,
|
|
580
|
+
boundaries: z.array(ToolBoundaryProposalSchema),
|
|
581
|
+
concerns: z.array(Short).max(32),
|
|
582
|
+
reason: Reason,
|
|
583
|
+
});
|
|
584
|
+
const MasterCurrentSchema = strictObject({
|
|
585
|
+
run: CurrentPlanBindingSchema,
|
|
586
|
+
plan: CurrentPlanProjectionSchema,
|
|
587
|
+
snapshot: CurrentExecutionSnapshotSchema.optional(),
|
|
588
|
+
});
|
|
589
|
+
export const MasterDecisionInputSchema = strictObject({
|
|
590
|
+
phase: z.enum(['discovery', 'revision']),
|
|
591
|
+
/** `research_review` is the pre-planning two-way research checkpoint. */
|
|
592
|
+
decisionPurpose: z.enum(['research_review']).optional(),
|
|
593
|
+
/** Explicit user scope or priorities. This guides semantic decisions but is not recording evidence. */
|
|
594
|
+
userGuidance: utf8Text(1, 4_000).optional(),
|
|
595
|
+
discovery: ToolSelectionAdvisorInputSchema,
|
|
596
|
+
current: MasterCurrentSchema.optional(),
|
|
597
|
+
toolSelectionAdvice: ToolSelectionAdvisorOutputSchema.optional(),
|
|
598
|
+
plannerProposals: z.array(FocusedPlannerProposalSchema),
|
|
599
|
+
/** Rejected planner output is advisory, never an executable proposal. */
|
|
600
|
+
plannerFailures: z
|
|
601
|
+
.array(
|
|
602
|
+
strictObject({
|
|
603
|
+
toolId: PromptToolIdSchema,
|
|
604
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
605
|
+
parseErrors: z.array(z.string()),
|
|
606
|
+
}),
|
|
607
|
+
)
|
|
608
|
+
.optional(),
|
|
609
|
+
apiResearch: z.array(ApiResearchHandoffSchema).default([]),
|
|
610
|
+
/** Exact factual no-op found after a completed master -> researcher cycle. */
|
|
611
|
+
researchNoProgress: z.array(ApiResearchNoProgressSchema).max(64).optional(),
|
|
612
|
+
verificationFindings: PromptEvidenceProjectionSchema.optional(),
|
|
613
|
+
}).superRefine((value, ctx) => {
|
|
614
|
+
if ((value.phase === 'revision') !== Boolean(value.current))
|
|
615
|
+
schemaIssue(ctx, ['current'], 'revision alone requires current-plan state');
|
|
616
|
+
});
|
|
617
|
+
export type MasterDecisionInput = z.input<typeof MasterDecisionInputSchema>;
|
|
618
|
+
const MasterDecisionBindingSchema = z.union([RunIdentitySchema, CurrentPlanBindingSchema]);
|
|
619
|
+
export const MasterDecisionOutputSchema = strictObject({
|
|
620
|
+
binding: MasterDecisionBindingSchema,
|
|
621
|
+
outcome: z.enum(['accepted', 'rejected', 'revised']),
|
|
622
|
+
reason: Reason,
|
|
623
|
+
/** Public tool names whose retained planner/compiler conversations need work. */
|
|
624
|
+
recallToolNames: z.array(SemanticToolCandidateSchema.shape.toolName),
|
|
625
|
+
/** Precise requests back to retained per-tool API researchers. */
|
|
626
|
+
researchFollowUps: z.array(ApiResearchFollowUpDirectiveSchema).optional(),
|
|
627
|
+
desiredPlan: DesiredTeachingPlanSchema,
|
|
628
|
+
});
|
|
629
|
+
export const ParameterSelectionAdvisorInputSchema = strictObject({
|
|
630
|
+
run: CurrentPlanBindingSchema,
|
|
631
|
+
recordingIndex: RecordingIndexSchema,
|
|
632
|
+
currentPlan: CurrentPlanProjectionSchema,
|
|
633
|
+
snapshot: CurrentExecutionSnapshotSchema,
|
|
634
|
+
toolId: PromptToolIdSchema,
|
|
635
|
+
evidence: PromptEvidenceProjectionSchema,
|
|
636
|
+
});
|
|
637
|
+
export type ParameterSelectionAdvisorInput = z.infer<typeof ParameterSelectionAdvisorInputSchema>;
|
|
638
|
+
const ParameterAdvisorProducerSchema = strictObject({
|
|
639
|
+
toolId: PromptToolIdSchema,
|
|
640
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
641
|
+
proof: ToolVerificationPayloadSchema,
|
|
642
|
+
}).superRefine((producer, ctx) => {
|
|
643
|
+
if (producer.proof.toolId !== producer.toolId)
|
|
644
|
+
schemaIssue(ctx, ['proof', 'toolId'], 'producer proof belongs to another tool');
|
|
645
|
+
});
|
|
646
|
+
/** Focused analyzer view issued only after the full parameter input validates. */
|
|
647
|
+
export const ParameterSelectionAdvisorPromptInputSchema = strictObject({
|
|
648
|
+
run: CurrentPlanBindingSchema,
|
|
649
|
+
targetTool: EditableTeachingToolSchema,
|
|
650
|
+
targetProof: ToolVerificationPayloadSchema,
|
|
651
|
+
incomingChainEdges: z.array(ChainEdgeSchema),
|
|
652
|
+
producers: z.array(ParameterAdvisorProducerSchema),
|
|
653
|
+
evidence: PromptEvidenceProjectionSchema,
|
|
654
|
+
}).superRefine((value, ctx) => {
|
|
655
|
+
if (value.targetProof.toolId !== value.targetTool.id)
|
|
656
|
+
schemaIssue(ctx, ['targetProof', 'toolId'], 'target proof belongs to another tool');
|
|
657
|
+
value.incomingChainEdges.forEach((edge, index) => {
|
|
658
|
+
if (edge.consumerToolId !== value.targetTool.id)
|
|
659
|
+
schemaIssue(ctx, ['incomingChainEdges', index], 'incoming edge belongs to another consumer');
|
|
660
|
+
});
|
|
661
|
+
const expectedProducerIds = [
|
|
662
|
+
...new Set(value.incomingChainEdges.map(({ producerToolId }) => producerToolId)),
|
|
663
|
+
].sort();
|
|
664
|
+
const actualProducerIds = value.producers.map(({ toolId }) => toolId).sort();
|
|
665
|
+
if (digest(expectedProducerIds) !== digest(actualProducerIds))
|
|
666
|
+
schemaIssue(ctx, ['producers'], 'producer proofs do not match incoming chain edges');
|
|
667
|
+
});
|
|
668
|
+
const ParameterAdviceBindingSchema = strictObject({
|
|
669
|
+
runId: PromptIdSchema,
|
|
670
|
+
recordingSha256: PromptShaSchema,
|
|
671
|
+
toolId: PromptToolIdSchema,
|
|
672
|
+
compileInputsSha256: PromptShaSchema,
|
|
673
|
+
});
|
|
674
|
+
export const ParameterSelectionAdvisorOutputSchema = strictObject({
|
|
675
|
+
binding: ParameterAdviceBindingSchema,
|
|
676
|
+
likelyParams: z.array(TeachingParameterSchema).max(64),
|
|
677
|
+
evidenceRefs: z.array(ContentAddressedRefSchema).min(1).max(16),
|
|
678
|
+
concerns: z.array(Short).max(32),
|
|
679
|
+
reason: Reason,
|
|
680
|
+
}).superRefine((value, ctx) => {
|
|
681
|
+
const names = value.likelyParams.map(({ name }) => name);
|
|
682
|
+
if (new Set(names).size !== names.length)
|
|
683
|
+
schemaIssue(ctx, ['likelyParams'], 'duplicate parameter');
|
|
684
|
+
});
|
|
685
|
+
const ClaimSchema = strictObject({
|
|
686
|
+
id: PromptIdSchema,
|
|
687
|
+
kind: z.enum(['blocker', 'waiver', 'exclusion']),
|
|
688
|
+
statement: Short,
|
|
689
|
+
toolId: PromptToolIdSchema.optional(),
|
|
690
|
+
evidenceRefs: z.array(ContentAddressedRefSchema).min(1).max(32),
|
|
691
|
+
});
|
|
692
|
+
const CompletionActualResultSchema = strictObject({
|
|
693
|
+
observed: z.boolean(),
|
|
694
|
+
preview: utf8Text(0, 32_000),
|
|
695
|
+
shape: utf8Text(1, 512),
|
|
696
|
+
count: z.number().int().nonnegative().nullable(),
|
|
697
|
+
truncated: z.boolean(),
|
|
698
|
+
});
|
|
699
|
+
/**
|
|
700
|
+
* Controller-issued, already-redacted live result evidence. It is deliberately
|
|
701
|
+
* separate from immutable receipts so receipts can stay value-free while the
|
|
702
|
+
* independent completion reviewer sees enough bounded semantics to judge the
|
|
703
|
+
* promised result.
|
|
704
|
+
*/
|
|
705
|
+
const CompletionToolResultEvidencePayloadSchema = strictObject({
|
|
706
|
+
toolId: PromptToolIdSchema,
|
|
707
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
708
|
+
implementationPlanRef: ImplementationPlanRefSchema,
|
|
709
|
+
verificationCaseId: PromptIdSchema,
|
|
710
|
+
expectedResult: utf8Text(1, 2_000),
|
|
711
|
+
resultReceiptRef: ContentAddressedRefSchema,
|
|
712
|
+
invocationParameters: ScalarParameterValuesSchema.optional(),
|
|
713
|
+
chainEdgeId: PromptIdSchema.optional(),
|
|
714
|
+
actualResult: CompletionActualResultSchema,
|
|
715
|
+
});
|
|
716
|
+
export const CompletionToolResultEvidenceSchema = contentProjection(
|
|
717
|
+
CompletionToolResultEvidencePayloadSchema,
|
|
718
|
+
);
|
|
719
|
+
export type CompletionToolResultEvidence = z.infer<typeof CompletionToolResultEvidenceSchema>;
|
|
720
|
+
/**
|
|
721
|
+
* Host-current input for the small semantic gate that decides whether one
|
|
722
|
+
* mechanically verified build is a credible usable MVP. The richer host view
|
|
723
|
+
* is validated before the analyzer receives the focused projection below.
|
|
724
|
+
*/
|
|
725
|
+
const ResultDerivationSchema = strictObject({
|
|
726
|
+
buildRef: ContentAddressedRefSchema,
|
|
727
|
+
artifactRef: ContentAddressedRefSchema,
|
|
728
|
+
source: utf8Text(0, 16_000),
|
|
729
|
+
truncated: z.boolean(),
|
|
730
|
+
requestSource: utf8Text(0, 32_000).optional(),
|
|
731
|
+
requestSourceTruncated: z.boolean().optional(),
|
|
732
|
+
researchSummary: utf8Text(0, 16_000).optional(),
|
|
733
|
+
researchEvidence: strictObject({
|
|
734
|
+
requestSource: utf8Text(0, 32_000),
|
|
735
|
+
requestSourceTruncated: z.boolean(),
|
|
736
|
+
observations: z
|
|
737
|
+
.array(
|
|
738
|
+
ApiResearchObservationSchema.pick({
|
|
739
|
+
id: true,
|
|
740
|
+
candidateSha256: true,
|
|
741
|
+
requestDefinitionSha256: true,
|
|
742
|
+
invocationParameters: true,
|
|
743
|
+
executionMechanism: true,
|
|
744
|
+
result: true,
|
|
745
|
+
resultInspections: true,
|
|
746
|
+
}),
|
|
747
|
+
)
|
|
748
|
+
.max(8),
|
|
749
|
+
}).optional(),
|
|
750
|
+
});
|
|
751
|
+
export const BaselineMvpReviewInputSchema = strictObject({
|
|
752
|
+
run: CurrentPlanBindingSchema,
|
|
753
|
+
recordingIndex: RecordingIndexSchema,
|
|
754
|
+
currentPlan: CurrentPlanProjectionSchema,
|
|
755
|
+
snapshot: CurrentExecutionSnapshotSchema,
|
|
756
|
+
toolId: PromptToolIdSchema,
|
|
757
|
+
resultEvidence: CompletionToolResultEvidenceSchema,
|
|
758
|
+
resultDerivation: ResultDerivationSchema.optional(),
|
|
759
|
+
});
|
|
760
|
+
export type BaselineMvpReviewInput = z.infer<typeof BaselineMvpReviewInputSchema>;
|
|
761
|
+
const BaselineMvpReviewBindingSchema = CurrentPlanBindingSchema.extend({
|
|
762
|
+
toolId: PromptToolIdSchema,
|
|
763
|
+
compileInputsSha256: PromptShaSchema,
|
|
764
|
+
currentBuildRef: ContentAddressedRefSchema,
|
|
765
|
+
executionBindingSha256: PromptShaSchema,
|
|
766
|
+
resultReceiptRef: ContentAddressedRefSchema,
|
|
767
|
+
resultEvidenceRef: ContentAddressedRefSchema,
|
|
768
|
+
}).strict();
|
|
769
|
+
export const BaselineMvpReviewerPromptInputSchema = strictObject({
|
|
770
|
+
binding: BaselineMvpReviewBindingSchema,
|
|
771
|
+
resultDerivation: ResultDerivationSchema.optional(),
|
|
772
|
+
intendedOperation: strictObject({
|
|
773
|
+
toolName: SemanticToolCandidateSchema.shape.toolName,
|
|
774
|
+
description: SemanticToolCandidateSchema.shape.description,
|
|
775
|
+
expectedOutput: SemanticToolCandidateSchema.shape.expectedOutput,
|
|
776
|
+
}),
|
|
777
|
+
baseline: strictObject({
|
|
778
|
+
verificationCaseId: PromptIdSchema,
|
|
779
|
+
expectedResult: utf8Text(1, 2_000),
|
|
780
|
+
actualResult: CompletionActualResultSchema,
|
|
781
|
+
invocationParameters: ScalarParameterValuesSchema.optional(),
|
|
782
|
+
resultEvidenceRef: ContentAddressedRefSchema,
|
|
783
|
+
resultReceiptRef: ContentAddressedRefSchema,
|
|
784
|
+
chainEdgeId: PromptIdSchema.optional(),
|
|
785
|
+
/** Exact members of the one agent-declared chain invocation. */
|
|
786
|
+
chainInvocationEdgeIds: z.array(PromptIdSchema).min(1).optional(),
|
|
787
|
+
}),
|
|
788
|
+
}).superRefine((input, ctx) => {
|
|
789
|
+
const { chainEdgeId, chainInvocationEdgeIds } = input.baseline;
|
|
790
|
+
if (Boolean(chainEdgeId) !== Boolean(chainInvocationEdgeIds))
|
|
791
|
+
schemaIssue(
|
|
792
|
+
ctx,
|
|
793
|
+
['baseline', 'chainInvocationEdgeIds'],
|
|
794
|
+
'chain invocation members are required exactly when a chain edge is present',
|
|
795
|
+
);
|
|
796
|
+
if (
|
|
797
|
+
chainInvocationEdgeIds &&
|
|
798
|
+
(new Set(chainInvocationEdgeIds).size !== chainInvocationEdgeIds.length ||
|
|
799
|
+
(chainEdgeId !== undefined && !chainInvocationEdgeIds.includes(chainEdgeId)))
|
|
800
|
+
)
|
|
801
|
+
schemaIssue(
|
|
802
|
+
ctx,
|
|
803
|
+
['baseline', 'chainInvocationEdgeIds'],
|
|
804
|
+
'chain invocation members must be unique and include the receipt edge',
|
|
805
|
+
);
|
|
806
|
+
});
|
|
807
|
+
export const BaselineMvpReviewOutputSchema = strictObject({
|
|
808
|
+
binding: BaselineMvpReviewBindingSchema,
|
|
809
|
+
status: z.enum(['credible', 'revision_required']),
|
|
810
|
+
reason: Short,
|
|
811
|
+
evidenceRefs: z.array(ContentAddressedRefSchema).min(1).max(4),
|
|
812
|
+
});
|
|
813
|
+
export const CompletionReviewInputSchema = strictObject({
|
|
814
|
+
userGuidance: utf8Text(1, 4_000).optional(),
|
|
815
|
+
terminalIntent: z.enum(['completed', 'partial', 'blocked']),
|
|
816
|
+
run: CurrentPlanBindingSchema,
|
|
817
|
+
recordingIndex: RecordingIndexSchema,
|
|
818
|
+
currentPlan: CurrentPlanProjectionSchema,
|
|
819
|
+
snapshot: CurrentExecutionSnapshotSchema,
|
|
820
|
+
history: ReceiptHistoryProjectionSchema,
|
|
821
|
+
evidence: PromptEvidenceProjectionSchema,
|
|
822
|
+
claims: z.array(ClaimSchema),
|
|
823
|
+
/** Optional until the controller has captured a bounded result projection. */
|
|
824
|
+
toolResultEvidence: z.array(CompletionToolResultEvidenceSchema).optional(),
|
|
825
|
+
semanticReviewHistory: z
|
|
826
|
+
.array(
|
|
827
|
+
strictObject({
|
|
828
|
+
toolName: Short,
|
|
829
|
+
planRevision: z.number().int().nonnegative(),
|
|
830
|
+
buildRef: ContentAddressedRefSchema,
|
|
831
|
+
resultReceiptRef: ContentAddressedRefSchema,
|
|
832
|
+
reviewRef: ContentAddressedRefSchema,
|
|
833
|
+
invocationParameters: ScalarParameterValuesSchema.optional(),
|
|
834
|
+
status: z.enum(['credible', 'revision_required']),
|
|
835
|
+
reason: Short,
|
|
836
|
+
}),
|
|
837
|
+
)
|
|
838
|
+
.optional(),
|
|
839
|
+
});
|
|
840
|
+
export type CompletionReviewInput = z.infer<typeof CompletionReviewInputSchema>;
|
|
841
|
+
const FindingSchema = strictObject({
|
|
842
|
+
severity: z.enum(['blocking', 'warning']),
|
|
843
|
+
message: Short,
|
|
844
|
+
toolId: PromptToolIdSchema.optional(),
|
|
845
|
+
evidenceRefs: z.array(ContentAddressedRefSchema).max(32),
|
|
846
|
+
}).refine((finding) => finding.severity !== 'blocking' || finding.evidenceRefs.length > 0, {
|
|
847
|
+
path: ['evidenceRefs'],
|
|
848
|
+
message: 'blocking findings require evidence',
|
|
849
|
+
});
|
|
850
|
+
const CompletionToolResultReviewSchema = strictObject({
|
|
851
|
+
toolId: PromptToolIdSchema,
|
|
852
|
+
chainEdgeId: PromptIdSchema.optional(),
|
|
853
|
+
status: z.enum(['credible', 'revision_required']),
|
|
854
|
+
reason: Short,
|
|
855
|
+
evidenceRefs: z.array(ContentAddressedRefSchema).min(1).max(32),
|
|
856
|
+
});
|
|
857
|
+
export const CompletionReviewOutputSchema = strictObject({
|
|
858
|
+
binding: CurrentPlanBindingSchema,
|
|
859
|
+
verdict: z.enum(['passed', 'failed']),
|
|
860
|
+
summary: Reason,
|
|
861
|
+
findings: z.array(FindingSchema),
|
|
862
|
+
toolResultReviews: z.array(CompletionToolResultReviewSchema),
|
|
863
|
+
claimDispositions: z.array(
|
|
864
|
+
strictObject({
|
|
865
|
+
claimId: PromptIdSchema,
|
|
866
|
+
status: z.enum(['supported', 'unsupported']),
|
|
867
|
+
reason: Short,
|
|
868
|
+
evidenceRefs: z.array(ContentAddressedRefSchema).min(1).max(32),
|
|
869
|
+
}),
|
|
870
|
+
),
|
|
871
|
+
}).superRefine((value, ctx) => {
|
|
872
|
+
const blocking = value.findings.some(({ severity }) => severity === 'blocking');
|
|
873
|
+
if ((value.verdict === 'passed') === blocking)
|
|
874
|
+
schemaIssue(ctx, ['verdict'], 'verdict conflicts with blocking findings');
|
|
875
|
+
});
|