Add prompt input materials and session IDs
This commit is contained in:
@@ -15,6 +15,12 @@ type LLMMessage struct {
|
||||
|
||||
type StructuredCompletionRequest struct {
|
||||
StageName string `json:"stage_name"`
|
||||
PromptID string `json:"prompt_id,omitempty"`
|
||||
PromptVersion string `json:"prompt_version,omitempty"`
|
||||
ProfileID string `json:"profile_id,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
Inputs LLMInputSet `json:"inputs,omitempty"`
|
||||
Vars map[string]any `json:"vars,omitempty"`
|
||||
Messages []LLMMessage `json:"messages"`
|
||||
Model string `json:"model,omitempty"`
|
||||
ResponseSchemaName string `json:"response_schema_name,omitempty"`
|
||||
@@ -34,6 +40,44 @@ type StructuredLLMClient interface {
|
||||
CompleteStructured(ctx context.Context, req StructuredCompletionRequest, out any) (StructuredCompletionResponse, error)
|
||||
}
|
||||
|
||||
type LLMInputMaterial struct {
|
||||
Name string `json:"name"`
|
||||
MediaType string `json:"media_type,omitempty"`
|
||||
Content []byte `json:"-"`
|
||||
Digest string `json:"digest,omitempty"`
|
||||
OriginURI string `json:"origin_uri,omitempty"`
|
||||
SizeBytes int64 `json:"size_bytes,omitempty"`
|
||||
}
|
||||
|
||||
func NewLLMInputMaterial(name string, mediaType string, content []byte, digest string, originURI string) LLMInputMaterial {
|
||||
return LLMInputMaterial{
|
||||
Name: name,
|
||||
MediaType: mediaType,
|
||||
Content: append([]byte(nil), content...),
|
||||
Digest: digest,
|
||||
OriginURI: originURI,
|
||||
SizeBytes: int64(len(content)),
|
||||
}
|
||||
}
|
||||
|
||||
func (material LLMInputMaterial) Clone() LLMInputMaterial {
|
||||
material.Content = append([]byte(nil), material.Content...)
|
||||
return material
|
||||
}
|
||||
|
||||
type LLMInputSet map[string]LLMInputMaterial
|
||||
|
||||
func (set LLMInputSet) Clone() LLMInputSet {
|
||||
if len(set) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(LLMInputSet, len(set))
|
||||
for key, material := range set {
|
||||
out[key] = material.Clone()
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type ParseRequest struct {
|
||||
SourceID string `json:"source_id,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
@@ -57,12 +101,14 @@ type SourceChunk struct {
|
||||
}
|
||||
|
||||
type ChunkRequest struct {
|
||||
Source *source.SourceDocument `json:"-"`
|
||||
References ReferenceSet `json:"references,omitempty"`
|
||||
LLMClient StructuredLLMClient `json:"-"`
|
||||
LLMProfile string `json:"llm_profile,omitempty"`
|
||||
Options map[string]any `json:"options,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
Source *source.SourceDocument `json:"-"`
|
||||
SourceInput LLMInputMaterial `json:"source_input,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
References ReferenceSet `json:"references,omitempty"`
|
||||
LLMClient StructuredLLMClient `json:"-"`
|
||||
LLMProfile string `json:"llm_profile,omitempty"`
|
||||
Options map[string]any `json:"options,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type ChunkResult struct {
|
||||
@@ -118,6 +164,8 @@ type ExtractionRequest struct {
|
||||
Source *source.SourceDocument `json:"-"`
|
||||
Chunk *SourceChunk `json:"chunk,omitempty"`
|
||||
AmbientContext map[string]any `json:"ambient_context,omitempty"`
|
||||
SourceInput LLMInputMaterial `json:"source_input,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
References ReferenceSet `json:"references,omitempty"`
|
||||
LLMClient StructuredLLMClient `json:"-"`
|
||||
LLMProfile string `json:"llm_profile,omitempty"`
|
||||
@@ -164,14 +212,16 @@ type Merger interface {
|
||||
}
|
||||
|
||||
type NormalizeRequest struct {
|
||||
Source *source.SourceDocument `json:"-"`
|
||||
LaneID string `json:"lane_id"`
|
||||
Candidates []artifacts.ArtifactCandidate `json:"candidates"`
|
||||
References ReferenceSet `json:"references,omitempty"`
|
||||
LLMClient StructuredLLMClient `json:"-"`
|
||||
LLMProfile string `json:"llm_profile,omitempty"`
|
||||
Options map[string]any `json:"options,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
Source *source.SourceDocument `json:"-"`
|
||||
LaneID string `json:"lane_id"`
|
||||
Candidates []artifacts.ArtifactCandidate `json:"candidates"`
|
||||
SourceInput LLMInputMaterial `json:"source_input,omitempty"`
|
||||
SessionID string `json:"session_id,omitempty"`
|
||||
References ReferenceSet `json:"references,omitempty"`
|
||||
LLMClient StructuredLLMClient `json:"-"`
|
||||
LLMProfile string `json:"llm_profile,omitempty"`
|
||||
Options map[string]any `json:"options,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
type NormalizeResult struct {
|
||||
|
||||
@@ -251,6 +251,53 @@ func TestReferenceItemJSONOmitsContent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLLMInputMaterialCopiesContentAndOmitsContentFromJSON(t *testing.T) {
|
||||
content := []byte("raw source bytes")
|
||||
material := NewLLMInputMaterial("transcript", "application/json", content, "sha256:source", "file:///tmp/source.json")
|
||||
content[0] = 'R'
|
||||
if got := string(material.Content); got != "raw source bytes" {
|
||||
t.Fatalf("material content = %q, want defensive copy", got)
|
||||
}
|
||||
if material.SizeBytes != int64(len("raw source bytes")) {
|
||||
t.Fatalf("SizeBytes = %d, want content length", material.SizeBytes)
|
||||
}
|
||||
|
||||
clone := material.Clone()
|
||||
clone.Content[0] = 'X'
|
||||
if got := string(material.Content); got != "raw source bytes" {
|
||||
t.Fatalf("cloned material content aliased original: %q", got)
|
||||
}
|
||||
|
||||
encoded, err := json.Marshal(material)
|
||||
if err != nil {
|
||||
t.Fatalf("json.Marshal() error = %v, want nil", err)
|
||||
}
|
||||
var got map[string]any
|
||||
if err := json.Unmarshal(encoded, &got); err != nil {
|
||||
t.Fatalf("json.Unmarshal() error = %v, want nil", err)
|
||||
}
|
||||
if _, ok := got["content"]; ok {
|
||||
t.Fatalf("encoded material leaked content: %s", encoded)
|
||||
}
|
||||
if _, ok := got["Content"]; ok {
|
||||
t.Fatalf("encoded material leaked Content: %s", encoded)
|
||||
}
|
||||
if got["digest"] != "sha256:source" || got["origin_uri"] != "file:///tmp/source.json" {
|
||||
t.Fatalf("encoded material = %#v, want non-secret provenance", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLLMInputSetCloneCopiesContent(t *testing.T) {
|
||||
set := LLMInputSet{
|
||||
"transcript": NewLLMInputMaterial("transcript", "application/json", []byte("source"), "sha256:source", "file:///tmp/source.json"),
|
||||
}
|
||||
clone := set.Clone()
|
||||
clone["transcript"].Content[0] = 'S'
|
||||
if got := string(set["transcript"].Content); got != "source" {
|
||||
t.Fatalf("input set clone aliased content: %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFakeMergeNormalizeAndOutputContracts(t *testing.T) {
|
||||
candidate := artifacts.ArtifactCandidate{
|
||||
Index: 0,
|
||||
|
||||
Reference in New Issue
Block a user