tycono 0.3.30 → 0.3.31

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": "tycono",
3
- "version": "0.3.30",
3
+ "version": "0.3.31",
4
4
  "description": "Build an AI company. Watch them work.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,9 @@
14
14
  import { executionManager, type Execution } from './execution-manager.js';
15
15
  import { createSession, getSession, listSessions, addMessage, type Message } from './session-store.js';
16
16
  import Anthropic from '@anthropic-ai/sdk';
17
+ import { ClaudeCliProvider } from '../engine/llm-adapter.js';
17
18
  import { buildOrgTree, getSubordinates } from '../engine/org-tree.js';
19
+ import { readConfig } from './company-config.js';
18
20
  import fs from 'node:fs';
19
21
  import path from 'node:path';
20
22
  import { COMPANY_ROOT } from './file-reader.js';
@@ -332,28 +334,7 @@ class SupervisorHeartbeat {
332
334
  * Uses Haiku LLM for classification when ANTHROPIC_API_KEY is available.
333
335
  * Falls back to regex heuristic when no API key.
334
336
  */
335
- private async classifyDirective(text: string): Promise<boolean> {
336
- // Try AI classification first (fast, accurate, language-agnostic)
337
- if (process.env.ANTHROPIC_API_KEY) {
338
- try {
339
- const result = await this.classifyWithHaiku(text);
340
- console.log(`[Supervisor] AI classified "${text.slice(0, 40)}" as ${result ? 'conversation' : 'task'}`);
341
- return result;
342
- } catch (err) {
343
- console.warn(`[Supervisor] AI classification failed, falling back to regex:`, err);
344
- }
345
- }
346
-
347
- // Fallback: regex heuristic
348
- return this.isConversationDirectiveFallback(text);
349
- }
350
-
351
- private async classifyWithHaiku(text: string): Promise<boolean> {
352
- const client = new Anthropic();
353
- const response = await client.messages.create({
354
- model: 'claude-haiku-4-5-20251001',
355
- max_tokens: 1,
356
- system: `You classify user messages to a CEO AI assistant.
337
+ private static readonly CLASSIFY_SYSTEM = `You classify user messages to a CEO AI assistant.
357
338
  Reply with exactly one character:
358
339
  - "Q" if the message is a question, status check, or casual conversation (no action needed)
359
340
  - "T" if the message is a task, work instruction, delegation request, or any directive that requires action (creating, building, fixing, assigning work to team members, etc.)
@@ -365,11 +346,45 @@ Examples:
365
346
  "현재 상태 알려줘" → Q
366
347
  "게임 만들어 CTO에게 시켜" → T
367
348
  "how's it going?" → Q
368
- "deploy the app" → T`,
369
- messages: [{ role: 'user', content: text }],
370
- });
371
- const reply = (response.content[0] as { type: 'text'; text: string }).text.trim();
372
- return reply === 'Q';
349
+ "deploy the app" → T`;
350
+
351
+ private async classifyDirective(text: string): Promise<boolean> {
352
+ // Try AI classification (fast, accurate, language-agnostic)
353
+ try {
354
+ const config = readConfig(COMPANY_ROOT);
355
+ const engine = config.engine || process.env.EXECUTION_ENGINE || 'claude-cli';
356
+
357
+ let reply: string;
358
+ if (engine === 'claude-cli') {
359
+ // Claude CLI (Claude Max) — use claude -p with haiku model
360
+ const provider = new ClaudeCliProvider({ model: 'claude-haiku-4-5-20251001' });
361
+ const response = await provider.chat(
362
+ SupervisorHeartbeat.CLASSIFY_SYSTEM,
363
+ [{ role: 'user', content: text }],
364
+ );
365
+ reply = response.content.find(c => c.type === 'text')?.text?.trim() ?? '';
366
+ } else if (process.env.ANTHROPIC_API_KEY) {
367
+ // BYOK — use Anthropic SDK directly
368
+ const client = new Anthropic();
369
+ const response = await client.messages.create({
370
+ model: 'claude-haiku-4-5-20251001',
371
+ max_tokens: 1,
372
+ system: SupervisorHeartbeat.CLASSIFY_SYSTEM,
373
+ messages: [{ role: 'user', content: text }],
374
+ });
375
+ reply = (response.content[0] as { type: 'text'; text: string }).text.trim();
376
+ } else {
377
+ // No engine available — regex fallback
378
+ return this.isConversationDirectiveFallback(text);
379
+ }
380
+
381
+ const isConversation = reply === 'Q';
382
+ console.log(`[Supervisor] AI classified "${text.slice(0, 40)}" as ${isConversation ? 'conversation' : 'task'} (engine=${engine})`);
383
+ return isConversation;
384
+ } catch (err) {
385
+ console.warn(`[Supervisor] AI classification failed, falling back to regex:`, err);
386
+ return this.isConversationDirectiveFallback(text);
387
+ }
373
388
  }
374
389
 
375
390
  private isConversationDirectiveFallback(text: string): boolean {