Clarify artifact reader ownership transfer
This commit is contained in:
43
artifact_ownership_contract_test.go
Normal file
43
artifact_ownership_contract_test.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
package promptkit_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.maximumdirect.net/configkit"
|
||||||
|
"go.maximumdirect.net/promptkit"
|
||||||
|
)
|
||||||
|
|
||||||
|
type independentArtifactReader struct{}
|
||||||
|
|
||||||
|
func (independentArtifactReader) Read(_ context.Context, ref promptkit.ArtifactRef) (*promptkit.Artifact, error) {
|
||||||
|
return &promptkit.Artifact{Body: []byte(ref.Body), Hash: ref.Body}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestConcurrentPreparationWithTransferredArtifacts(t *testing.T) {
|
||||||
|
input := configkit.Input{Source: configkit.Mapping("ownership", map[string]any{
|
||||||
|
"profiles": []any{map[string]any{"id": "profile", "endpoint": "https://example.invalid/v1", "model": "model"}},
|
||||||
|
"prompts": []any{map[string]any{"id": "prompt", "default_profile": "profile", "inputs": []any{map[string]any{"name": "document", "required": true}}, "messages": []any{map[string]any{"role": "user", "content": `{{input "document"}}`}}, "output": map[string]any{"format": "text", "validation_mode": "none"}}},
|
||||||
|
})}
|
||||||
|
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &input}}, promptkit.WithArtifactReader(independentArtifactReader{}))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var group sync.WaitGroup
|
||||||
|
for i := range 24 {
|
||||||
|
group.Go(func() {
|
||||||
|
value := fmt.Sprintf("body-%d", i)
|
||||||
|
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{PromptID: "prompt", Inputs: map[string]promptkit.ArtifactRef{"document": promptkit.Inline(value)}})
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("prepare: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(prepared.Messages) != 1 || prepared.Messages[0].Content != value || prepared.InputHashes["document"] != value {
|
||||||
|
t.Errorf("prepared = %+v", prepared)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
group.Wait()
|
||||||
|
}
|
||||||
@@ -891,6 +891,11 @@ of collaborator errors. Implementations must honor cancellation, safely manage
|
|||||||
copies they retain, avoid unsafe logging of content or credentials, and enforce
|
copies they retain, avoid unsafe logging of content or credentials, and enforce
|
||||||
the application policy that motivated the injection.
|
the application policy that motivated the injection.
|
||||||
|
|
||||||
|
A successful `ArtifactReader.Read` transfers the returned artifact and mutable
|
||||||
|
body storage to Promptkit. Readers that previously reused a returned buffer
|
||||||
|
must instead return independent storage and stop mutating it after return;
|
||||||
|
private scratch buffers may still be reused when the returned bytes are copied.
|
||||||
|
|
||||||
## Handle Errors
|
## Handle Errors
|
||||||
|
|
||||||
Use `errors.Is` with the
|
Use `errors.Is` with the
|
||||||
|
|||||||
@@ -244,6 +244,10 @@ Focused authentication and public smoke tests pass on Go 1.27.3.
|
|||||||
the accepted handoff, without promising safety for contract-violating readers.
|
the accepted handoff, without promising safety for contract-violating readers.
|
||||||
Explain migration in consumer guidance; no borrowing/release protocol is added.
|
Explain migration in consumer guidance; no borrowing/release protocol is added.
|
||||||
|
|
||||||
|
Completion: ArtifactReader ownership and migration guidance require independent
|
||||||
|
transferred storage. Focused concurrent preparation, adapter isolation, and
|
||||||
|
cause-propagation tests pass with the race detector on Go 1.27.3.
|
||||||
|
|
||||||
## Stage 9: Detach Prepared Ownership And Session Storage
|
## Stage 9: Detach Prepared Ownership And Session Storage
|
||||||
|
|
||||||
**Catalog:** 16, 18. **Files:** runner/prepared state and domain session normalization.
|
**Catalog:** 16, 18. **Files:** runner/prepared state and domain session normalization.
|
||||||
|
|||||||
8
types.go
8
types.go
@@ -295,15 +295,17 @@ type Artifact struct {
|
|||||||
//
|
//
|
||||||
// Read may be called concurrently. It must honor ctx cancellation to make
|
// Read may be called concurrently. It must honor ctx cancellation to make
|
||||||
// Prepare, PrepareExecution, and Run responsive to cancellation. The engine
|
// Prepare, PrepareExecution, and Run responsive to cancellation. The engine
|
||||||
// passes a copied ref and immediately copies the returned Artifact.Body; it
|
// passes a copied ref and defensively copies the returned Artifact.Body.
|
||||||
// does not retain either value. Readers supply artifact metadata, and the
|
// A successful Read transfers the returned artifact and its mutable body
|
||||||
|
// storage to Promptkit. The reader must not mutate them through retained
|
||||||
|
// aliases after return. Private buffers may be reused only when the returned
|
||||||
|
// storage is independent. Readers supply artifact metadata, and the
|
||||||
// engine assigns an input-map name only when the returned artifact name is
|
// engine assigns an input-map name only when the returned artifact name is
|
||||||
// empty.
|
// empty.
|
||||||
//
|
//
|
||||||
// An injected reader owns any application-specific path containment,
|
// An injected reader owns any application-specific path containment,
|
||||||
// authorization, content-size, and content-type policy. It must protect
|
// authorization, content-size, and content-type policy. It must protect
|
||||||
// sensitive references and bodies in its logging and in any copies it retains.
|
// sensitive references and bodies in its logging and in any copies it retains.
|
||||||
// It may reuse or mutate the returned artifact and body after Read returns.
|
|
||||||
//
|
//
|
||||||
// Returning a non-nil error makes the engine return an error matching
|
// Returning a non-nil error makes the engine return an error matching
|
||||||
// ErrArtifactLoad while preserving the reader error through errors.Is.
|
// ErrArtifactLoad while preserving the reader error through errors.Is.
|
||||||
|
|||||||
Reference in New Issue
Block a user