Skip to content

innomon/agentic

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Agentic

A config-driven agentic framework built on Google's ADK-Go. Define agents, models, tools, and workflows entirely in YAML — extend with WebAssembly plugins, no recompilation needed.

Work In Progress: Do not use yet

Features

  • Config-Driven: All agents, models, tools, and workflows defined in YAML
  • Multiple Agent Types: LLM, sequential, parallel, loop, routing, and WASM agents
  • Multi-Model Support: Gemini, OpenAI, Ollama (local), and custom providers
  • WebAssembly Extensions: Sandboxed WASM tools and agents via wazero with security policies, OCI registry support, and per-invocation isolation
  • Role-Based Routing: Route users to agents based on database-stored roles with admin config override and contextual disambiguation
  • Persistent Memory: Database-backed conversation memory (PostgreSQL, SQLite)
  • JWT Authentication: Optional RS256 JWT verification middleware
  • User Profile Database: GORM-backed user management with JSONB profile/metadata
  • OpenAI-Compatible Proxy: Drop-in proxy for OpenAI API consumers
  • Console & Web UI: Interactive terminal with file attachments, browser UI, and REST API

Quick Start

  1. Set your API key:

    export GOOGLE_API_KEY="your-api-key"
  2. Build:

    go build -o agentic .
  3. Run:

    ./agentic console

Usage

Console Mode

Interactive terminal with @/path/to/file attachment syntax:

./agentic console
Agentic Console (attach files with @/path/to/file syntax)
Example: Analyze this document @./document.pdf
Type '/help' for commands, '/exit' to quit.

User -> Summarize this report @./report.pdf
[Attached: report.pdf (application/pdf, 125432 bytes)]

Agent -> ...

Web UI Mode

./agentic web

Open http://localhost:8080/ui/ in your browser. Supports drag-and-drop file uploads.

Custom Configuration

Load any YAML config file:

./agentic examples/farmer/config.yaml console
./agentic examples/med-fhir/config.yaml web
./agentic path/to/my-config.yaml console

Command Line

./agentic [config.yaml] [mode] [options]

Modes:
  console   Interactive terminal mode
  web       Web UI + REST API mode

Options:
  --help    Show help message

Examples

Pre-built use-case configurations in examples/:

Example Description Run Command
med-fhir Medical document → FHIR R5 JSON ./agentic examples/med-fhir/config.yaml console
farmer Organic farming advisor (India) ./agentic examples/farmer/config.yaml console
routing Role-based user routing ./agentic examples/routing/config.yaml console
search Web search via Google Search ./agentic examples/search/config.yaml console
wasm-sequential WASM orchestrator agent ./agentic examples/wasm-sequential/config.yaml console

Configuration

All configuration is in YAML. The default config is config/config.yaml.

Minimal Configuration

root_agent: RootAgent

models:
  gemini-flash:
    provider: gemini
    model_id: gemini-2.0-flash
    default: true

agents:
  RootAgent:
    description: General-purpose assistant
    model: gemini-flash
    instruction: |
      You are a helpful assistant.

Root Agent

The root_agent field specifies the entry-point agent. Defaults to RootAgent if omitted.

Models

models:
  gemini-flash:
    provider: gemini
    model_id: gemini-2.0-flash
    default: true

  gpt4o:
    provider: openai
    model_id: gpt-4o

  local-llama:
    provider: ollama
    model_id: llama3.2
    base_url: http://localhost:11434/v1

  vertex-model:
    provider: gemini
    model_id: gemini-2.0-flash
    backend: vertexai
    project: my-gcp-project
    location: us-central1
Field Description Required
provider gemini, openai, or ollama Yes
model_id Provider-specific model identifier Yes
default Set to true for default model No
api_key API key (uses env var if omitted) No
backend For Gemini: gemini (default) or vertexai No
project GCP project ID (Vertex AI) No
location GCP region (Vertex AI) No
base_url Server URL (required for Ollama) No

Agents

agents:
  MyAgent:
    type: llm            # optional, defaults to "llm"
    description: Agent description
    model: gemini-flash
    tools: [tool1, tool2]
    sub_agents:
      - SubAgent1
    instruction: |
      System prompt...
Field Description Required
type Agent type (default: llm) No
description Agent description for routing Yes
model Model name from models config Yes (for llm)
sub_agents List of sub-agent names No
tools List of tool names No
instruction System prompt Yes (for llm)
max_iterations Loop iterations (0 = until escalation) No (for loop)

Built-in Agent Types

Type Description
llm Standard LLM agent (default)
sequential Executes sub-agents once in order
parallel Executes sub-agents concurrently
loop Repeatedly executes sub-agents
routing Role-based user routing with disambiguation
wasm WebAssembly agent via wazero
gnogent-deterministic Deterministic GnoVM agent (no LLM)

Workflow Examples

agents:
  Pipeline:
    type: sequential
    description: Process documents in stages
    sub_agents: [ExtractAgent, TransformAgent, ValidateAgent]

  MultiAnalysis:
    type: parallel
    description: Run analyses simultaneously
    sub_agents: [SentimentAgent, EntityAgent, SummaryAgent]

  RefineLoop:
    type: loop
    description: Iterative refinement
    max_iterations: 3
    sub_agents: [DraftAgent, ReviewAgent]

Routing Agent

Routes users to sub-agents based on database roles:

agents:
  Router:
    type: routing
    model: gemini-flash
    admin_users: [admin1, admin2]
    role_routes:
      admin: AdminAgent
      user: UserAgent
      anonymous: PublicAgent
    tools: [get_user_profile]
    sub_agents: [AdminAgent, UserAgent, PublicAgent]
Field Description Required
admin_users User IDs granted admin role (config-only) No
role_routes Map of role → sub-agent name Yes
model Model for disambiguation Yes

Routing logic:

  1. Retrieves user profile via get_user_profile tool
  2. Admin users (from config) route to admin agent
  3. Pending/Suspended users are denied
  4. Single role → direct route; multiple roles → LLM disambiguation
  5. Unknown users → anonymous agent or reject

See examples/routing/ for a complete example.

Deterministic GnoVM Agent

Runs agents entirely through GnoVM logic — no LLM required. User input is processed deterministically through the GnoVM brain, which manages mood, friendship, and personality state persisted to Postgres.

agents:
  Gnogent:
    type: gnogent-deterministic
    description: Stateful deterministic agent powered by GnoVM
    database:
      dsn: postgres://user:pass@localhost/mydb
      auto_migrate: true
    gnovm:
      source_file: ./gno/agent.gno
      pkg_path: gno/agent
Field Description Required
database.dsn PostgreSQL connection string Yes
database.auto_migrate Auto-create schema on startup No
gnovm.source_file Path to .gno source file Yes
gnovm.pkg_path GnoVM package path (default: gno/agent) No

Each turn executes: thaw (restore VM state from DB) → SyncState (evolve mood/personality) → GetSystemContext (produce response) → AddTurn (archive conversation) → freeze (persist VM state to DB).

Tools

Define tools in YAML, attach to agents by name:

tools:
  get_weather:
    description: Get current weather for a location
    parameters:
      location: {type: string, required: true}
      unit: {type: string, description: celsius or fahrenheit}

agents:
  WeatherAgent:
    model: gemini-flash
    tools: [get_weather]

Register Go handlers:

registry.RegisterToolHandler("get_weather", func(ctx context.Context, args map[string]any) (any, error) {
    location := args["location"].(string)
    return map[string]any{"temperature": 22, "condition": "sunny"}, nil
})

Tool Types

Type Description
builtin Default — Go-registered handler
gemini Gemini built-in tools (e.g., google_search)
userdb GORM-backed user profile CRUD
wasm Sandboxed WebAssembly module

UserDB Tool Type

GORM-backed user profile management:

tools:
  get_user_profile:
    type: userdb
    op: get_profile
    description: Retrieve user profile
    parameters:
      user_id: {type: string, required: true}
    db:
      driver: postgres
      dsn: postgres://user:pass@localhost/mydb
      auto_migrate: true
    admin_users: [admin1]

Operations: get_profile, create_user, update_status, update_roles, update_channels, delete_user.

Wasm Tool Type

Sandboxed WebAssembly tools with security policies:

tools:
  my_wasm_tool:
    type: wasm
    description: Run a sandboxed WASM tool
    module_path: ./plugins/tool.wasm
    security:
      allowed_paths: [/data/input]
      allowed_domains: [api.example.com]
      memory_max_pages: 256

  oci_tool:
    type: wasm
    description: WASM tool from OCI registry
    oci_ref: ghcr.io/myorg/my-tool:latest
Field Description Required
module_path Path to local .wasm file Yes (or oci_ref)
oci_ref OCI registry reference Yes (or module_path)
cache_dir OCI blob cache directory No
security.allowed_paths Read-only filesystem mounts No
security.allowed_domains Network allow-list No
security.memory_max_pages Memory limit (default: 256 = 16MB) No

Wasm module ABI: export alloc(size) -> ptr, run_tool(ptr, len) -> i64, optionally free(ptr, size). Host functions: env.log_msg, env.http_fetch.

Wasm Agent Type

Run WebAssembly modules as agents with sub-agent access:

agents:
  Orchestrator:
    type: wasm
    description: WASM orchestrator
    module_path: ./plugins/orchestrator.wasm
    sub_agents: [Agent1, Agent2]

The module exports execute() -> i32. Host functions: env.subagent_count, env.subagent_name, env.run_subagent, env.log_msg.

Extensibility

Custom Agent Types

import "github.com/innomon/agentic/internal/registry"

type MyAgentConfig struct {
    registry.AgentBase `yaml:",inline"`
    CustomField string `yaml:"custom_field"`
}

func init() {
    registry.RegisterAgentType("myType", func(ctx context.Context, name string, cfg *MyAgentConfig, models registry.ModelRegistry, tools registry.ToolRegistry, sub []agent.Agent) (agent.Agent, error) {
        return myAgent, nil
    })
}

Custom Tool Types

import "github.com/innomon/agentic/internal/registry"

type APIToolConfig struct {
    registry.ToolBase `yaml:",inline"`
    Endpoint string `yaml:"endpoint"`
}

func init() {
    registry.RegisterToolType("api", func(ctx context.Context, name string, cfg *APIToolConfig) (tool.Tool, error) {
        return apiTool, nil
    })
}

Custom Model Providers

import "github.com/innomon/agentic/internal/registry"

type MyProviderConfig struct {
    registry.ModelBase `yaml:",inline"`
    Endpoint string `yaml:"endpoint"`
}

func init() {
    registry.RegisterModelProvider("myprovider", func(ctx context.Context, cfg *MyProviderConfig) (model.LLM, error) {
        return myModel, nil
    })
}

Session Configuration

Session stores active conversation state. Defaults to in-memory.

session:
  provider: database
  driver: postgres
  dsn: postgres://user:pass@localhost/mydb
  auto_migrate: true
Field Description Required
provider inmemory (default), database, gnogent, or vertexai No
driver postgres or sqlite Yes (for database)
dsn Connection string Yes (for database)
auto_migrate Auto-create schema No
project GCP project ID Yes (for vertexai)
location GCP region Yes (for vertexai)
reasoning_engine Reasoning Engine resource Yes (for vertexai)
# Gnogent provider (Postgres-backed with GnoVM session tables):
session:
  provider: gnogent
  dsn: postgres://user:pass@localhost/mydb
  auto_migrate: true

Memory Configuration

Memory stores agent conversation history. Defaults to in-memory.

memory:
  provider: database
  driver: postgres
  dsn: postgres://user:pass@localhost/mydb
  auto_migrate: true
Field Description Required
provider inmemory (default), database, or gnogent No
driver postgres or sqlite Yes (for database)
dsn Connection string Yes (for database)
auto_migrate Auto-create schema No
# Gnogent provider (Postgres-backed with GnoVM memory tables):
memory:
  provider: gnogent
  dsn: postgres://user:pass@localhost/mydb
  auto_migrate: true

Authentication

Optional RS256 JWT authentication for API endpoints:

auth:
  jwt:
    public_key_path: secrets/jwt_public.pem
    issuer: my-gateway
    audience: agentic

Generate keys:

openssl genrsa -out secrets/jwt_private.pem 2048
openssl rsa -in secrets/jwt_private.pem -pubout -out secrets/jwt_public.pem

Set BYPASS_AUTH=true for local development (localhost only).

REST API

Files can be sent via base64-encoded inline data:

# Create session
SESSION=$(curl -s -X POST "http://localhost:8080/api/apps/Agentic/users/user/sessions" \
  -H "Content-Type: application/json" -d '{}' | grep -o '"id":"[^"]*"' | cut -d'"' -f4)

# Send message with file
curl -N -X POST "http://localhost:8080/api/run_sse" \
  -H "Content-Type: application/json" \
  -d '{
    "appName": "Agentic",
    "userId": "user",
    "sessionId": "'"$SESSION"'",
    "streaming": true,
    "newMessage": {
      "role": "user",
      "parts": [
        {"text": "Analyze this document"},
        {"inlineData": {"mimeType": "application/pdf", "data": "'"$(base64 -w0 file.pdf)"'"}}
      ]
    }
  }'

OpenAI-Compatible Proxy

cd openai-proxy
go build -o openai-proxy .
./openai-proxy -config config.yaml
proxy:
  listen: ":9080"
  adk:
    endpoint: http://localhost:8080
    app_name: Agentic
from openai import OpenAI

client = OpenAI(base_url="http://localhost:9080/v1", api_key="not-required")
response = client.chat.completions.create(
    model="Agentic",
    messages=[{"role": "user", "content": "Hello"}],
    stream=True
)

Project Structure

agentic/
├── main.go                          # Entry point
├── config/
│   └── config.yaml                  # Default configuration
├── examples/
│   ├── med-fhir/                    # Medical FHIR transcription
│   ├── farmer/                      # Organic farming advisor
│   ├── routing/                     # Role-based routing
│   ├── search/                      # Web search agent
│   └── wasm-sequential/             # WASM orchestrator
├── internal/
│   ├── auth/                        # JWT verification middleware
│   ├── compreg/                     # Component register
│   ├── config/                      # Config file loader
│   ├── console/                     # Console with @file attachments
│   ├── gnogent/                     # Deterministic GnoVM agent (no LLM)
│   ├── memory/                      # Database-backed memory (GORM)
│   ├── registry/                    # Unified registry (agents, models, tools)
│   ├── routing/                     # Role-based routing agent
│   ├── userdb/                      # User profile database
│   └── wasm/                        # WASM runtime (wazero)
├── openai-proxy/                    # OpenAI-compatible proxy
├── docs/                            # Design documents
├── patches/                         # ADK-Go fork patches
├── go.mod
└── go.sum

Environment Variables

Variable Description
GOOGLE_API_KEY Gemini model access
OPENAI_API_KEY OpenAI model access
BYPASS_AUTH Skip JWT for localhost (dev only)

Prerequisites

  • Go 1.24+
  • API key for your chosen model provider (Gemini, OpenAI), or Ollama for local models

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published