Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .motoko/config/default/openkb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"openkb": {
"timeout_ms": 600000,
"max_output_chars": 12000,
"wiki_dir": ".openkb"
}
}
2 changes: 1 addition & 1 deletion ailang.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"ailang_version": "v0.16.2",
"generated_at": "2026-05-06T14:27:08.196158Z",
"generated_at": "2026-05-07T20:59:06.46743002Z",
"generator": "ailang lock v0.16.2",
"packages": [
{
Expand Down
543 changes: 543 additions & 0 deletions raw/2026-03-30-ailang-swe-agent-debug.md

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions raw/2026-03-30-ailang-swe-agent-extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Session Summary: AILANG SWE Agent Extensions — 2026-03-30

## What was changed

Custom system prompt support via `SYSTEM_MD` environment variable.

---

## Motivation

The system prompt was hardcoded in `swe/prompts.ail` as `base_system(cwd)`. There was no way to override it without editing source. A `SYSTEM.md` file provides a stable, version-controllable override point for per-repo or per-task prompt customisation.

---

## Files modified

### `swe/rpc.ail`

Three changes:

**1. New import**
```ailang
import std/fs (readFile, fileExists)
```
`std/fs` already existed in the runtime. `fileExists` guards against a missing path being treated as a runtime error rather than a graceful fallback.

**2. Effect signature of `main`**

`FS` added:
```ailang
export func main() -> () ! {Net, AI, SharedMem, IO, Env, FS, Clock}
```
Scope is `main` only. `rpc_loop`, `conversation_loop`, and all helpers are unaffected.

**3. System prompt resolution in `main`**

Replaces the single `with_cache_hint(base_system(cwd), hint)` line with:
```ailang
let system_md_path = getEnvOr("SYSTEM_MD", "")
let raw_system =
if system_md_path != "" && fileExists(system_md_path)
then readFile(system_md_path)
else base_system(cwd)
let system = with_cache_hint(raw_system, hint)
```

Precedence:
1. `SYSTEM_MD` path — file content used verbatim.
2. `base_system(cwd)` — built-in prompt with workdir-specific bash idioms.

In both cases `with_cache_hint` appends a trajectory hint when the SharedMem cache has a match. Existing behaviour is preserved exactly when `SYSTEM_MD` is unset.

### `tui/src/brain.ts`

`FS` appended to the `--caps` flag passed to `ailang run`:
```
"Net,AI,SharedMem,IO,Env,Clock,FS"
```
`SYSTEM_MD` requires no additional wiring — it already flows through `...process.env` in the spawn env block.

### `tui/src/index.ts`

`SYSTEM_MD` added to the env var documentation comment at the top of the file:
```
// SYSTEM_MD — path to a SYSTEM.md file whose content replaces the built-in system prompt
```

---

## Usage

```bash
# Point at any file
SYSTEM_MD=/path/to/SYSTEM.md node tui/dist/index.js "Fix the regression"

# Relative path, co-located with the repo under repair
SYSTEM_MD=./SYSTEM.md WORKDIR=/repo node tui/dist/index.js "..."

# No SYSTEM_MD set — falls back to built-in base_system(cwd) as before
node tui/dist/index.js "Fix the regression"
```

The `SYSTEM.md` file content is used as-is. The trajectory cache hint is still appended when available, regardless of whether a custom prompt is in use.

---

## What was not changed

- `swe/prompts.ail` — `base_system`, `with_cache_hint`, `fmt_msgs`, `fmt_obs` are all unchanged. The module remains pure (no FS effects).
- `swe/rpc.ail` loop logic — `rpc_loop` and `conversation_loop` are unmodified.
- TypeScript build — `npm run build` passes with zero errors after the change.
114 changes: 114 additions & 0 deletions raw/2026-03-30-ailang-swe-agent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Session Summary: AILANG SWE Agent — 2026-03-30

## What was built

A full software engineering agent on top of the AILANG language runtime, consisting of a TypeScript terminal frontend and an AILANG brain process that communicates over a JSONL pipe.

---

## Repository layout produced

```
ailang_agent/
├── tui/
│ ├── src/
│ │ ├── env-server.ts Express server: POST /exec, /snapshot, /restore, GET /health
│ │ ├── env-server.test.ts 4 acceptance tests (all passing)
│ │ ├── brain.ts Spawns ailang subprocess, wires JSONL pipe
│ │ ├── models.ts KNOWN_MODELS list (7 providers)
│ │ ├── ui.ts pi-tui terminal UI (history, status bar, /model overlay)
│ │ └── index.ts Entry point; wires env-server + brain + UI
│ ├── package.json deps: @mariozechner/pi-tui, express, chalk, typescript
│ └── tsconfig.json module: Node16, target: ES2022
├── swe/
│ ├── types.ail Msg, ExecResult, AgentState, StepOutcome
│ ├── parse.ail extract_bash, is_done, parse_cwd (pure)
│ ├── env_client.ail exec_in — HTTP POST to env-server
│ ├── prompts.ail base_system, with_cache_hint, fmt_msgs, fmt_obs
│ ├── cache.ail get_hint, put_trajectory via std/sem
│ └── rpc.ail rpc_loop, main — always-yolo brain, 50-step budget
├── runtime-patches/
│ ├── io_poll_stdin.builtin.go Patch for internal/builtins/io.go
│ ├── io_poll_stdin.effects.go Patch for internal/effects/io.go
│ └── README.md
├── scripts/
│ ├── install-prerequisites.sh Installs Go, Node.js, npm deps (Debian + macOS)
│ └── run-agent.sh Runs tui/dist/index.js by absolute path
├── Makefile Added: build, run, install targets
└── README.md Full install + run documentation
```

---

## Architecture

Three-process design:

1. **TypeScript process** (`node tui/dist/index.js`) owns the terminal and the environment server
2. **Embedded environment server** (express, default :8080) executes bash commands via `execSync`
3. **AILANG brain process** (`ailang run swe/rpc.ail`) communicates over JSONL on stdin/stdout

The brain always runs in yolo mode — no confirm/reject step. It emits JSONL events to stdout (session_start, thinking, proposed_cmd, obs, done, error) and reads JSONL commands from stdin (abort, model_change).

---

## Key decisions

### Yolo mode only
The Mode ADT was eliminated entirely. AgentState carries no mode field. The loop reduces to: call LLM → extract bash block → execute → emit observation → recurse.

### JSONL protocol
All IPC is newline-delimited JSON. readline splits on `
` only (never Unicode line separators). Malformed lines are silently skipped on the TypeScript side.

### `_io_poll_stdin` builtin
A non-blocking stdin peek builtin was required for the brain to check for abort/model_change commands without blocking the recursive loop. This was:
- Specified in `runtime-patches/` with full Go code
- Applied directly to the AILANG repo at `ailang/internal/builtins/io.go` and `ailang/internal/effects/io.go`
- Verified: `ailang run --caps IO --entry main /tmp/test_poll.ail` prints `poll result: ''`

### Model switching (phases 0-4)
Model changes sent via `/model` are stored in SharedMem (`_sharedmem_put("swe:current_model", ...)`) but the running process continues using the original `--ai` flag. The new model takes effect on the next brain invocation. Phase 5 (optional) swaps one line: `call(...)` → `call_with(model2, ...)`.

### Trajectory cache
After a successful run, the final output is stored in SharedMem via `std/sem` under a key derived from the task text. On subsequent runs against the same task, the hint is injected into the system prompt via `with_cache_hint`.

---

## Bugs fixed during session

### tsconfig module mismatch
`module: ESNext` is incompatible with `moduleResolution: Node16`. Fixed to `module: Node16`.

### pi-tui API mismatch
The plan assumed a React-like options-object API (`new Text(str, {bold, color})`, `new Box({scrollable, grow})`). The actual installed API is positional: `Text(text?, paddingX?, paddingY?, bgFn?)`. ui.ts was rewritten after reading the actual `.d.ts` files. Key differences:
- `Text` — no colour options; use chalk via `bgFn` parameter
- `Box` — no scrollable/grow; plain container with padding
- `Markdown` — requires a full `MarkdownTheme` object as 4th argument
- `Input` — no constructor args; use `setValue("")` to clear (no `clear()` method)
- `SelectList` — takes `SelectItem[]` (not strings), `maxVisible: number`, and a theme object; `onSelect` receives `SelectItem`
- `showOverlay` — returns `OverlayHandle`; call `handle.hide()` to dismiss (no `hideOverlay()` method)

### Wrong working directory
Running `node tui/dist/index.js` from inside `ailang/` resolved to `ailang/tui/dist/index.js` which does not exist. Fixed with `scripts/run-agent.sh`, which resolves the path relative to the script's own location using `$(dirname ${BASH_SOURCE[0]})/..`.

---

## Files verified

- `npm run build` — passes (zero TypeScript errors)
- `npm test` — 4/4 env-server acceptance tests pass:
- echo command returns stdout and exit_code 0
- nonzero-exit command returns correct exit_code
- timeout enforced (sleep 30 killed after 1s)
- GET /health returns `{status: "ok"}`
- `ailang run --caps IO --entry main /tmp/test_poll.ail` — `_io_poll_stdin(())` returns `""`

---

## What remains

- **AILANG brain untestable without `ailang check`** — the `.ail` files are written to spec but cannot be type-checked in this environment without a working `ailang check` command against the swe/ module tree.
- **Phase 5** (optional): swap `call(fmt_msgs(...))` → `call_with(model2, fmt_msgs(...))` in `swe/rpc.ail` once the `call_with` builtin is implemented in the runtime.
- **Phase 4**: SWE-bench 10-issue sample benchmark to gate further work.
- **SharedMem persistence**: the trajectory cache survives only as long as the SharedMem process lives; no cross-restart persistence without a separate store.
113 changes: 113 additions & 0 deletions raw/2026-03-31-ailang-agents-md-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# AGENTS.md Loading Bug Fix

## Overview
Fixed critical bugs in the `swe/agents_md.ail` module that prevented AGENTS.md file discovery and loading from working correctly.

## Problems Identified

### 1. Placeholder Assignments (Critical)
Lines 47-48 contained non-functional placeholder code:
```ailang
let last_slash = last_slash; // Never computed
let has_agents = has_agents; // Never computed
let parent = parent; // Never computed
```
These were never replaced with actual implementations.

### 2. Incorrect Function Syntax
Multiple functions used `=` syntax for multi-statement bodies:
```ailang
// Wrong - cannot have multiple statements after =
func dirname(path: string) -> string =
let clean = ...;
let last_slash = ...;
...

// Correct - use {} blocks
func dirname(path: string) -> string {
let clean = ...;
let last_slash = ...;
...
}
```
Affected functions: `dirname`, `walk_agents`, `load_agents_recursive`, `with_agents_context`

### 3. Import Conflict: `length` Function
Both `std/string` and `std/list` export a `length` function:
- `std/string.length(s: string) -> int`
- `std/list.length[a](xs: [a]) -> int` (polymorphic)

Importing `length` from `std/string` shadowed the polymorphic list version, causing type errors when used on lists.

**Fix:** Import both with disambiguation:
```ailang
import std/string (..., length as str_length)
import std/list (..., length)
```

Then use `str_length` for strings and `length` for lists.

### 4. Missing Effect Annotations
Functions that call `load_agents_content` (which requires `FS` effect) were missing the effect declaration:
- `swe/agents_md.ail:with_agents_context` - added `! {FS}`
- `swe/prompts.ail:with_agents_context` - added `! {FS}`

### 5. Type Inference Issues with `foldlE`
The original implementation attempted to use `foldlE` for loading files:
```ailang
let formatted = foldlE(format_agent_file, "", agents_files);
```

This caused persistent type unification errors despite multiple attempts. Replaced with a simple recursive function:
```ailang
func load_agents_recursive(file_list: [string], acc: string) -> string ! {FS} {
match file_list {
[] => acc,
[f, ...rest] => {
let new_acc = acc ++ "\n## AGENTS.md: " ++ f ++ "\n" ++ readFile(f) ++ "\n```\n" ++ "\n";
load_agents_recursive(rest, new_acc)
}
}
}
```

## Files Modified

### `/workspaces/ailang_agent/swe/agents_md.ail`
- Fixed all placeholder assignments with actual implementations
- Changed function syntax from `=` to `{}` for multi-statement bodies
- Fixed imports to disambiguate `length` functions
- Replaced `foldlE` with recursive `load_agents_recursive`
- Added `! {FS}` effect to `with_agents_context`

### `/workspaces/ailang_agent/swe/prompts.ail`
- Added `! {FS}` effect to `with_agents_context` function signature

## Verification

All modules now compile successfully:
```
✓ No errors found in swe/agents_md.ail
✓ No errors found in swe/prompts.ail
✓ No errors found in swe/rpc.ail
```

## Functionality

The fixed implementation:
1. **Discovers AGENTS.md files** by walking up the directory tree from a given working directory
2. **Collects files in root-first order** (root-most to closest to working directory)
3. **Loads and formats content** with headers showing file paths
4. **Integrates with system prompts** via `with_agents_context` in `swe/prompts.ail`
5. **Handles missing files gracefully** - returns empty string if no AGENTS.md found

## Usage

```ailang
import swe/prompts (base_system, with_agents_context)

let system = base_system("/path/to/workdir");
let system_with_agents = with_agents_context(system, "/path/to/workdir");
```

The `with_agents_context` function automatically discovers and loads all AGENTS.md files from the working directory upward, injecting their content into the system prompt.
40 changes: 40 additions & 0 deletions raw/2026-03-31-ailang-replace-fork.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Replace ailang/ with arniwesth/ailang fork

**Date:** 2026-03-31

## What was done

Replaced the `ailang/` directory (previously cloned from `https://github.com/sunholo-data/ailang.git`) with the fork at `https://github.com/arniwesth/ailang.git`, then reapplied the required runtime patches.

## Steps

1. **Saved patch context** — confirmed the two modified Go files in the old clone matched the patch specs in `runtime-patches/`.

2. **Removed old clone** — deleted `ailang/` (sunholo-data origin).

3. **Cloned the fork**:
```
git clone https://github.com/arniwesth/ailang.git ailang
```

4. **Reapplied runtime patch to `internal/effects/io.go`**:
- Added `RegisterOp("IO", "pollStdin", ioPollStdin)` inside `init()`, after the existing `readLine` registration.
- Added the full `ioPollStdin` function (non-blocking stdin peek via `bufio.Reader.Buffered()`).

5. **Reapplied runtime patch to `internal/builtins/io.go`**:
- Added the `_io_poll_stdin` builtin registration inside `registerIO()`, after the `_io_readLine` block.
- Used variable names `implPollStdin`/`typePollStdin` (the fork already uses `impl5`/`type5` for the `_io_exit` builtin added since the original).

6. **Built and installed**:
```
go build ./cmd/ailang
go install ./cmd/ailang
```

7. **Verified**: `_io_poll_stdin(())` returns `""` when no input is buffered.

## Notes

- The fork (`arniwesth/ailang`) is ahead of `sunholo-data/ailang` — it includes additional builtins (`_io_exit`) and other changes not present in the original.
- The stdlib in the fork carries version tag `v0.10.0` while the dev binary reports `dev`, producing a harmless version mismatch warning at runtime.
- Only the Go source patches from `runtime-patches/` were reapplied. The prompt markdown and test file changes from the old clone were not carried over (they were not Go code and not referenced by `runtime-patches/`).
Loading