Adopt location registry durable contract
This commit is contained in:
@@ -40,7 +40,7 @@ func referenceSlots() []contracts.ReferenceSlot {
|
||||
Description: "Required normalized location registry used only for location identity grounding, never as occurrence evidence.",
|
||||
Required: true,
|
||||
AcceptedMediaTypes: []string{"application/json"},
|
||||
AcceptedArtifactKinds: []contracts.ArtifactKind{dnd.LocationListKind},
|
||||
AcceptedArtifactKinds: []contracts.ArtifactKind{dnd.LocationRegistryKind},
|
||||
MaxBytes: LocationRegistryMaxBytes,
|
||||
})
|
||||
sort.Slice(slots, func(left, right int) bool { return slots[left].Name < slots[right].Name })
|
||||
|
||||
@@ -111,7 +111,7 @@ func TestExtractRequiresRegistryAndAcceptsEmptyRegistryWithNoOccurrences(t *test
|
||||
if len(client.requests) != 0 {
|
||||
t.Fatalf("LLM calls = %d", len(client.requests))
|
||||
}
|
||||
empty := dnd.LocationList{Locations: []dnd.Location{}}
|
||||
empty := dnd.LocationRegistry{Locations: []dnd.Location{}}
|
||||
references := registryReferences(t, empty)
|
||||
req := extractionRequest()
|
||||
req.References = references
|
||||
@@ -196,7 +196,7 @@ func TestExtractorContractsMetadataAndFailures(t *testing.T) {
|
||||
slot = candidate
|
||||
}
|
||||
}
|
||||
if !slot.Required || !reflect.DeepEqual(slot.AcceptedArtifactKinds, []contracts.ArtifactKind{dnd.LocationListKind}) || slot.MaxBytes != LocationRegistryMaxBytes {
|
||||
if !slot.Required || !reflect.DeepEqual(slot.AcceptedArtifactKinds, []contracts.ArtifactKind{dnd.LocationRegistryKind}) || slot.MaxBytes != LocationRegistryMaxBytes {
|
||||
t.Fatalf("location registry slot = %#v", slot)
|
||||
}
|
||||
registry := pipeline.NewExtractorRegistry()
|
||||
@@ -220,17 +220,17 @@ func TestExtractorContractsMetadataAndFailures(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func locationRegistry(t *testing.T, names ...string) dnd.LocationList {
|
||||
func locationRegistry(t *testing.T, names ...string) dnd.LocationRegistry {
|
||||
t.Helper()
|
||||
locations := make([]dnd.Location, len(names))
|
||||
for index, name := range names {
|
||||
refs := []source.SourceRef{{SourceID: "other-session", StartUnitID: index + 1, EndUnitID: index + 1}}
|
||||
locations[index] = dnd.Location{ID: identity.DeriveID(name, refs), Name: name, SourceRefs: refs}
|
||||
}
|
||||
return dnd.LocationList{Locations: locations}
|
||||
return dnd.LocationRegistry{Locations: locations}
|
||||
}
|
||||
|
||||
func registryReferences(t *testing.T, locations dnd.LocationList) contracts.ReferenceSet {
|
||||
func registryReferences(t *testing.T, locations dnd.LocationRegistry) contracts.ReferenceSet {
|
||||
t.Helper()
|
||||
content, err := locationcodec.New().Encode(locations)
|
||||
if err != nil {
|
||||
|
||||
@@ -47,9 +47,9 @@ func canonicalizeLocation(location *locationResponse, order shared.SourceRefOrde
|
||||
return order.EarliestValid(refs)
|
||||
}
|
||||
|
||||
func canonicalLocationList(response extractionResponse, sourceID string) dnd.LocationList {
|
||||
func canonicalLocationRegistry(response extractionResponse, sourceID string) dnd.LocationRegistry {
|
||||
if response.Locations == nil {
|
||||
return dnd.LocationList{Locations: nil}
|
||||
return dnd.LocationRegistry{Locations: nil}
|
||||
}
|
||||
locations := make([]dnd.Location, len(response.Locations))
|
||||
for index, location := range response.Locations {
|
||||
@@ -60,7 +60,7 @@ func canonicalLocationList(response extractionResponse, sourceID string) dnd.Loc
|
||||
SourceRefs: refs,
|
||||
}
|
||||
}
|
||||
return dnd.LocationList{Locations: locations}
|
||||
return dnd.LocationRegistry{Locations: locations}
|
||||
}
|
||||
|
||||
func canonicalSourceRefs(values []locationSourceRefResponse, sourceID string) []source.SourceRef {
|
||||
|
||||
@@ -31,7 +31,7 @@ func referenceSlots() []contracts.ReferenceSlot {
|
||||
return shared.ReferenceSlots(referenceSlotDescriptions)
|
||||
}
|
||||
|
||||
var _ contracts.Extractor[dnd.LocationList] = (*Extractor)(nil)
|
||||
var _ contracts.Extractor[dnd.LocationRegistry] = (*Extractor)(nil)
|
||||
var _ contracts.ManifestMetadataProvider = (*Extractor)(nil)
|
||||
var _ pipeline.CheckpointFingerprintProvider = (*Extractor)(nil)
|
||||
|
||||
@@ -95,16 +95,16 @@ func (e *Extractor) CheckpointFingerprints() []pipeline.CheckpointFingerprint {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Extractor) Extract(ctx context.Context, req contracts.TypedExtractionRequest) (contracts.TypedExtractionResult[dnd.LocationList], error) {
|
||||
func (e *Extractor) Extract(ctx context.Context, req contracts.TypedExtractionRequest) (contracts.TypedExtractionResult[dnd.LocationRegistry], error) {
|
||||
if e == nil {
|
||||
return contracts.TypedExtractionResult[dnd.LocationList]{}, extractorErrorf("extractor must not be nil")
|
||||
return contracts.TypedExtractionResult[dnd.LocationRegistry]{}, extractorErrorf("extractor must not be nil")
|
||||
}
|
||||
if e.llm == nil {
|
||||
return contracts.TypedExtractionResult[dnd.LocationList]{}, extractorErrorf("LLM client must not be nil")
|
||||
return contracts.TypedExtractionResult[dnd.LocationRegistry]{}, extractorErrorf("LLM client must not be nil")
|
||||
}
|
||||
sourceInput, err := shared.PrepareChunkExtraction(ctx, req)
|
||||
if err != nil {
|
||||
return contracts.TypedExtractionResult[dnd.LocationList]{}, extractorErrorf("%w", err)
|
||||
return contracts.TypedExtractionResult[dnd.LocationRegistry]{}, extractorErrorf("%w", err)
|
||||
}
|
||||
order := shared.NewSourceRefOrder(req.Source)
|
||||
|
||||
@@ -114,22 +114,22 @@ func (e *Extractor) Extract(ctx context.Context, req contracts.TypedExtractionRe
|
||||
ProfileID: req.LLMProfile, SessionID: req.SessionID,
|
||||
Inputs: shared.PromptInputs(sourceInput, req.References),
|
||||
}, &response); err != nil {
|
||||
return contracts.TypedExtractionResult[dnd.LocationList]{}, extractorErrorf("complete structured output: %w", err)
|
||||
return contracts.TypedExtractionResult[dnd.LocationRegistry]{}, extractorErrorf("complete structured output: %w", err)
|
||||
}
|
||||
canonicalizeResponse(&response, order, req.Source.ID)
|
||||
return contracts.TypedExtractionResult[dnd.LocationList]{Value: canonicalLocationList(response, req.Source.ID)}, nil
|
||||
return contracts.TypedExtractionResult[dnd.LocationRegistry]{Value: canonicalLocationRegistry(response, req.Source.ID)}, nil
|
||||
}
|
||||
|
||||
func ModuleSpec() pipeline.ModuleSpec {
|
||||
return pipeline.ModuleSpec{
|
||||
Key: Key, Stage: pipeline.StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked,
|
||||
Requires: append([]string(nil), requiredCapabilities...), Provides: append([]string(nil), providedCapabilities...),
|
||||
ArtifactKind: dnd.LocationListKind, ReferenceSlots: referenceSlots(),
|
||||
ArtifactKind: dnd.LocationRegistryKind, ReferenceSlots: referenceSlots(),
|
||||
}
|
||||
}
|
||||
|
||||
func Register(registry *pipeline.ExtractorRegistry) error {
|
||||
return pipeline.RegisterExtractorBuilder(registry, ModuleSpec(), validateOptions, func(request pipeline.BuildRequest) (contracts.Extractor[dnd.LocationList], error) {
|
||||
return pipeline.RegisterExtractorBuilder(registry, ModuleSpec(), validateOptions, func(request pipeline.BuildRequest) (contracts.Extractor[dnd.LocationRegistry], error) {
|
||||
options, err := DecodeOptions(request.Options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestExtractMapsLocationsWithOwnedEvidenceAndDeterministicOrder(t *testing.T
|
||||
t.Fatalf("Extract() error = %v, want nil", err)
|
||||
}
|
||||
refs := []source.SourceRef{{SourceID: "session-locations", StartUnitID: 1, EndUnitID: 1}, {SourceID: "session-locations", StartUnitID: 2, EndUnitID: 2}}
|
||||
want := dnd.LocationList{Locations: []dnd.Location{
|
||||
want := dnd.LocationRegistry{Locations: []dnd.Location{
|
||||
{ID: identity.DeriveID("Old Mill", refs), Name: "Old Mill", SourceRefs: refs},
|
||||
{ID: identity.DeriveID("The Tavern", []source.SourceRef{{SourceID: "session-locations", StartUnitID: 3, EndUnitID: 3}}), Name: "The Tavern", SourceRefs: []source.SourceRef{{SourceID: "session-locations", StartUnitID: 3, EndUnitID: 3}}},
|
||||
}}
|
||||
|
||||
@@ -18,7 +18,7 @@ func TestModuleRegistrationAndMetadata(t *testing.T) {
|
||||
if _, err := New(&fakeLocationsLLMClient{}, Options{}, contracts.ReferenceSet{}, contracts.ReferenceSet{}); err == nil || !strings.Contains(err.Error(), "at most one") {
|
||||
t.Fatalf("New() error = %v, want reference-set rejection", err)
|
||||
}
|
||||
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.locations"}, ArtifactKind: dnd.LocationListKind, ReferenceSlots: referenceSlots()}
|
||||
want := pipeline.ModuleSpec{Key: Key, Stage: pipeline.StageExtract, ExecutionClass: contracts.ExecutionClassLLMBacked, Requires: []string{"chunks", "source.transcript"}, Provides: []string{"dnd.locations"}, ArtifactKind: dnd.LocationRegistryKind, ReferenceSlots: referenceSlots()}
|
||||
if got := ModuleSpec(); !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user