freddie 0.0.98 → 0.0.100
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.100",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Open JS agent harness built on pi-mono, floosie, xstate, and anentrypoint-design",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"xstate": "^5.31.0",
|
|
28
28
|
"zod": "^4.0.0",
|
|
29
29
|
"anentrypoint-design": "^0.0.94",
|
|
30
|
-
"acptoapi": "^1.0.
|
|
30
|
+
"acptoapi": "^1.0.63"
|
|
31
31
|
},
|
|
32
32
|
"optionalDependencies": {
|
|
33
33
|
"@libsql/darwin-arm64": "0.3.19",
|
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequire } from 'module'
|
|
2
|
+
import { getConfigValue } from '../../src/config.js'
|
|
3
|
+
import { MATRIX_FILE } from '../../src/agent/model-matrix.js'
|
|
2
4
|
import { flattenForOpenAI } from '../../src/agent/model-discovery.js'
|
|
3
5
|
import { logger } from '../../src/observability/log.js'
|
|
4
6
|
|
|
7
|
+
const _require = createRequire(import.meta.url)
|
|
8
|
+
const sdk = _require('acptoapi')
|
|
5
9
|
const log = logger('gui-llm-passthrough')
|
|
6
10
|
|
|
11
|
+
function matrixSource() { return process.env.FREDDIE_MATRIX_URL || MATRIX_FILE }
|
|
12
|
+
|
|
7
13
|
export default {
|
|
8
14
|
name: 'gui-llm-passthrough', surfaces: 'gui',
|
|
9
15
|
register({ gui }) {
|
|
10
|
-
gui.route('GET', '/v1/models', (_, res) => {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
16
|
+
gui.route('GET', '/v1/models', async (_, res) => {
|
|
17
|
+
try {
|
|
18
|
+
const rows = await sdk.listAllModelsAndQueues({ queuesMap: getConfigValue('agent.model_queues', {}) || {}, matrixSource: matrixSource() })
|
|
19
|
+
const local = flattenForOpenAI()
|
|
20
|
+
const seen = new Set(rows.map(r => r.id))
|
|
21
|
+
for (const r of local) if (!seen.has(r.id)) rows.push(r)
|
|
22
|
+
if (rows.length === 0) rows.push({ id: 'freddie/auto', object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'freddie' })
|
|
23
|
+
res.json({ object: 'list', data: rows })
|
|
24
|
+
} catch (e) { log.error('list-models-failed', { error: String(e.message || e) }); res.json({ object: 'list', data: flattenForOpenAI() }) }
|
|
14
25
|
})
|
|
15
26
|
gui.route('POST', '/v1/chat/completions', async (req, res) => {
|
|
16
27
|
const { model, messages, tools, stream } = req.body || {}
|
|
17
28
|
if (!Array.isArray(messages) || messages.length === 0) return res.status(400).json({ error: { message: 'messages required' } })
|
|
18
29
|
try {
|
|
19
|
-
|
|
20
|
-
if (typeof model === 'string' && model.includes('/')) {
|
|
21
|
-
const idx = model.indexOf('/'); provider = model.slice(0, idx); mdl = model.slice(idx + 1)
|
|
22
|
-
}
|
|
23
|
-
const call = resolveCallLLM({ provider, model: mdl })
|
|
24
|
-
const out = await call({ messages, tools: tools?.map(t => ({ name: t.function?.name, description: t.function?.description, parameters: t.function?.parameters })) || [], model: mdl })
|
|
25
|
-
const id = 'chatcmpl-' + Math.random().toString(36).slice(2, 12)
|
|
26
|
-
const created = Math.floor(Date.now() / 1000)
|
|
27
|
-
const choice = { index: 0, message: { role: 'assistant', content: out.content || '', ...(out.tool_calls?.length ? { tool_calls: out.tool_calls.map(tc => ({ id: tc.id, type: 'function', function: { name: tc.name, arguments: JSON.stringify(tc.arguments || {}) } })) } : {}) }, finish_reason: 'stop' }
|
|
30
|
+
const out = await sdk.chat({ model: model || 'freddie/auto', messages, tools, queuesMap: getConfigValue('agent.model_queues', {}) || {}, matrixSource: matrixSource(), output: 'openai' })
|
|
28
31
|
if (stream) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
const id = 'chatcmpl-' + Math.random().toString(36).slice(2, 12)
|
|
33
|
+
const created = Math.floor(Date.now() / 1000)
|
|
34
|
+
const content = out?.choices?.[0]?.message?.content || ''
|
|
35
|
+
res.setHeader('content-type', 'text/event-stream'); res.setHeader('cache-control', 'no-cache')
|
|
36
|
+
res.write(`data: ${JSON.stringify({ id, object: 'chat.completion.chunk', created, model: model || 'freddie/auto', choices: [{ index: 0, delta: { role: 'assistant', content }, finish_reason: null }] })}\n\n`)
|
|
32
37
|
res.write(`data: ${JSON.stringify({ id, object: 'chat.completion.chunk', created, model: model || 'freddie/auto', choices: [{ index: 0, delta: {}, finish_reason: 'stop' }] })}\n\n`)
|
|
33
|
-
res.write('data: [DONE]\n\n')
|
|
34
|
-
res.end()
|
|
35
|
-
return
|
|
38
|
+
res.write('data: [DONE]\n\n'); res.end(); return
|
|
36
39
|
}
|
|
37
|
-
res.json(
|
|
38
|
-
} catch (e) {
|
|
39
|
-
log.error('chat-completions-failed', { error: String(e.message || e) })
|
|
40
|
-
res.status(500).json({ error: { message: String(e.message || e), type: 'upstream_error' } })
|
|
41
|
-
}
|
|
40
|
+
res.json(out)
|
|
41
|
+
} catch (e) { log.error('chat-completions-failed', { error: String(e.message || e) }); res.status(500).json({ error: { message: String(e.message || e), type: 'upstream_error' } }) }
|
|
42
42
|
})
|
|
43
43
|
},
|
|
44
44
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { createRequire } from 'module'
|
|
1
2
|
import { discoverAndPersist, listKnownProviders } from '../../src/agent/model-discovery.js'
|
|
2
|
-
import { PROVIDER_KEYS, DEFAULTS } from '../../src/agent/llm_resolver.js'
|
|
3
3
|
import { getConfigValue, saveConfigValue } from '../../src/config.js'
|
|
4
|
-
import {
|
|
4
|
+
import { MATRIX_FILE } from '../../src/agent/model-matrix.js'
|
|
5
5
|
import fs from 'node:fs'
|
|
6
6
|
import path from 'node:path'
|
|
7
7
|
import { spawn } from 'node:child_process'
|
|
8
|
+
const _require = createRequire(import.meta.url)
|
|
9
|
+
const { PROVIDER_KEYS, PROVIDER_DEFAULTS: DEFAULTS, getStatus, peekStatus, listAllQueues } = _require('acptoapi')
|
|
8
10
|
|
|
9
11
|
const MATRIX_PATH = path.resolve(new URL('.', import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, '$1'), '..', '..', '.gm', 'model-availability.json')
|
|
10
12
|
let _rebuildInFlight = null
|
|
@@ -18,7 +20,19 @@ export default {
|
|
|
18
20
|
try { const provider = req.body?.provider; const result = await discoverAndPersist({ provider }); res.json(result) }
|
|
19
21
|
catch (e) { res.status(500).json({ error: String(e.message || e) }) }
|
|
20
22
|
})
|
|
21
|
-
gui.route('GET', '/api/models/queues', (_, res) =>
|
|
23
|
+
gui.route('GET', '/api/models/queues', (_, res) => {
|
|
24
|
+
const local = getConfigValue('agent.model_queues', {}) || {}
|
|
25
|
+
try {
|
|
26
|
+
const all = listAllQueues({ queuesMap: local })
|
|
27
|
+
const merged = { ...local }
|
|
28
|
+
for (const q of all) if (!merged[q.name]) merged[q.name] = q.links.map(m => ({ model: m, source: q.source }))
|
|
29
|
+
res.json(merged)
|
|
30
|
+
} catch { res.json(local) }
|
|
31
|
+
})
|
|
32
|
+
gui.route('GET', '/api/models/sampler/peek/:provider', (req, res) => {
|
|
33
|
+
try { res.json(peekStatus(req.params.provider)) }
|
|
34
|
+
catch (e) { res.status(500).json({ error: String(e.message || e) }) }
|
|
35
|
+
})
|
|
22
36
|
gui.route('POST', '/api/models/queues', (req, res) => {
|
|
23
37
|
const { name, entries } = req.body || {}
|
|
24
38
|
if (!name || !Array.isArray(entries)) return res.status(400).json({ error: 'name and entries[] required' })
|
|
@@ -2,11 +2,9 @@ import { createRequire } from 'module'
|
|
|
2
2
|
import { listAllProfiles } from '../../src/commands/profile.js'
|
|
3
3
|
import { COMMAND_REGISTRY } from '../../src/commands/registry.js'
|
|
4
4
|
import { getFreddieHome } from '../../src/home.js'
|
|
5
|
-
import { PROVIDER_KEYS, DEFAULTS } from '../../src/agent/llm_resolver.js'
|
|
6
|
-
import { getStatus } from '../../src/agent/model-sampler.js'
|
|
7
5
|
import { resolveKey } from '../../src/agent/credential_sources.js'
|
|
8
6
|
const _require = createRequire(import.meta.url)
|
|
9
|
-
const { probeModels, getCachedModels } = _require('acptoapi')
|
|
7
|
+
const { probeModels, getCachedModels, PROVIDER_KEYS, PROVIDER_DEFAULTS: DEFAULTS, getStatus, peekStatus } = _require('acptoapi')
|
|
10
8
|
export default {
|
|
11
9
|
name: 'gui-profiles-commands-health', surfaces: 'gui',
|
|
12
10
|
register({ gui }) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createRequire } from 'module'
|
|
2
2
|
import { getConfigValue } from '../config.js'
|
|
3
3
|
import { MATRIX_FILE } from './model-matrix.js'
|
|
4
|
+
import { callLLM as bridgeCall, isReachable as bridgeReachable } from './acptoapi-bridge.js'
|
|
4
5
|
export { matrixUsable } from './model-matrix.js'
|
|
5
6
|
|
|
6
7
|
const _require = createRequire(import.meta.url)
|
|
@@ -46,7 +47,12 @@ export function resolveCallLLM({ provider, model } = {}) {
|
|
|
46
47
|
throw new Error('no LLM backend reachable: set a provider API key or start acptoapi (http://127.0.0.1:4800/v1)' + (status ? ' | sampler: ' + status : ''))
|
|
47
48
|
}
|
|
48
49
|
try {
|
|
49
|
-
const
|
|
50
|
+
const isSimple = typeof m === 'string' && !m.includes(',') && !/^queue\//.test(m)
|
|
51
|
+
if (isSimple && await bridgeReachable()) return await bridgeCall({ ...input, model: m })
|
|
52
|
+
const opts = { model: m, messages: toMsgs(input.messages), tools: toTools(input.tools), onFallback: input.onFallback, output: 'openai' }
|
|
53
|
+
if (/^queue\//.test(m)) opts.queuesMap = getConfigValue('agent.model_queues', {}) || {}
|
|
54
|
+
if (m.includes(',') || /^queue\//.test(m)) opts.matrixSource = process.env.FREDDIE_MATRIX_URL || MATRIX_FILE
|
|
55
|
+
const r = await sdk.chat(opts)
|
|
50
56
|
return adapt(r)
|
|
51
57
|
} catch (e) {
|
|
52
58
|
if (/queue not found or empty/i.test(e.message)) throw e
|