desktop

command
v0.35.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 29, 2025 License: MIT Imports: 16 Imported by: 0

README

Desktop Integration Guide

Aster supports three popular desktop frameworks: Wails, Tauri, and Electron.

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│                    Frontend (Web UI)                        │
│                 Vue/React/Svelte/etc.                       │
└─────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                   Desktop Bridge                            │
│  ┌─────────────┬─────────────┬────────────┬───────────────┐ │
│  │   Wails    │    Tauri    │  Electron  │     Web       │ │
│  │ (Go Bind)  │   (HTTP)    │   (HTTP)   │   (HTTP)      │ │
│  └─────────────┴─────────────┴────────────┴───────────────┘ │
└─────────────────────────────────────────────────────────────┘
                            │
                            ▼
┌─────────────────────────────────────────────────────────────┐
│                     Aster Core                              │
│  ┌─────────────┬─────────────┬────────────┬───────────────┐ │
│  │   Agent    │  Permission │   Tools    │   Session     │ │
│  │   System   │   System    │  Registry  │    Store      │ │
│  └─────────────┴─────────────┴────────────┴───────────────┘ │
└─────────────────────────────────────────────────────────────┘

Quick Start

Wails provides the most seamless integration since it uses direct Go function binding.

// main.go
package main

import (
    "github.com/astercloud/aster/pkg/desktop"
    "github.com/wailsapp/wails/v2"
)

func main() {
    app, _ := desktop.NewApp(&desktop.AppConfig{
        Framework: desktop.FrameworkWails,
    })

    // ... create and register agent ...

    wails.Run(&options.App{
        Title:  "Aster Desktop",
        Width:  1024,
        Height: 768,
        Bind: []interface{}{
            app.Bridge(),
        },
    })
}
// frontend/src/api.js
export async function chat(agentId, message) {
    return await window.go.desktop.WailsBridge.Chat(agentId, message);
}

export async function cancel(agentId) {
    return await window.go.desktop.WailsBridge.Cancel(agentId);
}

export async function approve(agentId, callId, decision, note) {
    return await window.go.desktop.WailsBridge.Approve(agentId, callId, decision, note);
}

Tauri uses a local HTTP server for communication.

// src-tauri/main.rs
use std::process::Command;

fn main() {
    // Start Aster backend
    let _child = Command::new("./aster-desktop")
        .args(["--framework", "tauri", "--port", "9528"])
        .spawn()
        .expect("Failed to start Aster");

    tauri::Builder::default()
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
// src/api.js
const API_URL = 'http://127.0.0.1:9528';

export async function chat(agentId, message) {
    const res = await fetch(`${API_URL}/api/chat`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ agent_id: agentId, message }),
    });
    return res.json();
}

// SSE for streaming events
export function subscribeEvents(onEvent) {
    const eventSource = new EventSource(`${API_URL}/api/events`);

    eventSource.addEventListener('text_chunk', (e) => {
        const data = JSON.parse(e.data);
        onEvent('text_chunk', data);
    });

    eventSource.addEventListener('tool_start', (e) => {
        const data = JSON.parse(e.data);
        onEvent('tool_start', data);
    });

    eventSource.addEventListener('tool_end', (e) => {
        const data = JSON.parse(e.data);
        onEvent('tool_end', data);
    });

    eventSource.addEventListener('approval_required', (e) => {
        const data = JSON.parse(e.data);
        onEvent('approval_required', data);
    });

    return () => eventSource.close();
}
3. Electron

Electron also uses HTTP server communication.

// main.js
const { app, BrowserWindow } = require('electron');
const { spawn } = require('child_process');
const path = require('path');

let asterProcess;

function startAster() {
    const asterPath = path.join(__dirname, 'aster-desktop');
    asterProcess = spawn(asterPath, ['--framework', 'electron', '--port', '9527']);

    asterProcess.stdout.on('data', (data) => {
        console.log(`Aster: ${data}`);
    });
}

app.whenReady().then(() => {
    startAster();

    const win = new BrowserWindow({
        width: 1024,
        height: 768,
        webPreferences: {
            preload: path.join(__dirname, 'preload.js'),
        },
    });

    win.loadFile('index.html');
});

app.on('will-quit', () => {
    if (asterProcess) {
        asterProcess.kill();
    }
});
// preload.js
const { contextBridge } = require('electron');

const API_URL = 'http://127.0.0.1:9527';

contextBridge.exposeInMainWorld('aster', {
    chat: async (agentId, message) => {
        const res = await fetch(`${API_URL}/api/chat`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ agent_id: agentId, message }),
        });
        return res.json();
    },

    cancel: async (agentId) => {
        const res = await fetch(`${API_URL}/api/cancel`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ agent_id: agentId }),
        });
        return res.json();
    },

    approve: async (agentId, callId, decision, note) => {
        const res = await fetch(`${API_URL}/api/approve`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                agent_id: agentId,
                call_id: callId,
                decision,
                note,
            }),
        });
        return res.json();
    },

    subscribeEvents: (onEvent) => {
        const eventSource = new EventSource(`${API_URL}/api/events`);

        ['text_chunk', 'tool_start', 'tool_end', 'approval_required', 'error', 'done']
            .forEach(type => {
                eventSource.addEventListener(type, (e) => {
                    onEvent(type, JSON.parse(e.data));
                });
            });

        return () => eventSource.close();
    },
});

API Reference

REST Endpoints
Method Endpoint Description
POST /api/chat Send a message to the agent
POST /api/cancel Cancel current operation
POST /api/approve Respond to permission request
GET /api/status?agent_id=xxx Get agent status
GET /api/history?agent_id=xxx Get conversation history
DELETE /api/history?agent_id=xxx Clear conversation history
GET /api/config Get configuration
POST /api/config Set configuration
GET /api/agents List all agents
GET /api/events SSE event stream
Request/Response Format
Chat Request
{
    "agent_id": "agent-123",
    "message": "Hello, world!"
}
Approval Request
{
    "agent_id": "agent-123",
    "call_id": "call-456",
    "decision": "allow",  // "allow", "deny", "allow_always", "deny_always"
    "note": "User approved"
}
SSE Event Types
Event Description
connected Connection established
text_chunk Streaming text content
tool_start Tool execution started
tool_end Tool execution ended
tool_progress Tool execution progress
approval_required Permission request
error Error occurred
done Response complete
status_change Agent status changed

Permission Modes

The permission system supports three modes:

  1. auto_approve - All tool executions are automatically approved
  2. smart_approve - Low-risk tools auto-approved, high-risk requires confirmation
  3. always_ask - All tool executions require user confirmation
app, _ := desktop.NewApp(&desktop.AppConfig{
    PermissionMode: permission.ModeSmartApprove,
})

Building for Distribution

Wails
wails build -platform darwin/amd64
wails build -platform windows/amd64
wails build -platform linux/amd64
Tauri
cargo tauri build
Electron
npm run make

Cross-Platform Paths

Aster uses platform-specific paths for configuration and data:

Platform Config Data Logs
macOS ~/Library/Application Support/aster Same Same
Linux ~/.config/aster ~/.local/share/aster ~/.local/state/aster/logs
Windows %APPDATA%\aster Same Same

These paths are automatically managed by pkg/config/paths.go.

Documentation

Overview

Example: Desktop Application with Wails/Tauri/Electron

This example demonstrates how to use Aster as a desktop application with different frontend frameworks.

Usage:

go run main.go -framework wails    # For Wails integration
go run main.go -framework tauri    # For Tauri integration
go run main.go -framework electron # For Electron integration
go run main.go -framework web      # For web development

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL