apple: native @Generable metadata schema for §B enrichment#7
Open
jakejimenez wants to merge 1 commit into
Open
apple: native @Generable metadata schema for §B enrichment#7jakejimenez wants to merge 1 commit into
jakejimenez wants to merge 1 commit into
Conversation
PR #6 added §B metadata enrichment but had to skip Apple Intelligence because nlci-apple's Swift bridge constrained output to a single CommandResult struct. On the project's recommended setup (Apple as primary backend), §B silently degraded to hardcoded scaffold values. This change extends the bridge so Apple gets the full §B benefit natively, without needing Ollama or a YAML round-trip. Swift side (apple/Sources/NLCIApple/): - MetadataResult.swift adds three @generable structs: ToolMetadata (description, system_prompt, safety, synonyms), SafetyRules, and SynonymEntry (a keyword + targets pair, since Dictionary isn't auto-Generable). - BridgeInput.swift adds a `mode` field (default "command" preserves pre-existing behavior for old Go callers). - BridgeOutput.swift adds `metadata` (populated in metadata mode) and `capabilities` (populated by --ping so Go can detect stale binaries). - App.swift switches on input.mode to pick CommandResult vs ToolMetadata when calling session.respond(generating:). Go side: - internal/backend/metadata.go introduces an optional capability interface MetadataGenerator + types MetadataRequest, MetadataResult, Safety. Backends opt in by implementing it; others fall through to PR #6's textual YAML prompt path. Idiomatic Go capability detection (cf. io.WriterTo). - internal/backend/apple.go: Ping now parses --ping output for the capabilities array; HasCapability gates the new method; GenerateMetadata sends mode="metadata", parses BridgeOutput.metadata, and flattens the array-of-pairs synonyms into a map[string][]string. - cmd/nlci/main.go: runMetadataEnrichment type-asserts the active backend for backend.MetadataGenerator and prefers native generation; on error or no-implementation it falls through to enrichInitMetadata. convertNativeMetadata maps the backend type into the cmd-local EnrichmentMetadata, applying the same placeholder-leak guard as the YAML parser. Verified end-to-end with `nlci init jq` on Apple Intelligence: - description: "Process JSON data using `jq` for transformations…" (was: "jq CLI") - system_prompt: tool-specific guidance referencing real jq flags (was: generic "You are an expert jq user") - safety + synonyms populated from the model's reading of the help text (was: empty arrays + heuristic-only synonyms) Backward compatibility: - Old Swift binary + new Go: HasCapability("metadata") is false, GenerateMetadata returns an actionable rebuild error, init falls through to YAML path (which also fails on Apple), scaffold gets hardcoded values. User sees a clear "make build-apple && make install-apple" hint. - New Swift binary + old Go: BridgeInput.mode defaults to "command" via decodeIfPresent, behavior unchanged. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Stacked on #6. PR #6 introduced §B metadata enrichment but had to skip Apple Intelligence —
nlci-apple's Swift bridge was hardcoded to a single@Generable CommandResultschema, so it couldn't return the structured YAML §B asks for. On the project's recommended setup (Apple as primary backend),nlci initquietly fell back to hardcoded scaffold values. This PR closes that gap so Apple gets §B natively, without needing an Ollama detour.Architecture
A new
modefield inBridgeInputselects which@Generableschema the model is constrained to. NewToolMetadata/SafetyRules/SynonymEntrystructs in Swift map 1:1 onto the existingEnrichmentMetadatatype in Go.On the Go side, a new optional capability interface
backend.MetadataGeneratoris type-asserted at the call site (idiomatic Go capability detection — cf.io.WriterTo).AppleBackendimplements it; other backends don't, so they fall through to PR #6's existing YAML-prompt path. No change to the coreBackendinterface.```
runMetadataEnrichment
↓ Resolve active backend
├── implements MetadataGenerator? → GenerateMetadata (native @generable)
└── otherwise → enrichInitMetadata (YAML prompt)
```
Backward compatibility
--pingnow returns acapabilities: ["command", "metadata"]array.AppleBackend.Pingcaches it;HasCapability("metadata")gates the new method. Old Swift binaries don't emit the array, so the gate is closed and an actionable error directs the user to rebuild:In the other direction, old Go binaries don't set
mode, and the new Swift bridge'sdecodeIfPresentdefaults it to"command"— behavior unchanged.Verified end-to-end
`nlci init jq` on Apple Intelligence produces:
Total init time: ~11s for jq end-to-end. Apple Intelligence handles the structured generation natively in one round-trip.
Files
Test plan
Known follow-ups
The model occasionally over-populates `safety.require_confirmation` for non-destructive flags (e.g. it added jq's output-format flags like `-c`, `-R` to the confirmation list). This is a prompt-tuning issue, not architectural — the YAML can be edited by the user, and the prompt's `@Guide(description:)` strings can be tightened in a follow-up to be more explicit about what counts as destructive.
🤖 Generated with Claude Code