diff --git a/NOTICE b/NOTICE index d944d6d0..930ec534 100644 --- a/NOTICE +++ b/NOTICE @@ -7,3 +7,26 @@ The syntax-highlighting definitions in internal/tui/render/lexers are generated from the lexers of Chroma (https://github.com/alecthomas/chroma), Copyright (C) 2017 Alec Thomas, used under the MIT license. See internal/tui/render/lexers for that license text and for how the files are regenerated. + +The chat templates in internal/inference/launch/templates are copied unchanged +from their publishers and used under the Apache License, Version 2.0: +gpt-oss.jinja is the gpt-oss chat template published by OpenAI at +https://huggingface.co/openai/gpt-oss-20b; gemma4.jinja is the Gemma 4 chat +template published by Google at https://huggingface.co/google/gemma-4-12B-it. +The revision of each is recorded in internal/inference/launch/template.go. + +Gemma 4 is licensed by Google under Apache 2.0 (the model card declares +license: apache-2.0 and links https://ai.google.dev/gemma/docs/gemma_4_license, +which is the unmodified Apache 2.0 text). Unlike earlier Gemma releases, it is +not under the Gemma Terms of Use (https://ai.google.dev/gemma/terms), whose +scope lists only those earlier models and which points Gemma 4 to its own +licence. The template and the weights are under the same terms; Flynn does not +distribute the weights. + +The container security profiles in deploy/seccomp/flynn.json and +deploy/apparmor/flynn-container are Docker's default seccomp profile and +AppArmor template from moby/profiles (https://github.com/moby/profiles), +Copyright The Moby Authors, used under the Apache License, Version 2.0. Each +is modified by one rule, described in dev/container-profiles, which also +pins the upstream commit. Unchanged copies of the upstream files are in +deploy/testdata. diff --git a/internal/inference/launch/template.go b/internal/inference/launch/template.go index 6cb45e1a..f803baf9 100644 --- a/internal/inference/launch/template.go +++ b/internal/inference/launch/template.go @@ -24,15 +24,17 @@ import ( // from the model. // gptOSSTemplate is OpenAI's published chat template for gpt-oss (the chat_template.jinja -// in openai/gpt-oss-20b, Apache-2.0), byte for byte the template the ggml-org GGUF +// in openai/gpt-oss-20b at revision 6cee5e81ee83917806bbde320786a8fb61efebee, +// Apache-2.0, attributed in NOTICE), byte for byte the template the ggml-org GGUF // conversion embeds. It renders the harmony format, including tool definitions and the // reasoning_effort setting. // //go:embed templates/gpt-oss.jinja var gptOSSTemplate string -// gemma4Template is Google's canonical Gemma 4 chat template (Apache-2.0), as embedded in -// google/gemma-4-12B-it-qat-q4_0-gguf. llama.cpp has no built-in name for Gemma 4; it +// gemma4Template is Google's canonical Gemma 4 chat template (the chat_template.jinja in +// google/gemma-4-12B-it at revision 43c9d014b231474fa7212dbb48a762566c2b255d, Apache-2.0, +// attributed in NOTICE), byte for byte. llama.cpp has no built-in name for Gemma 4; it // recognises the family from the template source, so the source has to be supplied. // //go:embed templates/gemma4.jinja diff --git a/internal/inference/launch/template_test.go b/internal/inference/launch/template_test.go index 1daded3c..441f172d 100644 --- a/internal/inference/launch/template_test.go +++ b/internal/inference/launch/template_test.go @@ -1,6 +1,8 @@ package launch import ( + "crypto/sha256" + "encoding/hex" "strings" "testing" ) @@ -174,3 +176,23 @@ func TestNativeToolCallsFollowsTheRoute(t *testing.T) { t.Error("llama3 runs with --no-jinja and cannot take tools") } } + +// TestEmbeddedTemplatesAreThePublishersOwn holds each embedded template to the SHA-256 of +// the file its publisher ships at the revision recorded on its variable. NOTICE states the +// templates are copied unchanged, and an edit made here would break that statement and +// leave Flynn serving a prompt format no upstream model was trained on. Updating a template +// means taking the publisher's newer file whole, then updating the revision and this digest. +func TestEmbeddedTemplatesAreThePublishersOwn(t *testing.T) { + for name, want := range map[string]string{ + "gpt-oss": "a4c9919cbbd4acdd51ccffe22da049264b1b73e59055fa58811a99efbd7c8146", + "gemma4": "ae53464bf3be25802b3a5b37def7fd89667067d7577049b3b2d74c4d8de4c6d4", + } { + sum := sha256.Sum256([]byte(embeddedTemplates[name])) + if got := hex.EncodeToString(sum[:]); got != want { + t.Errorf("%s template sha256 = %s, want the publisher's %s", name, got, want) + } + } + if len(embeddedTemplates) != 2 { + t.Errorf("embedded templates = %d, want 2: a new one needs its publisher's digest here and a NOTICE entry", len(embeddedTemplates)) + } +} diff --git a/watch/marker.go b/watch/marker.go index 206b6a16..391172a6 100644 --- a/watch/marker.go +++ b/watch/marker.go @@ -1,8 +1,9 @@ // Package watch turns in-tree source comments into governed run inputs. It tails a -// working tree for aider-style ai! and ai? markers left in trailing comments; when -// one appears it becomes a turn the agent runs, and the marker's file and line are -// carried onto the run so its provenance lands in the sealed record like any other -// input. The marker is cleared once picked up so the same request never fires twice. +// working tree for trailing comments that open with an ai! marker (change the code) or +// an ai? marker (answer a question); when one appears it becomes a turn the agent runs, +// and the marker's file and line are carried onto the run so its provenance lands in the +// sealed record like any other input. The marker is cleared once picked up so the same +// request never fires twice. package watch import (