mirror of
https://github.com/Ryder-Sun/Meldwork.git
synced 2026-11-07 06:56:03 -10:00
fix: honor MiMo native provider configuration when checking readiness
Recognize the selected custom Provider instead of treating official-account whoami output as proof that a configured native model cannot run. Keep native model and credential selection inside MiMo and isolate auth probes in tests. Checks on the combined working tree: focused context/preferences/MiMo/preload 47/47 passed; readiness/WorkBuddy/catalog 71/71 passed. Real MiMo ACP first call, native Session continuation, and production Electron group invocation passed without forcing a model. git diff --cached --check passed.
This commit is contained in:
1 parent
f77fd8b0c0
commit
7f9e95d86c
4 files changed
+69
-4
No files matched your search
@@ -0,0 +1,23 @@
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
const os = require('node:os')
|
||||
|
||||
function mimoConfiguredProvider(options = {}) {
|
||||
const env = options.env || process.env
|
||||
const root = env.XDG_CONFIG_HOME || path.join(options.home || os.homedir(), '.config')
|
||||
try {
|
||||
const file = path.join(root, 'mimocode', 'mimocode.json')
|
||||
if (fs.statSync(file).size > 2 * 1024 * 1024) return false
|
||||
const config = JSON.parse(fs.readFileSync(file, 'utf8'))
|
||||
if (typeof config.model !== 'string' || !config.model.includes('/')) return false
|
||||
const provider = config.provider?.[config.model.split('/')[0]]
|
||||
let key = provider?.options?.apiKey
|
||||
if (typeof key !== 'string' || !key.trim()) return false
|
||||
const reference = key.match(/^\{env:([A-Za-z_][A-Za-z0-9_]*)\}$/)
|
||||
if (reference) key = env[reference[1]]
|
||||
else if (/^\{.*\}$/.test(key)) return false
|
||||
return typeof key === 'string' && Boolean(key.trim())
|
||||
} catch { return false }
|
||||
}
|
||||
|
||||
module.exports = { mimoConfiguredProvider }
|
||||
@@ -7,6 +7,7 @@ const { promisify } = require('node:util')
|
||||
const { prepareCommand, searchPath } = require('./cli/cli-adapters.cjs')
|
||||
const { isOpenClawSecretReference } = require('./cli/openclaw-runtime.cjs')
|
||||
const { NETWORK_ENV_KEYS, networkEnvironment } = require('./cli/cli-network-environment.cjs')
|
||||
const { mimoConfiguredProvider } = require('./cli/mimo-native-config.cjs')
|
||||
|
||||
const execFileAsync = promisify(execFile)
|
||||
|
||||
@@ -746,6 +747,9 @@ async function queryMimoAuthState(options = {}) {
|
||||
async function resolveNativeCredentialState(kind, options = {}) {
|
||||
const current = nativeCredentialState(kind, options)
|
||||
if (kind === 'mimo') {
|
||||
if (current.state === 'ready' || mimoConfiguredProvider(options)) {
|
||||
return { state: 'ready', source: 'native-credential' }
|
||||
}
|
||||
return await queryMimoAuthState(options) || current
|
||||
}
|
||||
if (kind === 'openclaw') {
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
const test = require('node:test')
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const os = require('node:os')
|
||||
const path = require('node:path')
|
||||
const { resolveNativeCredentialState } = require('../../../src/agents/local-agent-readiness.cjs')
|
||||
|
||||
test('MiMo selected native provider remains usable without signing in to the built-in account', async t => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'meldwork-mimo-selected-'))
|
||||
t.after(() => fs.rmSync(home, { recursive: true, force: true }))
|
||||
const root = path.join(home, '.config', 'mimocode')
|
||||
fs.mkdirSync(root, { recursive: true })
|
||||
const config = { model: 'private/text', provider: { private: { options: { apiKey: 'synthetic-key' } } } }
|
||||
const file = path.join(root, 'mimocode.json')
|
||||
fs.writeFileSync(file, JSON.stringify(config))
|
||||
const probe = async () => ({ stdout: 'Not logged in. Run `mimo auth login` to log in.' })
|
||||
const options = { home, env: {}, executable: '/tmp/mimo', execFileFn: probe }
|
||||
const result = await resolveNativeCredentialState('mimo', options)
|
||||
assert.deepEqual(result, { state: 'ready', source: 'native-credential' })
|
||||
assert.equal(JSON.stringify(result).includes('synthetic-key'), false)
|
||||
config.model = 'unconfigured/text'
|
||||
fs.writeFileSync(file, JSON.stringify(config))
|
||||
assert.equal((await resolveNativeCredentialState('mimo', options)).state, 'missing')
|
||||
config.model = 'private/text'
|
||||
config.provider.private.options.apiKey = '{env:PRIVATE_MODEL_KEY}'
|
||||
fs.writeFileSync(file, JSON.stringify(config))
|
||||
assert.equal((await resolveNativeCredentialState('mimo', options)).state, 'missing')
|
||||
assert.equal((await resolveNativeCredentialState('mimo', { ...options, env: { PRIVATE_MODEL_KEY: 'native-env-value' } })).state, 'ready')
|
||||
})
|
||||
@@ -771,13 +771,16 @@ test('OpenClaw model status overrides a stale gateway token without exposing aut
|
||||
}
|
||||
})
|
||||
|
||||
test('MiMo readiness uses the installed CLI identity without forwarding private values', async () => {
|
||||
test('MiMo readiness uses the installed CLI identity without forwarding private values', async (t) => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'meldwork-mimo-auth-'))
|
||||
t.after(() => fs.rmSync(home, { recursive: true, force: true }))
|
||||
const calls = []
|
||||
for (const stdout of [
|
||||
'\u001b[32mProvider: MiMo\u001b[0m\nUser ID: user-123',
|
||||
'Provider: MiMo\nType: OAuth',
|
||||
]) {
|
||||
const result = await resolveNativeCredentialState('mimo', {
|
||||
home,
|
||||
env: { PATH: '/usr/bin', MELDWORK_PRIVATE_VALUE: 'desktop-private-value' },
|
||||
executable: '/tmp/mimo',
|
||||
execFileFn: async (command, args, options) => {
|
||||
@@ -795,8 +798,11 @@ test('MiMo readiness uses the installed CLI identity without forwarding private
|
||||
assert.equal(calls.every(call => call.env.MELDWORK_PRIVATE_VALUE === undefined), true)
|
||||
})
|
||||
|
||||
test('MiMo readiness recognizes ANSI-colored logged-out output even when the CLI exits zero', async () => {
|
||||
test('MiMo readiness recognizes ANSI-colored logged-out output even when the CLI exits zero', async (t) => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'meldwork-mimo-auth-'))
|
||||
t.after(() => fs.rmSync(home, { recursive: true, force: true }))
|
||||
const result = await resolveNativeCredentialState('mimo', {
|
||||
home,
|
||||
env: {},
|
||||
executable: '/tmp/mimo',
|
||||
execFileFn: async () => ({
|
||||
@@ -807,8 +813,10 @@ test('MiMo readiness recognizes ANSI-colored logged-out output even when the CLI
|
||||
assert.deepEqual(result, { state: 'missing', source: 'native-auth-status' })
|
||||
})
|
||||
|
||||
test('MiMo readiness remains unknown for missing or malformed identity output', async () => {
|
||||
assert.deepEqual(await resolveNativeCredentialState('mimo', {}), {
|
||||
test('MiMo readiness remains unknown for missing or malformed identity output', async (t) => {
|
||||
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'meldwork-mimo-auth-'))
|
||||
t.after(() => fs.rmSync(home, { recursive: true, force: true }))
|
||||
assert.deepEqual(await resolveNativeCredentialState('mimo', { home, env: {} }), {
|
||||
state: 'unknown', source: 'unverified',
|
||||
})
|
||||
|
||||
@@ -820,6 +828,7 @@ test('MiMo readiness remains unknown for missing or malformed identity output',
|
||||
'Authentication status unavailable',
|
||||
]) {
|
||||
const result = await resolveNativeCredentialState('mimo', {
|
||||
home,
|
||||
env: {},
|
||||
executable: '/tmp/mimo',
|
||||
execFileFn: async () => ({ stdout }),
|
||||
|
||||
Reference in new issue
Block a user