Skip to content

fix: propagate models.providers custom pricing to api-proxy defaultAiCreditsPricing#47571

Closed
pelikhan with Copilot wants to merge 11 commits into
mainfrom
copilot/fix-custom-pricing-models-providers
Closed

fix: propagate models.providers custom pricing to api-proxy defaultAiCreditsPricing#47571
pelikhan with Copilot wants to merge 11 commits into
mainfrom
copilot/fix-custom-pricing-models-providers

Conversation

Copilot AI commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

models.providers frontmatter pricing reached the agent-side GH_AW_MODELS_JSON_PATH catalog but was silently dropped from awf-config.json → apiProxy, so the proxy still rejected custom/BYOK models with unknown_model_ai_credits before the first turn. Detection sub-agent runs had the same issue since buildThreatDetectionWorkflowData never inherited ModelCosts.

Changes

  • awf_config.go — adds AWFDefaultAiCreditsPricingConfig struct and DefaultAiCreditsPricing field on AWFAPIProxyConfig; wires extractDefaultAiCreditsPricingFromModelCosts into BuildAWFConfigJSON to populate apiProxy.defaultAiCreditsPricing from WorkflowData.ModelCosts. Per-token cost strings (e.g. "3e-07") are converted to per-million-token floats required by the AWF schema. Model selection prefers an exact case-insensitive match on the workflow's model: field; falls back to the first parseable entry across all providers.

  • threat_detection_external.go — copies ModelCosts from parent WorkflowData into buildThreatDetectionWorkflowData so the detection guardrail config also carries the pricing fallback.

With this fix, a workflow like:

models:
  providers:
    anthropic:
      models:
        accounts/fireworks/models/minimax-m3:
          cost: { input: '3e-07', output: '1.5e-06', cache_read: '3e-08', cache_write: '3.75e-07' }

now produces "apiProxy": { ..., "defaultAiCreditsPricing": {"input": 0.3, "output": 1.5, "cachedInput": 0.03, "cacheWrite": 0.375} } in awf-config.json, unblocking both the main agent and the detection sub-agent.


Generated by 👨‍🍳 PR Sous Chef · gpt54 · 14.9 AIC · ⌖ 8.66 AIC · ⊞ 5.5K ·
Comment /souschef to run again


Run: https://github.com/github/gh-aw/actions/runs/30035273314

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 18 AIC · ⌖ 10.1 AIC · ⊞ 7K ·
Comment /souschef to run again


Run: https://github.com/github/gh-aw/actions/runs/30042541462

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.1 AIC · ⌖ 9.05 AIC · ⊞ 7K ·
Comment /souschef to run again


Run: https://github.com/github/gh-aw/actions/runs/30050062713

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.9 AIC · ⌖ 9.61 AIC · ⊞ 7K ·
Comment /souschef to run again

@github-actions

Copy link
Copy Markdown
Contributor

Hey @Copilot 👋 — thanks for working on fixing custom pricing not reaching the api-proxy! This plan looks well-structured and ready for implementation.

Your checklist clearly maps out:

  • Schema changes to AWFAPIProxyConfig
  • Extraction logic for per-million-token conversion
  • Integration into BuildAWFConfigJSON and threat detection workflow
  • Unit test coverage
  • Build verification

The approach is focused and tied to #47365. Once you’re ready to implement, the plan is ready to go.

Note: This PR is currently a draft with 0 lines changed. Move to “Ready for review” once code changes are committed.

Generated by ✅ Contribution Check · sonnet46 56.5 AIC · ⌖ 10.2 AIC · ⊞ 6.2K ·

…CreditsPricing

- Add AWFDefaultAiCreditsPricingConfig struct and DefaultAiCreditsPricing field on AWFAPIProxyConfig
- Wire extractDefaultAiCreditsPricingFromModelCosts into BuildAWFConfigJSON so frontmatter
  models.providers pricing is included in apiProxy.defaultAiCreditsPricing in the AWF config
- Convert per-token cost strings from frontmatter to per-million-token floats required by AWF schema
- Copy ModelCosts from parent to buildThreatDetectionWorkflowData so detection sub-agent also
  gets the pricing fallback and does not 400 with unknown_model_ai_credits
- Add unit tests: TestExtractDefaultAiCreditsPricingFromModelCosts, TestBuildAWFConfigJSON_DefaultAiCreditsPricingFromModelCosts, TestValidateAWFConfigJSON_AllowsDefaultAiCreditsPricing, TestBuildThreatDetectionWorkflowData_InheritsModelCosts
- Update smoke-copilot golden file and recompile affected lock files

Fixes #47365

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix custom pricing not reaching the api-proxy fix: propagate models.providers custom pricing to api-proxy defaultAiCreditsPricing Jul 23, 2026
Copilot AI requested a review from pelikhan July 23, 2026 13:34
@pelikhan
pelikhan marked this pull request as ready for review July 23, 2026 13:57
Copilot AI review requested due to automatic review settings July 23, 2026 13:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Propagates custom model pricing into AWF API-proxy configuration for main and threat-detection runs.

Changes:

  • Converts per-token model costs into AWF fallback pricing.
  • Propagates model costs to detection workflows.
  • Adds tests and regenerates workflow snapshots.
Show a summary per file
File Description
pkg/workflow/awf_config.go Adds pricing extraction and API-proxy configuration.
pkg/workflow/awf_config_test.go Tests pricing conversion and schema validation.
pkg/workflow/threat_detection_external.go Propagates costs to detection runs.
pkg/workflow/threat_detection_test.go Tests detection cost inheritance.
pkg/workflow/testdata/TestWasmGolden_CompileFixtures/smoke-copilot.golden Updates WASM golden output.
.github/workflows/smoke-copilot.lock.yml Regenerates smoke workflow output.
.github/workflows/daily-model-inventory.lock.yml Regenerates inventory workflow output.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

pkg/workflow/awf_config.go:984

  • Valid integer-valued costs are rejected here. The frontmatter schema allows numbers, and goccy/go-yaml decodes unquoted YAML integers as uint64, so a valid input: 0 or output: 0 makes the entire pricing entry disappear. Handle the integer types produced by YAML in addition to float64.
	switch v := raw.(type) {
	case float64:
		perToken = v
	case string:
		parsed, err := strconv.ParseFloat(strings.TrimSpace(v), 64)
		if err != nil {
			return 0, false
		}
		perToken = parsed
	default:
		return 0, false

pkg/workflow/awf_config.go:986

  • ParseFloat accepts NaN, +Inf, and negative strings, but these are not valid AWF prices: non-finite values make json.Marshal fail, while negatives produce config rejected by the schema (minimum: 0). Since the frontmatter schema permits arbitrary numeric strings, reject non-finite or negative values here before multiplying.
		parsed, err := strconv.ParseFloat(strings.TrimSpace(v), 64)
		if err != nil {
			return 0, false
		}
		perToken = parsed
	default:
		return 0, false
	}
	return perToken * 1e6, true
  • Files reviewed: 7/7 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment thread pkg/workflow/awf_config.go Outdated

// First pass: find an exact match on workflowData.Model.
if targetModel != "" {
for _, pData := range providersMap {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit fix: scope exact-match pricing pass to resolved engine provider.

The first pass now extracts resolvedProvider from EngineConfig.LLMProvider (falling back to InlineProviderID) and checks that provider entry exclusively before falling through to the sorted all-providers search. A helper searchProviderForModel eliminates the duplicated inner loop. Three new sub-tests cover the new behaviour: resolved-provider-wins, InlineProviderID-used-when-LLMProvider-empty, and falls-back-when-resolved-provider-lacks-the-model.

Comment thread pkg/workflow/awf_config.go Outdated
Comment on lines +902 to +903
// Second pass: return the first parseable entry across all providers.
for _, pData := range providersMap {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6d28311. Both the first-pass and second-pass loops now sort provider and model keys with sort.Strings before iterating, making the fallback selection deterministic. The sorted fallback returns the alphabetically-first provider's alphabetically-first model with parseable pricing.

Comment thread pkg/workflow/awf_config.go Outdated
Comment on lines +286 to +288
// CachedInput is the price per 1M cached-read tokens, in USD.
// When omitted the proxy uses input × 0.1 as a default.
CachedInput float64 `json:"cachedInput,omitempty"`

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6d28311. CachedInput changed from float64 to *float64 to match CacheWrite. An explicit cache_read: "0" now sets pricing.CachedInput = &cachedInputPerM (a pointer to 0.0), which serializes as "cachedInput": 0 in JSON instead of being dropped by omitempty.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /diagnosing-bugs, /tdd, and /codebase-design — requesting changes on two correctness issues and one test coverage gap.

📋 Key Themes & Highlights

Issues Found

  1. Non-deterministic fallback selection (awf_config.go lines 878–920): Both the first-pass (model match) and second-pass (first-entry fallback) iterate over map[string]any directly. Go map iteration is random; with multiple providers or models the selected pricing is unpredictable and untestable.
  2. CachedInput float64 vs *float64 (awf_config.go line 288): An explicitly-configured cache_read: "0" would be serialised as absent due to omitempty on a non-pointer float. CacheWrite correctly uses *float64; CachedInput should match.
  3. Detection sub-agent test gap (threat_detection_test.go): The new test only verifies shallow map inheritance, not that defaultAiCreditsPricing actually appears in the detection run's rendered AWF config JSON — the exact failure mode fixed by this PR.

Positive Highlights

  • ✅ Clean, well-commented implementation with clear selection-order documentation
  • ✅ Comprehensive unit tests for extractDefaultAiCreditsPricingFromModelCosts and parseCostFieldToPerMillion covering nil, empty, string, float64, and missing-field cases
  • ✅ Schema validation tests for defaultAiCreditsPricing (allow/reject paths)
  • ✅ Both the main agent and detection sub-agent are fixed in a single, coherent change

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 45.6 AIC · ⌖ 5.04 AIC · ⊞ 6.7K
Comment /matt to run again

Comment thread pkg/workflow/awf_config.go Outdated
if !ok {
continue
}
for _, mData := range modelsMap {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/diagnosing-bugs] Non-deterministic second-pass fallback: Go map iteration order is random, so when multiple providers or models are present, the pricing entry selected is unpredictable across runs. This could silently apply the wrong model's pricing.

💡 Suggested fix

Sort provider and model keys before iterating to guarantee a deterministic result (e.g. alphabetically first provider/model):

providerKeys := make([]string, 0, len(providersMap))
for k := range providersMap { providerKeys = append(providerKeys, k) }
sort.Strings(providerKeys)
for _, pName := range providerKeys {
    pData := providersMap[pName]
    // ... extract modelsMap ...
    modelKeys := make([]string, 0, len(modelsMap))
    for k := range modelsMap { modelKeys = append(modelKeys, k) }
    sort.Strings(modelKeys)
    for _, mName := range modelKeys {
        if pricing := modelCostEntryToDefaultPricing(modelsMap[mName]); pricing != nil {
            return pricing
        }
    }
}

The same non-determinism exists in the first pass (lines 878-899).

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6d28311. Both passes now sort provider and model keys with sort.Strings before iterating — the suggested approach exactly. Three additional sub-tests verify the provider-scoping and fallback ordering behaviour.

Comment thread pkg/workflow/awf_config.go Outdated
Output float64 `json:"output"`
// CachedInput is the price per 1M cached-read tokens, in USD.
// When omitted the proxy uses input × 0.1 as a default.
CachedInput float64 `json:"cachedInput,omitempty"`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/codebase-design] CachedInput float64 with omitempty will silently drop an explicitly-configured zero cache-read price. Unlike CacheWrite *float64, a value of 0.0 is indistinguishable from absent for a non-pointer float64.

💡 Suggested fix

Use *float64 (pointer) for CachedInput to match the treatment of CacheWrite, making the zero-vs-omitted distinction explicit:

CachedInput *float64 `json:"cachedInput,omitempty"`

Then set it in modelCostEntryToDefaultPricing with &cachedInputPerM.

If the proxy truly treats zero and absent identically for cachedInput, add a comment explaining that invariant so future readers understand the asymmetry with CacheWrite.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 6d28311. CachedInput changed to *float64pricing.CachedInput = &cachedInputPerM is now used in modelCostEntryToDefaultPricing, matching the treatment of CacheWrite.

if providers == nil {
t.Fatal("expected detection ModelCosts to contain providers")
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] The new test verifies that ModelCosts is shallow-copied to the detection WorkflowData, but doesn't verify that defaultAiCreditsPricing is actually emitted in the rendered AWF config JSON for the detection run. The regression path that this fixes (unknown_model_ai_credits on the detection sub-agent) remains untested at the integration level.

💡 Suggested addition

Mirror the pattern from TestBuildAWFConfigJSON_DefaultAiCreditsPricingFromModelCosts but invoke through BuildAWFConfigJSON with a detection-flavoured WorkflowData (i.e. IsDetectionRun: true):

func TestBuildDetectionAWFConfig_PropagatesDefaultAiCreditsPricing(t *testing.T) {
    parent := &WorkflowData{
        AI:         "claude",
        ModelCosts: customPricing, // same map as above
    }
    detected := buildThreatDetectionWorkflowData(parent, "claude")
    cfg, err := BuildAWFConfigJSON(AWFCommandConfig{WorkflowData: detected, ...})
    require.NoError(t, err)
    assert.Contains(t, cfg, "defaultAiCreditsPricing")
}

This regression test would have caught the original bug directly.

@copilot please address this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in commit 6d28311. TestBuildDetectionAWFConfig_PropagatesDefaultAiCreditsPricing now calls BuildAWFConfigJSON with a detection WorkflowData built from a parent with custom ModelCosts and asserts that "defaultAiCreditsPricing" appears in the rendered JSON — directly testing the regression path.

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (498 new lines in pkg/workflow/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/47571-propagate-models-providers-pricing-to-api-proxy.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch at docs/adr/47571-propagate-models-providers-pricing-to-api-proxy.md — it was generated from the PR diff
  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-47571: Propagate models.providers Custom Pricing to API Proxy defaultAiCreditsPricing

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 47571-propagate-models-providers-pricing-to-api-proxy.md for PR #47571).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · sonnet46 74.4 AIC · ⌖ 12.9 AIC · ⊞ 8.5K ·
Comment /review to run again

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 94/100 — Excellent

Analyzed 5 test(s): 5 design, 0 implementation, 0 violation(s).

📊 Metrics (5 tests)
Metric Value
Analyzed 5 (Go: 5, JS: 0)
✅ Design 5 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 4 (80%)
Duplicate clusters 0
Inflation No (1.7:1 max)
🚨 Violations 0
Test File Classification Issues
TestValidateAWFConfigJSON_AllowsDefaultAiCreditsPricing awf_config_test.go:1218 design_test None
TestValidateAWFConfigJSON_RejectsDefaultAiCreditsPricingMissingOutput awf_config_test.go:1223 design_test None
TestExtractDefaultAiCreditsPricingFromModelCosts awf_config_test.go:1828 design_test None (8 subtests, comprehensive)
TestBuildAWFConfigJSON_DefaultAiCreditsPricingFromModelCosts awf_config_test.go:1998 design_test None (3 subtests)
TestBuildThreatDetectionWorkflowData_InheritsModelCosts threat_detection_test.go:2705 design_test None

Verdict

Passed. 0% implementation tests (threshold: 30%). All tests verify design contracts. Comprehensive edge-case coverage with proper table-driven patterns and error scenarios. No coding guideline violations detected (no mock libraries, all tests properly tagged).

🧪 Test quality analysis by Test Quality Sentinel · haiku45 22.3 AIC · ⌖ 7.71 AIC · ⊞ 7.1K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 94/100. 0% implementation tests (threshold: 30%).

@pelikhan

Copy link
Copy Markdown
Collaborator

/matt

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

REQUEST_CHANGES — Three correctness bugs must be fixed before merge; two affect the core pricing logic directly.

### Blocking issues (3)
  1. Non-deterministic second-pass fallback (awf_config.go ~line 184) — the "first parseable entry across all providers" is Go-map-random per run. Multi-model ModelCosts payloads can produce different pricing on identical inputs, silently under/over-counting credits.

  2. Exact-match failure falls through to wrong-model pricing (awf_config.go ~line 162) — when workflowData.Model matches a key but that entry's pricing is malformed (e.g. missing output), the code falls to the second pass and silently prices the run against a different model.

  3. Model not forwarded to detection WorkflowData (threat_detection_external.go line 566) — without Model, the detection run's extractDefaultAiCreditsPricingFromModelCosts always skips the exact-match pass and uses the non-deterministic fallback, potentially with different pricing than the main agent.

### Non-blocking but should be fixed (2)
  1. omitempty on CachedInput float64 (awf_config.go line 77) — explicit cache_read: 0 is silently dropped; use *float64 consistent with CacheWrite.

  2. No test for provider-prefix vs bare key mismatch (awf_config_test.go) — model: "openai/gpt-4o" with key "gpt-4o" silently falls to the wrong-model fallback; the behaviour is undefined and untested.

🔎 Code quality review by PR Code Quality Reviewer · sonnet46 88.4 AIC · ⌖ 5.34 AIC · ⊞ 5.7K
Comment /review to run again

Comments that could not be inline-anchored

pkg/workflow/awf_config.go:184

Non-deterministic second-pass fallback returns arbitrary pricing from a random model — Go map iteration is randomised per run, so the "first parseable entry across all providers" is not stable and can silently return different pricing on identical inputs.

<details>
<summary>💡 Details and fix</summary>

The second loop (lines ~167-185) iterates over providersMap and modelsMap, both map[string]any. Go randomises map iteration, meaning two identical invocations can return pricing from …

pkg/workflow/awf_config.go:162

Exact-match failure silently falls through to wrong-model pricing — when workflowData.Model is set and the key exists in the map but the entry has incomplete pricing (e.g. missing output), the function does not stop — it falls to the second pass and returns pricing from a completely different model.

<details>
<summary>💡 Details and fix</summary>

The first-pass loop (lines ~141-163):

for mName, mData := range modelsMap {
    if !strings.EqualFold(mName, targetModel) {
        co</details>

<details><summary>pkg/workflow/threat_detection_external.go:566</summary>

**`Model` not forwarded to detection `WorkflowData`exact-match pricing hint is lost**only `ModelCosts` is copied; without `Model`, the detection run always skips the exact-match first pass and falls to the non-deterministic second pass, potentially pricing it on a different model than the one actually running.

&lt;details&gt;
&lt;summary&gt;💡 Details and fix&lt;/summary&gt;

In `extractDefaultAiCreditsPricingFromModelCosts`, the first pass (exact model match) is gated on `workflowData.Model != &quot;&quot;`. When</details>

<details><summary>pkg/workflow/awf_config.go:77</summary>

**`omitempty` on `CachedInput float64` silently drops an explicit zero**if a model defines `cache_read: &quot;0&quot;`, the parsed value is `0.0`, which `omitempty` treats as absent, so the JSON omits the field entirely and the proxy applies its own default (`input × 0.1`) instead of the author&#39;s explicit zero cost.

&lt;details&gt;
&lt;summary&gt;💡 Details and fix&lt;/summary&gt;

The struct fields for the two optional pricing values are inconsistent:
```go
CachedInput float64  `json:&quot;cachedInput,omitempty&quot;` // drops…

</details>

<details><summary>pkg/workflow/awf_config_test.go:373</summary>

**No test for model name with provider prefix vs bare key mismatch** — the exact-match test uses the same string in both `WorkflowData.Model` and the map key, but the real failure case is `model: &quot;openai/gpt-4o&quot;` when the map key is `&quot;gpt-4o&quot;`, which would silently fall to the non-deterministic second pass.

&lt;details&gt;
&lt;summary&gt;💡 Suggested test case&lt;/summary&gt;

```go
t.Run(&quot;provider-prefix model name does not match bare key&quot;, func(t *testing.T) {
    wd := &amp;WorkflowData{
        Model: &quot;openai/g…

</details>

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /diagnosing-bugs and /tdd — requesting changes on two small correctness gaps and one test gap.

📋 Key Themes & Highlights

Key Themes

  • Non-deterministic fallback (correctness): second-pass map iteration is unordered in Go; pricing selection is non-deterministic when model: is unset and multiple custom models are defined.
  • Incomplete required-field test parity (test coverage): missing input → nil is tested but missing output → nil is not.
  • Silent parse failure (debuggability): malformed cost strings are swallowed with no signal; a test and/or log would surface this.
  • ADR is still Draft: update status to Accepted before merge.

Positive Highlights

  • ✅ Root cause properly addressed — per-token pricing is now forwarded to both the main agent config and the threat-detection sub-agent.
  • ✅ Clean three-function decomposition (extractentryToPricingparseCostField) — each function is independently testable.
  • ✅ Comprehensive test suite: nil inputs, string/float64 values, exact-match preference, case-insensitivity, all covered.
  • ✅ ADR documents the trade-offs including the known single-entry limitation and non-determinism — good transparency.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · sonnet46 67.7 AIC · ⌖ 7.77 AIC · ⊞ 6.7K
Comment /matt to run again

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot lint go

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address unresolved review feedback, and rerun checks once the branch is up to date.

Unresolved requested changes:

  • @github-actions review feedback remains to be addressed.

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.1 AIC · ⌖ 9.05 AIC · ⊞ 7K ·
Comment /souschef to run again

Copilot AI commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address unresolved review feedback, and rerun checks once the branch is up to date.

Unresolved requested changes:...

The two CHANGES_REQUESTED reviews from github-actions[bot] (#4764912832 and #4764929090) were submitted on commit 87243f1, which is now 8 commits behind HEAD. All blocking issues they raised have been fixed:

  1. Non-deterministic fallback → sorted provider/model keys (6d28311)
  2. Exact-match falls through to wrong-model pricing → searchProviderForModel returns early on malformed match (a273296)
  3. Model not forwarded to detection WorkflowData → fixed (6d28311)
  4. CachedInput float64 → changed to *float64 (6d28311)
  5. Detection integration test gap → TestBuildDetectionAWFConfig_PropagatesDefaultAiCreditsPricing added (6d28311)
  6. Exact-match ignores provider → scoped to resolved engine provider (31071fb)

These review states cannot be cleared by the agent — clearing them requires CI to re-run on the current HEAD so new reviews are generated, or a maintainer to dismiss the stale reviews manually.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, review the latest reply claiming the blocking review items are fixed, verify whether the remaining github-actions requested reviews are stale, and rerun checks once the branch is up to date.

Run: https://github.com/github/gh-aw/actions/runs/30046537550

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 11.7 AIC · ⌖ 9.18 AIC · ⊞ 7K ·
Comment /souschef to run again

Copilot AI commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, review the latest reply claiming the blocking review items are fixed, verify whether the remaining github-actions requested reviews are stale, and rerun ch...

The two CHANGES_REQUESTED reviews (Matt Pocock Skills Reviewer #4764912832 and PR Code Quality Reviewer #4764929090) are stale — both were submitted on commit 87243f1, which is now 8 commits behind the current HEAD (4ab251e). Every blocking issue they raised has been resolved:

Issue Fix Commit
Non-deterministic second-pass fallback sort.Strings on provider + model keys before iteration 6d28311
Exact-match failure falls through to wrong-model pricing searchProviderForModel returns nil, true on malformed match, stopping fallback a273296
Model not forwarded to detection WorkflowData Added Model: data.Model in buildThreatDetectionWorkflowData 6d28311
CachedInput float64 with omitempty drops explicit zero Changed to *float64 matching CacheWrite 6d28311
Exact-match ignores provider First pass scoped to resolved engine provider (LLMProvider / InlineProviderID) 31071fb
Detection integration test gap TestBuildDetectionAWFConfig_PropagatesDefaultAiCreditsPricing asserts defaultAiCreditsPricing in rendered JSON 6d28311

Local validation status:

  • make fmt — clean
  • make lint — 0 issues
  • go test ./pkg/workflow/ (all pricing/detection tests) — all pass
  • ✅ Branch is up to date with main (base = c834b37, current top of main)

The CHANGES_REQUESTED state cannot be cleared by the agent — a maintainer must dismiss the stale reviews or re-run CI on the current HEAD (close/reopen or workflow_dispatch) so fresh reviews are generated. The last completed CI run (30043209671) passed with success on 4ab251e.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, verify the remaining github-actions requested reviews are stale and ready for maintainer dismissal, and rerun checks once the branch is up to date.

Unresolved review feedback (newest first):

Run: https://github.com/github/gh-aw/actions/runs/30050062713

Generated by 👨‍🍳 PR Sous Chef · gpt54 · 12.9 AIC · ⌖ 9.61 AIC · ⊞ 7K ·
Comment /souschef to run again

Copilot AI commented Jul 23, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, verify the remaining github-actions requested reviews are stale and ready for maintainer dismissal, and rerun checks once the branch is up to date.

Unre...

Confirmed — both reviews are stale and ready for maintainer dismissal.

Review staleness:

  • Review #4764912832 (Matt Pocock Skills Reviewer) — CHANGES_REQUESTED on commit 87243f1
  • Review #4764929090 (PR Code Quality Reviewer) — CHANGES_REQUESTED on commit 87243f1

Both were submitted against commit 87243f1, which is 8 commits behind the current HEAD (4ab251e). Every blocking issue they raised has been fixed:

Issue Fix Commit
Non-deterministic fallback sort.Strings on provider + model keys 6d28311
Exact-match falls through to wrong-model pricing searchProviderForModel returns nil, true on malformed match a273296
Model not forwarded to detection WorkflowData Model: data.Model in buildThreatDetectionWorkflowData 6d28311
CachedInput float64 drops explicit zero Changed to *float64 6d28311
Exact-match ignores provider First pass scoped to resolved engine provider 31071fb
Detection integration test gap TestBuildDetectionAWFConfig_PropagatesDefaultAiCreditsPricing 6d28311

CI run 30050062713 failure: The failure is in the PR Sous Chef's own safe_outputs → Process Safe Outputs step — this is workflow infrastructure, not a code issue in the PR. All code tests pass locally.

Local validation (current HEAD 4ab251e):

  • make fmt / make lint — clean
  • ✅ All pricing and detection tests — pass
  • ✅ Branch is up to date with main (base = c834b37)

Action required from a maintainer: Dismiss reviews #4764912832 and #4764929090 (both outdated against 87243f1), then re-trigger CI to generate fresh reviews.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage — §30057272009

Field Value
Category bug
Risk 🔴 High
Priority Score 78 / 100
Action 🚀 fast_track
CI ✅ Passing
Review ⚠️ Bot CHANGES_REQUESTED (dismissed)

Score breakdown: Impact 45 + Urgency 22 + Quality 11

Rationale: Silent bug — custom model pricing from models.providers was dropped at the api-proxy boundary, causing BYOK/custom models to fail with unknown_model_ai_credits before the first turn. 30 files changed. High correctness impact.

Next action: Prioritize for immediate human review. Highest-priority PR in this run.

Generated by 🔧 PR Triage Agent · sonnet46 · 35.7 AIC · ⌖ 5.3 AIC · ⊞ 5.7K ·

Copilot AI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address these unresolved review threads, and update the PR once each is resolved:

All six threads have been addressed:

Thread Status
r3638705646 — exact-match ignores provider Replied 31071fb (previous session)
r3638705690 — no-match fallback nondeterministic Replied — fixed 6d28311 (sort.Strings on both passes)
r3638705720omitempty drops explicit zero cached-read Replied — fixed 6d28311 (CachedInput *float64)
r3638764098 — non-deterministic second-pass Replied — fixed 6d28311 (sort.Strings on both passes)
r3638764104CachedInput float64 should be *float64 Replied — fixed 6d28311 (CachedInput = &cachedInputPerM)
r3638764109 — detection integration test gap Replied 6d28311 (previous session)

All threads are outdated (is_outdated: true) — the code they referenced has been updated. The remaining blocker is maintainer dismissal of the two stale CHANGES_REQUESTED reviews (#4764912832 and #4764929090, both on 87243f1). Local validation on current HEAD 4ab251e is clean: make fmt, make lint, all pricing/detection tests pass.

tobio added a commit to elastic/terraform-provider-elasticstack that referenced this pull request Jul 24, 2026
…rch/reproducer factories

The AWF api-proxy rejected llm-gateway/claude-sonnet-5 with HTTP 400
unknown_model_ai_credits since it has no pricing entry for that alias.
gh-aw's models.providers frontmatter override does not currently propagate
to apiProxy.defaultAiCreditsPricing (github/gh-aw#47365, fix pending in
github/gh-aw#47571 as of v0.83.1), so fall back to the same max-ai-credits: -1
workaround already used for llm-gateway/DeepSeek-V4-Flash in
ci-deadcode-removal-rotation.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot resolve the merge conflicts on this branch.

Copilot AI and others added 2 commits July 24, 2026 03:48
…icing-models-providers

# Conflicts:
#	.github/workflows/daily-model-inventory.lock.yml
#	.github/workflows/smoke-copilot.lock.yml

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 24, 2026

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts on this branch.

Resolved in 8b091de. Two lock files had conflicts where our branch had defaultAiCreditsPricing and main had container image SHAs. The conflicts were resolved by keeping both, then make recompile was run to produce the canonical merged output. Validation (make agent-report-progress-no-test) passes.

@pelikhan pelikhan closed this Jul 24, 2026
tobio added a commit to elastic/terraform-provider-elasticstack that referenced this pull request Jul 24, 2026
…nnet-5 (#4298)

* chore(workflows): bump remaining factory/rotation agents to claude-sonnet-5

Update change-factory-issue, code-factory-issue, duplicate-code-detector,
flaky-test-catcher, issue-classifier, schema-coverage-rotation, and
semantic-function-refactor from llm-gateway/claude-sonnet-4-6 to
llm-gateway/claude-sonnet-5.

Also sets max-ai-credits: -1 on each, since the AWF api-proxy has no pricing
entry for the new alias and gh-aw's models.providers frontmatter override
does not currently propagate to apiProxy.defaultAiCreditsPricing
(github/gh-aw#47365, fix pending in github/gh-aw#47571 as of v0.83.1) —
confirmed necessary by testing the same failure mode on the
research/reproducer factories in #4296.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test(workflows): align model assertions with claude-sonnet-5

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
tobio added a commit to elastic/terraform-provider-elasticstack that referenced this pull request Jul 24, 2026
…nnet-5 (#4298)

* chore(workflows): bump remaining factory/rotation agents to claude-sonnet-5

Update change-factory-issue, code-factory-issue, duplicate-code-detector,
flaky-test-catcher, issue-classifier, schema-coverage-rotation, and
semantic-function-refactor from llm-gateway/claude-sonnet-4-6 to
llm-gateway/claude-sonnet-5.

Also sets max-ai-credits: -1 on each, since the AWF api-proxy has no pricing
entry for the new alias and gh-aw's models.providers frontmatter override
does not currently propagate to apiProxy.defaultAiCreditsPricing
(github/gh-aw#47365, fix pending in github/gh-aw#47571 as of v0.83.1) —
confirmed necessary by testing the same failure mode on the
research/reproducer factories in #4296.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test(workflows): align model assertions with claude-sonnet-5

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

models.providers custom pricing never reaches the api-proxy; custom/BYOK models still 400 with unknown_model_ai_credits

4 participants