Skip to content

Conversation

@mostlygeek
Copy link
Owner

@mostlygeek mostlygeek commented Oct 4, 2025

Changes:

  • add Metadata key to ModelConfig
  • include metadata in /v1/models under llamaswap_meta key
  • add recursive macro substitution into Metadata
  • change macros to be any scalar type

Note about this PR:

The code for this PR was primarily written by Claude Code + Sonnet 4.5. I've very been against agentic code generation because the code was usually shit, very verbose and hard to review. CC with Sonnet 4.5 is the first time where those things haven't been entirely true for me.

This PR includes a workflow that I've been prototyping and found to be reliable using Sonnet 4.5:

  • Create a plan in ai-plans/issue-<num>-short-description.md
  • The plan should be written by a human. I've committed the version that I initially wrote. It's about 24 lines of requirements in point form.
  • Tell CC: "plan expansion". This is a trigger phrase in CLAUDE.md to follow the guidelines for a plan.
  • Review the plan after expansion. I review this very carefully making sure things look good.
  • Tell CC: "paint it". This is a trigger phrase in CLAUDE.md to start automated assembly. I prefer to choose to accept all changes and review when Claude is done.
  • Review the changes. Tell Claude to make any changes. I prefer to avoid manual changes to the source so Claude's current context remains consistent.

I've kept the stages I went through as individual commits to make it easier to see the process.

From sitting down to write out the first plan to this PR was about 2.5 hours.

Summary by CodeRabbit

  • New Features

    • Model configs can include typed metadata (strings, numbers, booleans, nested lists/maps) with macro substitution preserved by type.
    • API model listings return optional llamaswap_meta for models that provide metadata.
  • Documentation

    • Added project overview and workflow guide (CLAUDE.md).
  • Tests

    • Expanded tests for typed/nested macros, precedence, validation, and API metadata serialization.
  • Chores

    • Added a dev test Makefile target to streamline proxy testing.

First initial plan (pre-expansion) to implement metadata in models
configurations.
- add Metadata key to ModelConfig
- include metadata in /v1/models under llamaswap_meta key
- add recursive macro substitution into Metadata
- change macros to be any scalar type
@coderabbitai
Copy link

coderabbitai bot commented Oct 4, 2025

Walkthrough

Adds typed macro support and recursive metadata macro substitution during config load, exposes per-model metadata in the /v1/models API as meta.llamaswap, expands tests for typed/nested macros, adds a test-dev Make target, and introduces a new docs file CLAUDE.md.

Changes

Cohort / File(s) Summary
Docs
CLAUDE.md
New documentation describing the project, workflow, testing commands, and task/workflow rules; no code logic changes.
Build / Dev
Makefile
Adds test-dev target and updates .PHONY to include it.
Config Example
config.example.yaml
Adds typed model macros (e.g., integer default_ctx, float temp), updates model cmd to use --temperature ${temp}, and adds a metadata block demonstrating typed and interpolated values (lists, maps, scalars).
Config Core (Typed Macros & Metadata)
proxy/config/config.go, proxy/config/model_config.go
MacroList changed from map[string]string to map[string]any; ModelConfig gains Metadata map[string]any; validateMacro updated to accept any and enforce scalar types; adds substituteMetadataMacros for recursive substitution and applies metadata macro substitution during config load; adds macro name/pattern regex and PORT handling.
Config Tests
proxy/config/config_test.go, proxy/config/config_posix_test.go, proxy/config/config_windows_test.go
Tests updated/added to validate typed macros, nested metadata structures, macro precedence, unknown-macro errors, and macro type validation; tests updated to use MacroList type.
API response
proxy/proxymanager.go
listModelsHandler now conditionally includes model metadata under meta.llamaswap when ModelConfig.Metadata is non-empty.
API Tests
proxy/proxymanager_test.go
Adds TestProxyManager_ListModelsHandler_WithMetadata asserting presence, types, and interpolation for meta.llamaswap; duplicate test function appears twice in the file.
AI Plan
ai-plans/issue-264-add-metadata.md
New design/testing plan documenting typed metadata macros, substitution rules, validation, API exposure, and test coverage.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant YAML as Config (YAML)
  participant Loader as LoadConfigFromReader
  participant Macro as Macro Merger
  participant Subst as substituteMetadataMacros
  participant Store as ModelConfig

  YAML->>Loader: Read global + per-model config
  Loader->>Macro: Merge macros (MacroList map[string]any, add MODEL_ID/PORT)
  Loader->>Subst: Substitute macros in string fields (cmd, cmdStop, etc.)
  Loader->>Subst: Recursively substitute macros in Metadata (maps, lists, scalars)
  Subst-->>Loader: Metadata with preserved scalar types / interpolated strings
  Loader->>Store: Save ModelConfig with substituted Metadata
Loading
sequenceDiagram
  autonumber
  participant Client as Client
  participant API as listModelsHandler
  participant Cfg as Loaded ModelConfigs

  Client->>API: GET /v1/models
  API->>Cfg: Iterate model configs
  alt model.Metadata non-empty
    API->>API: Add `meta.llamaswap` to model record
  else metadata empty
    API->>API: Omit `meta.llamaswap`
  end
  API-->>Client: JSON list (ids + optional meta.llamaswap)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

enhancement, configuration

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the core change by indicating that the proxy component now supports schemaless metadata in model configurations, matching the modifications to ModelConfig, Metadata handling, and macro substitution in the proxy module. It is specific and clear about the feature added without unnecessary detail.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch model-metadata-264

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ef3bad7 and 16777df.

📒 Files selected for processing (2)
  • proxy/config/config.go (9 hunks)
  • proxy/config/config_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
proxy/config/config_test.go (1)
proxy/config/config.go (1)
  • LoadConfigFromReader (108-293)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: run-tests
🔇 Additional comments (14)
proxy/config/config_test.go (6)

521-558: Excellent test coverage for typed macro substitution.

The test thoroughly validates both direct type-preserving substitution and string interpolation with type conversion. The assertions correctly verify that:

  • Scalar types (int, float, bool, string) are preserved when directly substituted
  • String interpolation converts all macro values to strings
  • Both global macros and PORT macro work in metadata

560-599: Comprehensive testing of nested metadata structures.

The test effectively validates recursive macro substitution across:

  • Nested maps (multi-level)
  • Arrays with macro interpolation
  • Deep nesting scenarios

The type assertions correctly verify the structure and values at each level.


601-632: Good validation of macro precedence rules.

The test correctly verifies that model-level macros override global macros while global macros remain accessible. This ensures the merging logic in the implementation works as designed.


634-648: Appropriate error handling test for unknown macros.

The test verifies that unknown macros in metadata produce clear error messages that include both the model name and macro name, which aids debugging.


650-666: Validates constraint on composite macro types.

The test correctly verifies that non-scalar types (nested maps) are rejected during macro validation, preventing type confusion in command field substitution.


668-759: Thorough validation of all scalar types.

The test suite comprehensively covers:

  • All valid scalar types (string, int, float, bool)
  • Invalid composite types (array, map)

The table-driven approach makes it easy to understand and extend.

proxy/config/config.go (8)

19-19: Breaking type change enables typed macro feature.

Changing MacroList from map[string]string to map[string]any is necessary to support typed macros in metadata. The AI summary confirms that related files (config_posix_test.go, config_windows_test.go) have been updated to reflect this change.


28-31: Efficient regex compilation at package initialization.

Extracting regex patterns to package-level variables is good practice—they're compiled once rather than repeatedly, and can be reused throughout the package.


190-190: Ensure MODEL_ID is available before PORT in merged macros.

Adding MODEL_ID to merged macros at line 190 (before PORT assignment at line 217) ensures both reserved macros are available for metadata substitution. The positioning is correct given the control flow.


195-201: Type conversion for command field substitution.

Converting macro values to strings using fmt.Sprintf("%v", macroValue) enables typed macros to be interpolated into command strings while maintaining backward compatibility with string-based substitution.


216-219: PORT added to merged macros for metadata access.

Adding PORT to mergedMacros after port assignment enables the dynamically-assigned port to be referenced in metadata. The placement after command substitution (lines 193-202) ensures PORT isn't substituted in commands prematurely.


244-251: Type-safe metadata substitution with proper error context.

The metadata substitution correctly:

  • Guards with a length check to skip empty metadata
  • Propagates errors with model context
  • Type-asserts the result to map[string]any

The type assertion on line 250 is safe because substituteMetadataMacros will only return map[string]any for a map[string]any input (or an error), preventing panics.


389-415: Robust macro validation with type checking.

The updated validateMacro function correctly:

  • Accepts any type to support typed macros
  • Validates scalar types using a type switch
  • Enforces string length limits
  • Rejects composite types (arrays, maps) that cannot be safely converted to strings
  • Checks reserved macro names

The error messages clearly indicate the specific violation.


417-475: Well-designed recursive metadata substitution.

The substituteMetadataMacros function implements a clean recursive algorithm that:

  1. Preserves types for direct substitution (lines 424-430): When a string exactly matches ${MACRO}, it returns the macro's native type
  2. Converts for interpolation (lines 432-445): When macros appear within larger strings, all values convert to strings
  3. Recursively processes structures (lines 447-469): Maps and slices are processed recursively, maintaining structure integrity
  4. Handles errors properly: Unknown macros produce clear error messages

The distinction between direct substitution (type-preserving) and string interpolation (type-converting) is exactly the right semantic for metadata.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
Makefile (1)

26-29: Consider preserving staticcheck exit status for visibility.

The || true suppresses staticcheck failures, which could hide code quality issues during development. Consider one of these alternatives:

  • Remove || true and let staticcheck failures be visible (developers can still iterate)
  • Add a warning message when staticcheck fails: staticcheck ./proxy/... || echo "⚠️ staticcheck found issues"
  • Use a separate target for strict checking vs. fast iteration

Apply this diff if you want to preserve visibility of staticcheck issues:

 test-dev: proxy/ui_dist/placeholder.txt
 	go test -short ./proxy/...
-	staticcheck ./proxy/... || true
+	staticcheck ./proxy/... || echo "⚠️  Warning: staticcheck found issues"
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1f61791 and 5cede03.

📒 Files selected for processing (10)
  • CLAUDE.md (1 hunks)
  • Makefile (2 hunks)
  • ai-plans/issue-264-add-metadata.md (1 hunks)
  • config.example.yaml (3 hunks)
  • proxy/config/config.go (6 hunks)
  • proxy/config/config_posix_test.go (1 hunks)
  • proxy/config/config_test.go (1 hunks)
  • proxy/config/model_config.go (1 hunks)
  • proxy/proxymanager.go (1 hunks)
  • proxy/proxymanager_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
proxy/config/config_posix_test.go (1)
proxy/config/config.go (1)
  • MacroList (19-19)
proxy/config/config_test.go (1)
proxy/config/config.go (1)
  • LoadConfigFromReader (103-288)
proxy/proxymanager_test.go (1)
proxy/config/config.go (1)
  • LoadConfigFromReader (103-288)
🔇 Additional comments (6)
config.example.yaml (1)

149-172: LGTM! Comprehensive metadata examples.

The metadata examples effectively demonstrate the new functionality:

  • Type preservation with scalar values (port, temperature)
  • String interpolation in the note field
  • Complex types (arrays, nested objects) with macro substitution
proxy/proxymanager.go (1)

373-376: LGTM! Clean conditional metadata inclusion.

The implementation correctly adds llamaswap_meta only when metadata is present, preserving backward compatibility for models without metadata.

proxy/config/model_config.go (1)

34-37: LGTM! Appropriate field addition.

The Metadata field addition is well-documented with an issue reference and uses the appropriate map[string]any type to support flexible metadata structures.

proxy/config/config_posix_test.go (1)

166-168: LGTM! Test correctly updated for MacroList type.

The test properly reflects the MacroList type change from map[string]string to map[string]any.

proxy/config/config_test.go (1)

521-761: LGTM! Excellent test coverage for metadata and typed macros.

The test suite comprehensively covers:

  • Type preservation for all scalar types (string, int, float, bool)
  • String interpolation behavior
  • Nested data structures (maps and arrays)
  • Macro precedence (model-level overriding global)
  • Error handling for unknown macros and invalid types
  • Validation distinguishing scalar vs. composite macro types

This thorough coverage will help prevent regressions as the metadata feature evolves.

proxy/proxymanager_test.go (1)

285-357: LGTM! Comprehensive metadata testing.

  • Type preservation (int, float, bool) in llamaswap_meta
  • String interpolation for composed values
  • Nested metadata structures
  • Conditional metadata presence

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
proxy/config/config_windows_test.go (1)

158-160: Type update looks correct.

The update to MacroList properly reflects the type change from map[string]string to map[string]any. The test continues to validate string macro substitution, which remains a valid use case.

Consider adding test cases for non-string scalar macro types (int, float, bool) to verify they work correctly on Windows, if not already covered elsewhere.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5cede03 and 12d5409.

📒 Files selected for processing (1)
  • proxy/config/config_windows_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
proxy/config/config_windows_test.go (1)
proxy/config/config.go (1)
  • MacroList (19-19)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: run-tests

@mostlygeek mostlygeek merged commit 70930e4 into main Oct 5, 2025
3 checks passed
@mostlygeek mostlygeek deleted the model-metadata-264 branch October 5, 2025 02:56
@mostlygeek mostlygeek changed the title proxy: implement schemaless metadata in model configs proxy: support user defined metadata in model configuration Oct 5, 2025
@bjodah
Copy link

bjodah commented Oct 5, 2025

Thank you for the feature, and thank you for taking the time to document your process so thoroughly , it's inspiring and instructive to read!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants