Function bodies 29 total
abortAgent function · typescript · L16-L21 (6 LOC)src/main/agent.ts
export function abortAgent() {
if (currentController) {
currentController.abort();
currentController = null;
}
}createModel function · typescript · L23-L46 (24 LOC)src/main/agent.ts
function createModel(provider: {
providerType: string;
apiKey: string;
model: string;
baseUrl?: string | null;
}): BaseChatModel {
switch (provider.providerType) {
case 'openai':
return new ChatOpenAI({
openAIApiKey: provider.apiKey,
model: provider.model,
...(provider.baseUrl ? { configuration: { baseURL: provider.baseUrl } } : {}),
streaming: true,
});
case 'anthropic':
default:
return new ChatAnthropic({
anthropicApiKey: provider.apiKey,
model: provider.model,
...(provider.baseUrl ? { anthropicApiUrl: provider.baseUrl } : {}),
streaming: true,
});
}
}loadHistory function · typescript · L48-L61 (14 LOC)src/main/agent.ts
function loadHistory(sessionId: string) {
const db = getDb();
const rows = db
.select()
.from(messagesTable)
.where(eq(messagesTable.sessionId, sessionId))
.orderBy(messagesTable.createdAt)
.all();
return rows.map((r) => {
if (r.role === 'human') return new HumanMessage(r.content);
return new AIMessage(r.content);
});
}runAgent function · typescript · L63-L222 (160 LOC)src/main/agent.ts
export async function runAgent(
sessionId: string,
userMessage: string,
mainWindow: BrowserWindow,
tools: StructuredTool[]
) {
const provider = getActiveProvider();
if (!provider?.apiKey) {
mainWindow.webContents.send('agent:error', 'No active provider configured');
return;
}
currentController = new AbortController();
const startTime = Date.now();
let step = 0;
const totalTokens = { input: 0, output: 0 };
try {
const model = createModel(provider);
const boundModel = tools.length > 0 ? model.bindTools(tools) : model;
const callModel = async (state: typeof MessagesAnnotation.State) => {
const response = await boundModel.invoke(state.messages);
return { messages: [response] };
};
const graphBuilder = new StateGraph(MessagesAnnotation)
.addNode('agent', callModel)
.addEdge('__start__', 'agent');
if (tools.length > 0) {
const toolNode = new ToolNode(tools);
graphBuilder
.addNode('tools',getDb function · typescript · L9-L17 (9 LOC)src/main/db.ts
export function getDb() {
if (!_db) {
const dbPath = join(app.getPath('userData'), 'agt-os.db');
const sqlite = new Database(dbPath);
sqlite.pragma('journal_mode = WAL');
_db = drizzle(sqlite, { schema });
}
return _db;
}initDatabase function · typescript · L19-L79 (61 LOC)src/main/db.ts
export function initDatabase() {
const db = getDb();
const sqlite = (db as unknown as { session: { client: Database.Database } }).session.client;
sqlite.exec(`
CREATE TABLE IF NOT EXISTS sessions (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS messages (
id TEXT PRIMARY KEY,
session_id TEXT REFERENCES sessions(id),
role TEXT NOT NULL,
content TEXT NOT NULL,
tool_calls TEXT,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS themes (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
tokens TEXT NOT NULL,
is_dark INTEGER DEFAULT 0
);
CREATE TABLE IF NOT EXISTS trace_logs (
id TEXT PRIMARY KEY,
session_id TEXT REFERENCES sessions(id),
step INTEGER NOT NULL,
tool_name TEXT,
content TEXT NOT NULL,
status TEXT NOT NULL DEFAULT 'success',
error_message TEXT,
token_usage TEXT,
createWindow function · typescript · L15-L31 (17 LOC)src/main/index.ts
async function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 900,
webPreferences: {
preload: join(__dirname, '../preload/index.cjs'),
nodeIntegration: false,
contextIsolation: true,
},
});
if (process.env.VITE_DEV_SERVER_URL) {
mainWindow.loadURL(process.env.VITE_DEV_SERVER_URL);
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'));
}
}Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
PluginLoader class · typescript · L7-L53 (47 LOC)src/main/plugin-loader.ts
export class PluginLoader {
private pluginsPath: string;
private tools: StructuredTool[] = [];
constructor(pluginsPath: string) {
this.pluginsPath = pluginsPath;
}
async loadPlugins() {
if (!fs.existsSync(this.pluginsPath)) {
fs.mkdirSync(this.pluginsPath, { recursive: true });
}
const files = fs.readdirSync(this.pluginsPath);
this.tools = [];
for (const file of files) {
if (file.endsWith('.js') || file.endsWith('.ts')) {
const fullPath = path.resolve(this.pluginsPath, file);
try {
const fileUrl = `${pathToFileURL(fullPath).href}?t=${Date.now()}`;
const plugin = await import(fileUrl);
const manifest = plugin.manifest || plugin.default?.manifest;
const execute = plugin.execute || plugin.default?.execute;
if (manifest && typeof execute === 'function') {
const dynamicTool = tool(
async (input) => execute(input),
{
nameconstructor method · typescript · L11-L13 (3 LOC)src/main/plugin-loader.ts
constructor(pluginsPath: string) {
this.pluginsPath = pluginsPath;
}loadPlugins method · typescript · L15-L48 (34 LOC)src/main/plugin-loader.ts
async loadPlugins() {
if (!fs.existsSync(this.pluginsPath)) {
fs.mkdirSync(this.pluginsPath, { recursive: true });
}
const files = fs.readdirSync(this.pluginsPath);
this.tools = [];
for (const file of files) {
if (file.endsWith('.js') || file.endsWith('.ts')) {
const fullPath = path.resolve(this.pluginsPath, file);
try {
const fileUrl = `${pathToFileURL(fullPath).href}?t=${Date.now()}`;
const plugin = await import(fileUrl);
const manifest = plugin.manifest || plugin.default?.manifest;
const execute = plugin.execute || plugin.default?.execute;
if (manifest && typeof execute === 'function') {
const dynamicTool = tool(
async (input) => execute(input),
{
name: manifest.id,
description: manifest.description,
schema: z.object(manifest.schema),
}
);
this.tools.push(dyasync method · typescript · L34-L39 (6 LOC)src/main/plugin-loader.ts
async (input) => execute(input),
{
name: manifest.id,
description: manifest.description,
schema: z.object(manifest.schema),
}getTools method · typescript · L50-L52 (3 LOC)src/main/plugin-loader.ts
getTools() {
return this.tools;
}getKeysPath function · typescript · L8-L10 (3 LOC)src/main/providers.ts
function getKeysPath() {
return join(app.getPath('userData'), 'provider-keys.json');
}readKeys function · typescript · L12-L20 (9 LOC)src/main/providers.ts
function readKeys(): Record<string, string> {
const keysPath = getKeysPath();
if (!fs.existsSync(keysPath)) return {};
try {
return JSON.parse(fs.readFileSync(keysPath, 'utf-8'));
} catch {
return {};
}
}writeKeys function · typescript · L22-L24 (3 LOC)src/main/providers.ts
function writeKeys(keys: Record<string, string>) {
fs.writeFileSync(getKeysPath(), JSON.stringify(keys, null, 2), 'utf-8');
}About: code-quality intelligence by Repobility · https://repobility.com
encryptKey function · typescript · L26-L32 (7 LOC)src/main/providers.ts
function encryptKey(apiKey: string): string {
if (safeStorage.isEncryptionAvailable()) {
return safeStorage.encryptString(apiKey).toString('base64');
}
console.warn('[agt-os] safeStorage not available, storing key in plaintext');
return `plain:${apiKey}`;
}decryptKey function · typescript · L34-L39 (6 LOC)src/main/providers.ts
function decryptKey(stored: string): string {
if (stored.startsWith('plain:')) {
return stored.slice(6);
}
return safeStorage.decryptString(Buffer.from(stored, 'base64'));
}addProvider function · typescript · L41-L66 (26 LOC)src/main/providers.ts
export function addProvider(data: {
name: string;
providerType: string;
baseUrl?: string;
model: string;
apiKey: string;
}) {
const db = getDb();
const id = crypto.randomUUID();
db.insert(providers).values({
id,
name: data.name,
providerType: data.providerType,
baseUrl: data.baseUrl ?? null,
model: data.model,
isActive: false,
createdAt: new Date(),
}).run();
const keys = readKeys();
keys[id] = encryptKey(data.apiKey);
writeKeys(keys);
return id;
}getProviders function · typescript · L68-L70 (3 LOC)src/main/providers.ts
export function getProviders() {
return getDb().select().from(providers).all();
}getProviderWithKey function · typescript · L72-L80 (9 LOC)src/main/providers.ts
export function getProviderWithKey(id: string) {
const db = getDb();
const provider = db.select().from(providers).where(eq(providers.id, id)).get();
if (!provider) return null;
const keys = readKeys();
const apiKey = keys[id] ? decryptKey(keys[id]) : null;
return { ...provider, apiKey };
}getActiveProvider function · typescript · L82-L90 (9 LOC)src/main/providers.ts
export function getActiveProvider() {
const db = getDb();
const provider = db.select().from(providers).where(eq(providers.isActive, true)).get();
if (!provider) return null;
const keys = readKeys();
const apiKey = keys[provider.id] ? decryptKey(keys[provider.id]) : null;
return { ...provider, apiKey };
}setActiveProvider function · typescript · L92-L96 (5 LOC)src/main/providers.ts
export function setActiveProvider(id: string) {
const db = getDb();
db.update(providers).set({ isActive: false }).run();
db.update(providers).set({ isActive: true }).where(eq(providers.id, id)).run();
}deleteProvider function · typescript · L98-L105 (8 LOC)src/main/providers.ts
export function deleteProvider(id: string) {
const db = getDb();
db.delete(providers).where(eq(providers.id, id)).run();
const keys = readKeys();
delete keys[id];
writeKeys(keys);
}Repobility · code-quality intelligence · https://repobility.com
getWrapped function · typescript · L9-L16 (8 LOC)src/preload/index.ts
function getWrapped(func: Callback) {
let wrapped = listenerMap.get(func)
if (!wrapped) {
wrapped = (_event: IpcRendererEvent, ...args: unknown[]) => func(...args)
listenerMap.set(func, wrapped)
}
return wrapped
}App function · typescript · L22-L175 (154 LOC)src/renderer/App.tsx
function App() {
const [sessions, setSessions] = useState<Session[]>([]);
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
const [messages, setMessages] = useState<Message[]>([]);
const [isStreaming, setIsStreaming] = useState(false);
const [streamingContent, setStreamingContent] = useState('');
const [hasProvider, setHasProvider] = useState<boolean | null>(null);
const messageListRef = useRef<HTMLDivElement>(null);
const scrollToBottom = useCallback(() => {
if (messageListRef.current) {
messageListRef.current.scrollTop = messageListRef.current.scrollHeight;
}
}, []);
// Check if provider is configured
useEffect(() => {
ipc.invoke('provider:list').then((providers: unknown[]) => {
setHasProvider(providers.length > 0);
});
}, []);
// Load sessions
useEffect(() => {
ipc.invoke('session:list').then((list: Session[]) => {
setSessions(list);
});
}, []);
// Load messages when session chanChatInput function · typescript · L10-L65 (56 LOC)src/renderer/components/ChatInput.tsx
function ChatInput({ onSend, onAbort, disabled, isStreaming }: ChatInputProps) {
const [text, setText] = useState('');
const textareaRef = useRef<HTMLTextAreaElement>(null);
const handleSend = () => {
const trimmed = text.trim();
if (!trimmed || disabled) return;
onSend(trimmed);
setText('');
if (textareaRef.current) {
textareaRef.current.style.height = 'auto';
}
};
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};
const handleInput = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setText(e.target.value);
const el = e.target;
el.style.height = 'auto';
el.style.height = Math.min(el.scrollHeight, 200) + 'px';
};
return (
<div className="chat-input">
<textarea
ref={textareaRef}
className="chat-input__textarea"
value={text}
onChange={handleInput}
onKeyDown={handleKeyDown}
ChatMessage function · typescript · L9-L21 (13 LOC)src/renderer/components/ChatMessage.tsx
function ChatMessage({ role, content, isStreaming }: ChatMessageProps) {
return (
<div className={`chat-message chat-message--${role}`}>
<div className="chat-message__label">
{role === 'human' ? 'You' : 'AI'}
</div>
<div className="chat-message__content">
{content}
{isStreaming && <span className="chat-cursor" />}
</div>
</div>
);
}ProviderSetup function · typescript · L7-L79 (73 LOC)src/renderer/components/ProviderSetup.tsx
function ProviderSetup({ onComplete }: ProviderSetupProps) {
const [providerType, setProviderType] = useState('anthropic');
const [apiKey, setApiKey] = useState('');
const [model, setModel] = useState('claude-sonnet-4-20250514');
const [loading, setLoading] = useState(false);
const [error, setError] = useState('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!apiKey.trim()) return;
setLoading(true);
setError('');
try {
// @ts-expect-error electron exposed via preload
await window.electron.ipcRenderer.invoke('provider:add', {
name: providerType.charAt(0).toUpperCase() + providerType.slice(1),
providerType,
model,
apiKey: apiKey.trim(),
});
onComplete();
} catch (err: unknown) {
setError(err instanceof Error ? err.message : 'Failed to save provider');
} finally {
setLoading(false);
}
};
return (
<div className="provider-overlay">
Sidebar function · typescript · L15-L34 (20 LOC)src/renderer/components/Sidebar.tsx
function Sidebar({ sessions, activeSessionId, onSelectSession, onNewChat }: SidebarProps) {
return (
<aside className="sidebar">
<button className="sidebar__new-btn" onClick={onNewChat}>
+ New Chat
</button>
<div className="sidebar__list">
{sessions.map((s) => (
<div
key={s.id}
className={`sidebar__item ${s.id === activeSessionId ? 'sidebar__item--active' : ''}`}
onClick={() => onSelectSession(s.id)}
>
{s.title}
</div>
))}
</div>
</aside>
);
}