freddie 0.0.129 → 0.0.131

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.129",
3
+ "version": "0.0.131",
4
4
  "type": "module",
5
5
  "description": "Open JS agent harness built on pi-mono, floosie, xstate, and anentrypoint-design",
6
6
  "bin": {
@@ -25,7 +25,7 @@
25
25
  "@libsql/client": "^0.5.0",
26
26
  "@mariozechner/pi-ai": "^0.70.6",
27
27
  "@mariozechner/pi-tui": "^0.70.6",
28
- "acptoapi": "^1.0.144",
28
+ "acptoapi": "^1.0.146",
29
29
  "anentrypoint-design": "latest",
30
30
  "commander": "^14.0.0",
31
31
  "dotenv": "^16.6.1",
@@ -26,7 +26,21 @@ export const _tool = ({
26
26
  const t = setTimeout(() => { try { child.kill('SIGKILL') } catch {} resolve({ exitCode: -1, stdout, stderr: stderr + '\n[timeout]', timedOut: true }) }, timeout_ms)
27
27
  child.stdout?.on('data', d => stdout += d.toString())
28
28
  child.stderr?.on('data', d => stderr += d.toString())
29
- child.on('close', code => { clearTimeout(t); resolve({ exitCode: code, stdout, stderr }) })
29
+ child.on('close', code => {
30
+ clearTimeout(t)
31
+ const result = { exitCode: code, stdout, stderr }
32
+ // Windows cmd.exe can silently swallow ALL output (exit 0, empty
33
+ // stdout+stderr) for certain nested-quote one-liners (witnessed:
34
+ // node -e with double-quoted body containing single-quoted JS
35
+ // strings plus an embedded literal \n) -- indistinguishable from
36
+ // "ran fine and printed nothing" without this signal, and models
37
+ // have been observed misdiagnosing it as "bash tool unavailable"
38
+ // and silently substituting an unverified reimplementation.
39
+ if (process.platform === 'win32' && code === 0 && !stdout && !stderr && command.length > 40) {
40
+ result.note = 'exitCode 0 with no output at all on a non-trivial command is unusual on Windows -- cmd.exe can silently swallow output for commands with nested quotes (e.g. node -e one-liners mixing double/single quotes and \\n). If you expected output, try writing the script to a file and running it instead of an inline -e/-c one-liner.'
41
+ }
42
+ resolve(result)
43
+ })
30
44
  child.on('error', e => { clearTimeout(t); resolve({ exitCode: -1, stdout, stderr: stderr + '\n' + e.message }) })
31
45
  })
32
46
  },
@@ -74,6 +74,29 @@ 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.
87
+ function orderByScore(links) {
88
+ let pool
89
+ try { pool = typeof sdk.buildAutoChain === 'function' ? sdk.buildAutoChain(undefined, { hasTools: true }) : [] } catch { pool = [] }
90
+ if (!Array.isArray(pool) || !pool.length) return links
91
+ const rank = new Map(pool.map((l, i) => [l.model, i]))
92
+ return [...links].sort((a, b) => {
93
+ const ra = rank.has(a) ? rank.get(a) : Infinity
94
+ const rb = rank.has(b) ? rank.get(b) : Infinity
95
+ if (ra !== rb) return ra - rb
96
+ return links.indexOf(a) - links.indexOf(b)
97
+ })
98
+ }
99
+
77
100
  async function buildModel({ provider, model, inputModel }) {
78
101
  if (provider) return `${provider}/${model || DEFAULTS[provider] || ''}`.replace(/\/$/, '')
79
102
  if (model) return model
@@ -88,7 +111,7 @@ async function buildModel({ provider, model, inputModel }) {
88
111
  const pref = getConfigValue('agent.model_preference', [])
89
112
  if (Array.isArray(pref) && pref.length) {
90
113
  const links = pref.map(p => `${p.provider}/${p.model || DEFAULTS[p.provider] || ''}`.replace(/\/$/, '')).filter(s => s.includes('/'))
91
- if (links.length) return links.join(', ')
114
+ if (links.length) return orderByScore(links).join(', ')
92
115
  }
93
116
  const auto = typeof sdk.buildAutoChain === 'function' ? sdk.buildAutoChain(undefined) : []
94
117
  const keyed = Array.isArray(auto) ? auto.filter(l => { const p = l.model.split('/')[0]; const env = PROVIDER_KEYS[p]; return env && process.env[env] }) : []