@agi-cli/server 0.1.127 → 0.1.129

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.127",
3
+ "version": "0.1.129",
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.127",
33
- "@agi-cli/database": "0.1.127",
32
+ "@agi-cli/sdk": "0.1.129",
33
+ "@agi-cli/database": "0.1.129",
34
34
  "drizzle-orm": "^0.44.5",
35
35
  "hono": "^4.9.9",
36
36
  "zod": "^4.1.8"
@@ -1,4 +1,8 @@
1
1
  export type AGIEventType =
2
+ | 'solforge.payment.required'
3
+ | 'solforge.payment.signing'
4
+ | 'solforge.payment.complete'
5
+ | 'solforge.payment.error'
2
6
  | 'session.created'
3
7
  | 'session.updated'
4
8
  | 'message.created'
@@ -1,4 +1,4 @@
1
- import { loadConfig } from '@agi-cli/sdk';
1
+ import { loadConfig, catalog } from '@agi-cli/sdk';
2
2
  import { getDb } from '@agi-cli/database';
3
3
  import { sessions } from '@agi-cli/database/schema';
4
4
  import { eq } from 'drizzle-orm';
@@ -40,6 +40,16 @@ export interface SetupResult {
40
40
 
41
41
  const THINKING_BUDGET = 16000;
42
42
 
43
+ function getSolforgeUnderlyingProvider(
44
+ model: string,
45
+ ): 'anthropic' | 'openai' | null {
46
+ const entry = catalog.solforge?.models?.find((m) => m.id === model);
47
+ const npm = entry?.provider?.npm;
48
+ if (npm === '@ai-sdk/anthropic') return 'anthropic';
49
+ if (npm === '@ai-sdk/openai') return 'openai';
50
+ return null;
51
+ }
52
+
43
53
  export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
44
54
  const cfgTimer = time('runner:loadConfig+db');
45
55
  const cfg = await loadConfig(opts.projectRoot);
@@ -200,6 +210,7 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
200
210
  : undefined;
201
211
  const model = await resolveModel(opts.provider, opts.model, cfg, {
202
212
  systemPrompt: oauthSystemPrompt,
213
+ sessionId: opts.sessionId,
203
214
  });
204
215
  debugLog(
205
216
  `[RUNNER] Model created: ${JSON.stringify({ id: model.modelId, provider: model.provider })}`,
@@ -236,6 +247,20 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
236
247
  providerOptions.google = {
237
248
  thinkingConfig: { thinkingBudget: THINKING_BUDGET },
238
249
  };
250
+ } else if (opts.provider === 'solforge') {
251
+ const underlying = getSolforgeUnderlyingProvider(opts.model);
252
+ if (underlying === 'anthropic') {
253
+ providerOptions.anthropic = {
254
+ thinking: { type: 'enabled', budgetTokens: THINKING_BUDGET },
255
+ };
256
+ if (maxOutputTokens && maxOutputTokens > THINKING_BUDGET) {
257
+ effectiveMaxOutputTokens = maxOutputTokens - THINKING_BUDGET;
258
+ }
259
+ } else if (underlying === 'openai') {
260
+ providerOptions.openai = {
261
+ reasoningSummary: 'auto',
262
+ };
263
+ }
239
264
  }
240
265
  }
241
266
 
@@ -305,9 +305,10 @@ async function generateSessionTitle(args: {
305
305
  const promptText = String(content ?? '').slice(0, 2000);
306
306
 
307
307
  const titlePrompt = [
308
- "Create a short, descriptive session title from the user's request.",
309
- 'Max 6–8 words. No quotes. No trailing punctuation.',
310
- 'Avoid generic phrases like "help me"; be specific.',
308
+ 'Generate a brief title (6-8 words) summarizing what the user wants to do.',
309
+ 'Rules: Plain text only. No markdown, no quotes, no punctuation, no emojis.',
310
+ 'Focus on the core task or topic. Be specific but concise.',
311
+ 'Examples: "Fix TypeScript build errors", "Add dark mode toggle", "Refactor auth middleware"',
311
312
  ].join(' ');
312
313
 
313
314
  // Build system prompt and messages
@@ -409,8 +410,17 @@ async function generateSessionTitle(args: {
409
410
 
410
411
  function sanitizeTitle(raw: string): string {
411
412
  let s = raw.trim();
413
+ s = s.replace(/^#+\s*/, '');
414
+ s = s.replace(/\*\*([^*]+)\*\*/g, '$1');
415
+ s = s.replace(/\*([^*]+)\*/g, '$1');
416
+ s = s.replace(/__([^_]+)__/g, '$1');
417
+ s = s.replace(/_([^_]+)_/g, '$1');
418
+ s = s.replace(/`([^`]+)`/g, '$1');
419
+ s = s.replace(/~~([^~]+)~~/g, '$1');
420
+ s = s.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1');
412
421
  s = s.replace(/^["']|["']$/g, '');
413
- s = s.replace(/[.!?]+$/, '');
422
+ s = s.replace(/^[-–—•*]\s*/, '');
423
+ s = s.replace(/[.!?:;,]+$/, '');
414
424
  s = s.replace(/\s+/g, ' ');
415
425
  if (s.length > 80) s = s.slice(0, 80).trim();
416
426
  return s;
@@ -424,7 +434,7 @@ async function touchSessionLastActive(args: {
424
434
  try {
425
435
  await db
426
436
  .update(sessions)
427
- .set({ updatedAt: Date.now() })
437
+ .set({ lastActiveAt: Date.now() })
428
438
  .where(eq(sessions.id, sessionId))
429
439
  .run();
430
440
  } catch (err) {
@@ -13,7 +13,7 @@ export async function resolveModel(
13
13
  provider: ProviderName,
14
14
  model: string,
15
15
  cfg: AGIConfig,
16
- options?: { systemPrompt?: string },
16
+ options?: { systemPrompt?: string; sessionId?: string },
17
17
  ) {
18
18
  if (provider === 'openai') {
19
19
  return resolveOpenAIModel(model, cfg, options);
@@ -32,7 +32,7 @@ export async function resolveModel(
32
32
  return resolveOpencodeModel(model, cfg);
33
33
  }
34
34
  if (provider === 'solforge') {
35
- return resolveSolforgeModel(model);
35
+ return resolveSolforgeModel(model, options?.sessionId);
36
36
  }
37
37
  if (provider === 'zai') {
38
38
  return getZaiInstance(cfg, model);
@@ -1,6 +1,16 @@
1
- import { createSolforgeModel } from '@agi-cli/sdk';
1
+ import {
2
+ createSolforgeModel,
3
+ catalog,
4
+ type SolforgePaymentCallbacks,
5
+ } from '@agi-cli/sdk';
6
+ import { publish } from '../../events/bus.ts';
2
7
 
3
- export function resolveSolforgeModel(model: string) {
8
+ function getProviderNpm(model: string): string | undefined {
9
+ const entry = catalog.solforge?.models?.find((m) => m.id === model);
10
+ return entry?.provider?.npm;
11
+ }
12
+
13
+ export function resolveSolforgeModel(model: string, sessionId?: string) {
4
14
  const privateKey = process.env.SOLFORGE_PRIVATE_KEY ?? '';
5
15
  if (!privateKey) {
6
16
  throw new Error(
@@ -10,6 +20,42 @@ export function resolveSolforgeModel(model: string) {
10
20
  const baseURL = process.env.SOLFORGE_BASE_URL;
11
21
  const rpcURL = process.env.SOLFORGE_SOLANA_RPC_URL;
12
22
  const topupAmount = process.env.SOLFORGE_TOPUP_MICRO_USDC;
23
+
24
+ const callbacks: SolforgePaymentCallbacks = sessionId
25
+ ? {
26
+ onPaymentRequired: (amountUsd) => {
27
+ publish({
28
+ type: 'solforge.payment.required',
29
+ sessionId,
30
+ payload: { amountUsd },
31
+ });
32
+ },
33
+ onPaymentSigning: () => {
34
+ publish({
35
+ type: 'solforge.payment.signing',
36
+ sessionId,
37
+ payload: {},
38
+ });
39
+ },
40
+ onPaymentComplete: (data) => {
41
+ publish({
42
+ type: 'solforge.payment.complete',
43
+ sessionId,
44
+ payload: data,
45
+ });
46
+ },
47
+ onPaymentError: (error) => {
48
+ publish({
49
+ type: 'solforge.payment.error',
50
+ sessionId,
51
+ payload: { error },
52
+ });
53
+ },
54
+ }
55
+ : {};
56
+
57
+ const providerNpm = getProviderNpm(model);
58
+
13
59
  return createSolforgeModel(
14
60
  model,
15
61
  { privateKey },
@@ -17,6 +63,8 @@ export function resolveSolforgeModel(model: string) {
17
63
  baseURL,
18
64
  rpcURL,
19
65
  topupAmountMicroUsdc: topupAmount,
66
+ callbacks,
67
+ providerNpm,
20
68
  },
21
69
  );
22
70
  }