codeep 1.2.5 → 1.2.7

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/dist/api/index.js CHANGED
@@ -272,6 +272,7 @@ async function chatOpenAI(message, history, model, apiKey, onChunk, abortSignal)
272
272
  model,
273
273
  messages,
274
274
  stream,
275
+ ...(stream ? { stream_options: { include_usage: true } } : {}),
275
276
  temperature,
276
277
  max_tokens: maxTokens,
277
278
  }),
@@ -323,6 +324,12 @@ async function handleOpenAIStream(body, onChunk) {
323
324
  chunks.push(content);
324
325
  onChunk(content);
325
326
  }
327
+ // Capture usage from final chunk (stream_options: include_usage)
328
+ if (parsed.usage) {
329
+ const usage = extractOpenAIUsage(parsed);
330
+ if (usage)
331
+ recordTokenUsage(usage, parsed.model || 'unknown', config.get('provider'));
332
+ }
326
333
  }
327
334
  catch {
328
335
  // Ignore parse errors
@@ -418,6 +425,9 @@ async function handleAnthropicStream(body, onChunk) {
418
425
  const decoder = new TextDecoder();
419
426
  const chunks = [];
420
427
  let buffer = '';
428
+ let inputTokens = 0;
429
+ let outputTokens = 0;
430
+ let streamModel = '';
421
431
  while (true) {
422
432
  const { done, value } = await reader.read();
423
433
  if (done)
@@ -437,6 +447,15 @@ async function handleAnthropicStream(body, onChunk) {
437
447
  onChunk(text);
438
448
  }
439
449
  }
450
+ // message_start contains input_tokens
451
+ if (parsed.type === 'message_start' && parsed.message?.usage) {
452
+ inputTokens = parsed.message.usage.input_tokens || 0;
453
+ streamModel = parsed.message.model || '';
454
+ }
455
+ // message_delta contains output_tokens
456
+ if (parsed.type === 'message_delta' && parsed.usage) {
457
+ outputTokens = parsed.usage.output_tokens || 0;
458
+ }
440
459
  }
441
460
  catch {
442
461
  // Ignore parse errors
@@ -444,6 +463,10 @@ async function handleAnthropicStream(body, onChunk) {
444
463
  }
445
464
  }
446
465
  }
466
+ // Record token usage
467
+ if (inputTokens > 0 || outputTokens > 0) {
468
+ recordTokenUsage({ promptTokens: inputTokens, completionTokens: outputTokens, totalTokens: inputTokens + outputTokens }, streamModel || 'unknown', config.get('provider'));
469
+ }
447
470
  // Strip <think> tags from MiniMax responses
448
471
  return stripThinkTags(chunks.join(''));
449
472
  }
@@ -49,6 +49,25 @@ export const PROVIDERS = {
49
49
  envKey: 'MINIMAX_API_KEY',
50
50
  subscribeUrl: 'https://platform.minimax.io/subscribe/coding-plan?code=2lWvoWUhrp&source=link',
51
51
  },
52
+ 'anthropic': {
53
+ name: 'Anthropic',
54
+ description: 'Claude AI models',
55
+ protocols: {
56
+ anthropic: {
57
+ baseUrl: 'https://api.anthropic.com',
58
+ authHeader: 'x-api-key',
59
+ supportsNativeTools: true,
60
+ },
61
+ },
62
+ models: [
63
+ { id: 'claude-sonnet-4-5-20250929', name: 'Claude Sonnet 4.5', description: 'Best balance of speed and intelligence' },
64
+ { id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5', description: 'Fastest and most affordable' },
65
+ { id: 'claude-opus-4-6', name: 'Claude Opus 4.6', description: 'Most capable model' },
66
+ ],
67
+ defaultModel: 'claude-sonnet-4-5-20250929',
68
+ defaultProtocol: 'anthropic',
69
+ envKey: 'ANTHROPIC_API_KEY',
70
+ },
52
71
  };
53
72
  export function getProvider(id) {
54
73
  return PROVIDERS[id] || null;
@@ -1189,14 +1189,17 @@ export class App {
1189
1189
  logoutProviders: this.logoutProviders,
1190
1190
  logoutCallback: this.logoutCallback,
1191
1191
  };
1192
+ const syncState = () => {
1193
+ this.logoutOpen = state.logoutOpen;
1194
+ this.logoutIndex = state.logoutIndex;
1195
+ this.logoutCallback = state.logoutCallback;
1196
+ };
1192
1197
  handleLogoutKeyComponent(event, state, {
1193
1198
  onClose: () => { },
1194
- onRender: () => this.render(),
1199
+ onRender: () => { syncState(); this.render(); },
1195
1200
  onSelect: () => { },
1196
1201
  });
1197
- this.logoutOpen = state.logoutOpen;
1198
- this.logoutIndex = state.logoutIndex;
1199
- this.logoutCallback = state.logoutCallback;
1202
+ syncState();
1200
1203
  }
1201
1204
  /**
1202
1205
  * Handle login keys
@@ -2376,7 +2379,11 @@ export class App {
2376
2379
  leftText = ` ${this.notification}`;
2377
2380
  }
2378
2381
  else {
2379
- leftText = ` ${this.messages.length} messages`;
2382
+ const stats = this.options.getStatus().tokenStats;
2383
+ const tokenInfo = stats && stats.totalTokens > 0
2384
+ ? ` | ${stats.totalTokens < 1000 ? stats.totalTokens : (stats.totalTokens / 1000).toFixed(1) + 'K'} tokens`
2385
+ : '';
2386
+ leftText = ` ${this.messages.length} messages${tokenInfo}`;
2380
2387
  }
2381
2388
  if (this.isStreaming) {
2382
2389
  rightText = 'Streaming... (Esc to cancel)';
@@ -14,7 +14,7 @@ import { runAgent } from '../utils/agent.js';
14
14
  import { config, loadApiKey, loadAllApiKeys, getCurrentProvider, getModelsForCurrentProvider, PROTOCOLS, LANGUAGES, setProvider, setApiKey, clearApiKey, getApiKey, autoSaveSession, saveSession, startNewSession, getCurrentSessionId, loadSession, listSessionsWithInfo, deleteSession, renameSession, hasReadPermission, hasWritePermission, setProjectPermission, initializeAsProject, isManuallyInitializedProject, } from '../config/index.js';
15
15
  import { isProjectDirectory, getProjectContext } from '../utils/project.js';
16
16
  import { getCurrentVersion } from '../utils/update.js';
17
- import { getProviderList } from '../config/providers.js';
17
+ import { getProviderList, getProvider } from '../config/providers.js';
18
18
  import { getSessionStats } from '../utils/tokenTracker.js';
19
19
  // State
20
20
  let projectPath = process.cwd();
@@ -899,10 +899,18 @@ function handleCommand(command, args) {
899
899
  }
900
900
  // Protocol and language
901
901
  case 'protocol': {
902
- const protocols = Object.entries(PROTOCOLS).map(([key, name]) => ({
902
+ const currentProvider = getCurrentProvider();
903
+ const providerConfig = getProvider(currentProvider.id);
904
+ const protocols = Object.entries(PROTOCOLS)
905
+ .filter(([key]) => providerConfig?.protocols[key])
906
+ .map(([key, name]) => ({
903
907
  key,
904
908
  label: name,
905
909
  }));
910
+ if (protocols.length <= 1) {
911
+ app.notify(`${currentProvider.name} only supports ${protocols[0]?.label || 'one'} protocol`);
912
+ break;
913
+ }
906
914
  const currentProtocol = config.get('protocol') || 'openai';
907
915
  app.showSelect('Select Protocol', protocols, currentProtocol, (item) => {
908
916
  config.set('protocol', item.key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeep",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",