Skip to content

pancsta/secai

Repository files navigation

secai

secai is a Golang framework for Reasoning AI Workflows, implemented using a unique state machine which thrives in complexity. It's a solid foundation for complex, proactive, and long-lived AI Agents with deep and structured memory. Each bot ships with embedded devtools and several UIs. The execution flow is graph-based, which allows for precise behavior modeling of agents, including interruptions, concurrency, and fault tolerance.

It's a sophisticated replacement for frameworks like LangGraph and offers deeply relational consensus of state.

v0.5 - Fully Embedded

Live debugger | Live SQL | Read logs | Browse files

Debugger REPL DB DB Log
Dashboard
Click to see the diagram

v0.4 - Local One

AI-gent Cook on qwen3-vl-30b

Click to see the diagram

v0.2 - User Demo

Screenshots and YouTube are also available.

Note

User demo (7m captions-only) showcasing a cooking assistant which helps to pick a recipe from ingredients AND cook it.

Click to see screenshots
Intro AI-gent Cook Debugger 1 Debugger 2 Memory & Stories
User Interfaces Outro      
     
Diagram

v0.1 - Platform Demo

Screenshots and YouTube are also available.

Note

Platform demo (5m captions-only), showcasing all nine ways an agent can be seen, in addition to the classic chat view.

Click to see screenshots
SVG graph am-dbg Grafana Jaeger REPL
SQL IDE Bash Prompts  
 
Diagram

Features

  • multi-prompt agency
    • a single agent/bot is built of several AI prompts
    • each state can have a prompt bound to it, with dedicated history and documents
  • atomic consensus with relations and negotiation
    • eg states excluding each other can't be active simultaneously
  • dedicated DSL layer for bot schema
    • suitable for non-coding authors
  • structured prompt input/output via JSON schemas
  • declarative flow definitions for non-linear flows
  • cancellation support (interrupts)
  • choice menu (list of offers)
  • prompt history
    • embedded SQLite
    • JSONL log
    • "latest prompt" files
  • proactive stories with actors
    • stories have actions and progress
  • LLM-sourced story switching (orienting)
    • on prompts and timeouts
  • dynamic flow graph for the memory
    • LLM creates an actionable state-machine
  • TUIs and WebAssembly PWAs for user interfaces

Goals

  • precision
  • correctness
  • granular debugging

Devtools

All devtools are available on the web, some also as TUIs, and some as regular files. Everything is shipped as a single file.

  • debugger
  • REPL
  • diagrams (D2 SVGs)
  • DB browser
  • log viewer
  • observability (OpenTelemetry, Prometheus, Loki)

Tools

  • websearch (dockerized searxng)
  • HTML scrape (embedded colly)

Implementation

Architecture

  • Agent (actor)
    • state-machine schema
    • prompts
    • tools
  • Tool (actor)
    • state-machine schema
  • Memory
    • state-machine schema
  • Prompt (state)
    • params schema
    • result schema
    • history log
    • documents
  • Stories (state)
    • actors (state machines)
    • actions
    • progress
  • Document
    • title
    • content

Try It

$ ./ai-gent-cook
AI-gent Cook v0.5.0

Web:
- http://localhost:12854
- http://localhost:12854/agent

Files:
- config: config.kdl
- log:    tmp-cook/cook.jsonl

TUI:
- http://localhost:7856
- ssh localhost -p 7955 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no

REPL:
- http://localhost:13179
- ./cook repl

Log:
- http://localhost:12858
- ./cook log --tail
- tail -f tmp-cook/cook.jsonl -n 100 | fblog -d -x msg -x time -x level

Debugger:
- http://localhost:13178
- files: http://localhost:13171
- ssh localhost -p 13172 -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no

DB:
- Base: http://localhost:13180
- Agent: http://localhost:13181
- History: http://localhost:13182

https://AI-gents.work

Schema Examples

Code snippets from state and prompt schemas of examples/cook. Both schemas are pure and debuggable Golang code.

State Schema

// CookStatesDef contains all the states of the Cook state machine.
type CookStatesDef struct {
	*am.StatesBase

	// ...

	// prompts

	RestoreJokes string
	GenJokes     string
	JokesReady   string

	GenSteps string
	// StepsReady implies the steps have been translated into actionable memory.
	StepsReady string

	GenStepComments   string
	StepCommentsReady string

	// inherit from AgentLLM
	*ssllm.AgentLLMStatesDef
}

// ...

// CookSchema represents all relations and properties of CookStates.
var CookSchema = SchemaMerge(
	// inherit from AgentLLM
	ssllm.LLMAgentSchema,
	am.Schema{
        
		// gen AI

		ssC.RestoreJokes: {
			Auto:    true,
			Require: S{ssC.DBReady, ssC.CharacterReady},
			Remove:  sgC.Jokes,
		},
		ssC.GenJokes: {
			Require: S{ssC.CharacterReady, ssC.DBReady},
			Remove:  sgC.Jokes,
			Tags:    S{ssbase.TagPrompt},
		},
		ssC.JokesReady: {Remove: sgC.Jokes},

		ssC.GenSteps: {
			Auto:    true,
			Require: S{ssC.StoryCookingStarted},
			Remove:  S{ssC.StepsReady},
			Tags:    S{ssbase.TagPrompt},
		},
		ssC.StepsReady: {
			Require: S{ssC.RecipeReady},
			Remove:  S{ssC.GenSteps},
		},

		ssC.GenStepComments: {
			Auto:    true,
			Require: S{ssC.StoryCookingStarted, ssC.StepsReady},
			Remove:  S{ssC.StepCommentsReady},
			Tags:    S{ssbase.TagPrompt},
		},
		ssC.StepCommentsReady: {Remove: S{ssC.GenStepComments}},

		ssC.Orienting: {
			Multi: true,
			Tags:  S{ssbase.TagPrompt},
		},
		ssC.OrientingMove: {},
	})

Prompt Schema

The comments attached to Params* and Result* are sent over to AI models.

// RECIPE

type PromptRecipePicking = secai.Prompt[ParamsRecipePicking, ResultRecipePicking]

func NewPromptRecipePicking(agent shared.AgentBaseAPI) *PromptRecipePicking {
	return secai.NewPrompt[ParamsRecipePicking, ResultRecipePicking](
		agent, ss.StoryRecipePicking, `
			- You're a database of cooking recipes.
		`, `
			1. Suggest recipes based on user's ingredients.
			2. If possible, find 1 extra recipe, which is well known, but 1-3 ingredients are missing.
			3. Summarize the propositions using the character's personality.
		`, `
			- Limit the amount of recipes to the requested number (excluding the extra recipe).
			- Include an image URL per each recipe
		`)
}

type Recipe struct {
	Name  string
	Desc  string
	Steps string
}

type ParamsRecipePicking struct {
	// List of available ingredients.
	Ingredients []Ingredient
	// The number of recipes needed.
	Amount int
}

type ResultRecipePicking struct {
	// List of proposed recipes
	Recipes []Recipe
	// Extra recipe with unavailable ingredients.
	ExtraRecipe Recipe
	// Message to the user, summarizing the recipes. Max 3 sentences.
	Summary string
}

// ...

var StoryRecipePicking = &shared.Story{
	StoryInfo: shared.StoryInfo{
		State: ss.StoryRecipePicking,
		Title: "Recipe Picking",
		Desc:  "The bot offers some recipes, based on the ingredients.",
	},
	Agent: shared.StoryActor{
		Trigger: amhelp.Cond{
			Is:  am.S{ss.Ready, ss.IngredientsReady},
			Not: am.S{ss.RecipeReady},
		},
	},
}

Read the full state schema and prompt schema.

Documentation

Getting Started

We can use one of the examples as a starting template. It allows for further semver updates of the base framework.

  1. Choose the source example
    • export SECAI_EXAMPLE=cook
    • export SECAI_EXAMPLE=research (broken since v0.4.0)
  2. git clone https://github.com/pancsta/secai.git
  3. install task ./secai/scripts/deps.sh
  4. copy the agent cp -R secai/examples/$SECAI_EXAMPLE MYAGENT
  5. cd MYAGENT && go mod init github.com/USER/MYAGENT
  6. get fresh configs
    1. task sync-taskfile
    2. task sync-configs
  7. start it task start
  8. look around task --list-all
  9. configure the bot $EDITOR config.kdl

Differences

secai differs from other AI agents / workflows frameworks in the way it treats AI prompts. Most frameworks call each prompt an "agent", while secai treats prompts as simple DB queries with IoC (Inversion of Control). Tool usage happens manually through typesafe params / results. This approach increases determinism, safety, and overfall control. This multi-prompt workflow forms an actual bot / agent. This does not mean agents can't be composed into larger groups, which happens simply on the state level (via piping / aRPC), as the underlying workflow engine (asyncmachine) doesn't depend on AI at all.

The flow graph, unlike in regular workflows, is not path-based - each node (state) can be activated anytime (same as calling a function), and the edges between nodes are meant to resolve the state consensus. It's a directed multi-graph of states with a negotiation phase.

Scripting

arpc offers CLI access to remote agents, including subscription. It's perfect for quick and simple integrations, scripts, or experiments.

Example: $ arpc -f tmp/research.addr -- when . Requesting && echo "REQUESTING"

  1. Connect to the address from tmp/research.addr
  2. When the last connected agent (.) goes into state Requesting
  3. Print "REQUESTING" and exit

License

To help keep AI open, this project migrated to GPL starting from v0.3.0.

Acknowledgements