@myvillage/cli 1.79.0 → 1.80.1

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": "@myvillage/cli",
3
- "version": "1.79.0",
3
+ "version": "1.80.1",
4
4
  "description": "MyVillageOS CLI for community developers",
5
5
  "type": "module",
6
6
  "bin": {
@@ -64,7 +64,9 @@ export async function agentLoop(agentName, { signal }) {
64
64
  }
65
65
  const apiKey = process.env.SELF_HOSTED_API_KEY || globalConfig.selfHostedApiKey || 'not-needed';
66
66
  const openai = createOpenAI({ apiKey, baseURL });
67
- model = openai(modelId);
67
+ // Most OpenAI-compatible servers (vLLM, Ollama, LM Studio, Baseten) serve
68
+ // /chat/completions but not the Responses API that openai(id) defaults to.
69
+ model = openai.chat(modelId);
68
70
  } else if (provider === 'myvillage') {
69
71
  // MyVillage-hosted models via the AI Gateway. OpenAI-compatible; the villager's
70
72
  // OAuth token is the credential, and MVTs are deducted server-side by usage.
@@ -74,8 +76,23 @@ export async function agentLoop(agentName, { signal }) {
74
76
  throw new Error('Not logged in. Run `myvillage login` to use MyVillage-hosted models.');
75
77
  }
76
78
  const { apiBaseUrl } = getConfig();
77
- const openai = createOpenAI({ apiKey: token, baseURL: `${apiBaseUrl}/ai` });
78
- model = openai(modelId);
79
+ // The model client is built once, but OAuth tokens rotate (~1h). A static
80
+ // bearer would 401 on every gateway call after expiry for long-lived agents,
81
+ // so inject the current token per request — refreshing first if it expired.
82
+ const gatewayFetch = async (url, init = {}) => {
83
+ if (isTokenExpired()) {
84
+ try { await refreshAccessToken(); } catch { /* fall through with the existing token */ }
85
+ }
86
+ const current = getAccessToken();
87
+ const headers = new Headers(init.headers);
88
+ if (current) headers.set('authorization', `Bearer ${current}`);
89
+ return fetch(url, { ...init, headers });
90
+ };
91
+ const openai = createOpenAI({ apiKey: token, baseURL: `${apiBaseUrl}/ai`, fetch: gatewayFetch });
92
+ // The AI Gateway implements the OpenAI Chat Completions API (/chat/completions).
93
+ // @ai-sdk/openai's default `openai(id)` targets the newer Responses API
94
+ // (/responses), which the gateway does not serve — so pin to chat explicitly.
95
+ model = openai.chat(modelId);
79
96
  } else {
80
97
  const apiKey = process.env.ANTHROPIC_API_KEY || globalConfig.anthropicApiKey;
81
98
  if (!apiKey) {
@@ -29,6 +29,7 @@ import {
29
29
  shareKnowledgeAsAgent,
30
30
  retryAgentTask,
31
31
  retryFailedAgentTasks,
32
+ listHostedModels,
32
33
  } from '../utils/api.js';
33
34
  import {
34
35
  getAgentDir,
@@ -139,11 +140,22 @@ export async function agentCreateLocalCommand() {
139
140
  type: 'list',
140
141
  name: 'model',
141
142
  message: 'Model:',
142
- choices: (prev) => {
143
+ choices: async (prev) => {
143
144
  if (prev.provider === 'myvillage') {
144
- return [
145
- { name: 'Vee 1.3 (recommended)', value: 'vee-1.3' },
146
- ];
145
+ // Pull the live catalog of hosted models from the gateway; fall back to
146
+ // the default slug if the network/catalog is unavailable.
147
+ try {
148
+ const models = await listHostedModels();
149
+ if (Array.isArray(models) && models.length > 0) {
150
+ return models.map((m) => ({
151
+ name: m.description ? `${m.name} — ${m.description}` : m.name || m.slug,
152
+ value: m.slug,
153
+ }));
154
+ }
155
+ } catch {
156
+ /* offline or gateway unavailable — fall through to default */
157
+ }
158
+ return [{ name: 'Vee 1.3 (recommended)', value: 'vee-1.3' }];
147
159
  }
148
160
  if (prev.provider === 'openai') {
149
161
  return [
package/src/utils/api.js CHANGED
@@ -131,6 +131,15 @@ export async function getGameStatus(gameId) {
131
131
  return response.data;
132
132
  }
133
133
 
134
+ // ── AI Gateway (MyVillage-hosted models) ────────────────
135
+
136
+ /** List the MyVillage-hosted models available through the AI Gateway. */
137
+ export async function listHostedModels() {
138
+ const client = getApiClient();
139
+ const response = await client.get('/ai/models');
140
+ return response.data?.models || [];
141
+ }
142
+
134
143
  // ── Network API Client (/api/network) ───────────────────
135
144
 
136
145
  export function getNetworkClient() {