@agi-cli/server 0.1.98 → 0.1.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": "@agi-cli/server",
3
- "version": "0.1.98",
3
+ "version": "0.1.100",
4
4
  "description": "HTTP API server for AGI CLI",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -29,8 +29,8 @@
29
29
  "typecheck": "tsc --noEmit"
30
30
  },
31
31
  "dependencies": {
32
- "@agi-cli/sdk": "0.1.98",
33
- "@agi-cli/database": "0.1.98",
32
+ "@agi-cli/sdk": "0.1.100",
33
+ "@agi-cli/database": "0.1.100",
34
34
  "drizzle-orm": "^0.44.5",
35
35
  "hono": "^4.9.9",
36
36
  "zod": "^4.1.8"
@@ -17,6 +17,7 @@ import {
17
17
  isProviderAuthorized,
18
18
  ensureProviderEnv,
19
19
  isProviderId,
20
+ providerEnvVar,
20
21
  type ProviderId,
21
22
  } from '@agi-cli/sdk';
22
23
  import { sessions } from '@agi-cli/database/schema';
@@ -126,6 +127,7 @@ async function processAskRequest(
126
127
  google: { enabled: true },
127
128
  openrouter: { enabled: true },
128
129
  opencode: { enabled: true },
130
+ solforge: { enabled: true },
129
131
  },
130
132
  paths: {
131
133
  dataDir: `${projectRoot}/.agi`,
@@ -137,11 +139,15 @@ async function processAskRequest(
137
139
 
138
140
  if (request.credentials) {
139
141
  for (const [provider, creds] of Object.entries(request.credentials)) {
140
- const envKey = `${provider.toUpperCase()}_API_KEY`;
142
+ const envKey =
143
+ providerEnvVar(provider as ProviderId) ??
144
+ `${provider.toUpperCase()}_API_KEY`;
141
145
  process.env[envKey] = creds.apiKey;
142
146
  }
143
147
  } else if (request.config?.apiKey) {
144
- const envKey = `${injectedProvider.toUpperCase()}_API_KEY`;
148
+ const envKey =
149
+ providerEnvVar(injectedProvider) ??
150
+ `${injectedProvider.toUpperCase()}_API_KEY`;
145
151
  process.env[envKey] = request.config.apiKey;
146
152
  }
147
153
  } else {
@@ -76,12 +76,15 @@ export async function updateSessionTokensIncremental(
76
76
  : priorCachedMsg;
77
77
 
78
78
  // Compute deltas for this step; clamp to 0 in case provider reports smaller values
79
+ // Cached tokens reduce the billable input, so we subtract them from the delta
79
80
  const deltaInput = Math.max(0, cumPrompt - priorPromptMsg);
80
81
  const deltaOutput = Math.max(0, cumCompletion - priorCompletionMsg);
81
82
  const deltaCached = Math.max(0, cumCached - priorCachedMsg);
82
83
  const deltaReasoning = Math.max(0, cumReasoning - priorReasoningMsg);
83
84
 
84
- const nextInputSess = priorInputSess + deltaInput;
85
+ // Session input should only count non-cached tokens
86
+ // Total cached tokens are tracked separately for reference
87
+ const nextInputSess = priorInputSess + deltaInput - deltaCached;
85
88
  const nextOutputSess = priorOutputSess + deltaOutput;
86
89
  const nextCachedSess = priorCachedSess + deltaCached;
87
90
  const nextReasoningSess = priorReasoningSess + deltaReasoning;
@@ -14,6 +14,7 @@ const FALLBACK_ORDER: ProviderId[] = [
14
14
  'google',
15
15
  'opencode',
16
16
  'openrouter',
17
+ 'solforge',
17
18
  ];
18
19
 
19
20
  type SelectionInput = {
@@ -1,5 +1,11 @@
1
1
  import type { AGIConfig, ProviderId } from '@agi-cli/sdk';
2
- import { catalog, getAuth, refreshToken, setAuth } from '@agi-cli/sdk';
2
+ import {
3
+ catalog,
4
+ createSolforgeModel,
5
+ getAuth,
6
+ refreshToken,
7
+ setAuth,
8
+ } from '@agi-cli/sdk';
3
9
  import { openai, createOpenAI } from '@ai-sdk/openai';
4
10
  import { anthropic, createAnthropic } from '@ai-sdk/anthropic';
5
11
  import { google } from '@ai-sdk/google';
@@ -159,6 +165,26 @@ export async function resolveModel(
159
165
  return ocCompat(resolvedModelId);
160
166
  return ocOpenAI(resolvedModelId);
161
167
  }
168
+ if (provider === 'solforge') {
169
+ const privateKey = process.env.SOLFORGE_PRIVATE_KEY ?? '';
170
+ if (!privateKey) {
171
+ throw new Error(
172
+ 'Solforge provider requires SOLFORGE_PRIVATE_KEY (base58 Solana secret).',
173
+ );
174
+ }
175
+ const baseURL = process.env.SOLFORGE_BASE_URL;
176
+ const rpcURL = process.env.SOLFORGE_SOLANA_RPC_URL;
177
+ const topupAmount = process.env.SOLFORGE_TOPUP_MICRO_USDC;
178
+ return createSolforgeModel(
179
+ model,
180
+ { privateKey },
181
+ {
182
+ baseURL,
183
+ rpcURL,
184
+ topupAmountMicroUsdc: topupAmount,
185
+ },
186
+ );
187
+ }
162
188
  throw new Error(`Unsupported provider: ${provider}`);
163
189
  }
164
190
 
@@ -220,41 +220,7 @@ export function adaptTools(
220
220
  stepIndex: ctx.stepIndex,
221
221
  },
222
222
  });
223
- // Optionally persist in the background without blocking ordering
224
- (async () => {
225
- try {
226
- const index = await ctx.nextIndex();
227
- await ctx.db.insert(messageParts).values({
228
- id: callPartId,
229
- messageId: ctx.messageId,
230
- index,
231
- stepIndex: ctx.stepIndex,
232
- type: 'tool_call',
233
- content: JSON.stringify({ name, args, callId }),
234
- agent: ctx.agent,
235
- provider: ctx.provider,
236
- model: ctx.model,
237
- startedAt: startTs,
238
- toolName: name,
239
- toolCallId: callId,
240
- });
241
- } catch {}
242
- })();
243
- if (typeof base.onInputAvailable === 'function') {
244
- // biome-ignore lint/suspicious/noExplicitAny: AI SDK types are complex
245
- await base.onInputAvailable(options as any);
246
- }
247
- return;
248
- }
249
-
250
- // Publish promptly so UI shows the call header before results
251
- publish({
252
- type: 'tool.call',
253
- sessionId: ctx.sessionId,
254
- payload: { name, args, callId, stepIndex: ctx.stepIndex },
255
- });
256
- // Persist best-effort in the background to avoid delaying output
257
- (async () => {
223
+ // Persist synchronously to maintain correct ordering
258
224
  try {
259
225
  const index = await ctx.nextIndex();
260
226
  await ctx.db.insert(messageParts).values({
@@ -272,7 +238,37 @@ export function adaptTools(
272
238
  toolCallId: callId,
273
239
  });
274
240
  } catch {}
275
- })();
241
+ if (typeof base.onInputAvailable === 'function') {
242
+ // biome-ignore lint/suspicious/noExplicitAny: AI SDK types are complex
243
+ await base.onInputAvailable(options as any);
244
+ }
245
+ return;
246
+ }
247
+
248
+ // Publish promptly so UI shows the call header before results
249
+ publish({
250
+ type: 'tool.call',
251
+ sessionId: ctx.sessionId,
252
+ payload: { name, args, callId, stepIndex: ctx.stepIndex },
253
+ });
254
+ // Persist synchronously to maintain correct ordering
255
+ try {
256
+ const index = await ctx.nextIndex();
257
+ await ctx.db.insert(messageParts).values({
258
+ id: callPartId,
259
+ messageId: ctx.messageId,
260
+ index,
261
+ stepIndex: ctx.stepIndex,
262
+ type: 'tool_call',
263
+ content: JSON.stringify({ name, args, callId }),
264
+ agent: ctx.agent,
265
+ provider: ctx.provider,
266
+ model: ctx.model,
267
+ startedAt: startTs,
268
+ toolName: name,
269
+ toolCallId: callId,
270
+ });
271
+ } catch {}
276
272
  if (typeof base.onInputAvailable === 'function') {
277
273
  // biome-ignore lint/suspicious/noExplicitAny: AI SDK types are complex
278
274
  await base.onInputAvailable(options as any);