freddie 0.0.132 → 0.0.133

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "freddie",
3
- "version": "0.0.132",
3
+ "version": "0.0.133",
4
4
  "type": "module",
5
5
  "description": "Open JS agent harness built on pi-mono, floosie, xstate, and anentrypoint-design",
6
6
  "bin": {
@@ -74,16 +74,9 @@ function adapt(result) {
74
74
  // Mirror lib/named-chains.js BUILTIN — acptoapi resolves unknown names.
75
75
  const NAMED_CHAIN_NAMES = new Set(['fast', 'cheap', 'smart', 'reasoning', 'free', 'local', 'auto'])
76
76
 
77
- // A hand-typed agent.model_preference used to be joined in its literal config
78
- // order, permanently overriding acptoapi's own swe_bench-score-aware ranking
79
- // (buildAutoChain sorts by score + tool-capability tiering) with no
80
- // reconciliation at all — witnessed picking a 62-score model ahead of a
81
- // 79.6-score one purely because it was configured first. Re-rank the user's
82
- // chosen providers using acptoapi's OWN scored pool (buildAutoChain is a
83
- // sanctioned top-level export; this never reaches into unexported internals
84
- // like lib/swe-bench-scores) so provider CHOICE stays user-controlled while
85
- // ORDER reflects real capability. Unscored links keep their relative config
86
- // order at the tail, matching acptoapi's own null-score handling.
77
+ // User's explicit model_preference is preserved in config order they chose
78
+ // those providers in that order and the SWE-bench re-rank would defeat the
79
+ // purpose. orderByScore is only used for the auto-chain path (no preference).
87
80
  function orderByScore(links) {
88
81
  let pool
89
82
  try { pool = typeof sdk.buildAutoChain === 'function' ? sdk.buildAutoChain(undefined, { hasTools: true }) : [] } catch { pool = [] }
@@ -110,11 +103,32 @@ async function buildModel({ provider, model, inputModel }) {
110
103
  }
111
104
  const pref = getConfigValue('agent.model_preference', [])
112
105
  if (Array.isArray(pref) && pref.length) {
106
+ // Preserve user's explicit config order — they chose these providers in
107
+ // this sequence. Only filter out providers where the sampler reports them
108
+ // as actively in backoff (ok===false) to avoid inserting definitely-dead
109
+ // links. SWE-bench re-rank via orderByScore is NOT applied here since it
110
+ // would override the user's deliberate ordering.
113
111
  const links = pref.map(p => `${p.provider}/${p.model || DEFAULTS[p.provider] || ''}`.replace(/\/$/, '')).filter(s => s.includes('/'))
114
- if (links.length) return orderByScore(links).join(', ')
112
+ if (!links.length) return ''
113
+ // Filter by sampler state if available
114
+ const status = typeof sdk.getStatus === 'function' ? sdk.getStatus() : []
115
+ if (status.length) {
116
+ const blocked = new Set(status.filter(s => s.ok === false).map(s => s.provider))
117
+ const filtered = links.filter(l => !blocked.has(l.split('/')[0]))
118
+ if (filtered.length) return filtered.join(', ')
119
+ }
120
+ return links.join(', ')
115
121
  }
116
122
  const auto = typeof sdk.buildAutoChain === 'function' ? sdk.buildAutoChain(undefined) : []
117
123
  const keyed = Array.isArray(auto) ? auto.filter(l => { const p = l.model.split('/')[0]; const env = PROVIDER_KEYS[p]; return env && process.env[env] }) : []
124
+ // Filter out providers in sampler backoff so the chain doesn't waste slots
125
+ // on links that will be immediately skipped with sampler_backoff reason.
126
+ const status = typeof sdk.getStatus === 'function' ? sdk.getStatus() : []
127
+ if (status.length && keyed.length) {
128
+ const blocked = new Set(status.filter(s => s.ok === false).map(s => s.provider))
129
+ const filtered = keyed.filter(l => !blocked.has(l.model.split('/')[0]))
130
+ if (filtered.length) return filtered.map(l => l.model).join(', ')
131
+ }
118
132
  if (keyed.length) return keyed.map(l => l.model).join(', ')
119
133
  // No local provider keys — delegate to acptoapi if reachable.
120
134
  if (await cachedReachable()) return process.env.FREDDIE_LLM_MODEL || 'auto'