freddie 0.0.112 → 0.0.114
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.
|
|
3
|
+
"version": "0.0.114",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Open JS agent harness built on pi-mono, floosie, xstate, and anentrypoint-design",
|
|
6
6
|
"bin": {
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"@mariozechner/pi-ai": "^0.70.6",
|
|
27
27
|
"@mariozechner/pi-coding-agent": "^0.70.6",
|
|
28
28
|
"@mariozechner/pi-tui": "^0.70.6",
|
|
29
|
-
"acptoapi": "^1.0.
|
|
30
|
-
"anentrypoint-design": "^0.0.
|
|
29
|
+
"acptoapi": "^1.0.112",
|
|
30
|
+
"anentrypoint-design": "^0.0.135",
|
|
31
31
|
"commander": "^14.0.0",
|
|
32
32
|
"express": "^5.0.0",
|
|
33
33
|
"flatspace": "^1.0.18",
|
|
@@ -32,14 +32,12 @@ export async function callLLM({ messages, tools = [], model } = {}) {
|
|
|
32
32
|
const headers = { 'content-type': 'application/json', authorization: 'Bearer none' }
|
|
33
33
|
const cwd = process.cwd()
|
|
34
34
|
if (Array.isArray(tools) && tools.length) headers['x-cwd'] = cwd
|
|
35
|
-
//
|
|
36
|
-
// (gh-pages →
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const _pageLb = (() => { try { const h = ((typeof location !== 'undefined' && location.hostname) || '').toLowerCase(); return h === 'localhost' || h === '127.0.0.1' || h === '' || h === '::1' } catch { return true } })()
|
|
40
|
-
if (_isLb && !_pageLb) throw new Error(`acptoapi unreachable: page on ${typeof location !== 'undefined' ? location.hostname : '?'} cannot reach loopback ${base}`)
|
|
35
|
+
// Rely on AbortController timeout. acptoapi v1+ ships CORS + Private
|
|
36
|
+
// Network Access headers so cross-origin loopback (gh-pages → localhost)
|
|
37
|
+
// succeeds when acptoapi is running. The earlier preemptive loopback
|
|
38
|
+
// refusal caused false negatives on reachable endpoints.
|
|
41
39
|
const _ac = new AbortController()
|
|
42
|
-
const _tid = setTimeout(() => _ac.abort(new Error('acptoapi fetch timeout')),
|
|
40
|
+
const _tid = setTimeout(() => _ac.abort(new Error('acptoapi fetch timeout')), 60000)
|
|
43
41
|
let res
|
|
44
42
|
try {
|
|
45
43
|
res = await fetch(base.replace(/\/$/, '') + '/chat/completions', {
|
|
@@ -23,9 +23,26 @@ const toMsgs = ms => ms.map(m => {
|
|
|
23
23
|
|
|
24
24
|
const tryJson = s => { try { return typeof s === 'string' ? JSON.parse(s) : (s || {}) } catch { return {} } }
|
|
25
25
|
|
|
26
|
+
function flattenContent(c) {
|
|
27
|
+
// Anthropic-shape arrays (returned by ACP daemons routed through acptoapi)
|
|
28
|
+
// come as [{ type: 'text', text: '...' }, { type: 'tool_use', ... }]. Pull
|
|
29
|
+
// out concatenated text so the agent loop has something to display, and
|
|
30
|
+
// surface tool_use blocks separately so callers can map them.
|
|
31
|
+
if (typeof c === 'string') return { text: c, toolUses: [] }
|
|
32
|
+
if (Array.isArray(c)) {
|
|
33
|
+
const text = c.filter(p => p && (p.type === 'text' || typeof p.text === 'string')).map(p => p.text || '').join('')
|
|
34
|
+
const toolUses = c.filter(p => p && p.type === 'tool_use')
|
|
35
|
+
return { text, toolUses }
|
|
36
|
+
}
|
|
37
|
+
return { text: '', toolUses: [] }
|
|
38
|
+
}
|
|
39
|
+
|
|
26
40
|
function adapt(result) {
|
|
27
41
|
const c = result?.choices?.[0]?.message || {}
|
|
28
|
-
|
|
42
|
+
const flat = flattenContent(c.content)
|
|
43
|
+
const openaiTC = Array.isArray(c.tool_calls) ? c.tool_calls.map(tc => ({ id: tc.id, name: tc.function?.name, arguments: tryJson(tc.function?.arguments) })) : []
|
|
44
|
+
const anthropicTC = flat.toolUses.map(t => ({ id: t.id, name: t.name, arguments: t.input || {} }))
|
|
45
|
+
return { content: flat.text, tool_calls: openaiTC.concat(anthropicTC), raw: result }
|
|
29
46
|
}
|
|
30
47
|
|
|
31
48
|
// Names callers can use as model= to select a curated acptoapi chain.
|
|
@@ -70,7 +87,11 @@ export function resolveCallLLM({ provider, model } = {}) {
|
|
|
70
87
|
return await bridgeCall({ ...input, model: m })
|
|
71
88
|
}
|
|
72
89
|
|
|
73
|
-
|
|
90
|
+
// fallbackOn list mirrors acptoapi/lib/named-chains.js FALLBACK_ON.
|
|
91
|
+
// Without this, comma-separated model lists default to ['error'] and
|
|
92
|
+
// rate-limited / empty / timed-out responses don't trigger chain
|
|
93
|
+
// fallback — the request just throws.
|
|
94
|
+
const opts = { model: m, messages: toMsgs(input.messages), tools: toTools(input.tools), onFallback: input.onFallback, output: 'openai', fallbackOn: ['error', 'rate_limit', 'timeout', 'empty'] }
|
|
74
95
|
if (/^queue\//.test(m)) opts.queuesMap = getConfigValue('agent.model_queues', {}) || {}
|
|
75
96
|
if (m.includes(',') || /^queue\//.test(m)) opts.matrixSource = process.env.FREDDIE_MATRIX_URL || MATRIX_FILE
|
|
76
97
|
|