@saccolabs/tars 1.0.35 → 1.0.37
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/auth/credential-manager.d.ts +14 -0
- package/dist/auth/credential-manager.js +60 -0
- package/dist/auth/credential-manager.js.map +1 -0
- package/dist/auth/oauth-service.d.ts +23 -0
- package/dist/auth/oauth-service.js +84 -0
- package/dist/auth/oauth-service.js.map +1 -0
- package/dist/cli/commands/setup.js +32 -96
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/start.js +3 -2
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/discord/discord-bot.js +15 -5
- package/dist/discord/discord-bot.js.map +1 -1
- package/dist/memory/memory-manager.js +10 -5
- package/dist/memory/memory-manager.js.map +1 -1
- package/dist/scripts/debug-cli.js +7 -34
- package/dist/scripts/debug-cli.js.map +1 -1
- package/dist/supervisor/cron-service.d.ts +21 -0
- package/dist/supervisor/cron-service.js +105 -0
- package/dist/supervisor/cron-service.js.map +1 -0
- package/dist/supervisor/gemini-engine.d.ts +52 -0
- package/dist/supervisor/gemini-engine.js +380 -0
- package/dist/supervisor/gemini-engine.js.map +1 -0
- package/dist/supervisor/heartbeat-service.d.ts +1 -11
- package/dist/supervisor/heartbeat-service.js +8 -84
- package/dist/supervisor/heartbeat-service.js.map +1 -1
- package/dist/supervisor/main.js +8 -34
- package/dist/supervisor/main.js.map +1 -1
- package/dist/supervisor/session-manager.js +16 -15
- package/dist/supervisor/session-manager.js.map +1 -1
- package/dist/supervisor/supervisor.d.ts +5 -6
- package/dist/supervisor/supervisor.js +20 -24
- package/dist/supervisor/supervisor.js.map +1 -1
- package/dist/types/index.d.ts +4 -0
- package/extensions/memory/dist/store.js +39 -6
- package/extensions/memory/dist/store.js.map +1 -1
- package/extensions/memory/src/store.ts +45 -6
- package/extensions/memory/tsconfig.json +2 -1
- package/extensions/tasks/tsconfig.json +2 -1
- package/package.json +7 -3
- package/src/prompts/system.md +12 -0
- package/dist/supervisor/gemini-cli.d.ts +0 -17
- package/dist/supervisor/gemini-cli.js +0 -193
- package/dist/supervisor/gemini-cli.js.map +0 -1
|
@@ -1,48 +1,21 @@
|
|
|
1
1
|
import { Config } from '../config/config.js';
|
|
2
|
-
import {
|
|
3
|
-
import { execSync } from 'child_process';
|
|
2
|
+
import { GeminiEngine } from '../supervisor/gemini-engine.js';
|
|
4
3
|
async function main() {
|
|
5
|
-
console.log('🔍 Starting Debug CLI...');
|
|
6
|
-
console.log(`PATH: ${process.env.PATH}`);
|
|
7
|
-
try {
|
|
8
|
-
const geminiPath = execSync('which gemini').toString().trim();
|
|
9
|
-
console.log(`✅ Found gemini at: ${geminiPath}`);
|
|
10
|
-
}
|
|
11
|
-
catch (e) {
|
|
12
|
-
console.warn('⚠️ Could not find gemini in PATH');
|
|
13
|
-
}
|
|
4
|
+
console.log('🔍 Starting Debug CLI (Native)...');
|
|
14
5
|
const config = Config.getInstance();
|
|
15
6
|
console.log(`🏠 Home Dir: ${config.homeDir}`);
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
const engine = new GeminiEngine(config);
|
|
8
|
+
await engine.initialize();
|
|
9
|
+
const prompt = process.argv[2] || 'write a haiku';
|
|
10
|
+
console.log(`🚀 Running prompt: "${prompt}"`);
|
|
19
11
|
try {
|
|
20
|
-
await
|
|
12
|
+
await engine.run(prompt, (event) => {
|
|
21
13
|
console.log('--------------------------------------------------');
|
|
22
14
|
console.log(`📨 Event Type: ${event.type}`);
|
|
23
15
|
console.log(`📝 Raw Event: ${JSON.stringify(event, null, 2)}`);
|
|
24
|
-
if (event.sessionId) {
|
|
25
|
-
console.log(`✅ Session ID found in event: ${event.sessionId}`);
|
|
26
|
-
if (!capturedSessionId)
|
|
27
|
-
capturedSessionId = event.sessionId;
|
|
28
|
-
}
|
|
29
|
-
if (event.type === 'init') {
|
|
30
|
-
if (event.session_id) {
|
|
31
|
-
console.log(`✅ Session ID found in init (snake_case): ${event.session_id}`);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
console.warn('⚠️ No session_id in init event!');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
16
|
});
|
|
38
17
|
console.log('--------------------------------------------------');
|
|
39
18
|
console.log('✅ Run complete.');
|
|
40
|
-
if (capturedSessionId) {
|
|
41
|
-
console.log(`🎉 Final Session ID captured: ${capturedSessionId}`);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
console.error('❌ NO SESSION ID CAPTURED during run.');
|
|
45
|
-
}
|
|
46
19
|
}
|
|
47
20
|
catch (error) {
|
|
48
21
|
console.error('❌ Error during run:', error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug-cli.js","sourceRoot":"","sources":["../../src/scripts/debug-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"debug-cli.js","sourceRoot":"","sources":["../../src/scripts/debug-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAG9D,KAAK,UAAU,IAAI;IACf,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;IAEjD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IAE9C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;IAE1B,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,uBAAuB,MAAM,GAAG,CAAC,CAAC;IAE9C,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC/B,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;YAClE,OAAO,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Supervisor } from './supervisor.js';
|
|
2
|
+
import { Config } from '../config/config.js';
|
|
3
|
+
/**
|
|
4
|
+
* CronService - Dedicated operator for scheduled tasks.
|
|
5
|
+
* Runs on a tight interval to ensure precisely timed execution.
|
|
6
|
+
*/
|
|
7
|
+
export declare class CronService {
|
|
8
|
+
private readonly supervisor;
|
|
9
|
+
private readonly config;
|
|
10
|
+
private interval;
|
|
11
|
+
private isExecuting;
|
|
12
|
+
private static readonly POLL_INTERVAL_MS;
|
|
13
|
+
constructor(supervisor: Supervisor, config: Config);
|
|
14
|
+
start(): Promise<void>;
|
|
15
|
+
stop(): void;
|
|
16
|
+
private tick;
|
|
17
|
+
private runTask;
|
|
18
|
+
private calculateNextRun;
|
|
19
|
+
private loadTasks;
|
|
20
|
+
private saveTasks;
|
|
21
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import logger from '../utils/logger.js';
|
|
3
|
+
import { CronExpressionParser } from 'cron-parser';
|
|
4
|
+
/**
|
|
5
|
+
* CronService - Dedicated operator for scheduled tasks.
|
|
6
|
+
* Runs on a tight interval to ensure precisely timed execution.
|
|
7
|
+
*/
|
|
8
|
+
export class CronService {
|
|
9
|
+
supervisor;
|
|
10
|
+
config;
|
|
11
|
+
interval = null;
|
|
12
|
+
isExecuting = false;
|
|
13
|
+
static POLL_INTERVAL_MS = 60 * 1000; // Check every minute
|
|
14
|
+
constructor(supervisor, config) {
|
|
15
|
+
this.supervisor = supervisor;
|
|
16
|
+
this.config = config;
|
|
17
|
+
}
|
|
18
|
+
async start() {
|
|
19
|
+
logger.info(`⏰ Cron service started (Precision: ${CronService.POLL_INTERVAL_MS / 1000}s)`);
|
|
20
|
+
// Start the polling loop
|
|
21
|
+
this.interval = setInterval(() => this.tick(), CronService.POLL_INTERVAL_MS);
|
|
22
|
+
// Initial tick to catch any tasks immediately
|
|
23
|
+
this.tick();
|
|
24
|
+
}
|
|
25
|
+
stop() {
|
|
26
|
+
if (this.interval) {
|
|
27
|
+
clearInterval(this.interval);
|
|
28
|
+
this.interval = null;
|
|
29
|
+
}
|
|
30
|
+
logger.info('⏰ Cron service stopped');
|
|
31
|
+
}
|
|
32
|
+
async tick() {
|
|
33
|
+
if (this.isExecuting)
|
|
34
|
+
return;
|
|
35
|
+
this.isExecuting = true;
|
|
36
|
+
try {
|
|
37
|
+
const tasks = await this.loadTasks();
|
|
38
|
+
const now = new Date();
|
|
39
|
+
const dueTasks = tasks.filter((t) => t.enabled && new Date(t.nextRun) <= now);
|
|
40
|
+
if (dueTasks.length > 0) {
|
|
41
|
+
logger.info(`⏰ Cron: Found ${dueTasks.length} due tasks`);
|
|
42
|
+
for (const task of dueTasks) {
|
|
43
|
+
await this.runTask(task);
|
|
44
|
+
}
|
|
45
|
+
await this.saveTasks(tasks);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger.error(`❌ Cron service tick error: ${error.message}`);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
this.isExecuting = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async runTask(task) {
|
|
56
|
+
logger.info(`🚀 [CRON] Running task: ${task.title} (${task.id})`);
|
|
57
|
+
try {
|
|
58
|
+
// Tasks run in their own ephemeral session within the engine
|
|
59
|
+
const result = await this.supervisor.executeTask(task.prompt);
|
|
60
|
+
logger.info(`✅ [CRON] Task ${task.id} completed. Result length: ${result.length}`);
|
|
61
|
+
task.lastRun = new Date().toISOString();
|
|
62
|
+
task.failedCount = 0;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
logger.error(`❌ [CRON] Task ${task.id} failed: ${error.message}`);
|
|
66
|
+
task.failedCount++;
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
// Calculate next run
|
|
70
|
+
task.nextRun = this.calculateNextRun(task.schedule);
|
|
71
|
+
task.updatedAt = new Date().toISOString();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
calculateNextRun(schedule) {
|
|
75
|
+
try {
|
|
76
|
+
const interval = CronExpressionParser.parse(schedule);
|
|
77
|
+
const next = interval.next().toISOString();
|
|
78
|
+
return next || new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
const date = new Date(schedule);
|
|
82
|
+
if (!isNaN(date.getTime()) && schedule.includes('-')) {
|
|
83
|
+
return date.toISOString();
|
|
84
|
+
}
|
|
85
|
+
logger.warn(`⚠️ [CRON] Unrecognized schedule format: "${schedule}". Falling back to 24h.`);
|
|
86
|
+
return new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
async loadTasks() {
|
|
90
|
+
try {
|
|
91
|
+
const data = await fs.readFile(this.config.taskFilePath, 'utf-8');
|
|
92
|
+
return JSON.parse(data);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error.code === 'ENOENT')
|
|
96
|
+
return [];
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async saveTasks(tasks) {
|
|
101
|
+
const data = JSON.stringify(tasks, null, 2);
|
|
102
|
+
await fs.writeFile(this.config.taskFilePath, data, 'utf-8');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=cron-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cron-service.js","sourceRoot":"","sources":["../../src/supervisor/cron-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { EventEmitter } from 'events';
|
|
2
|
+
import { Config as TarsConfig } from '../config/config.js';
|
|
3
|
+
import { AttachmentContext } from '../types/index.js';
|
|
4
|
+
export interface GeminiEngineEvent {
|
|
5
|
+
type: string;
|
|
6
|
+
role?: 'user' | 'assistant' | 'system';
|
|
7
|
+
content?: string;
|
|
8
|
+
toolName?: string;
|
|
9
|
+
toolArgs?: any;
|
|
10
|
+
usageStats?: {
|
|
11
|
+
inputTokens: number;
|
|
12
|
+
outputTokens: number;
|
|
13
|
+
cachedTokens: number;
|
|
14
|
+
};
|
|
15
|
+
sessionId?: string;
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export type GeminiEngineOutputHandler = (event: GeminiEngineEvent) => void;
|
|
19
|
+
/**
|
|
20
|
+
* GeminiEngine - Native replacement for GeminiCli subprocess
|
|
21
|
+
*
|
|
22
|
+
* Uses @google/gemini-cli-core directly to interact with Gemini models.
|
|
23
|
+
* Operates within the ~/.tars isolated environment by overriding HOME.
|
|
24
|
+
*/
|
|
25
|
+
export declare class GeminiEngine extends EventEmitter {
|
|
26
|
+
private readonly tarsConfig;
|
|
27
|
+
private coreConfig;
|
|
28
|
+
private client;
|
|
29
|
+
private initialized;
|
|
30
|
+
private currentSessionId;
|
|
31
|
+
constructor(tarsConfig: TarsConfig);
|
|
32
|
+
/**
|
|
33
|
+
* Initializes the core Gemini client with proper auth and config.
|
|
34
|
+
*/
|
|
35
|
+
initialize(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Executes a prompt and streams events back.
|
|
38
|
+
*/
|
|
39
|
+
run(prompt: string, onEvent: GeminiEngineOutputHandler, sessionId?: string, attachments?: AttachmentContext[]): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Synchronous-style run for background tasks.
|
|
42
|
+
*/
|
|
43
|
+
runSync(prompt: string, sessionId?: string): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Maps native core events to Tars-compatible event format.
|
|
46
|
+
*/
|
|
47
|
+
private normalizeEvent;
|
|
48
|
+
/**
|
|
49
|
+
* Attempts to find and load session history from the Core's history directory.
|
|
50
|
+
*/
|
|
51
|
+
private loadResumedSessionData;
|
|
52
|
+
}
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
import { Config as CoreConfig, GeminiEventType, AuthType, promptIdContext, Scheduler, ApprovalMode, PolicyDecision } from '@google/gemini-cli-core';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import logger from '../utils/logger.js';
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
/**
|
|
8
|
+
* Detects the best authentication type based on environment variables.
|
|
9
|
+
* (Local implementation since it's not exported from core index)
|
|
10
|
+
*/
|
|
11
|
+
function getAuthTypeFromEnv() {
|
|
12
|
+
if (process.env['GOOGLE_GENAI_USE_GCA'] === 'true') {
|
|
13
|
+
return AuthType.LOGIN_WITH_GOOGLE;
|
|
14
|
+
}
|
|
15
|
+
if (process.env['GOOGLE_GENAI_USE_VERTEXAI'] === 'true') {
|
|
16
|
+
return AuthType.USE_VERTEX_AI;
|
|
17
|
+
}
|
|
18
|
+
if (process.env['GEMINI_API_KEY']) {
|
|
19
|
+
return AuthType.USE_GEMINI;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* GeminiEngine - Native replacement for GeminiCli subprocess
|
|
25
|
+
*
|
|
26
|
+
* Uses @google/gemini-cli-core directly to interact with Gemini models.
|
|
27
|
+
* Operates within the ~/.tars isolated environment by overriding HOME.
|
|
28
|
+
*/
|
|
29
|
+
export class GeminiEngine extends EventEmitter {
|
|
30
|
+
tarsConfig;
|
|
31
|
+
coreConfig;
|
|
32
|
+
client;
|
|
33
|
+
initialized = false;
|
|
34
|
+
currentSessionId = null;
|
|
35
|
+
constructor(tarsConfig) {
|
|
36
|
+
super();
|
|
37
|
+
this.tarsConfig = tarsConfig;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Initializes the core Gemini client with proper auth and config.
|
|
41
|
+
*/
|
|
42
|
+
async initialize() {
|
|
43
|
+
if (this.initialized)
|
|
44
|
+
return;
|
|
45
|
+
logger.info('🚀 Initializing Gemini Engine (Native Core)...');
|
|
46
|
+
const savedHome = process.env.HOME;
|
|
47
|
+
try {
|
|
48
|
+
// Ensure home directory exists
|
|
49
|
+
if (!fs.existsSync(this.tarsConfig.homeDir)) {
|
|
50
|
+
fs.mkdirSync(this.tarsConfig.homeDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
// Isolating to ~/.tars
|
|
53
|
+
process.env.HOME = this.tarsConfig.homeDir;
|
|
54
|
+
process.env.GEMINI_CLI_HOME = this.tarsConfig.homeDir;
|
|
55
|
+
// Tell the Gemini Core PromptProvider to use our custom system.md
|
|
56
|
+
const systemMdPath = path.join(this.tarsConfig.homeDir, '.gemini', 'system.md');
|
|
57
|
+
process.env.GEMINI_SYSTEM_MD = systemMdPath;
|
|
58
|
+
const authType = getAuthTypeFromEnv() || AuthType.LOGIN_WITH_GOOGLE;
|
|
59
|
+
this.coreConfig = new CoreConfig({
|
|
60
|
+
sessionId: uuidv4(),
|
|
61
|
+
targetDir: this.tarsConfig.homeDir,
|
|
62
|
+
cwd: this.tarsConfig.homeDir,
|
|
63
|
+
model: this.tarsConfig.geminiModel,
|
|
64
|
+
debugMode: false,
|
|
65
|
+
approvalMode: ApprovalMode.YOLO,
|
|
66
|
+
policyEngineConfig: {
|
|
67
|
+
defaultDecision: PolicyDecision.ALLOW
|
|
68
|
+
},
|
|
69
|
+
interactive: true,
|
|
70
|
+
enableHooks: true,
|
|
71
|
+
mcpEnabled: true,
|
|
72
|
+
extensionsEnabled: true,
|
|
73
|
+
enableAgents: true, // Enable agents support
|
|
74
|
+
skillsSupport: true,
|
|
75
|
+
adminSkillsEnabled: true,
|
|
76
|
+
noBrowser: true
|
|
77
|
+
});
|
|
78
|
+
await this.coreConfig.refreshAuth(authType);
|
|
79
|
+
await this.coreConfig.initialize();
|
|
80
|
+
this.client = this.coreConfig.getGeminiClient();
|
|
81
|
+
this.initialized = true;
|
|
82
|
+
this.currentSessionId = this.coreConfig.getSessionId();
|
|
83
|
+
logger.info('✨ Gemini Engine initialized successfully.');
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
logger.error(`❌ Failed to initialize Gemini Engine: ${error.message}`);
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
process.env.HOME = savedHome;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Executes a prompt and streams events back.
|
|
95
|
+
*/
|
|
96
|
+
async run(prompt, onEvent, sessionId, attachments) {
|
|
97
|
+
if (!this.initialized) {
|
|
98
|
+
await this.initialize();
|
|
99
|
+
}
|
|
100
|
+
const sid = sessionId || this.coreConfig.getSessionId();
|
|
101
|
+
const savedHome = process.env.HOME;
|
|
102
|
+
try {
|
|
103
|
+
process.env.HOME = this.tarsConfig.homeDir;
|
|
104
|
+
process.env.GEMINI_CLI_HOME = this.tarsConfig.homeDir;
|
|
105
|
+
// Session Swapping Logic or First Run
|
|
106
|
+
// We must call startChat at least once to initialize the GeminiChat session,
|
|
107
|
+
// even if the sessionId matches the coreConfig's initial ID.
|
|
108
|
+
if (this.currentSessionId !== sid || !this.client.isInitialized()) {
|
|
109
|
+
logger.debug(`🔄 Initializing/Swapping Gemini session to: ${sid}`);
|
|
110
|
+
const resumedData = await this.loadResumedSessionData(sid);
|
|
111
|
+
// @ts-ignore - access private to swap session
|
|
112
|
+
await this.client.startChat(undefined, resumedData || undefined);
|
|
113
|
+
this.currentSessionId = sid;
|
|
114
|
+
}
|
|
115
|
+
let currentRequestParts = [{ text: prompt }];
|
|
116
|
+
// Handle Multimodal Attachments
|
|
117
|
+
if (attachments && attachments.length > 0) {
|
|
118
|
+
for (const attachment of attachments) {
|
|
119
|
+
try {
|
|
120
|
+
const data = fs.readFileSync(attachment.path).toString('base64');
|
|
121
|
+
currentRequestParts.push({
|
|
122
|
+
inlineData: {
|
|
123
|
+
data,
|
|
124
|
+
mimeType: attachment.mimeType
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
logger.debug(`📎 Attached file to prompt: ${attachment.path} (${attachment.mimeType})`);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
logger.error(`Failed to read attachment ${attachment.path}: ${err.message}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
let turnCount = 0;
|
|
135
|
+
const maxTurns = 50; // Increased to handle complex autonomous tasks
|
|
136
|
+
const abortController = new AbortController();
|
|
137
|
+
let finalUsageStats = undefined;
|
|
138
|
+
while (turnCount < maxTurns) {
|
|
139
|
+
turnCount++;
|
|
140
|
+
const toolRequests = [];
|
|
141
|
+
let hasRealContent = false;
|
|
142
|
+
const stream = await promptIdContext.run(sid, () => {
|
|
143
|
+
return this.client.sendMessageStream(currentRequestParts, abortController.signal, 'tars-request' // Proper promptId
|
|
144
|
+
);
|
|
145
|
+
});
|
|
146
|
+
for await (const event of stream) {
|
|
147
|
+
logger.debug(`📨 Raw Gemini Event [Turn ${turnCount}]: ${JSON.stringify(event).substring(0, 200)}...`);
|
|
148
|
+
if (event.type === GeminiEventType.ToolCallRequest) {
|
|
149
|
+
toolRequests.push(event.value);
|
|
150
|
+
}
|
|
151
|
+
if (event.type === GeminiEventType.Finished) {
|
|
152
|
+
finalUsageStats = event.value.usageMetadata;
|
|
153
|
+
continue; // Don't emit done yet
|
|
154
|
+
}
|
|
155
|
+
const normalized = this.normalizeEvent(event, sid);
|
|
156
|
+
if (normalized) {
|
|
157
|
+
if (normalized.type === 'text' && normalized.content) {
|
|
158
|
+
hasRealContent = true;
|
|
159
|
+
}
|
|
160
|
+
onEvent(normalized);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (toolRequests.length === 0) {
|
|
164
|
+
logger.debug(`✅ Interaction complete after ${turnCount} turns.`);
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (turnCount >= maxTurns) {
|
|
168
|
+
logger.warn(`⚠️ Hit maxTurns (${maxTurns}) limit. Force terminating interaction.`);
|
|
169
|
+
onEvent({
|
|
170
|
+
type: 'text',
|
|
171
|
+
role: 'assistant',
|
|
172
|
+
content: '\n\n⚠️ *Task was complex and reached the maximum turn limit. I have executed as much as I could.*',
|
|
173
|
+
sessionId: sid
|
|
174
|
+
});
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
logger.debug(`🛠️ Executing ${toolRequests.length} tool calls...`);
|
|
178
|
+
// Execute tools using Scheduler
|
|
179
|
+
const scheduler = new Scheduler({
|
|
180
|
+
config: this.coreConfig,
|
|
181
|
+
messageBus: this.coreConfig.getMessageBus(),
|
|
182
|
+
getPreferredEditor: () => undefined,
|
|
183
|
+
schedulerId: sid
|
|
184
|
+
});
|
|
185
|
+
const completedCalls = await scheduler.schedule(toolRequests, abortController.signal);
|
|
186
|
+
// Emit tool responses so the Supervisor can log them
|
|
187
|
+
for (const call of completedCalls) {
|
|
188
|
+
const normalized = this.normalizeEvent({
|
|
189
|
+
type: GeminiEventType.ToolCallResponse,
|
|
190
|
+
value: call
|
|
191
|
+
}, sid);
|
|
192
|
+
if (normalized)
|
|
193
|
+
onEvent(normalized);
|
|
194
|
+
}
|
|
195
|
+
// Record results in chat recording service for persistence/memory
|
|
196
|
+
const model = this.tarsConfig.geminiModel;
|
|
197
|
+
this.client.getChat().recordCompletedToolCalls(model, completedCalls);
|
|
198
|
+
// Prepare next request with tool results
|
|
199
|
+
currentRequestParts = completedCalls
|
|
200
|
+
.map((call) => {
|
|
201
|
+
// Extract the functionResponse part
|
|
202
|
+
return call.response.responseParts.find((p) => 'functionResponse' in p);
|
|
203
|
+
})
|
|
204
|
+
.filter(Boolean);
|
|
205
|
+
if (currentRequestParts.length === 0) {
|
|
206
|
+
logger.warn('⚠️ No tool responses generated after execution.');
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Always emit final done event when exiting the loop
|
|
211
|
+
onEvent({
|
|
212
|
+
type: 'done',
|
|
213
|
+
usageStats: finalUsageStats
|
|
214
|
+
? {
|
|
215
|
+
inputTokens: finalUsageStats.promptTokenCount || 0,
|
|
216
|
+
outputTokens: finalUsageStats.candidatesTokenCount || 0,
|
|
217
|
+
cachedTokens: finalUsageStats.cachedContentTokenCount || 0
|
|
218
|
+
}
|
|
219
|
+
: undefined,
|
|
220
|
+
sessionId: sid
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
logger.error(`❌ Gemini Engine run error: ${error.message}`);
|
|
225
|
+
onEvent({ type: 'error', error: error.message });
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
finally {
|
|
229
|
+
process.env.HOME = savedHome;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Synchronous-style run for background tasks.
|
|
234
|
+
*/
|
|
235
|
+
async runSync(prompt, sessionId) {
|
|
236
|
+
let fullContent = '';
|
|
237
|
+
await this.run(prompt, (event) => {
|
|
238
|
+
if (event.content && event.role === 'assistant') {
|
|
239
|
+
fullContent += event.content;
|
|
240
|
+
}
|
|
241
|
+
}, sessionId);
|
|
242
|
+
return fullContent;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Maps native core events to Tars-compatible event format.
|
|
246
|
+
*/
|
|
247
|
+
normalizeEvent(event, sessionId) {
|
|
248
|
+
switch (event.type) {
|
|
249
|
+
case GeminiEventType.Content:
|
|
250
|
+
return {
|
|
251
|
+
type: 'text',
|
|
252
|
+
role: 'assistant',
|
|
253
|
+
content: event.value,
|
|
254
|
+
sessionId
|
|
255
|
+
};
|
|
256
|
+
case GeminiEventType.Thought:
|
|
257
|
+
// ThoughtSummary has subject and description
|
|
258
|
+
const thoughtText = event.value.subject
|
|
259
|
+
? `**${event.value.subject}** ${event.value.description}`
|
|
260
|
+
: event.value.description;
|
|
261
|
+
return {
|
|
262
|
+
type: 'thought',
|
|
263
|
+
content: thoughtText,
|
|
264
|
+
sessionId
|
|
265
|
+
};
|
|
266
|
+
case GeminiEventType.ToolCallRequest:
|
|
267
|
+
return {
|
|
268
|
+
type: 'tool_call',
|
|
269
|
+
toolName: event.value.name,
|
|
270
|
+
toolArgs: event.value.args,
|
|
271
|
+
sessionId
|
|
272
|
+
};
|
|
273
|
+
case GeminiEventType.ToolCallResponse:
|
|
274
|
+
// resultDisplay can be string | FileDiff | AnsiOutput | TodoList
|
|
275
|
+
const display = event.value.resultDisplay;
|
|
276
|
+
let content = '';
|
|
277
|
+
if (typeof display === 'string') {
|
|
278
|
+
content = display;
|
|
279
|
+
}
|
|
280
|
+
else if (display) {
|
|
281
|
+
content = JSON.stringify(display);
|
|
282
|
+
}
|
|
283
|
+
else if (event.value.error) {
|
|
284
|
+
content = event.value.error.message;
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
type: 'tool_response',
|
|
288
|
+
toolName: event.value.callId,
|
|
289
|
+
content,
|
|
290
|
+
sessionId
|
|
291
|
+
};
|
|
292
|
+
case GeminiEventType.Finished:
|
|
293
|
+
return {
|
|
294
|
+
type: 'done',
|
|
295
|
+
usageStats: event.value.usageMetadata
|
|
296
|
+
? {
|
|
297
|
+
inputTokens: event.value.usageMetadata.promptTokenCount || 0,
|
|
298
|
+
outputTokens: event.value.usageMetadata.candidatesTokenCount || 0,
|
|
299
|
+
cachedTokens: event.value.usageMetadata.cachedContentTokenCount || 0
|
|
300
|
+
}
|
|
301
|
+
: undefined,
|
|
302
|
+
sessionId
|
|
303
|
+
};
|
|
304
|
+
case GeminiEventType.Error:
|
|
305
|
+
return {
|
|
306
|
+
type: 'error',
|
|
307
|
+
error: event.value instanceof Error ? event.value.message : String(event.value),
|
|
308
|
+
sessionId
|
|
309
|
+
};
|
|
310
|
+
default:
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Attempts to find and load session history from the Core's history directory.
|
|
316
|
+
*/
|
|
317
|
+
async loadResumedSessionData(sessionId) {
|
|
318
|
+
try {
|
|
319
|
+
// Core history is usually in ~/.gemini/tmp/<hash>/chats/
|
|
320
|
+
// But we isolated HOME to ~/.tars, so it's in ~/.tars/.gemini/...
|
|
321
|
+
const projectRoot = this.tarsConfig.homeDir;
|
|
322
|
+
const geminiDir = path.join(this.tarsConfig.homeDir, '.gemini');
|
|
323
|
+
const tmpDir = path.join(geminiDir, 'tmp');
|
|
324
|
+
if (!fs.existsSync(tmpDir))
|
|
325
|
+
return null;
|
|
326
|
+
// 1. Try to find the exact project identifier from projects.json
|
|
327
|
+
let projectIdentifier = null;
|
|
328
|
+
const registryPath = path.join(geminiDir, 'projects.json');
|
|
329
|
+
if (fs.existsSync(registryPath)) {
|
|
330
|
+
try {
|
|
331
|
+
const registry = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
|
|
332
|
+
projectIdentifier = registry.projects[projectRoot] || null;
|
|
333
|
+
}
|
|
334
|
+
catch (e) {
|
|
335
|
+
logger.warn(`⚠️ Failed to read projects.json: ${e}`);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
// 2. Fallback: MD5 hash (used in some versions)
|
|
339
|
+
if (!projectIdentifier) {
|
|
340
|
+
const crypto = await import('node:crypto');
|
|
341
|
+
projectIdentifier = crypto.createHash('md5').update(projectRoot).digest('hex');
|
|
342
|
+
}
|
|
343
|
+
// 3. Search for the session file in candidate directories
|
|
344
|
+
// We search projectIdentifier first, then scan all if not found
|
|
345
|
+
const searchDirs = [projectIdentifier];
|
|
346
|
+
try {
|
|
347
|
+
const allDirs = fs.readdirSync(tmpDir);
|
|
348
|
+
for (const d of allDirs) {
|
|
349
|
+
if (d !== projectIdentifier)
|
|
350
|
+
searchDirs.push(d);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
catch (e) { }
|
|
354
|
+
const shortId = sessionId.slice(0, 8);
|
|
355
|
+
for (const dir of searchDirs) {
|
|
356
|
+
if (!dir)
|
|
357
|
+
continue;
|
|
358
|
+
const chatsDir = path.join(tmpDir, dir, 'chats');
|
|
359
|
+
if (!fs.existsSync(chatsDir))
|
|
360
|
+
continue;
|
|
361
|
+
const files = fs.readdirSync(chatsDir);
|
|
362
|
+
const sessionFile = files.find((f) => f.includes(`-${shortId}.json`));
|
|
363
|
+
if (sessionFile) {
|
|
364
|
+
const filePath = path.join(chatsDir, sessionFile);
|
|
365
|
+
const content = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
366
|
+
return {
|
|
367
|
+
conversation: content,
|
|
368
|
+
filePath
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
catch (e) {
|
|
375
|
+
logger.warn(`⚠️ Failed to load resumed session data: ${e}`);
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
//# sourceMappingURL=gemini-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini-engine.js","sourceRoot":"","sources":["../../src/supervisor/gemini-engine.ts"],"names":[],"mappings":"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"}
|