Remove legacy raw pipeline contracts
This commit is contained in:
@@ -245,7 +245,7 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (output RunOutput, err
|
||||
}, llmScope))
|
||||
return false, nil, err
|
||||
}
|
||||
validationWarnings, rejection, err := r.validateChunks(attemptCtx, doc, chunker.Key(), chunks, sourceInput, sessionID, input.pipeline.ChunkReferences.ReferenceSet, input.llmClient, input.Metadata, input.Prepared.chunkValidators, attempt, input.Debug)
|
||||
validationWarnings, rejection, err := r.validateChunks(attemptCtx, doc, chunker.Key(), chunks, sourceInput, sessionID, input.pipeline.ChunkReferences.ReferenceSet, input.Metadata, input.Prepared.chunkValidators, attempt, input.Debug)
|
||||
if err != nil || rejection != nil {
|
||||
_ = writeDebugTimed(debugRecorder, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageChunk),
|
||||
@@ -323,7 +323,7 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (output RunOutput, err
|
||||
} else {
|
||||
output.Manifest.ValidationStatus = "approved"
|
||||
}
|
||||
populateRawOutputManifest(&output)
|
||||
populateOutputManifest(&output)
|
||||
output.Manifest.CompletedAt = timePtr(time.Now().UTC())
|
||||
|
||||
encoder := input.Prepared.output
|
||||
@@ -377,534 +377,16 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (output RunOutput, err
|
||||
}
|
||||
|
||||
func (r *Runner) runLane(ctx context.Context, input RunInput, checkpoints CheckpointRecorder, checkpointLoader CheckpointLoader, doc *source.SourceDocument, sourceInput contracts.LLMInputMaterial, sessionID string, chunks []source.Chunk, prepared preparedLaneExecutor, output *RunOutput) error {
|
||||
if prepared.typed != nil {
|
||||
return r.runTypedLane(ctx, input, checkpoints, checkpointLoader, doc, sourceInput, sessionID, chunks, prepared, output)
|
||||
}
|
||||
return r.runLegacyLane(ctx, input, checkpoints, checkpointLoader, doc, sourceInput, sessionID, chunks, prepared, output)
|
||||
}
|
||||
|
||||
func (r *Runner) runLegacyLane(ctx context.Context, input RunInput, checkpoints CheckpointRecorder, checkpointLoader CheckpointLoader, doc *source.SourceDocument, sourceInput contracts.LLMInputMaterial, sessionID string, chunks []source.Chunk, prepared preparedLaneExecutor, output *RunOutput) error {
|
||||
lane := prepared.resolved
|
||||
if prepared.legacy == nil {
|
||||
return fmt.Errorf("resolved pipeline lane %q uses typed artifact kind %q, which the legacy raw runner cannot execute", lane.ID, lane.ArtifactKind)
|
||||
}
|
||||
extractor := prepared.legacy.extractor
|
||||
merger := prepared.legacy.merger
|
||||
normalizer := prepared.legacy.normalizer
|
||||
setLaneManifestMetadata(output, lane.ID, extractor, merger, normalizer)
|
||||
|
||||
extractOutputs := make([]contracts.ExtractOutput, 0, len(chunks))
|
||||
extractWarnings := []contracts.Warning{}
|
||||
extractRejectedStart := len(output.Rejected)
|
||||
chunksDigest, err := joinedChunkDigest(chunks)
|
||||
if err != nil {
|
||||
return fmt.Errorf("digest chunks for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
extractDependencies := digestFingerprints("chunks", chunksDigest)
|
||||
extractCheckpoint, extractDecision := checkpointLoader.Extract(lane.ID, extractor.Key(), extractDependencies)
|
||||
recordCheckpointEvent(output, checkpointLoader, string(StageExtract), lane.ID, extractor.Key(), extractDecision)
|
||||
extractStarted := time.Now().UTC()
|
||||
if err := writeDebugTimed(input.Debug, path.Join("extract", debugPathComponent(lane.ID), "input.json"), debugTimedEnvelope{
|
||||
Stage: string(StageExtract),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: extractor.Key(),
|
||||
StartedAt: extractStarted,
|
||||
Payload: map[string]any{
|
||||
"reused": extractDecision.Reused,
|
||||
"decision": extractDecision,
|
||||
"source": debugSourceDocumentEnvelope(doc),
|
||||
"chunks": debugSourceChunkEnvelopes(chunks),
|
||||
"options": redactSensitiveMap(lane.Extract.Options),
|
||||
"metadata": redactSensitiveMap(input.Metadata),
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write extract debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
if extractDecision.Reused {
|
||||
extractOutputs = cloneExtractOutputs(extractCheckpoint.Outputs)
|
||||
extractWarnings = cloneWarnings(extractCheckpoint.Warnings)
|
||||
output.Rejected = append(output.Rejected, cloneRejectedOutputs(extractCheckpoint.Rejected)...)
|
||||
output.Warnings = append(output.Warnings, extractWarnings...)
|
||||
} else {
|
||||
if err := checkpoints.ExtractRunning(lane.ID, extractor.Key(), extractDependencies); err != nil {
|
||||
return fmt.Errorf("write extract checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
for index := range chunks {
|
||||
chunk := chunks[index]
|
||||
var acceptedOutput contracts.ExtractOutput
|
||||
var acceptedWarnings []contracts.Warning
|
||||
accepted, rejection, err := runWithRetry(ctx, lane.Extract.Retries, func(attempt int) (bool, *contracts.RejectedOutput, error) {
|
||||
attemptStarted := time.Now().UTC()
|
||||
attemptPath := path.Join("extract", debugPathComponent(lane.ID), fmt.Sprintf("chunk-%06d", chunk.Index+1), fmt.Sprintf("attempt-%02d", attempt))
|
||||
attemptCtx, llmScope := withDebugLLMScope(ctx, attemptPath)
|
||||
result, err := extractor.Extract(attemptCtx, contracts.ExtractionRequest{
|
||||
Source: doc,
|
||||
Chunk: &chunk,
|
||||
SourceInput: chunkInputMaterial(sourceInput, chunk),
|
||||
SessionID: sessionID,
|
||||
References: CloneReferenceSet(lane.ExtractReferences.ReferenceSet),
|
||||
LLMClient: input.llmClient,
|
||||
LLMProfile: lane.Extract.LLMProfile,
|
||||
Options: cloneOptions(lane.Extract.Options),
|
||||
Metadata: input.Metadata,
|
||||
})
|
||||
if err != nil {
|
||||
_ = writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageExtract),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: extractor.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Error: err.Error(),
|
||||
}, llmScope))
|
||||
return false, nil, fmt.Errorf("extract lane %q chunk %q with extractor %q: %w", lane.ID, chunk.ID, extractor.Key(), err)
|
||||
}
|
||||
extractOutput := result.Output
|
||||
extractOutput.LaneID = lane.ID
|
||||
extractOutput.ExtractorKey = extractor.Key()
|
||||
extractOutput.SourceID = doc.ID
|
||||
extractOutput.ChunkID = chunk.ID
|
||||
extractOutput.ChunkIndex = chunk.Index
|
||||
extractOutput.Payload.Warnings = append(extractOutput.Payload.Warnings, result.Warnings...)
|
||||
validationWarnings, rejection, err := r.validateRaw(attemptCtx, rawValidationTarget{
|
||||
stage: StageExtract,
|
||||
laneID: lane.ID,
|
||||
moduleKey: extractor.Key(),
|
||||
source: doc,
|
||||
sourceID: doc.ID,
|
||||
chunkID: chunk.ID,
|
||||
chunkIndex: chunk.Index,
|
||||
chunk: &chunk,
|
||||
sourceInput: chunkInputMaterial(sourceInput, chunk),
|
||||
sessionID: sessionID,
|
||||
references: lane.ExtractReferences.ReferenceSet,
|
||||
llmClient: input.llmClient,
|
||||
schema: extractOutput.Schema,
|
||||
payload: extractOutput.Payload,
|
||||
metadata: input.Metadata,
|
||||
prepared: prepared.extractValidators,
|
||||
attempt: attempt,
|
||||
debug: input.Debug,
|
||||
})
|
||||
if err != nil || rejection != nil {
|
||||
_ = writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageExtract),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: extractor.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Payload: map[string]any{
|
||||
"output": debugExtractOutputEnvelope(extractOutput),
|
||||
"warnings": append(cloneWarnings(result.Warnings), validationWarnings...),
|
||||
"rejection": debugRejectedOutputPtr(rejection),
|
||||
},
|
||||
}, llmScope))
|
||||
return false, rejection, err
|
||||
}
|
||||
acceptedOutput = cloneExtractOutput(extractOutput)
|
||||
acceptedWarnings = append(cloneWarnings(result.Warnings), validationWarnings...)
|
||||
if err := writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageExtract),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: extractor.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Payload: map[string]any{
|
||||
"output": debugExtractOutputEnvelope(extractOutput),
|
||||
"warnings": acceptedWarnings,
|
||||
},
|
||||
}, llmScope)); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, nil, nil
|
||||
})
|
||||
if err != nil {
|
||||
_ = checkpoints.ExtractFailed(lane.ID, extractor.Key(), extractDependencies, err)
|
||||
return err
|
||||
}
|
||||
if !accepted {
|
||||
output.Rejected = append(output.Rejected, *rejection)
|
||||
continue
|
||||
}
|
||||
output.Warnings = append(output.Warnings, acceptedWarnings...)
|
||||
extractWarnings = append(extractWarnings, acceptedWarnings...)
|
||||
extractOutputs = append(extractOutputs, acceptedOutput)
|
||||
}
|
||||
extractRejected := cloneRejectedOutputs(output.Rejected[extractRejectedStart:])
|
||||
if err := checkpoints.ExtractSucceeded(lane.ID, extractor.Key(), extractDependencies, extractOutputs, extractRejected, extractWarnings); err != nil {
|
||||
return fmt.Errorf("write extract checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
}
|
||||
if err := writeDebugTimed(input.Debug, path.Join("extract", debugPathComponent(lane.ID), "output.json"), debugTimedEnvelope{
|
||||
Stage: string(StageExtract),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: extractor.Key(),
|
||||
StartedAt: extractStarted,
|
||||
Payload: map[string]any{
|
||||
"reused": extractDecision.Reused,
|
||||
"outputs": debugExtractOutputEnvelopes(extractOutputs),
|
||||
"rejected": debugRejectedOutputEnvelopes(output.Rejected[extractRejectedStart:]),
|
||||
"warnings": extractWarnings,
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write extract debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
|
||||
if len(extractOutputs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var acceptedMerge contracts.MergeOutput
|
||||
var mergeWarnings []contracts.Warning
|
||||
mergeDependencies := rawOutputDigests(extractPayloads(extractOutputs))
|
||||
mergeCheckpoint, mergeDecision := checkpointLoader.Merge(lane.ID, merger.Key(), mergeDependencies)
|
||||
recordCheckpointEvent(output, checkpointLoader, string(StageMerge), lane.ID, merger.Key(), mergeDecision)
|
||||
mergeStarted := time.Now().UTC()
|
||||
if err := writeDebugTimed(input.Debug, path.Join("merge", debugPathComponent(lane.ID), "input.json"), debugTimedEnvelope{
|
||||
Stage: string(StageMerge),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: merger.Key(),
|
||||
StartedAt: mergeStarted,
|
||||
Payload: map[string]any{
|
||||
"reused": mergeDecision.Reused,
|
||||
"decision": mergeDecision,
|
||||
"source": debugSourceDocumentEnvelope(doc),
|
||||
"extract_outputs": debugExtractOutputEnvelopes(extractOutputs),
|
||||
"options": redactSensitiveMap(lane.Merge.Options),
|
||||
"metadata": redactSensitiveMap(input.Metadata),
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write merge debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
if mergeDecision.Reused {
|
||||
acceptedMerge = cloneMergeOutput(mergeCheckpoint.Output)
|
||||
mergeWarnings = cloneWarnings(mergeCheckpoint.Warnings)
|
||||
output.Warnings = append(output.Warnings, mergeWarnings...)
|
||||
} else {
|
||||
if err := checkpoints.MergeRunning(lane.ID, merger.Key(), mergeDependencies); err != nil {
|
||||
return fmt.Errorf("write merge checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
mergeAccepted, mergeRejection, err := runWithRetry(ctx, lane.Merge.Retries, func(attempt int) (bool, *contracts.RejectedOutput, error) {
|
||||
attemptStarted := time.Now().UTC()
|
||||
attemptPath := path.Join("merge", debugPathComponent(lane.ID), fmt.Sprintf("attempt-%02d", attempt))
|
||||
attemptCtx, llmScope := withDebugLLMScope(ctx, attemptPath)
|
||||
mergeResult, err := merger.Merge(attemptCtx, contracts.MergeRequest{
|
||||
Source: doc,
|
||||
LaneID: lane.ID,
|
||||
ExtractOutputs: cloneExtractOutputs(extractOutputs),
|
||||
SourceInput: sourceInput.Clone(),
|
||||
SessionID: sessionID,
|
||||
References: CloneReferenceSet(lane.MergeReferences.ReferenceSet),
|
||||
LLMClient: input.llmClient,
|
||||
LLMProfile: lane.Merge.LLMProfile,
|
||||
Options: cloneOptions(lane.Merge.Options),
|
||||
Metadata: input.Metadata,
|
||||
})
|
||||
if err != nil {
|
||||
_ = writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageMerge),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: merger.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Error: err.Error(),
|
||||
}, llmScope))
|
||||
return false, nil, fmt.Errorf("merge lane %q with merger %q: %w", lane.ID, merger.Key(), err)
|
||||
}
|
||||
mergeOutput := mergeResult.Output
|
||||
mergeOutput.LaneID = lane.ID
|
||||
mergeOutput.MergerKey = merger.Key()
|
||||
mergeOutput.SourceID = doc.ID
|
||||
mergeOutput.Payload.Warnings = append(mergeOutput.Payload.Warnings, mergeResult.Warnings...)
|
||||
validationWarnings, rejection, err := r.validateRaw(attemptCtx, rawValidationTarget{
|
||||
stage: StageMerge,
|
||||
laneID: lane.ID,
|
||||
moduleKey: merger.Key(),
|
||||
source: doc,
|
||||
sourceID: doc.ID,
|
||||
sourceInput: sourceInput.Clone(),
|
||||
sessionID: sessionID,
|
||||
references: lane.MergeReferences.ReferenceSet,
|
||||
llmClient: input.llmClient,
|
||||
schema: mergeOutput.Schema,
|
||||
payload: mergeOutput.Payload,
|
||||
extractOutputs: extractOutputs,
|
||||
metadata: input.Metadata,
|
||||
prepared: prepared.mergeValidators,
|
||||
attempt: attempt,
|
||||
debug: input.Debug,
|
||||
})
|
||||
if err != nil || rejection != nil {
|
||||
_ = writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageMerge),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: merger.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Payload: map[string]any{
|
||||
"output": debugMergeOutputEnvelope(mergeOutput),
|
||||
"warnings": append(cloneWarnings(mergeResult.Warnings), validationWarnings...),
|
||||
"rejection": debugRejectedOutputPtr(rejection),
|
||||
},
|
||||
}, llmScope))
|
||||
return false, rejection, err
|
||||
}
|
||||
acceptedMerge = cloneMergeOutput(mergeOutput)
|
||||
mergeWarnings = append(cloneWarnings(mergeResult.Warnings), validationWarnings...)
|
||||
if err := writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageMerge),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: merger.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Payload: map[string]any{
|
||||
"output": debugMergeOutputEnvelope(mergeOutput),
|
||||
"warnings": mergeWarnings,
|
||||
},
|
||||
}, llmScope)); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, nil, nil
|
||||
})
|
||||
if err != nil {
|
||||
_ = checkpoints.MergeFailed(lane.ID, merger.Key(), mergeDependencies, err)
|
||||
return err
|
||||
}
|
||||
if !mergeAccepted {
|
||||
output.Rejected = append(output.Rejected, *mergeRejection)
|
||||
if err := checkpoints.MergeRejected(lane.ID, merger.Key(), mergeDependencies, *mergeRejection); err != nil {
|
||||
return fmt.Errorf("write merge checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
if err := writeDebugTimed(input.Debug, path.Join("merge", debugPathComponent(lane.ID), "output.json"), debugTimedEnvelope{
|
||||
Stage: string(StageMerge),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: merger.Key(),
|
||||
StartedAt: mergeStarted,
|
||||
Payload: map[string]any{
|
||||
"accepted": false,
|
||||
"rejection": debugRejectedOutputEnvelope(*mergeRejection),
|
||||
"warnings": mergeWarnings,
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write merge debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
output.Warnings = append(output.Warnings, mergeWarnings...)
|
||||
if err := checkpoints.MergeSucceeded(lane.ID, merger.Key(), mergeDependencies, acceptedMerge, mergeWarnings); err != nil {
|
||||
return fmt.Errorf("write merge checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
}
|
||||
if err := writeDebugTimed(input.Debug, path.Join("merge", debugPathComponent(lane.ID), "output.json"), debugTimedEnvelope{
|
||||
Stage: string(StageMerge),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: merger.Key(),
|
||||
StartedAt: mergeStarted,
|
||||
Payload: map[string]any{
|
||||
"reused": mergeDecision.Reused,
|
||||
"accepted": true,
|
||||
"output": debugMergeOutputEnvelope(acceptedMerge),
|
||||
"warnings": mergeWarnings,
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write merge debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
|
||||
var acceptedNormalize contracts.NormalizeOutput
|
||||
var normalizeWarnings []contracts.Warning
|
||||
normalizeDependencies := rawOutputDigests([]contracts.RawPayload{acceptedMerge.Payload})
|
||||
normalizeCheckpoint, normalizeDecision := checkpointLoader.Normalize(lane.ID, normalizer.Key(), normalizeDependencies)
|
||||
recordCheckpointEvent(output, checkpointLoader, string(StageNormalize), lane.ID, normalizer.Key(), normalizeDecision)
|
||||
normalizeStarted := time.Now().UTC()
|
||||
if err := writeDebugTimed(input.Debug, path.Join("normalize", debugPathComponent(lane.ID), "input.json"), debugTimedEnvelope{
|
||||
Stage: string(StageNormalize),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: normalizer.Key(),
|
||||
StartedAt: normalizeStarted,
|
||||
Payload: map[string]any{
|
||||
"reused": normalizeDecision.Reused,
|
||||
"decision": normalizeDecision,
|
||||
"source": debugSourceDocumentEnvelope(doc),
|
||||
"merge_output": debugMergeOutputEnvelope(acceptedMerge),
|
||||
"options": redactSensitiveMap(lane.Normalize.Options),
|
||||
"metadata": redactSensitiveMap(input.Metadata),
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write normalize debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
if normalizeDecision.Reused {
|
||||
acceptedNormalize = cloneNormalizeOutput(normalizeCheckpoint.Output)
|
||||
normalizeWarnings = cloneWarnings(normalizeCheckpoint.Warnings)
|
||||
output.Warnings = append(output.Warnings, normalizeWarnings...)
|
||||
} else {
|
||||
if err := checkpoints.NormalizeRunning(lane.ID, normalizer.Key(), normalizeDependencies); err != nil {
|
||||
return fmt.Errorf("write normalize checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
normalizeAccepted, normalizeRejection, err := runWithRetry(ctx, lane.Normalize.Retries, func(attempt int) (bool, *contracts.RejectedOutput, error) {
|
||||
attemptStarted := time.Now().UTC()
|
||||
attemptPath := path.Join("normalize", debugPathComponent(lane.ID), fmt.Sprintf("attempt-%02d", attempt))
|
||||
attemptCtx, llmScope := withDebugLLMScope(ctx, attemptPath)
|
||||
normalizeResult, err := normalizer.Normalize(attemptCtx, contracts.NormalizeRequest{
|
||||
Source: doc,
|
||||
LaneID: lane.ID,
|
||||
MergeOutput: cloneMergeOutput(acceptedMerge),
|
||||
SourceInput: sourceInput.Clone(),
|
||||
SessionID: sessionID,
|
||||
References: CloneReferenceSet(lane.NormalizeReferences.ReferenceSet),
|
||||
LLMClient: input.llmClient,
|
||||
LLMProfile: lane.Normalize.LLMProfile,
|
||||
Options: cloneOptions(lane.Normalize.Options),
|
||||
Metadata: input.Metadata,
|
||||
})
|
||||
if err != nil {
|
||||
_ = writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageNormalize),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: normalizer.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Error: err.Error(),
|
||||
}, llmScope))
|
||||
return false, nil, fmt.Errorf("normalize lane %q with normalizer %q: %w", lane.ID, normalizer.Key(), err)
|
||||
}
|
||||
normalizeOutput := normalizeResult.Output
|
||||
normalizeOutput.LaneID = lane.ID
|
||||
normalizeOutput.NormalizerKey = normalizer.Key()
|
||||
normalizeOutput.SourceID = doc.ID
|
||||
normalizeOutput.Payload.Warnings = append(normalizeOutput.Payload.Warnings, normalizeResult.Warnings...)
|
||||
validationWarnings, rejection, err := r.validateRaw(attemptCtx, rawValidationTarget{
|
||||
stage: StageNormalize,
|
||||
laneID: lane.ID,
|
||||
moduleKey: normalizer.Key(),
|
||||
source: doc,
|
||||
sourceID: doc.ID,
|
||||
sourceInput: sourceInput.Clone(),
|
||||
sessionID: sessionID,
|
||||
references: lane.NormalizeReferences.ReferenceSet,
|
||||
llmClient: input.llmClient,
|
||||
schema: normalizeOutput.Schema,
|
||||
payload: normalizeOutput.Payload,
|
||||
mergeOutput: acceptedMerge,
|
||||
metadata: input.Metadata,
|
||||
prepared: prepared.normalizeValidators,
|
||||
attempt: attempt,
|
||||
debug: input.Debug,
|
||||
})
|
||||
if err != nil || rejection != nil {
|
||||
_ = writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageNormalize),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: normalizer.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Payload: map[string]any{
|
||||
"output": debugNormalizeOutputEnvelope(normalizeOutput),
|
||||
"warnings": append(cloneWarnings(normalizeResult.Warnings), validationWarnings...),
|
||||
"rejection": debugRejectedOutputPtr(rejection),
|
||||
},
|
||||
}, llmScope))
|
||||
return false, rejection, err
|
||||
}
|
||||
acceptedNormalize = cloneNormalizeOutput(normalizeOutput)
|
||||
normalizeWarnings = append(cloneWarnings(normalizeResult.Warnings), validationWarnings...)
|
||||
if err := writeDebugTimed(input.Debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(StageNormalize),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: normalizer.Key(),
|
||||
Attempt: attempt,
|
||||
StartedAt: attemptStarted,
|
||||
Payload: map[string]any{
|
||||
"output": debugNormalizeOutputEnvelope(normalizeOutput),
|
||||
"warnings": normalizeWarnings,
|
||||
},
|
||||
}, llmScope)); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
return true, nil, nil
|
||||
})
|
||||
if err != nil {
|
||||
_ = checkpoints.NormalizeFailed(lane.ID, normalizer.Key(), normalizeDependencies, err)
|
||||
return err
|
||||
}
|
||||
if !normalizeAccepted {
|
||||
output.Rejected = append(output.Rejected, *normalizeRejection)
|
||||
if err := checkpoints.NormalizeRejected(lane.ID, normalizer.Key(), normalizeDependencies, *normalizeRejection); err != nil {
|
||||
return fmt.Errorf("write normalize checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
if err := writeDebugTimed(input.Debug, path.Join("normalize", debugPathComponent(lane.ID), "output.json"), debugTimedEnvelope{
|
||||
Stage: string(StageNormalize),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: normalizer.Key(),
|
||||
StartedAt: normalizeStarted,
|
||||
Payload: map[string]any{
|
||||
"accepted": false,
|
||||
"rejection": debugRejectedOutputEnvelope(*normalizeRejection),
|
||||
"warnings": normalizeWarnings,
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write normalize debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
output.Warnings = append(output.Warnings, normalizeWarnings...)
|
||||
if err := checkpoints.NormalizeSucceeded(lane.ID, normalizer.Key(), normalizeDependencies, acceptedNormalize, normalizeWarnings); err != nil {
|
||||
return fmt.Errorf("write normalize checkpoint for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
}
|
||||
if err := writeDebugTimed(input.Debug, path.Join("normalize", debugPathComponent(lane.ID), "output.json"), debugTimedEnvelope{
|
||||
Stage: string(StageNormalize),
|
||||
LaneID: lane.ID,
|
||||
ModuleKey: normalizer.Key(),
|
||||
StartedAt: normalizeStarted,
|
||||
Payload: map[string]any{
|
||||
"reused": normalizeDecision.Reused,
|
||||
"accepted": true,
|
||||
"output": debugNormalizeOutputEnvelope(acceptedNormalize),
|
||||
"warnings": normalizeWarnings,
|
||||
},
|
||||
}); err != nil {
|
||||
return fmt.Errorf("write normalize debug artifact for lane %q: %w", lane.ID, err)
|
||||
}
|
||||
output.NormalizeOutputs = append(output.NormalizeOutputs, serializedOutputFromLegacy(acceptedNormalize))
|
||||
return nil
|
||||
}
|
||||
|
||||
type rawValidationTarget struct {
|
||||
stage ModuleStage
|
||||
laneID string
|
||||
moduleKey string
|
||||
source *source.SourceDocument
|
||||
sourceID string
|
||||
sourceInput contracts.LLMInputMaterial
|
||||
sessionID string
|
||||
references contracts.ReferenceSet
|
||||
llmClient contracts.StructuredLLMClient
|
||||
chunkID string
|
||||
chunkIndex int
|
||||
chunk *source.Chunk
|
||||
chunks []source.Chunk
|
||||
schema contracts.ResponseSchema
|
||||
payload contracts.RawPayload
|
||||
extractOutputs []contracts.ExtractOutput
|
||||
mergeOutput contracts.MergeOutput
|
||||
metadata map[string]any
|
||||
prepared preparedValidatorChain
|
||||
attempt int
|
||||
debug DebugRecorder
|
||||
return r.runTypedLane(ctx, input, checkpoints, checkpointLoader, doc, sourceInput, sessionID, chunks, prepared, output)
|
||||
}
|
||||
|
||||
func runWithRetry(ctx context.Context, retries int, run func(attempt int) (bool, *contracts.RejectedOutput, error)) (bool, *contracts.RejectedOutput, error) {
|
||||
attempts := 1
|
||||
if retries > 0 {
|
||||
attempts += retries
|
||||
}
|
||||
|
||||
var lastRejection *contracts.RejectedOutput
|
||||
attempts := retries + 1
|
||||
var last *contracts.RejectedOutput
|
||||
for attempt := 1; attempt <= attempts; attempt++ {
|
||||
if err := ctx.Err(); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
accepted, rejection, err := run(attempt)
|
||||
if err != nil {
|
||||
if ctxErr := ctx.Err(); ctxErr != nil {
|
||||
@@ -920,55 +402,22 @@ func runWithRetry(ctx context.Context, retries int, run func(attempt int) (bool,
|
||||
}
|
||||
if rejection != nil {
|
||||
rejection.AttemptCount = attempt
|
||||
lastRejection = rejection
|
||||
last = rejection
|
||||
}
|
||||
if ctxErr := ctx.Err(); ctxErr != nil {
|
||||
return false, nil, ctxErr
|
||||
}
|
||||
if attempt == attempts {
|
||||
if lastRejection == nil {
|
||||
lastRejection = &contracts.RejectedOutput{
|
||||
ReasonCode: "raw_output_rejected",
|
||||
Message: "raw output rejected",
|
||||
AttemptCount: attempt,
|
||||
}
|
||||
if last == nil {
|
||||
last = &contracts.RejectedOutput{ReasonCode: "output_rejected", Message: "output rejected", AttemptCount: attempt}
|
||||
}
|
||||
return false, lastRejection, nil
|
||||
return false, last, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, lastRejection, nil
|
||||
return false, last, nil
|
||||
}
|
||||
|
||||
func (r *Runner) validateChunksRaw(ctx context.Context, doc *source.SourceDocument, moduleKey string, chunks []source.Chunk, sourceInput contracts.LLMInputMaterial, sessionID string, references contracts.ReferenceSet, llmClient contracts.StructuredLLMClient, metadata map[string]any, prepared preparedValidatorChain, attempt int, debug DebugRecorder) ([]contracts.Warning, *contracts.RejectedOutput, error) {
|
||||
return r.validateRaw(ctx, rawValidationTarget{
|
||||
stage: StageChunk,
|
||||
moduleKey: moduleKey,
|
||||
source: doc,
|
||||
sourceID: doc.ID,
|
||||
sourceInput: sourceInput.Clone(),
|
||||
sessionID: sessionID,
|
||||
references: references,
|
||||
llmClient: llmClient,
|
||||
chunks: chunks,
|
||||
metadata: metadata,
|
||||
prepared: prepared,
|
||||
attempt: attempt,
|
||||
debug: debug,
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Runner) validateChunks(ctx context.Context, doc *source.SourceDocument, moduleKey string, chunks []source.Chunk, sourceInput contracts.LLMInputMaterial, sessionID string, references contracts.ReferenceSet, llmClient contracts.StructuredLLMClient, metadata map[string]any, prepared preparedValidatorChain, attempt int, debug DebugRecorder) ([]contracts.Warning, *contracts.RejectedOutput, error) {
|
||||
allLegacy := true
|
||||
for _, item := range prepared.validators {
|
||||
if item.resolved.Target != ValidatorTargetLegacyRaw && item.resolved.Target != "" {
|
||||
allLegacy = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if allLegacy {
|
||||
return r.validateChunksRaw(ctx, doc, moduleKey, chunks, sourceInput, sessionID, references, llmClient, metadata, prepared, attempt, debug)
|
||||
}
|
||||
func (r *Runner) validateChunks(ctx context.Context, doc *source.SourceDocument, moduleKey string, chunks []source.Chunk, sourceInput contracts.LLMInputMaterial, sessionID string, references contracts.ReferenceSet, metadata map[string]any, prepared preparedValidatorChain, attempt int, debug DebugRecorder) ([]contracts.Warning, *contracts.RejectedOutput, error) {
|
||||
content, err := json.Marshal(chunks)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("encode canonical chunks for validation: %w", err)
|
||||
@@ -989,8 +438,9 @@ func (r *Runner) validateChunks(ctx context.Context, doc *source.SourceDocument,
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("validator %q is incompatible with chunk validation", binding.Module)
|
||||
}
|
||||
debugRequest := contracts.ValidationRequest{Stage: string(StageChunk), ModuleKey: moduleKey, Source: doc, SourceID: doc.ID, SourceInput: sourceInput.Clone(), SessionID: sessionID, References: CloneReferenceSet(references), LLMProfile: binding.LLMProfile, Metadata: cloneMetadata(metadata), Chunks: cloneSourceChunks(chunks), Schema: contracts.ResponseSchema{ID: schema.ID, Name: schema.Name, Version: schema.Version, JSONSchema: append([]byte(nil), schema.JSONSchema...)}, Payload: contracts.RawPayload{Content: content, MediaType: "application/json"}}
|
||||
debugCall := debugValidationCall{ValidatorName: binding.Module, Request: debugValidationRequestEnvelope(debugRequest), Result: debugValidationResultEnvelope(result)}
|
||||
debugContent := debugContentEnvelope(content, "application/json", nil, nil)
|
||||
debugContent.ContentDigest = debugContentDigest(content)
|
||||
debugCall := debugValidationCall{ValidatorName: binding.Module, Request: map[string]any{"stage": string(StageChunk), "module_key": moduleKey, "source_id": doc.ID, "schema": schema, "schema_digest": contracts.DigestArtifactSchema(schema), "content": debugContent, "metadata": redactSensitiveMap(metadata)}, Result: debugValidationResultEnvelope(result)}
|
||||
if err != nil {
|
||||
debugCall.Error = err.Error()
|
||||
}
|
||||
@@ -1003,11 +453,11 @@ func (r *Runner) validateChunks(ctx context.Context, doc *source.SourceDocument,
|
||||
if !result.Approved {
|
||||
reason := result.ReasonCode
|
||||
if reason == "" {
|
||||
reason = "raw_output_rejected"
|
||||
reason = "output_rejected"
|
||||
}
|
||||
message := result.Message
|
||||
if message == "" {
|
||||
message = "raw output rejected"
|
||||
message = "output rejected"
|
||||
}
|
||||
return nil, &contracts.RejectedOutput{Stage: string(StageChunk), ModuleKey: moduleKey, ValidatorName: binding.Module, ReasonCode: reason, Message: message, AttemptCount: attempt, DiagnosticArtifactPath: result.DiagnosticArtifactPath}, nil
|
||||
}
|
||||
@@ -1016,97 +466,6 @@ func (r *Runner) validateChunks(ctx context.Context, doc *source.SourceDocument,
|
||||
return warnings, nil, nil
|
||||
}
|
||||
|
||||
func (r *Runner) validateRaw(ctx context.Context, target rawValidationTarget) ([]contracts.Warning, *contracts.RejectedOutput, error) {
|
||||
if len(target.prepared.validators) == 0 {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
var warnings []contracts.Warning
|
||||
for index, preparedValidator := range target.prepared.validators {
|
||||
validator := preparedValidator.legacy
|
||||
validatorBinding := preparedValidator.resolved
|
||||
if validator == nil {
|
||||
return nil, nil, fmt.Errorf("validator %q is not available on the legacy raw path", validatorBinding.Binding.Module)
|
||||
}
|
||||
request := target.validationRequest(validatorBinding.Binding)
|
||||
started := time.Now().UTC()
|
||||
attemptPath := path.Join("validate", debugPathComponent(string(target.stage)), debugPathComponent(target.laneID), debugPathComponent(target.moduleKey), fmt.Sprintf("%02d-%s-attempt-%02d", index+1, debugPathComponent(validator.Name()), target.attempt))
|
||||
validatorCtx, llmScope := withDebugLLMScope(ctx, attemptPath)
|
||||
result, err := validator.Validate(validatorCtx, request)
|
||||
debugPayload := debugValidationCall{
|
||||
ValidatorName: validator.Name(),
|
||||
Request: debugValidationRequestEnvelope(request),
|
||||
Result: debugValidationResultEnvelope(result),
|
||||
}
|
||||
if err != nil {
|
||||
debugPayload.Error = err.Error()
|
||||
}
|
||||
if debugErr := writeDebugTimed(target.debug, attemptPath+".json", debugEnvelopeWithLLMCalls(debugTimedEnvelope{
|
||||
Stage: string(target.stage),
|
||||
LaneID: target.laneID,
|
||||
ModuleKey: target.moduleKey,
|
||||
Attempt: target.attempt,
|
||||
StartedAt: started,
|
||||
Payload: debugPayload,
|
||||
Error: debugPayload.Error,
|
||||
}, llmScope)); debugErr != nil {
|
||||
return nil, nil, fmt.Errorf("write validation debug artifact: %w", debugErr)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("validate raw %s output with validator %q: %w", target.stage, validator.Name(), err)
|
||||
}
|
||||
if !result.Approved {
|
||||
reasonCode := strings.TrimSpace(result.ReasonCode)
|
||||
if reasonCode == "" {
|
||||
reasonCode = "raw_output_rejected"
|
||||
}
|
||||
message := strings.TrimSpace(result.Message)
|
||||
if message == "" {
|
||||
message = "raw output rejected"
|
||||
}
|
||||
return nil, &contracts.RejectedOutput{
|
||||
Stage: string(target.stage),
|
||||
LaneID: target.laneID,
|
||||
ModuleKey: target.moduleKey,
|
||||
ChunkID: target.chunkID,
|
||||
ChunkIndex: target.chunkIndex,
|
||||
ValidatorName: validator.Name(),
|
||||
ReasonCode: reasonCode,
|
||||
Message: message,
|
||||
AttemptCount: target.attempt,
|
||||
DiagnosticArtifactPath: result.DiagnosticArtifactPath,
|
||||
}, nil
|
||||
}
|
||||
warnings = append(warnings, result.Warnings...)
|
||||
}
|
||||
return warnings, nil, nil
|
||||
}
|
||||
|
||||
func (target rawValidationTarget) validationRequest(binding ModuleBinding) contracts.ValidationRequest {
|
||||
return contracts.ValidationRequest{
|
||||
Stage: string(target.stage),
|
||||
LaneID: target.laneID,
|
||||
ModuleKey: target.moduleKey,
|
||||
Source: target.source,
|
||||
SourceID: target.sourceID,
|
||||
SourceInput: target.sourceInput.Clone(),
|
||||
SessionID: target.sessionID,
|
||||
References: CloneReferenceSet(target.references),
|
||||
LLMClient: target.llmClient,
|
||||
LLMProfile: binding.LLMProfile,
|
||||
Options: cloneOptions(binding.Options),
|
||||
Metadata: cloneMetadata(target.metadata),
|
||||
Schema: cloneResponseSchema(target.schema),
|
||||
Payload: cloneRawPayload(target.payload),
|
||||
ChunkID: target.chunkID,
|
||||
ChunkIndex: target.chunkIndex,
|
||||
Chunk: cloneSourceChunkPtr(target.chunk),
|
||||
Chunks: cloneSourceChunks(target.chunks),
|
||||
ExtractOutputs: cloneExtractOutputs(target.extractOutputs),
|
||||
MergeOutput: cloneMergeOutput(target.mergeOutput),
|
||||
}
|
||||
}
|
||||
|
||||
func resolvedValidatorChain(stage ModuleStage, laneID string, moduleKey string, chains []ResolvedValidatorChain) ResolvedValidatorChain {
|
||||
for _, chain := range chains {
|
||||
if chain.Stage != stage {
|
||||
@@ -1250,7 +609,7 @@ func validatorChainManifests(chains []ResolvedValidatorChain) []artifacts.Valida
|
||||
|
||||
func failOutput(output RunOutput) RunOutput {
|
||||
if output.Manifest.PipelineID != "" {
|
||||
populateRawOutputManifest(&output)
|
||||
populateOutputManifest(&output)
|
||||
output.Manifest.ValidationStatus = "failed"
|
||||
output.Manifest.CompletedAt = timePtr(time.Now().UTC())
|
||||
}
|
||||
@@ -1274,7 +633,7 @@ func recordCheckpointEvent(output *RunOutput, loader CheckpointLoader, stage str
|
||||
})
|
||||
}
|
||||
|
||||
func populateRawOutputManifest(output *RunOutput) {
|
||||
func populateOutputManifest(output *RunOutput) {
|
||||
if output == nil {
|
||||
return
|
||||
}
|
||||
@@ -1325,59 +684,18 @@ func rejectedOutputManifests(rejected []contracts.RejectedOutput) []artifacts.Re
|
||||
return manifests
|
||||
}
|
||||
|
||||
func setLaneManifestMetadata(output *RunOutput, laneID string, modules ...any) {
|
||||
if output == nil {
|
||||
return
|
||||
}
|
||||
for i := range output.Manifest.ArtifactLanes {
|
||||
if output.Manifest.ArtifactLanes[i].ID != laneID {
|
||||
continue
|
||||
}
|
||||
|
||||
metadata := make(map[string]any)
|
||||
for _, module := range modules {
|
||||
moduleMetadata, ok := moduleManifestMetadata(module)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
key := manifestMetadataKey(module)
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
metadata[key] = moduleMetadata
|
||||
}
|
||||
if len(metadata) > 0 {
|
||||
output.Manifest.ArtifactLanes[i].Metadata = metadata
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func attachModuleManifestMetadata(output *RunOutput, moduleKey string, module any) {
|
||||
if output == nil {
|
||||
return
|
||||
}
|
||||
moduleMetadata, ok := moduleManifestMetadata(module)
|
||||
metadata, ok := moduleManifestMetadata(module)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if output.Manifest.ModuleMetadata == nil {
|
||||
output.Manifest.ModuleMetadata = make(map[string]map[string]any)
|
||||
}
|
||||
output.Manifest.ModuleMetadata[moduleKey] = moduleMetadata
|
||||
}
|
||||
|
||||
func manifestMetadataKey(module any) string {
|
||||
switch module.(type) {
|
||||
case contracts.LegacyRawExtractor:
|
||||
return "extractor"
|
||||
case contracts.LegacyRawMerger:
|
||||
return "merger"
|
||||
case contracts.LegacyRawNormalizer:
|
||||
return "normalizer"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
output.Manifest.ModuleMetadata[moduleKey] = metadata
|
||||
}
|
||||
|
||||
func moduleManifestMetadata(module any) (map[string]any, bool) {
|
||||
@@ -1557,20 +875,6 @@ func cloneWarnings(warnings []contracts.Warning) []contracts.Warning {
|
||||
return append([]contracts.Warning(nil), warnings...)
|
||||
}
|
||||
|
||||
func cloneRawPayload(payload contracts.RawPayload) contracts.RawPayload {
|
||||
return contracts.RawPayload{
|
||||
Content: append([]byte(nil), payload.Content...),
|
||||
MediaType: payload.MediaType,
|
||||
Metadata: cloneMetadata(payload.Metadata),
|
||||
Warnings: cloneWarnings(payload.Warnings),
|
||||
}
|
||||
}
|
||||
|
||||
func cloneResponseSchema(schema contracts.ResponseSchema) contracts.ResponseSchema {
|
||||
schema.JSONSchema = append([]byte(nil), schema.JSONSchema...)
|
||||
return schema
|
||||
}
|
||||
|
||||
func cloneSourceChunkPtr(chunk *source.Chunk) *source.Chunk {
|
||||
if chunk == nil {
|
||||
return nil
|
||||
@@ -1608,35 +912,6 @@ func cloneSourceUnits(units []source.SourceUnit) []source.SourceUnit {
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneExtractOutput(output contracts.ExtractOutput) contracts.ExtractOutput {
|
||||
output.Schema = cloneResponseSchema(output.Schema)
|
||||
output.Payload = cloneRawPayload(output.Payload)
|
||||
return output
|
||||
}
|
||||
|
||||
func cloneExtractOutputs(outputs []contracts.ExtractOutput) []contracts.ExtractOutput {
|
||||
if len(outputs) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]contracts.ExtractOutput, 0, len(outputs))
|
||||
for _, output := range outputs {
|
||||
out = append(out, cloneExtractOutput(output))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func cloneMergeOutput(output contracts.MergeOutput) contracts.MergeOutput {
|
||||
output.Schema = cloneResponseSchema(output.Schema)
|
||||
output.Payload = cloneRawPayload(output.Payload)
|
||||
return output
|
||||
}
|
||||
|
||||
func cloneNormalizeOutput(output contracts.NormalizeOutput) contracts.NormalizeOutput {
|
||||
output.Schema = cloneResponseSchema(output.Schema)
|
||||
output.Payload = cloneRawPayload(output.Payload)
|
||||
return output
|
||||
}
|
||||
|
||||
func cloneSerializedOutputs(outputs []contracts.SerializedOutput) []contracts.SerializedOutput {
|
||||
if len(outputs) == 0 {
|
||||
return nil
|
||||
@@ -1648,16 +923,6 @@ func cloneSerializedOutputs(outputs []contracts.SerializedOutput) []contracts.Se
|
||||
return out
|
||||
}
|
||||
|
||||
func serializedOutputFromLegacy(output contracts.NormalizeOutput) contracts.SerializedOutput {
|
||||
return contracts.SerializedOutput{
|
||||
LaneID: output.LaneID, NormalizerKey: output.NormalizerKey, SourceID: output.SourceID,
|
||||
Artifact: contracts.SerializedArtifact{
|
||||
Schema: contracts.ArtifactSchema{ID: output.Schema.ID, Name: output.Schema.Name, Version: output.Schema.Version, JSONSchema: append([]byte(nil), output.Schema.JSONSchema...)},
|
||||
MediaType: output.Payload.MediaType, Content: append([]byte(nil), output.Payload.Content...), Metadata: cloneMetadata(output.Payload.Metadata),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func cloneRejectedOutputs(rejected []contracts.RejectedOutput) []contracts.RejectedOutput {
|
||||
if len(rejected) == 0 {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user