|
|
|
|
@@ -112,89 +112,258 @@ There are only a few core actions:
|
|
|
|
|
- Writing to standard output
|
|
|
|
|
- Reasoning
|
|
|
|
|
|
|
|
|
|
### Scripts
|
|
|
|
|
#### Scripts
|
|
|
|
|
|
|
|
|
|
Scripts can run in one of 2 modes: single-shot or repeat.
|
|
|
|
|
Their mode and output (stdout and stderr) stay in the context until they are explicitly removed.
|
|
|
|
|
In this way the agent manages what information is available in the context.
|
|
|
|
|
|
|
|
|
|
#### Single-shot script
|
|
|
|
|
##### Single-shot script
|
|
|
|
|
|
|
|
|
|
The script is executed once.
|
|
|
|
|
This is useful for most operations e.g. writing to or moving a file or downloading content from the internet.
|
|
|
|
|
The next iteration starts after the scripts has finished.
|
|
|
|
|
|
|
|
|
|
#### Repeat script
|
|
|
|
|
##### Repeat script
|
|
|
|
|
|
|
|
|
|
The script is restarted on each iteration.
|
|
|
|
|
This is useful for monitoring files or the file system.
|
|
|
|
|
commands like `head` and `tail` can be used to limit the data in context.
|
|
|
|
|
The next iteration starts after all repeat scripts in context have finished.
|
|
|
|
|
|
|
|
|
|
### Use of XML
|
|
|
|
|
### Processes in SIA
|
|
|
|
|
|
|
|
|
|
The context and actions are formatted as XML.
|
|
|
|
|
For the context this adds clear rules for escaping.
|
|
|
|
|
This is usefull in case a previous context is embedded.
|
|
|
|
|
SIA operates through a coordinated system of processes, each with specialized responsibilities.
|
|
|
|
|
This choice is driven by dependency isolation for the llm engine implementations,
|
|
|
|
|
and the ability to use namespaces for process isolation of sia instances.
|
|
|
|
|
|
|
|
|
|
The LLM is free to escape data any way it wants,
|
|
|
|
|
as long as it results in valid XML.
|
|
|
|
|
The response is validated against a schema.
|
|
|
|
|
#### Main SIA Process
|
|
|
|
|
|
|
|
|
|
#### XML Data Flow
|
|
|
|
|
Entries store their content as raw text. During context compilation, the XML formatter
|
|
|
|
|
wraps text content in CDATA sections, except when the content contains CDATA closing sequences.
|
|
|
|
|
In those cases, the formatter uses standard XML escaping.
|
|
|
|
|
The core SIA application runs as a continuous process that cycles through its context generation, LLM interaction, and action execution loop.
|
|
|
|
|
This process is typically managed by the `restart.sh` script, which ensures SIA restarts whenever it stops.
|
|
|
|
|
This restart mechanism is a critical part of how SIA implements self-improvement:
|
|
|
|
|
|
|
|
|
|
This separation between storage and formatting:
|
|
|
|
|
- Keeps entry data clean and unescaped
|
|
|
|
|
- Centralizes XML formatting rules
|
|
|
|
|
- Makes it easy to change escaping rules without modifying entries
|
|
|
|
|
- Allows different formatting for different use cases
|
|
|
|
|
1. When SIA makes changes to its own code, it terminates with a special exit code (42)
|
|
|
|
|
2. The restart script detects this exit code and restarts SIA
|
|
|
|
|
3. Upon restart, SIA loads the modified Python files, effectively "installing" its own updates
|
|
|
|
|
|
|
|
|
|
The Context is escaped using CDATA blocks.
|
|
|
|
|
Except when the data contains CDATA closing sequences.
|
|
|
|
|
Then the whole block is escaped using standard XML escaping.
|
|
|
|
|
#### Testing Instances
|
|
|
|
|
|
|
|
|
|
SIA can create isolated test instances of itself to evaluate improvements and test capabilities.
|
|
|
|
|
These instances run in separate process spaces with their own resources and filesystem views, managed by the tool Bubblewrap.
|
|
|
|
|
This isolation ensures that test instances don't interfere with each other or the main SIA instance while allowing observation of their behavior.
|
|
|
|
|
Sub instances are explained in `procedures/self_improvement/reasoning.md`.
|
|
|
|
|
|
|
|
|
|
### The SIA process
|
|
|
|
|
|
|
|
|
|
SIA is typically runs with the `restart.sh` script.
|
|
|
|
|
This is a simple shell script that runs SIA in a loop.
|
|
|
|
|
When stopped, SIA restarts and reloads the Python files.
|
|
|
|
|
This is how SIA can self-update.
|
|
|
|
|
|
|
|
|
|
SIA can also run SIA processes as script.
|
|
|
|
|
This can be used for testing updates to the LLM or core functionality.
|
|
|
|
|
|
|
|
|
|
### Server for debuggin and human input
|
|
|
|
|
#### Web Server for Human Interaction
|
|
|
|
|
|
|
|
|
|
SIA can be started with an optional `--server` flag.
|
|
|
|
|
This starts a web server that can be used to interact with SIA.
|
|
|
|
|
It is made, specifically for reinforcement learning by human feedback.
|
|
|
|
|
It is made for debugging and stearing the model until it is properly trained.
|
|
|
|
|
The web interface takes over standard input and output.
|
|
|
|
|
It will display the context for editing before handing it to the LLM.
|
|
|
|
|
After each run of the LLM, before parsing, it will display the reasoning and actions.
|
|
|
|
|
It interactively displays if the actions can be parsed.
|
|
|
|
|
At any time, the user can write to the standard input of SIA.
|
|
|
|
|
After each run of the LLM, before parsing, it will display the response.
|
|
|
|
|
|
|
|
|
|
## Architecture
|
|
|
|
|
The web server uses WebSockets to maintain real-time communication with connected clients, broadcasting state updates as they occur and processing commands from the interface.
|
|
|
|
|
|
|
|
|
|
SIA follows a modular architecture centered around an agent that processes context through an LLM to generate actions.
|
|
|
|
|
The system can run in two modes: a standard command-line mode and an interactive web mode for debugging and human feedback.
|
|
|
|
|
#### LLM Engine Subprocesses
|
|
|
|
|
|
|
|
|
|
SIA communicates with LLM engines through dedicated subprocesses rather than directly integrating them into the main application.
|
|
|
|
|
Each LLM type (Gemma, QwQ, Mistral, etc.) runs in its own subprocess with a tailored environment.
|
|
|
|
|
This architecture provides several advantages:
|
|
|
|
|
|
|
|
|
|
1. **Dependency Isolation**: Different LLM implementations often have conflicting dependency requirements.
|
|
|
|
|
By running each in a separate subprocess with its own virtual environment, these conflicts are avoided.
|
|
|
|
|
|
|
|
|
|
2. **Resource Management**: LLM engines can be resource-intensive.
|
|
|
|
|
The subprocess approach allows for clean termination and resource reclamation when switching between models or canceling generation.
|
|
|
|
|
|
|
|
|
|
3. **Implementation Simplicity**: New LLM types can be added by implementing a focused subprocess runner without modifying the core SIA agent code.
|
|
|
|
|
|
|
|
|
|
### Use of XML
|
|
|
|
|
|
|
|
|
|
XML plays several crucial roles throughout SIA's architecture as a structured data format for different communication interfaces.
|
|
|
|
|
The consistent use of XML throughout SIA provides a unified approach to data representation, validation, and communication between components.
|
|
|
|
|
But because of how SIA operates it's necessary to treat some data as plain text.
|
|
|
|
|
|
|
|
|
|
#### Context and Entry Representation
|
|
|
|
|
|
|
|
|
|
The context and entries are formatted as XML before presenting them to the LLM.
|
|
|
|
|
CDATA sections keep escaping to a minimum.
|
|
|
|
|
This would not be the case when using e.g. json.
|
|
|
|
|
Entry id's and the delete action allow the LLM to manage it's own context.
|
|
|
|
|
|
|
|
|
|
**Example:**
|
|
|
|
|
```xml
|
|
|
|
|
<context
|
|
|
|
|
time="2024-10-18T12:00:00Z"
|
|
|
|
|
memory_used="9556302234"
|
|
|
|
|
memory_total="17179869184">
|
|
|
|
|
<repeat id="a3d89ee5-28ec-4c5a-b9e9-a30af53d43a0" exit_code="0">
|
|
|
|
|
<![CDATA[ls -lah /root/data]]>
|
|
|
|
|
<stdout>
|
|
|
|
|
<![CDATA[total 16K
|
|
|
|
|
drwxr-xr-x 1 sia 1049089 0 Oct 28 13:40 ./
|
|
|
|
|
drwxr-xr-x 1 sia 1049089 0 Oct 28 13:40 ../
|
|
|
|
|
]]>
|
|
|
|
|
</stdout>
|
|
|
|
|
<stderr/>
|
|
|
|
|
</repeat>
|
|
|
|
|
</context>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### XML formatting
|
|
|
|
|
|
|
|
|
|
During context compilation, the XML formatter wraps text content in CDATA sections when possible,
|
|
|
|
|
falling back to standard XML escaping when content contains CDATA closing sequences (`]]>`).
|
|
|
|
|
|
|
|
|
|
Because of how newlines are added for formatting, all data should be trimmed from leading and trailing whitespace when reading.
|
|
|
|
|
|
|
|
|
|
**Example of CDATA usage:**
|
|
|
|
|
```xml
|
|
|
|
|
<single id="12345678">
|
|
|
|
|
<![CDATA[echo "Hello world" > /tmp/test.txt]]>
|
|
|
|
|
<stdout>
|
|
|
|
|
<![CDATA[]]>
|
|
|
|
|
</stdout>
|
|
|
|
|
<stderr/>
|
|
|
|
|
</single>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Example of XML escaping when CDATA cannot be used:**
|
|
|
|
|
```xml
|
|
|
|
|
<reasoning id="87654321">
|
|
|
|
|
I noticed that the file contains a CDATA end marker like this: ]]>
|
|
|
|
|
I need to be careful when processing this content.
|
|
|
|
|
</reasoning>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notice how the content of this rendered entry can differ from the generated text.
|
|
|
|
|
The LLM needs to be trained to handle this properly.
|
|
|
|
|
|
|
|
|
|
#### XML Schema Validation
|
|
|
|
|
|
|
|
|
|
Responses from the LLM are validated against an XML schema (`action_schema.xsd`) that defines the structure and requirements for valid actions.
|
|
|
|
|
This ensures only supported actions are executed with required attributes.
|
|
|
|
|
|
|
|
|
|
**Example schema definition:**
|
|
|
|
|
```xml
|
|
|
|
|
<xs:element name="single">
|
|
|
|
|
<xs:complexType mixed="true">
|
|
|
|
|
<xs:sequence>
|
|
|
|
|
<xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
|
|
|
|
|
</xs:sequence>
|
|
|
|
|
<xs:attribute name="timeout" type="xs:float" use="optional"/>
|
|
|
|
|
<xs:attribute name="limit" type="xs:integer" use="optional"/>
|
|
|
|
|
</xs:complexType>
|
|
|
|
|
</xs:element>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**Example validation error:**
|
|
|
|
|
```xml
|
|
|
|
|
<parse_error id="20240512_123456_789">
|
|
|
|
|
<error>Missing required attribute 'id' on element 'delete'</error>
|
|
|
|
|
<content>
|
|
|
|
|
<![CDATA[<delete/>]]>
|
|
|
|
|
</content>
|
|
|
|
|
</parse_error>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
#### Logits Processing with XML Schema
|
|
|
|
|
|
|
|
|
|
SIA uses a custom XML schema validator (`lib/xml_schema_validator`) that can operate on token probabilities during text generation.
|
|
|
|
|
This guides the model toward valid XML structures.
|
|
|
|
|
It is most helpful when creating training data.
|
|
|
|
|
|
|
|
|
|
Logits processing is computationally expensive.
|
|
|
|
|
It is not supported for all LLM implementations so the SIA core should not make assumptions on the generated text.
|
|
|
|
|
|
|
|
|
|
#### Iteration Logging
|
|
|
|
|
|
|
|
|
|
All iterations of context-response pairs are stored in XML files, providing a structured record of agent behavior.
|
|
|
|
|
|
|
|
|
|
**Example iteration log file:**
|
|
|
|
|
```xml
|
|
|
|
|
<iteration system_prompt_hash="a1b2c3d4" action_schema_hash="e5f6g7h8">
|
|
|
|
|
<context>
|
|
|
|
|
<context time="2024-10-18T12:00:00Z" memory_used="9556302234" memory_total="17179869184">
|
|
|
|
|
<repeat id="a3d89ee5-28ec-4c5a-b9e9-a30af53d43a0" exit_code="0">
|
|
|
|
|
<![CDATA[ls -lah /root/data]]>
|
|
|
|
|
<stdout><![CDATA[total 16K
|
|
|
|
|
drwxr-xr-x 1 sia 1049089 0 Oct 28 13:40 ./
|
|
|
|
|
]]></stdout>
|
|
|
|
|
<stderr/>
|
|
|
|
|
</repeat>
|
|
|
|
|
</context>
|
|
|
|
|
</context>
|
|
|
|
|
<response><reasoning>
|
|
|
|
|
I should check what files are in the tasks directory to see if there are any pending tasks.
|
|
|
|
|
</reasoning></response>
|
|
|
|
|
</iteration>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Notice how the response is stored as plaintext, even though it contains an xml reasoning action.
|
|
|
|
|
When saving the iteration, the response is not parsed or validated yet.
|
|
|
|
|
Storing the response as plaintext helps debugging and retains info that would otherwise be lost.
|
|
|
|
|
E.g. delete actions do not create an entry and would be harder to find.
|
|
|
|
|
Or xml comments used for inline reasoning are not saved after parsing.
|
|
|
|
|
|
|
|
|
|
#### LLM Engine Communication
|
|
|
|
|
|
|
|
|
|
LLM engine subprocesses receive input as XML documents containing paths to required files and the context.
|
|
|
|
|
|
|
|
|
|
**Example input to LLM engine subprocess:**
|
|
|
|
|
```xml
|
|
|
|
|
<input>
|
|
|
|
|
<system_prompt_path>/root/sia/system_prompt.md</system_prompt_path>
|
|
|
|
|
<action_schema_path>/root/sia/action_schema.xsd</action_schema_path>
|
|
|
|
|
<context>
|
|
|
|
|
<context time="2024-10-18T12:00:00Z" memory_used="9556302234" memory_total="17179869184">
|
|
|
|
|
<!-- Working memory entries -->
|
|
|
|
|
</context>
|
|
|
|
|
</context>
|
|
|
|
|
<prefix><!-- Optional existing text to continue --></prefix>
|
|
|
|
|
</input>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Though the LLM can output any text, the goal is to output valid xml.
|
|
|
|
|
The logits processor can help enfoce this but ultimately the core application is responsible for parsing and interpreting the xml.
|
|
|
|
|
Because the LLM can output any text, the core application can't wait until the returnd text is valid xml.
|
|
|
|
|
To reliably indicate the end of text generation, we use the ASCII End of Transmission (EOT) character (ASCII code 4, `\u0004`).
|
|
|
|
|
This character was chosen because:
|
|
|
|
|
|
|
|
|
|
- It's specifically designed for this purpose in telecommunications protocols
|
|
|
|
|
- It should not appear in normal generated text
|
|
|
|
|
- It's a single byte, making it efficient to process
|
|
|
|
|
- It's standard across all platforms
|
|
|
|
|
|
|
|
|
|
**Example output from LLM engine subprocess:**
|
|
|
|
|
```
|
|
|
|
|
<reasoning>
|
|
|
|
|
I should check the current state of the system and see if there are any pending tasks.
|
|
|
|
|
</reasoning>\u0004
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The communication protocol between the SIA agent and LLM engine subprocesses has been designed with simplicity as the primary goal.
|
|
|
|
|
Opting for a minimal approach that:
|
|
|
|
|
|
|
|
|
|
- Keeps complexity on the agent side, not the llm engine
|
|
|
|
|
- Uses familiar XML format for inputs to align with SIA's existing patterns
|
|
|
|
|
- Utilizes standard ASCII chars to indicate EOT
|
|
|
|
|
|
|
|
|
|
### Core Components
|
|
|
|
|
|
|
|
|
|
#### Agent Architecture
|
|
|
|
|
#### Agent
|
|
|
|
|
The core of SIA is the agent, which exists in two variants:
|
|
|
|
|
- ProceduralAgent: Runs in a simple loop, processing context and executing actions directly
|
|
|
|
|
- WebAgent: Uses a state machine to allow human intervention and feedback through a web interface
|
|
|
|
|
- ProceduralAgent: Runs in a simple state machine, processing context and executing actions directly
|
|
|
|
|
- WebAgent: Gives more control on when to change state and allows human intervention and feedback through a web interface
|
|
|
|
|
|
|
|
|
|
Both agent types share common components:
|
|
|
|
|
- WorkingMemory: Maintains the current state through a collection of entries and system metrics
|
|
|
|
|
- ResponseParser: Converts LLM output into commands or entries
|
|
|
|
|
- XMLValidator: Validates responses against a schema
|
|
|
|
|
- IOBuffer: Handles input/output operations in an agent-appropriate way
|
|
|
|
|
- WorkingMemory
|
|
|
|
|
- ResponseParser
|
|
|
|
|
- IterationLogger
|
|
|
|
|
- IOBuffer
|
|
|
|
|
|
|
|
|
|
Interaction with these components and other shared behaviour is handled in BaseAgent.
|
|
|
|
|
|
|
|
|
|
#### Working Memory
|
|
|
|
|
The working memory stores the current state of the system through different types of entries:
|
|
|
|
|
@@ -205,7 +374,7 @@ The working memory stores the current state of the system through different type
|
|
|
|
|
- IOEntry: Input/output operations
|
|
|
|
|
|
|
|
|
|
Each entry can be serialized to XML for inclusion in the LLM context.
|
|
|
|
|
Working memory is cleaned through explicit delete commands or when context size limits are reached.
|
|
|
|
|
Working memory is cleaned through explicit delete commands issued by the LLM.
|
|
|
|
|
|
|
|
|
|
#### Command Processing
|
|
|
|
|
SIA distinguishes between two types of LLM outputs:
|
|
|
|
|
@@ -213,13 +382,14 @@ SIA distinguishes between two types of LLM outputs:
|
|
|
|
|
- DeleteCommand: Removes entries from working memory
|
|
|
|
|
- StopCommand: Terminates the agent
|
|
|
|
|
2. Entries: Records that become part of working memory
|
|
|
|
|
- Created from script executions, IO operations, reasoning, or errors
|
|
|
|
|
- Persist until explicitly deleted or context limits are reached
|
|
|
|
|
- Stay in the context until explicitly deleted
|
|
|
|
|
- May execute once, each iteration or not at all depending on entry type
|
|
|
|
|
|
|
|
|
|
#### IO Handling
|
|
|
|
|
IO operations are abstracted through an IOBuffer interface:
|
|
|
|
|
- StandardIOBuffer: Direct access to system stdin/stdout
|
|
|
|
|
- WebIOBuffer: Buffer for web interface communication
|
|
|
|
|
|
|
|
|
|
This abstraction allows the ResponseParser to generate consistent IOEntries regardless of agent type.
|
|
|
|
|
|
|
|
|
|
### Processing Flow
|
|
|
|
|
@@ -284,9 +454,8 @@ classDiagram
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class LLMEngine {
|
|
|
|
|
+LLMEngine(model_path str)
|
|
|
|
|
+set_model_path(model_path str) void
|
|
|
|
|
+infer(system_prompt str, main_context str) Iterator~str~
|
|
|
|
|
+LLMEngine(executable_path str)
|
|
|
|
|
+infer(system_prompt str, main_context str, prefix str) Iterator~str~
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class BaseAgent {
|
|
|
|
|
|