Version 2.55.0 Release: Rebranding to Astra
This commit is contained in:
+58
-10
@@ -207,7 +207,7 @@ export class AgentExecutor {
|
||||
|
||||
// Decide whether to use Multi-Agent Workflow (for complex requests)
|
||||
const isComplex = prompt && (prompt.length > 100 || /(분석|보고서|설계|기획|정리)/.test(prompt));
|
||||
if (isComplex && loopDepth === 0 && multiAgentEnabled) {
|
||||
if (isComplex && loopDepth === 0 && multiAgentEnabled && !this.isAstraModeArchitectureQuestion(prompt)) {
|
||||
return this.executeMultiAgentWorkflow(prompt!, modelName, options);
|
||||
}
|
||||
|
||||
@@ -293,6 +293,12 @@ export class AgentExecutor {
|
||||
if (projectBriefContext) {
|
||||
contextBlock += `\n\n${projectBriefContext}`;
|
||||
}
|
||||
const modeArchitectureContext = prompt && loopDepth === 0
|
||||
? this.buildAstraModeArchitectureContext(prompt)
|
||||
: '';
|
||||
if (modeArchitectureContext) {
|
||||
contextBlock += `\n\n${modeArchitectureContext}`;
|
||||
}
|
||||
|
||||
// 2. Setup History
|
||||
if (prompt !== null) {
|
||||
@@ -792,6 +798,40 @@ export class AgentExecutor {
|
||||
return /(어떤\s*거?\s*같|어때|어떻게\s*생각|의견|판단|방향|설계|아키텍처|구조|자비스|생각.*정리|갈림길|architecture|design|direction|opinion|think|judge)/i.test(prompt);
|
||||
}
|
||||
|
||||
private isAstraModeArchitectureQuestion(prompt: string): boolean {
|
||||
const mentionsGuard = /\bguard\b|가드|Guard|Chronicle Guard|Project Chronicle/i.test(prompt);
|
||||
const mentionsMultiAgent = /\bMA\b|multi[-\s]?agent|멀티\s*에이전트|다중\s*에이전트|Planner|Researcher|Writer/i.test(prompt);
|
||||
const asksDecision = /(분리|통합|모드|사용|좋을까|맞을까|구조|설계|아키텍처|의견|판단|어때|어떤\s*거?\s*같|separate|combine|mode|architecture|design|opinion)/i.test(prompt);
|
||||
return asksDecision && mentionsGuard && mentionsMultiAgent;
|
||||
}
|
||||
|
||||
private buildAstraModeArchitectureContext(prompt: string): string {
|
||||
if (!this.isAstraModeArchitectureQuestion(prompt)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return [
|
||||
'[ASTRA MODE ARCHITECTURE DECISION CONTEXT]',
|
||||
'The user is asking about Astra itself, specifically whether Guard mode and MA/Multi-Agent mode should remain separate.',
|
||||
'',
|
||||
'Confirmed implementation facts from the current codebase:',
|
||||
'- Guard is currently exposed as a sidebar toggle, but it defaults to enabled in the webview UI.',
|
||||
'- Guard context is built by buildProjectChronicleGuardContext(activeProject) and passed into AgentExecutor as designerContext.',
|
||||
'- In the normal single-agent path, designerContext is injected into the system prompt as [PROJECT CHRONICLE GUARD].',
|
||||
'- In the Multi-Agent path, designerContext is appended as Project Chronicle Guard context for the workflow manager.',
|
||||
'- Multi-Agent is controlled by the g1nation.multiAgentEnabled config and is only used for complex prompts.',
|
||||
'- Current risk: when Multi-Agent starts, it returns early before the normal path builds local project preflight, Second Brain Trace, recent project knowledge context, and thinking-partner context.',
|
||||
'',
|
||||
'Product decision guidance:',
|
||||
'- Do not treat Guard and MA as two equal user-facing modes.',
|
||||
'- Guard should be an always-on policy/context layer: project target, evidence discipline, record hygiene, tone, and decision logging.',
|
||||
'- MA should be an optional execution strategy chosen automatically for genuinely complex tasks.',
|
||||
'- Recommended UX: hide or de-emphasize the Guard toggle, show it as Auto/On by default, and let Astra route between single-agent and MA internally.',
|
||||
'- Recommended answer: give a clear verdict that separating them as peer modes is not ideal; separate them internally by responsibility instead.',
|
||||
'- Mention the concrete risk that MA can currently bypass richer context assembly, so unifying the context preparation before routing is the next engineering step.'
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
private buildJarvisProjectBriefContext(prompt: string, localPathContext: string, recentProjectKnowledgeContext: string): string {
|
||||
if (!this.isThinkingPartnerRequest(prompt)) {
|
||||
return '';
|
||||
@@ -1102,6 +1142,7 @@ export class AgentExecutor {
|
||||
private buildProjectKnowledgeFallbackAnswer(localPathContext: string, record?: { filePath: string; relativePath: string } | null): string {
|
||||
const pathMatch = localPathContext.match(/Path:\s*(.+)/);
|
||||
const projectPath = pathMatch?.[1]?.trim() || '제공된 로컬 프로젝트 경로';
|
||||
const projectDisplayName = this.getProjectDisplayName(projectPath);
|
||||
const treeMatch = localPathContext.match(/Scanned tree:\n([\s\S]*?)(?:\nPriority file previews:|$)/);
|
||||
const treePreview = treeMatch?.[1]?.trim().split('\n').slice(0, 18).join('\n') || '';
|
||||
const priorityMatches = this.extractPriorityPreviewFiles(localPathContext).slice(0, 10);
|
||||
@@ -1123,10 +1164,10 @@ export class AgentExecutor {
|
||||
'',
|
||||
'## 바로 만들 지식 초안',
|
||||
'```markdown',
|
||||
'# ConnectAI Project Knowledge Overview',
|
||||
`# ${projectDisplayName} Project Knowledge Overview`,
|
||||
'',
|
||||
'## Purpose',
|
||||
'ConnectAI는 VS Code 안에서 로컬 AI 에이전트, Second Brain, 프로젝트 기록, 에이전트 스킬을 연결하는 개발 보조 프로젝트다.',
|
||||
`${projectDisplayName}는 VS Code 안에서 로컬 AI 에이전트, Second Brain, 프로젝트 기록, 에이전트 스킬을 연결하는 개발 보조 프로젝트다.`,
|
||||
'',
|
||||
'## Confirmed Structure',
|
||||
'- `src/agent.ts`: 에이전트 실행, 로컬 경로 프리플라이트, Second Brain Trace, 액션 실행 흐름의 중심.',
|
||||
@@ -1140,7 +1181,7 @@ export class AgentExecutor {
|
||||
'- 전체 아키텍처는 파일 구조와 일부 프리뷰 기준으로 파악 가능하지만, 세부 동작 지식은 `src/agent.ts`, `src/sidebarProvider.ts`, `secondBrainTrace.ts`, `projectChronicle` 순서로 심화 분석해 보강해야 한다.',
|
||||
'',
|
||||
'## Recommended Next Record',
|
||||
'- `docs/records/ConnectAI/development/YYYY-MM-DD_connectai_project_knowledge_overview.md`',
|
||||
`- \`docs/records/${path.basename(projectPath)}/development/YYYY-MM-DD_${projectDisplayName.toLowerCase()}_project_knowledge_overview.md\``,
|
||||
'```',
|
||||
'',
|
||||
'## 다음 액션',
|
||||
@@ -1170,8 +1211,9 @@ export class AgentExecutor {
|
||||
|
||||
try {
|
||||
const projectName = path.basename(projectPath);
|
||||
const projectDisplayName = this.getProjectDisplayName(projectPath);
|
||||
const today = new Date().toISOString().slice(0, 10);
|
||||
const slug = projectName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'project';
|
||||
const slug = projectDisplayName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') || 'project';
|
||||
const relativePath = path.join('docs', 'records', projectName, 'development', `${today}_${slug}_project_knowledge_overview.md`);
|
||||
const filePath = path.join(projectPath, relativePath);
|
||||
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
||||
@@ -1187,19 +1229,20 @@ export class AgentExecutor {
|
||||
const pathMatch = localPathContext.match(/Path:\s*(.+)/);
|
||||
const projectPath = pathMatch?.[1]?.trim() || 'Unknown project path';
|
||||
const projectName = path.basename(projectPath);
|
||||
const projectDisplayName = this.getProjectDisplayName(projectPath);
|
||||
const treeMatch = localPathContext.match(/Scanned tree:\n([\s\S]*?)(?:\nPriority file previews:|$)/);
|
||||
const treePreview = treeMatch?.[1]?.trim().split('\n').slice(0, 80).join('\n') || '';
|
||||
const priorityFiles = this.extractPriorityPreviewFiles(localPathContext);
|
||||
|
||||
return [
|
||||
`# ${projectName} Project Knowledge Overview`,
|
||||
`# ${projectDisplayName} Project Knowledge Overview`,
|
||||
'',
|
||||
`Date: ${new Date().toISOString()}`,
|
||||
`Project: ${projectName}`,
|
||||
`Project: ${projectDisplayName}`,
|
||||
`Repository: \`${projectPath}\``,
|
||||
'',
|
||||
'## Purpose',
|
||||
`${projectName}는 VS Code 안에서 로컬 AI 에이전트, Second Brain, 프로젝트 기록, 에이전트 스킬을 연결하는 개발 보조 프로젝트다.`,
|
||||
`${projectDisplayName}는 VS Code 안에서 로컬 AI 에이전트, Second Brain, 프로젝트 기록, 에이전트 스킬을 연결하는 개발 보조 프로젝트다.`,
|
||||
'',
|
||||
'## Confirmed Structure',
|
||||
'- `src/agent.ts`: 에이전트 실행, 로컬 경로 프리플라이트, Second Brain Trace, 액션 실행 흐름의 중심.',
|
||||
@@ -1227,6 +1270,11 @@ export class AgentExecutor {
|
||||
].join('\n');
|
||||
}
|
||||
|
||||
private getProjectDisplayName(projectPath: string): string {
|
||||
const projectName = path.basename(projectPath);
|
||||
return /^connectai$/i.test(projectName) ? 'Astra' : projectName;
|
||||
}
|
||||
|
||||
private listProjectTree(root: string, current: string, depth: number, maxDepth: number, limit: number): string {
|
||||
if (limit <= 0 || depth > maxDepth) {
|
||||
return '';
|
||||
@@ -1646,7 +1694,7 @@ export class AgentExecutor {
|
||||
const cmd = match[1].trim();
|
||||
try {
|
||||
const safeCmd = sanitizeCommand(cmd);
|
||||
const terminal = vscode.window.terminals.find(t => t.name === 'G1nation Terminal') || vscode.window.createTerminal({ name: 'G1nation Terminal', cwd: rootPath });
|
||||
const terminal = vscode.window.terminals.find(t => t.name === 'Astra Terminal') || vscode.window.createTerminal({ name: 'Astra Terminal', cwd: rootPath });
|
||||
terminal.show();
|
||||
terminal.sendText(safeCmd);
|
||||
report.push(`🚀 Executed: ${safeCmd}`);
|
||||
@@ -1766,7 +1814,7 @@ export class AgentExecutor {
|
||||
try {
|
||||
const { execSync } = require('child_process');
|
||||
execSync(`git add .`, { cwd: brainDir });
|
||||
execSync(`git commit -m "[G1nation] Knowledge Update"`, { cwd: brainDir });
|
||||
execSync(`git commit -m "[Astra] Knowledge Update"`, { cwd: brainDir });
|
||||
execSync(`git push`, { cwd: brainDir });
|
||||
} catch (err) {
|
||||
logError('Second Brain sync failed.', err);
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ export interface BridgeInterface {
|
||||
|
||||
/**
|
||||
* BridgeServer:
|
||||
* 외부 툴(EZER, A.U 등)과 G1nation 확장을 연결하는 통신 브릿지.
|
||||
* 외부 툴(EZER, A.U 등)과 Astra 확장을 연결하는 통신 브릿지.
|
||||
* 서비스 레이어(AIService, BrainService)를 통해 비즈니스 로직을 분리하여 유지보수성을 극대화했습니다.
|
||||
*/
|
||||
export class BridgeServer {
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ export class HealthCheckMonitor {
|
||||
|
||||
if (reports.length > 0) {
|
||||
logWarn(`Health Check Warnings: ${reports.join(' | ')}`);
|
||||
vscode.window.showWarningMessage(`ConnectAI Health Warning: ${reports[0]}`);
|
||||
vscode.window.showWarningMessage(`Astra Health Warning: ${reports[0]}`);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -43,7 +43,7 @@ export class StatusBarManager {
|
||||
break;
|
||||
}
|
||||
|
||||
this.statusBarItem.text = `${icon} G1nation: ${status}`;
|
||||
this.statusBarItem.text = `${icon} Astra: ${status}`;
|
||||
this.statusBarItem.tooltip = detail || `Current State: ${status}`;
|
||||
|
||||
if (status === AgentStatus.Success || status === AgentStatus.Error) {
|
||||
|
||||
+5
-5
@@ -18,10 +18,10 @@ import { SidebarChatProvider } from './sidebarProvider';
|
||||
import { HealthCheckMonitor } from './core/health';
|
||||
|
||||
/**
|
||||
* G1nation Extension Entry Point
|
||||
* Astra Extension Entry Point
|
||||
*/
|
||||
export async function activate(context: vscode.ExtensionContext) {
|
||||
logInfo('ConnectAI activating...');
|
||||
logInfo('Astra activating...');
|
||||
|
||||
// Start Environment Health Monitoring
|
||||
HealthCheckMonitor.runAllChecks();
|
||||
@@ -30,7 +30,7 @@ export async function activate(context: vscode.ExtensionContext) {
|
||||
// 0. Validate Configuration
|
||||
const validation = validateConfig();
|
||||
if (!validation.valid) {
|
||||
vscode.window.showErrorMessage(`G1nation Configuration Error: ${validation.errors.join(' ')}`);
|
||||
vscode.window.showErrorMessage(`Astra Configuration Error: ${validation.errors.join(' ')}`);
|
||||
logError('Configuration validation failed.', { errors: validation.errors });
|
||||
}
|
||||
|
||||
@@ -144,12 +144,12 @@ async function _ensureBrainDir(context: vscode.ExtensionContext): Promise<string
|
||||
try {
|
||||
fs.mkdirSync(defaultDir, { recursive: true });
|
||||
// Create a welcome file
|
||||
fs.writeFileSync(path.join(defaultDir, 'Welcome.md'), "# Welcome to your Second Brain\n\nG1nation will store and retrieve knowledge from here.");
|
||||
fs.writeFileSync(path.join(defaultDir, 'Welcome.md'), "# Welcome to your Second Brain\n\nAstra will store and retrieve knowledge from here.");
|
||||
} catch (e) {}
|
||||
}
|
||||
return defaultDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* G1nation Extension Entry Point
|
||||
* Astra Extension Entry Point
|
||||
*/
|
||||
|
||||
@@ -38,6 +38,10 @@ export function buildProjectChronicleGuardContext(project: ProjectProfile | null
|
||||
'- Do not mark a decision as accepted until the user confirms it.',
|
||||
'- Before confirmation, call decisions "candidates" or "pending".',
|
||||
'- Prefer "reduced adoption" when the idea is useful but too large for the MVP.',
|
||||
'- For Astra mode-design questions, do not treat Guard and MA/Multi-Agent as two equal user-facing modes.',
|
||||
'- Treat Guard as a policy/context layer for evidence, project target, record hygiene, and thinking-partner tone.',
|
||||
'- Treat MA/Multi-Agent as an execution strategy that may be selected automatically for complex tasks.',
|
||||
'- If asked whether Guard and MA should be separated, recommend internal responsibility separation but a simpler Auto user experience.',
|
||||
'',
|
||||
'Evidence policy:',
|
||||
'- No Evidence, No Project Claim: do not state that the current project has a technical structure unless it is supported by user-provided facts, source code, design docs, project docs, or project records.',
|
||||
|
||||
+13
-13
@@ -626,7 +626,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
if (!name) return;
|
||||
|
||||
const description = await vscode.window.showInputBox({
|
||||
prompt: 'Optional description shown in the G1nation sidebar',
|
||||
prompt: 'Optional description shown in the Astra sidebar',
|
||||
value: ''
|
||||
});
|
||||
|
||||
@@ -687,7 +687,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
if (!folder) return;
|
||||
|
||||
const description = await vscode.window.showInputBox({
|
||||
prompt: 'Edit optional description shown in the G1nation sidebar',
|
||||
prompt: 'Edit optional description shown in the Astra sidebar',
|
||||
value: target.description || ''
|
||||
});
|
||||
|
||||
@@ -819,7 +819,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
`title: "${this._escapeYamlString(this._summarizeForTitle(firstUserMessage))}"`,
|
||||
`category: "${this._escapeYamlString(meta.category)}"`,
|
||||
`created_at: "${meta.createdAt}"`,
|
||||
`source: "ConnectAI conversation"`,
|
||||
`source: "Astra conversation"`,
|
||||
`brain: "${this._escapeYamlString(meta.activeBrainName)}"`,
|
||||
'status: raw',
|
||||
'---',
|
||||
@@ -874,7 +874,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
|
||||
private _summarizeForTitle(value: string): string {
|
||||
const normalized = value.replace(/\s+/g, ' ').trim();
|
||||
if (!normalized) return 'ConnectAI Conversation Raw Data';
|
||||
if (!normalized) return 'Astra Conversation Raw Data';
|
||||
return normalized.length > 80 ? `${normalized.slice(0, 80)}...` : normalized;
|
||||
}
|
||||
|
||||
@@ -930,7 +930,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
}
|
||||
vscode.window.withProgress({
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: "G1nation: Syncing Second Brain...",
|
||||
title: "Astra: Syncing Second Brain...",
|
||||
cancellable: false
|
||||
}, async () => {
|
||||
try {
|
||||
@@ -1573,7 +1573,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
this._chronicle.appendTimeline(profile, [`Auto ${recordType} record created: ${result.relativePath}`], createdAt);
|
||||
await this._context.globalState.update(SidebarChatProvider.lastAutoChronicleSignatureStateKey, signature);
|
||||
await this._sendChronicleRecords();
|
||||
vscode.window.setStatusBarMessage(`G1nation: Chronicle auto-saved ${recordType}`, 3500);
|
||||
vscode.window.setStatusBarMessage(`Astra: Chronicle auto-saved ${recordType}`, 3500);
|
||||
} catch (err: any) {
|
||||
logError('Automatic Chronicle record write failed.', { error: err?.message || String(err), recordType });
|
||||
}
|
||||
@@ -1944,7 +1944,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>G1nation</title>
|
||||
<title>Astra</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
@@ -2558,7 +2558,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
<body>
|
||||
<div class="header">
|
||||
<div class="header-top">
|
||||
<div class="brand"><div class="logo">✦</div> G1nation</div>
|
||||
<div class="brand"><div class="logo">✦</div> Astra</div>
|
||||
<div class="header-actions">
|
||||
<button class="icon-btn" id="newChatBtn" data-tooltip="New Chat">New</button>
|
||||
<button class="icon-btn" id="saveWikiRawBtn" data-tooltip="Save Wiki Raw">Wiki</button>
|
||||
@@ -2639,7 +2639,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
<div class="chat" id="chat">
|
||||
<div class="welcome">
|
||||
<div class="welcome-logo">✦</div>
|
||||
<div class="welcome-title">Welcome to G1nation</div>
|
||||
<div class="welcome-title">Welcome to Astra</div>
|
||||
<p>Your premium local AI assistant.<br>Ready to analyze projects and build reports.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2686,7 +2686,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
// [State Persistence - Tier 0] 즉시 복원 (Instant Restore from WebView State)
|
||||
const previousState = vscode.getState();
|
||||
if (previousState && previousState.history && previousState.history.length > 0) {
|
||||
console.log('[G1nation] Restoring from Webview State...');
|
||||
console.log('[Astra] Restoring from Webview State...');
|
||||
renderHistory(previousState.history);
|
||||
}
|
||||
|
||||
@@ -2899,7 +2899,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
|
||||
const head = document.createElement('div');
|
||||
head.className = 'msg-head';
|
||||
head.innerHTML = isUser ? '<div class="av av-user">U</div> You' : '<div class="av av-ai">✦</div> G1nation';
|
||||
head.innerHTML = isUser ? '<div class="av av-user">U</div> You' : '<div class="av av-ai">✦</div> Astra';
|
||||
|
||||
const body = document.createElement('div');
|
||||
body.className = 'msg-body markdown-body';
|
||||
@@ -2985,7 +2985,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
historyOverlay.classList.remove('visible');
|
||||
break;
|
||||
case 'clearChat':
|
||||
chat.innerHTML = '<div class="welcome"><div class="welcome-logo">✦</div><div class="welcome-title">Welcome to G1nation</div><p>Your premium local AI assistant.<br>Ready to analyze projects and build reports.</p></div>';
|
||||
chat.innerHTML = '<div class="welcome"><div class="welcome-logo">✦</div><div class="welcome-title">Welcome to Astra</div><p>Your premium local AI assistant.<br>Ready to analyze projects and build reports.</p></div>';
|
||||
break;
|
||||
case 'focusInput':
|
||||
input.focus();
|
||||
@@ -3325,7 +3325,7 @@ export class SidebarChatProvider implements vscode.WebviewViewProvider, BridgeIn
|
||||
try {
|
||||
localStorage.setItem('g1nation_last_model', _selectedModel);
|
||||
} catch(e) {
|
||||
console.warn('[G1nation] LocalStorage 저장 실패:', e);
|
||||
console.warn('[Astra] LocalStorage 저장 실패:', e);
|
||||
}
|
||||
// [State Persistence - Tier 1] VS Code 전역 설정에 동기화 (영구 저장)
|
||||
vscode.postMessage({ type: 'model', value: _selectedModel });
|
||||
|
||||
+3
-2
@@ -7,7 +7,7 @@ import { getConfig, BrainProfile, EXCLUDED_DIRS } from './config';
|
||||
|
||||
export type EngineKind = 'lmstudio' | 'ollama';
|
||||
|
||||
const outputChannel = vscode.window.createOutputChannel('Connect AI');
|
||||
const outputChannel = vscode.window.createOutputChannel('Astra');
|
||||
|
||||
function timestamp() {
|
||||
return new Date().toISOString();
|
||||
@@ -137,7 +137,8 @@ export function findBrainFiles(dir: string): string[] {
|
||||
return results;
|
||||
}
|
||||
|
||||
const BASE_SYSTEM_PROMPT = `You are G1nation, also called Steve when the user asks your name.
|
||||
const BASE_SYSTEM_PROMPT = `You are Astra, a Jarvis-style local project operating assistant.
|
||||
If the user asks your name, say you are Astra.
|
||||
Reply naturally in the user's language.
|
||||
|
||||
Core behavior:
|
||||
|
||||
Reference in New Issue
Block a user