sop

Scalable Objects Persistence


Project maintained by SharedCode Hosted on GitHub Pages — Theme by mattgraham

Evolution of an AI Agent: From Chatty Assistant to Scalable Data Engine

The Vision: AI as a Functional Runtime

When we started building the SOP AI Agent, the goal was never just to create another chatbot that summarizes text. The vision was far more ambitious: to create a conversational interface for high-scale data management.

We wanted an AI that could:

  1. Understand natural language intent (“Show me high-salary employees in Engineering”).
  2. Translate that into precise database operations.
  3. Execute complex workflows (Scripts) that behave like reliable server-side functions.

The ultimate goal was to have the AI act not just as a wrapper around a database, but as a programmable engine where a “Script” is effectively a stored procedure that can be invoked via a REST API.

The Paradigm: Natural Language Programming

We call this interface Natural Language Programming. The goal is to democratize software development by allowing typical users to author programs using plain English.

SOP functions as a compiler for this new language:

  1. Authoring: The user describes a workflow: “Check the inventory levels, and if any item is below 10 units, create a reorder request.”
  2. Compilation: The Agent translates these high-level intents into machine-executable scriptlets (our AST).
  3. Runtime: These scriptlets are stored as Scripts—effectively turning English instructions into repeatable, scalable software artifacts.

This shifts the role of the AI from a passive “assistant” to an active development platform, where the “code” is natural language and the “binary” is the JSON-based Script definition.

The Hardship: Growing Pains

1. The “Chatty” Trap

In our initial iteration, we fell into a common trap in AI development: anthropomorphism over structure. We designed the backend to “talk” like a human, streaming back logs of its thoughts mixed with data.

This led to Parsing Nightmares (frontend using Regex to hunt for JSON) and Scalability Bottlenecks (buffering massive responses in memory to validate them). We realized that to scale, we had to stop treating the AI as a chat partner and start treating it as a compute engine.

2. The State Management Nightmare

Perhaps the most difficult challenge was Recording vs. Runtime.

We initially tried to share state between the “User Session” and the “Script Runner”. This was a disaster. Scripts would accidentally commit user transactions, or user queries would bleed into script execution scopes. We needed a way to guarantee stability for the end-user recording session while maintaining a pristine environment for the runtime.

The Architecture: Built for Scale

We completely refactored the engine around three core pillars: AST Composability, Session Isolation, and Structured Streaming.

1. The AST & Composability

We moved away from “script recording” (saving text commands) to an Abstract Syntax Tree (AST) approach. We defined a rigid schema for a ScriptStep:

type ScriptStep struct {
    Name        string         // Unique identifier for the step
    Description string         // Human-readable explanation of what this step does
    Type        string         // "command", "ask", "if", "loop", "script", "tool"
    Command     string         // The actual instruction
    Args        map[string]any // Parameters
    Steps       []ScriptStep    // Nested steps (for loops/conditionals)
}

This design unlocked Composability and Self-Documentation.

2. Session Isolation

To solve the state management nightmare, we strictly separated the Recording Context from the Runtime Context.

3. Structured Streaming (The Heart & Soul)

Finally, to solve the “Chatty” trap and enable scaling, we implemented the JSON Streaming pattern, the heart & soul of SOP’s large data chunking extended to the AI space.

Instead of writing raw strings, the engine emits StepExecutionResult objects. We implemented a JSONStreamer that wraps the HTTP response writer.

type StepExecutionResult struct {
    Type    string `json:"type"`    // "command", "ask", "error"
    Result  string `json:"result"`  // The raw data payload
}

As soon as a step finishes, it is serialized and flushed.

The Result: A RESTful Experience

The transformation is profound. Running a complex AI script now feels exactly like calling a standard REST API endpoint.

We successfully bridged the gap between the flexibility of Generative AI and the rigidity required for data engineering. The SOP Agent is no longer just “chatting” about data; it is streaming it.