502 lines
21 KiB
Go
502 lines
21 KiB
Go
package configuration
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"gitea.maximumdirect.net/eric/ConfigKit"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/promptdef"
|
|
)
|
|
|
|
func TestLoadCapturesInheritedImportedContent(t *testing.T) {
|
|
files := fstest.MapFS{
|
|
"app/main.yaml": {Data: []byte("configkit:\n imports:\n - path: ../catalog/base.yaml\n - path: ../other/definition.yaml\ncollections:\n docs:\n prompts:\n child:\n extends: base\n")},
|
|
"catalog/base.yaml": {Data: []byte("collections:\n docs:\n release_version: r1\n prompts:\n base:\n version: \"v1\"\n messages:\n - role: ' USER '\n cache_control:\n type: ' ephemeral '\n ttl: ' 1h '\n content_file: ./body.md\n output:\n format: text\n validation_mode: basic\n")},
|
|
"catalog/body.md": {Data: []byte("Captured {{.name}}")},
|
|
"other/definition.yaml": {Data: []byte("collections:\n other:\n prompts:\n child:\n messages:\n - role: user\n content_file: ./body.md\n output:\n format: text\n validation_mode: none\n")},
|
|
"other/body.md": {Data: []byte("Other collection {{.name}}")},
|
|
}
|
|
namespace := configkit.NewFilesystem("embedded", files)
|
|
state, err := load(configkit.Input{
|
|
Source: namespace.File("app/main.yaml"), Imports: true,
|
|
Filesystem: &configkit.FilesystemContext{FS: &namespace, Root: "."},
|
|
}, nil)
|
|
if err != nil {
|
|
var loadError *configkit.LoadError
|
|
if errors.As(err, &loadError) {
|
|
t.Fatalf("%v: %+v", err, loadError.Diagnostics())
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
definition, inspection, err := state.prompt("docs/child")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if definition.Templates[0].Content != "Captured {{.name}}" || inspection.PromptHash == "" {
|
|
t.Fatalf("inherited file content was not captured: %+v, %+v", definition, inspection)
|
|
}
|
|
message := definition.Templates[0]
|
|
if message.Role != "user" || message.CacheControl == nil || message.CacheControl.Type != "ephemeral" || message.CacheControl.TTL != "1h" {
|
|
t.Fatalf("message metadata was not normalized: %+v", message)
|
|
}
|
|
field, ok := state.result.Metadata().Lookup(configkit.Keys("collections", "docs", "prompts", "child", "messages").Index(0).Key("content_file"))
|
|
if !ok || len(field.Origin.Locations) != 1 {
|
|
t.Fatalf("content origin was lost during normalization: %+v", field)
|
|
}
|
|
var originPath string
|
|
for _, source := range state.result.Sources() {
|
|
if source.ID == field.Origin.Locations[0].SourceID {
|
|
originPath = source.Path
|
|
}
|
|
}
|
|
if originPath != "catalog/base.yaml" {
|
|
t.Fatalf("content origin = %q, want catalog/base.yaml", originPath)
|
|
}
|
|
other, otherInspection, err := state.prompt("other/child")
|
|
if err != nil || other.Templates[0].Content != "Other collection {{.name}}" {
|
|
t.Fatalf("other collection did not retain its source context: %+v, %v", other, err)
|
|
}
|
|
files["catalog/body.md"].Data = []byte("Changed")
|
|
files["other/body.md"].Data = []byte("Changed other collection")
|
|
again, againInspection, err := state.prompt("docs/child")
|
|
if err != nil || again.Templates[0].Content != "Captured {{.name}}" || againInspection.PromptHash != inspection.PromptHash {
|
|
t.Fatalf("captured definition changed after source mutation: %+v, %+v, %v", again, againInspection, err)
|
|
}
|
|
definition.Templates[0].Content = "caller mutation"
|
|
third, _, err := state.prompt("docs/child")
|
|
if err != nil || third.Templates[0].Content != "Captured {{.name}}" {
|
|
t.Fatalf("caller mutation escaped into index: %+v, %v", third, err)
|
|
}
|
|
otherAgain, otherAgainInspection, err := state.prompt("other/child")
|
|
if err != nil || otherAgain.Templates[0].Content != "Other collection {{.name}}" || otherAgainInspection.PromptHash != otherInspection.PromptHash {
|
|
t.Fatalf("other captured definition changed after source mutation: %+v, %+v, %v", otherAgain, otherAgainInspection, err)
|
|
}
|
|
}
|
|
|
|
func TestLoadUsesExplicitMappingContextAndClosesContent(t *testing.T) {
|
|
filesystem := &countingFS{FS: fstest.MapFS{
|
|
"assets/body.md": {Data: []byte("From mapping")},
|
|
}}
|
|
namespace := configkit.NewFilesystem("mapping-context", filesystem)
|
|
source := configkit.Mapping("application", promptWithFile("body.md"))
|
|
state, err := load(configkit.Input{
|
|
Source: source,
|
|
Filesystem: &configkit.FilesystemContext{FS: &namespace, Root: ".", BaseDir: "assets"},
|
|
}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
definition, _, err := state.prompt("example")
|
|
if err != nil || definition.Templates[0].Content != "From mapping" || filesystem.contentOpened != 1 || filesystem.contentClosed != 1 {
|
|
t.Fatalf("mapping context or handle ownership failed: %+v, opens=%d closes=%d, %v", definition, filesystem.contentOpened, filesystem.contentClosed, err)
|
|
}
|
|
_, err = load(mapping("contextless", promptWithFile("body.md")), nil)
|
|
if err == nil || !strings.Contains(err.Error(), "/prompts/example/messages/0/content_file") {
|
|
t.Fatalf("expected semantic path for contextless resource, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadCapturesNativeContentFile(t *testing.T) {
|
|
root := t.TempDir()
|
|
definitionPath := filepath.Join(root, "definition.yaml")
|
|
contentPath := filepath.Join(root, "body.md")
|
|
if err := os.WriteFile(definitionPath, []byte("prompts:\n example:\n version: \"v1\"\n messages:\n - role: user\n content_file: body.md\n output:\n format: text\n validation_mode: basic\n"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(contentPath, []byte("Native body"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
state, err := load(configkit.Input{Source: configkit.File(definitionPath), Filesystem: &configkit.FilesystemContext{Root: root}}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(contentPath, []byte("Modified"), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
definition, _, err := state.prompt("example")
|
|
if err != nil || definition.Templates[0].Content != "Native body" {
|
|
t.Fatalf("native content was not captured: %+v, %v", definition, err)
|
|
}
|
|
}
|
|
|
|
func TestLoadRejectsMalformedStaticSyntaxAndCapturesOptionalVersion(t *testing.T) {
|
|
_, err := load(mapping("bad-template", map[string]any{"prompts": map[string]any{"example": map[string]any{
|
|
"messages": []any{map[string]any{"role": "user", "content": "{{if}}"}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}}}), nil)
|
|
if err == nil || !strings.Contains(err.Error(), "invalid template syntax") {
|
|
t.Fatalf("expected construction-time syntax error, got %v", err)
|
|
}
|
|
state, err := load(mapping("version metadata", map[string]any{"prompts": map[string]any{"example": map[string]any{
|
|
"version": "release label",
|
|
"messages": []any{map[string]any{"role": "user", "content": "one"}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}}}), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
definition, inspection, err := state.prompt("example")
|
|
if err != nil || definition.Version == nil || *definition.Version != "release label" ||
|
|
inspection.PromptVersion == nil || *inspection.PromptVersion != "release label" {
|
|
t.Fatalf("optional version metadata was not retained: definition=%+v inspection=%+v err=%v", definition, inspection, err)
|
|
}
|
|
}
|
|
|
|
func TestPromptVersionLabelPresenceAndOwnership(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
version any
|
|
include bool
|
|
wantPresent bool
|
|
wantValue string
|
|
}{
|
|
{name: "absent"},
|
|
{name: "null", include: true},
|
|
{name: "empty", version: "", include: true, wantPresent: true},
|
|
{name: "exact text", version: " Release/v1 ", include: true, wantPresent: true, wantValue: " Release/v1 "},
|
|
}
|
|
|
|
hashes := make(map[string]string, len(tests))
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
definition := map[string]any{
|
|
"messages": []any{map[string]any{"role": "user", "content": "hello"}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}
|
|
if test.include {
|
|
definition["version"] = test.version
|
|
}
|
|
state, err := load(mapping("prompt version label", map[string]any{
|
|
"prompts": map[string]any{"example": definition},
|
|
}), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
captured, inspection, err := state.prompt("example")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
identities, err := state.ListPrompts(context.Background())
|
|
if err != nil || len(identities) != 1 {
|
|
t.Fatalf("list prompt labels: %#v, %v", identities, err)
|
|
}
|
|
check := func(name string, value *string) {
|
|
t.Helper()
|
|
if !test.wantPresent {
|
|
if value != nil {
|
|
t.Errorf("%s label = %q, want absent", name, *value)
|
|
}
|
|
return
|
|
}
|
|
if value == nil || *value != test.wantValue {
|
|
t.Errorf("%s label = %v, want %q", name, value, test.wantValue)
|
|
}
|
|
}
|
|
check("definition", captured.Version)
|
|
check("inspection", inspection.PromptVersion)
|
|
check("listing", identities[0].Version)
|
|
if captured.Version != nil && (captured.Version == inspection.PromptVersion || captured.Version == identities[0].Version || inspection.PromptVersion == identities[0].Version) {
|
|
t.Fatal("returned prompt labels share mutable pointers")
|
|
}
|
|
hashes[test.name] = inspection.PromptHash
|
|
|
|
if captured.Version != nil {
|
|
*captured.Version = "mutated definition"
|
|
}
|
|
if inspection.PromptVersion != nil {
|
|
*inspection.PromptVersion = "mutated inspection"
|
|
}
|
|
if identities[0].Version != nil {
|
|
*identities[0].Version = "mutated listing"
|
|
}
|
|
again, againInspection, err := state.prompt("example")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
check("captured definition after mutation", again.Version)
|
|
check("captured inspection after mutation", againInspection.PromptVersion)
|
|
})
|
|
}
|
|
if hashes["absent"] == hashes["empty"] {
|
|
t.Fatal("absent and declared-empty labels produced the same definition hash")
|
|
}
|
|
}
|
|
|
|
func TestPromptVersionNullClearsInheritedLabel(t *testing.T) {
|
|
prompt := map[string]any{
|
|
"version": "base-label",
|
|
"messages": []any{map[string]any{"role": "user", "content": "hello"}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}
|
|
state, err := load(
|
|
mapping("clear inherited label", map[string]any{"prompts": map[string]any{"example": map[string]any{"version": nil}}}),
|
|
[]configkit.Underlay{{Inputs: []configkit.Input{mapping("base prompt", map[string]any{"prompts": map[string]any{"example": prompt}})}}},
|
|
)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
definition, inspection, err := state.prompt("example")
|
|
if err != nil || definition.Version != nil || inspection.PromptVersion != nil {
|
|
t.Fatalf("null overlay retained inherited label: definition=%+v inspection=%+v err=%v", definition, inspection, err)
|
|
}
|
|
}
|
|
|
|
func TestPromptInspectionLookupMatchesSnapshotSelectionAndOwnsInputs(t *testing.T) {
|
|
makePrompt := func(content string) map[string]any {
|
|
return map[string]any{
|
|
"default_profile": "partial",
|
|
"inputs": []any{map[string]any{
|
|
"name": "document", "required": true,
|
|
"content_type": " text/plain ", "description": " source document ",
|
|
}},
|
|
"messages": []any{map[string]any{"role": "user", "content": content}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "none"},
|
|
}
|
|
}
|
|
selectedPrompt := makePrompt("selected")
|
|
selectedPrompt["version"] = "v2"
|
|
state, err := load(mapping("prompt inspection lookup", map[string]any{
|
|
"profiles": map[string]any{"partial": map[string]any{}},
|
|
"prompts": map[string]any{
|
|
"selected": selectedPrompt,
|
|
},
|
|
}), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
{
|
|
inspection, err := state.GetPromptInspection(context.Background(), "selected")
|
|
if err != nil {
|
|
t.Fatalf("inspect prompt ID: %v", err)
|
|
}
|
|
definition, hash, err := state.GetPromptSnapshot(context.Background(), "selected")
|
|
if err != nil {
|
|
t.Fatalf("snapshot prompt ID: %v", err)
|
|
}
|
|
if inspection.PromptID != definition.ID || inspection.PromptVersion == nil || definition.Version == nil ||
|
|
*inspection.PromptVersion != *definition.Version ||
|
|
inspection.PromptHash != hash || inspection.DefaultProfileID != "partial" ||
|
|
len(inspection.Inputs) != 1 || inspection.Inputs[0].Name != "document" ||
|
|
inspection.Inputs[0].ContentType != "text/plain" || inspection.Inputs[0].Description != "source document" {
|
|
t.Fatalf("inspection did not match the selected snapshot: inspection=%+v definition=%+v hash=%q", inspection, definition, hash)
|
|
}
|
|
if len(definition.Inputs) != len(inspection.Inputs) || definition.Inputs[0].Name != inspection.Inputs[0].Name {
|
|
t.Fatalf("definition and inspection inputs diverged: definition=%+v inspection=%+v", definition.Inputs, inspection.Inputs)
|
|
}
|
|
}
|
|
|
|
owned, err := state.GetPromptInspection(context.Background(), "selected")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
owned.Inputs[0].Name = "caller mutation"
|
|
owned.Inputs[0].Description = "caller mutation"
|
|
again, err := state.GetPromptInspection(context.Background(), "selected")
|
|
if err != nil || again.Inputs[0].Name != "document" || again.Inputs[0].Description != "source document" {
|
|
t.Fatalf("inspection mutation escaped into captured state: inspection=%+v err=%v", again, err)
|
|
}
|
|
|
|
for _, id := range []string{"missing", " "} {
|
|
inspection, err := state.GetPromptInspection(context.Background(), id)
|
|
if inspection != nil || !errors.Is(err, promptdef.ErrPromptDefinitionNotFound) {
|
|
t.Errorf("inspection lookup %q=(%+v, %v), want not found", id, inspection, err)
|
|
}
|
|
definition, _, err := state.GetPromptSnapshot(context.Background(), id)
|
|
if definition != nil || !errors.Is(err, promptdef.ErrPromptDefinitionNotFound) {
|
|
t.Errorf("snapshot lookup %q=(%+v, %v), want not found", id, definition, err)
|
|
}
|
|
}
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
if _, err := state.GetPromptInspection(ctx, "selected"); !errors.Is(err, context.Canceled) {
|
|
t.Errorf("canceled inspection selection error=%v", err)
|
|
}
|
|
}
|
|
|
|
func TestLoadAcceptsEmptyInlineContentAndRejectsInvalidPromptFields(t *testing.T) {
|
|
state, err := load(mapping("empty-content", map[string]any{"prompts": map[string]any{" exact.id ": map[string]any{
|
|
"version": "v1",
|
|
"inputs": []any{map[string]any{"name": " note ", "required": true}},
|
|
"messages": []any{map[string]any{"role": " USER ", "content": "", "content_file": nil,
|
|
"cache_control": map[string]any{"type": " ephemeral ", "ttl": "1h "}}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}}}), nil)
|
|
if err != nil {
|
|
var loadError *configkit.LoadError
|
|
if errors.As(err, &loadError) {
|
|
t.Fatalf("%v: %+v", err, loadError.Diagnostics())
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
definition, _, err := state.prompt(" exact.id ")
|
|
if err != nil || definition.ID != " exact.id " || definition.Templates[0].Content != "" || definition.Templates[0].Role != "user" ||
|
|
definition.Inputs[0].Name != "note" || definition.Templates[0].CacheControl.TTL != "1h" {
|
|
t.Fatalf("explicit empty content or literal ID was changed: %+v, %v", definition, err)
|
|
}
|
|
if _, _, err := state.prompt("exact.id"); !errors.Is(err, errPromptNotFound) {
|
|
t.Fatalf("trimmed prompt identity unexpectedly matched: %v", err)
|
|
}
|
|
_, err = load(mapping("obsolete-field", map[string]any{"prompts": map[string]any{"example": map[string]any{
|
|
"version": "v1",
|
|
"id": "example", "messages": []any{map[string]any{"role": "user", "content": "ok"}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}}}), nil)
|
|
var loadError *configkit.LoadError
|
|
if !errors.As(err, &loadError) {
|
|
t.Fatalf("obsolete identity field should fail strict decoding: %v", err)
|
|
}
|
|
_, err = load(mapping("null-prompt", map[string]any{"prompts": map[string]any{"example": nil}}), nil)
|
|
if err == nil {
|
|
t.Fatal("null prompt collection was accepted")
|
|
}
|
|
}
|
|
|
|
func TestRequirementSnapshotCapturesMetadataPresenceAndNormalizedValues(t *testing.T) {
|
|
state, err := load(mapping("requirement-metadata", map[string]any{
|
|
"prompts": map[string]any{"example": map[string]any{
|
|
"version": "v1",
|
|
"session_id": "{{.session}}",
|
|
"inputs": []any{
|
|
map[string]any{"name": "absent"},
|
|
map[string]any{"name": "null", "content_type": nil, "description": nil},
|
|
map[string]any{"name": "empty", "content_type": "", "description": ""},
|
|
map[string]any{"name": "normalized", "content_type": " text/plain ", "description": " final text "},
|
|
},
|
|
"messages": []any{map[string]any{"role": "user", "content": "{{input \"absent\"}}"}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}},
|
|
}), nil)
|
|
if err != nil {
|
|
var loadError *configkit.LoadError
|
|
if errors.As(err, &loadError) {
|
|
t.Fatalf("%v: %+v", err, loadError.Diagnostics())
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
|
|
snapshot, ok := state.GetRequirementSnapshot("example")
|
|
if !ok || len(snapshot.Inputs) != 4 || len(snapshot.Templates.Messages) != 1 || snapshot.Templates.Session == nil {
|
|
t.Fatalf("requirement snapshot was not captured: %+v, %t", snapshot, ok)
|
|
}
|
|
for _, index := range []int{0, 1} {
|
|
if snapshot.Inputs[index].ContentType != nil || snapshot.Inputs[index].Description != nil {
|
|
t.Errorf("input %q should not have explicit string metadata: %+v", snapshot.Inputs[index].Name, snapshot.Inputs[index])
|
|
}
|
|
}
|
|
if snapshot.Inputs[2].ContentType == nil || *snapshot.Inputs[2].ContentType != "" ||
|
|
snapshot.Inputs[2].Description == nil || *snapshot.Inputs[2].Description != "" {
|
|
t.Errorf("explicit empty metadata presence was lost: %+v", snapshot.Inputs[2])
|
|
}
|
|
if snapshot.Inputs[3].ContentType == nil || *snapshot.Inputs[3].ContentType != "text/plain" ||
|
|
snapshot.Inputs[3].Description == nil || *snapshot.Inputs[3].Description != "final text" {
|
|
t.Errorf("snapshot did not use normalized final metadata: %+v", snapshot.Inputs[3])
|
|
}
|
|
|
|
definition, inspection, err := state.prompt("example")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(definition.Inputs) != 4 || len(inspection.Inputs) != 4 || inspection.Inputs[2].ContentType != "" || inspection.Inputs[2].Description != "" ||
|
|
inspection.Inputs[3].ContentType != "text/plain" || inspection.Inputs[3].Description != "final text" {
|
|
t.Fatalf("existing prompt inspection shape or normalized values changed: %+v", inspection)
|
|
}
|
|
|
|
*snapshot.Inputs[2].ContentType = "caller mutation"
|
|
snapshot.Inputs[3].Name = "caller mutation"
|
|
snapshot.Templates.Messages[0] = nil
|
|
again, ok := state.GetRequirementSnapshot("example")
|
|
if !ok || *again.Inputs[2].ContentType != "" || again.Inputs[3].Name != "normalized" || again.Templates.Messages[0] == nil {
|
|
t.Fatalf("snapshot mutation escaped into captured state: %+v, %t", again, ok)
|
|
}
|
|
}
|
|
|
|
func TestInputMetadataPresenceDoesNotChangePromptHashOrInspection(t *testing.T) {
|
|
variants := []struct {
|
|
name string
|
|
fields map[string]any
|
|
}{
|
|
{name: "absent"},
|
|
{name: "null", fields: map[string]any{"content_type": nil, "description": nil}},
|
|
{name: "empty", fields: map[string]any{"content_type": "", "description": ""}},
|
|
}
|
|
var expectedHash string
|
|
for _, variant := range variants {
|
|
t.Run(variant.name, func(t *testing.T) {
|
|
input := map[string]any{"name": "document"}
|
|
for name, value := range variant.fields {
|
|
input[name] = value
|
|
}
|
|
state, err := load(mapping("hash-"+variant.name, map[string]any{
|
|
"prompts": map[string]any{"same": map[string]any{
|
|
"version": "v1",
|
|
"inputs": []any{input},
|
|
"messages": []any{map[string]any{"role": "user", "content": "hello"}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}},
|
|
}), nil)
|
|
if err != nil {
|
|
var loadError *configkit.LoadError
|
|
if errors.As(err, &loadError) {
|
|
t.Fatalf("%v: %+v", err, loadError.Diagnostics())
|
|
}
|
|
t.Fatal(err)
|
|
}
|
|
_, inspection, err := state.prompt("same")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(inspection.Inputs) != 1 || inspection.Inputs[0].ContentType != "" || inspection.Inputs[0].Description != "" {
|
|
t.Fatalf("old inspection metadata changed: %+v", inspection.Inputs)
|
|
}
|
|
if expectedHash == "" {
|
|
expectedHash = inspection.PromptHash
|
|
} else if inspection.PromptHash != expectedHash {
|
|
t.Fatalf("metadata presence changed the definition hash: got %q, want %q", inspection.PromptHash, expectedHash)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func promptWithFile(name string) map[string]any {
|
|
return map[string]any{"prompts": map[string]any{"example": map[string]any{
|
|
"messages": []any{map[string]any{"role": "user", "content_file": name}},
|
|
"output": map[string]any{"format": "text", "validation_mode": "basic"},
|
|
}}}
|
|
}
|
|
|
|
type countingFS struct {
|
|
fs.FS
|
|
contentOpened int
|
|
contentClosed int
|
|
}
|
|
|
|
func (filesystem *countingFS) Open(name string) (fs.File, error) {
|
|
file, err := filesystem.FS.Open(name)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if name == "assets/body.md" {
|
|
filesystem.contentOpened++
|
|
return &countingFile{File: file, owner: filesystem}, nil
|
|
}
|
|
return file, nil
|
|
}
|
|
|
|
type countingFile struct {
|
|
fs.File
|
|
owner *countingFS
|
|
}
|
|
|
|
func (file *countingFile) Close() error {
|
|
file.owner.contentClosed++
|
|
return file.File.Close()
|
|
}
|