Skip to content
Merged
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ export default defineConfig({
{ text: 'flame_chase', link: '/flows/flame-chase' },
{ text: 'rlar', link: '/flows/rlar' },
{ text: 'humanize1', link: '/flows/humanize1' },
{ text: '…_agent_cleanup', link: '/flows/agent-cleanup' },
{ text: 'recursive_lean_prover', link: '/flows/recursive-lean-prover' },
{ text: 'aot', link: '/flows/aot' },
],
},
{
Expand Down
8 changes: 4 additions & 4 deletions docs/.vitepress/theme/components/HmzDaemon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -335,16 +335,16 @@ function reset() {
<span>{{ journal }} complete lines · append as events happen</span>
</div>
<div class="file state">
<strong>state.json</strong>
<span>revision {{ stateRevision }} · replace when the flow writes</span>
<strong>resume.jsonl</strong>
<span>{{ stateRevision }} state writes · each flushed as the flow makes it</span>
</div>
<div class="file errors">
<strong>daemon.log</strong>
<span>append failures that no terminal could show</span>
</div>
<p>
The terminal screen is not kept here. The journal records the run's shape, state is
what a resumable flow chose to keep, and the backend owns the conversation.
The terminal screen is not kept here. The epic records the run's shape, the engine's
journal what a resumable flow chose to keep, and the backend owns the conversation.
</p>
</aside>
</div>
Expand Down
4 changes: 2 additions & 2 deletions docs/.vitepress/theme/components/HmzFlows.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { FLOWS, type Place } from '../flows'
// separates is which of the two places one is kept in, which is the one thing that shows --
// the package is there before anything has been fetched, and the repository is not.
const WHERE: { id: Place | 'all'; said: string; note: string }[] = [
{ id: 'all', said: 'every flow', note: 'eleven, and humanize 1 is three of them' },
{ id: 'all', said: 'every flow', note: 'fourteen, and humanize 1 is three of them' },
{ id: 'package', said: 'in the package', note: 'chat, which is there before anything is fetched' },
{ id: 'flowverse', said: 'the official flowverse', note: 'humanfia/flowverse, fetched the first time somebody wants it' },
{ id: 'flowverse', said: 'the official flowverse', note: 'humanfia/flowverse, fetched as /flow first opens' },
]

const place = ref<Place | 'all'>('all')
Expand Down
77 changes: 44 additions & 33 deletions docs/.vitepress/theme/components/HmzSurfaces.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ type PlanMode = 'discussion' | 'direct'
type SurfaceKey = 'python' | 'cli' | 'tui' | 'daemon'

const PLAN_MODES: PlanMode[] = ['discussion', 'direct']
// What the params form offers for `turn_retries`: one more than the model takes, so that the
// refusal the model answers with is one a reader can reach.
const RETRIES = [0, 1, 2, 3, 4]

interface LookupRow {
key: string
Expand Down Expand Up @@ -39,8 +42,8 @@ interface GraphEdge {
}

const forked = ref(false)
const genIdea = ref(true)
const genPlan = ref(true)
const autoStart = ref(false)
const retries = ref(1)
const planMode = ref<PlanMode>('discussion')
const surface = ref<SurfaceKey>('tui')
const attached = ref(1)
Expand Down Expand Up @@ -76,16 +79,16 @@ const lookup = computed<LookupRow[]>(() =>
],
)

const configAccepted = computed(() => !genIdea.value || genPlan.value)
const configAccepted = computed(() => retries.value <= 3)
const configState = computed(() =>
configAccepted.value
? [
'accepted',
`idea ${genIdea.value ? 'on' : 'off'}`,
`plan ${genPlan.value ? 'on' : 'off'}`,
planMode.value,
`retries ${retries.value}`,
`auto-start ${autoStart.value ? 'on' : 'off'}`,
].join(' · ')
: 'refused · gen idea is on while gen plan is off',
: 'refused · turn_retries: input should be less than or equal to 3',
)
const resolved = computed(() =>
forked.value
Expand All @@ -98,8 +101,9 @@ const SURFACES: Surface[] = [
key: 'python',
label: 'Python SDK',
about:
'Builds a Run around the loaded runner and task, then runs it here or on a ' +
'thread of its own.',
'Hmz().run(flow, task, agents={role: spec}, envs=, params=, budget=, resume=, ' +
'outworlder=) loads a Runner and hands back a Run of it and the task: run here or ' +
'on a thread of its own, watched, stopped or closed.',
path: [
'python-workspace',
'workspace-run',
Expand All @@ -113,8 +117,8 @@ const SURFACES: Surface[] = [
key: 'cli',
label: 'CLI',
about:
'Reads the line into the same flow, agents, task and setup, then drives the SDK ' +
'Run to its return.',
'Hmz.read(argv) reads the line into a Line -- the flow, -a/-e/-p/-b and the task -- ' +
'then drives the same Run to its return.',
path: [
'cli-workspace',
'workspace-run',
Expand All @@ -128,8 +132,8 @@ const SURFACES: Surface[] = [
key: 'tui',
label: 'TUI',
about:
'Keeps the workspace and runner in hand so it can configure, watch and steer the ' +
'agent conversations while they run.',
'Sets the flow up by role, keeps its Runner and Run in hand, and answers for the ' +
'outworlder while it watches and steers the conversations.',
path: ['tui-workspace', 'workspace-runner', 'runner-conversations', 'runner-epic'],
nodes: ['tui', 'workspace', 'runner', 'conversations', 'epic'],
},
Expand Down Expand Up @@ -190,8 +194,8 @@ function forkFlow() {

function reset() {
forked.value = false
genIdea.value = true
genPlan.value = true
autoStart.value = false
retries.value = 1
planMode.value = 'discussion'
surface.value = 'tui'
attached.value = 1
Expand Down Expand Up @@ -258,30 +262,37 @@ function reset() {
</div>
</header>

<div class="group">gen-idea</div>
<label class="field switch">
<span class="field-copy">
<strong>gen idea</strong>
<span>open the idea into a grounded draft</span>
</span>
<span class="toggle">
<input v-model="genIdea" type="checkbox" />
{{ genIdea ? 'on' : 'off' }}
</span>
</label>

<div class="group plan">gen-plan</div>
<label class="field switch">
<span class="field-copy">
<strong>gen plan</strong>
<span>turn the draft into a plan</span>
<strong>auto start rlcr if converged</strong>
<span>no review gate once converged</span>
</span>
<span class="toggle">
<input v-model="genPlan" type="checkbox" />
{{ genPlan ? 'on' : 'off' }}
<input v-model="autoStart" type="checkbox" />
{{ autoStart ? 'on' : 'off' }}
</span>
</label>

<div class="field">
<div class="field-copy">
<strong>turn retries</strong>
<span>how many times a failed or empty turn is retried</span>
</div>
<div class="choices" role="group" aria-label="turn retries">
<button
v-for="one in RETRIES"
:key="one"
type="button"
:aria-pressed="retries === one"
:class="{ on: retries === one }"
@click="retries = one"
>
{{ one }}
</button>
</div>
</div>

<div class="field">
<div class="field-copy">
<strong>plan mode</strong>
Expand Down Expand Up @@ -310,9 +321,9 @@ function reset() {
{{ configState }}
</p>
<p class="model-note">
Turn gen plan off while gen idea remains on. The model refuses the relationship;
the interface only shows what it said. The whole set is validated again when the
current flow is loaded.
Ask for four retries. The model takes at most three and refuses it; the interface
only shows what it said. The whole set is validated again when the current flow is
loaded.
</p>
</section>
</div>
Expand Down
58 changes: 49 additions & 9 deletions docs/.vitepress/theme/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const FLOWS: Flow[] = [
link: '/flows/ralph-loop',
agents: 'agent',
said: 'A fresh session every round, so nothing carries over but the repository.',
ends: 'the run’s budget',
ends: 'three empty rounds in a row, or the run’s budget',
keeps: 'rounds',
place: 'flowverse',
family: 'fresh',
Expand All @@ -79,7 +79,7 @@ export const FLOWS: Flow[] = [
link: '/flows/stateful-ralph',
agents: 'agent',
said: 'One session, held for the whole run, re-sent the task every round.',
ends: 'the run’s budget',
ends: 'three empty rounds in a row, or the run’s budget',
keeps: 'rounds',
place: 'flowverse',
family: 'held',
Expand All @@ -90,7 +90,7 @@ export const FLOWS: Flow[] = [
link: '/flows/continue-loop',
agents: 'agent',
said: 'Sends the task once, then keeps nudging “continue” at the session that heard it.',
ends: 'the run’s budget',
ends: 'the run’s budget, or three failed turns in a row',
keeps: 'rounds',
place: 'flowverse',
family: 'nudge',
Expand All @@ -112,7 +112,7 @@ export const FLOWS: Flow[] = [
link: '/flows/flame-chase',
agents: 'first_chaser · second_chaser',
said: 'Two agents take turns on the same task, each reading the repository rather than a history.',
ends: 'the run’s budget, which the two spend between them',
ends: 'the run’s budget, which the two spend between them, or three failed turns in a row',
keeps: 'turn · rounds',
place: 'flowverse',
family: 'pair',
Expand All @@ -123,7 +123,7 @@ export const FLOWS: Flow[] = [
link: '/flows/rlar',
agents: 'actor · reviewer',
said: 'The actor remembers and the reviewer must not. The review is the actor’s next prompt.',
ends: 'the reviewer agreeing the work is done',
ends: 'the reviewer agreeing the work is done, or the run’s budget',
keeps: 'rounds · the review nobody acted on',
place: 'flowverse',
family: 'review',
Expand All @@ -134,7 +134,7 @@ export const FLOWS: Flow[] = [
link: '/flows/humanize1',
agents: '1, then 2, then 2 + you',
said: 'PolyArch/humanize as three flows: an idea, a plan both sides converged on, and a build under review.',
ends: 'its max rounds, for the loop of the three',
ends: 'the reviewer saying the plan is complete, or its max rounds, for the loop of the three',
keeps: 'the directory the loop is in, and its round',
place: 'flowverse',
family: 'phases',
Expand All @@ -159,6 +159,46 @@ export const FLOWS: Flow[] = [
place: 'flowverse',
family: 'lanes',
},
{
name: 'ralph_loop_agent_cleanup',
link: '/flows/agent-cleanup',
agents: 'agent · cleaner + you',
said: 'ralph_loop, with a cleaner that distills the workspace into one commit every few turns.',
ends: 'the run’s budget, or three empty turns in a row',
keeps: 'the turns, the epoch, the run’s own directory',
place: 'flowverse',
family: 'fresh',
},
{
name: 'flame_chase_agent_cleanup',
link: '/flows/agent-cleanup',
agents: 'first_chaser · second_chaser · cleaner + you',
said: 'flame_chase, with the same cleaner between the two chasers.',
ends: 'the run’s budget, or three empty turns in a row',
keeps: 'the turns, the epoch, the run’s own directory',
place: 'flowverse',
family: 'pair',
},
{
name: 'recursive_lean_prover',
link: '/flows/recursive-lean-prover',
agents: 'worker · reviewer',
said: 'A Lean theorem proved by recursive decomposition, each node built by humanize1’s phases in a worktree of its own.',
ends: 'the root theorem proved or refused, or the run’s budget',
keeps: 'the DAG, the accepted nodes, their worktrees and branches',
place: 'flowverse',
family: 'phases',
},
{
name: 'aot',
link: '/flows/aot',
agents: 'writer · critic + you',
said: 'Writes a flow from a description, and lands it once it has loaded, run on fakes and been read.',
ends: 'the flow landed, or its repairs running out',
keeps: '',
place: 'flowverse',
family: 'review',
},
]

/* ------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -484,7 +524,7 @@ export const SHAPES: Record<string, Shape> = {
lanes: [
{ id: 'builder', name: 'the builder', note: 'one session, the loop' },
{ id: 'reviewer', name: 'the reviewer', note: 'fresh, each round' },
{ id: 'you', name: 'you', note: 'asked once, never waited', tone: 6 },
{ id: 'you', name: 'you', note: 'asked only when you are there', tone: 6 },
],
steps: [
{
Expand All @@ -494,7 +534,7 @@ export const SHAPES: Record<string, Shape> = {
label: 'have you read the plan?',
session: 'none',
tone: 'ask',
carry: A('answered, or not', 'b1'),
carry: A('answered — skipped when you are away', 'b1'),
},
{
id: 'b1',
Expand Down Expand Up @@ -570,7 +610,7 @@ export const SHAPES: Record<string, Shape> = {
parallel_flame_chase_git_pr: {
of: 'parallel_flame_chase_git_pr',
lanes: [
{ id: 'co', name: 'the orchestrateor', note: 'plans once', tone: 6 },
{ id: 'co', name: 'the orchestrator', note: 'plans once', tone: 6 },
{ id: 'l1a', name: 'lane 1 · a', note: 'a clone of its own', tone: 1 },
{ id: 'l1b', name: 'lane 1 · b', note: 'a clone of its own', tone: 1 },
{ id: 'l2a', name: 'lane 2 · a', note: 'a clone of its own', tone: 2 },
Expand Down
7 changes: 2 additions & 5 deletions docs/contributing/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ src/hmz/
├── __main__.py python -m hmz
├── coganchor/ everything humanize knows about driving a coding agent CLI
├── flows/ the whole of what a flow imports, and nothing else: types
├── _legacy_flows/ the flow API before this one, until every way in has moved off it
├── runtime/ what a run is: driving one, writing it down, reading it back —
│ flowing/, which is everything humanize does to a flow, and
│ doing/, which is the whole of that as one object
Expand Down Expand Up @@ -44,7 +43,7 @@ for the anchor inside it, a program that ships to a target and could be lifted o
| `runtime/flowing/` | Everything humanize does to a flow, and none of it a thing a flow names. **The engine**: defining a flow, calling one, the views a flow is handed, budgets, the resume journal, refs and the module cache. **The drivers** the engine runs over, behind one SPI: an agent driver per harness over `coganchor`, and an environment driver for this machine and for ssh hosts. The parsers `-a`, `-e`, `-p` and `-b` are read with, the in-memory fake kit a flow is tested on, and where flows come from, finding one by name and the skills a flow brings. | `run_flow`, `load_flow`, `define_flow`, `running`, `open_agent`, `open_env`, `local_env`, `parse_agents`, `parse_envs`, `parse_params`, `parse_budget`, `run_fake`, `found`, `find`, `fork`, `flowverses`, `brought` |
| `coganchor/fallbacks.py` | The layer between an agent and its accounts: where a turn goes when the place taking it cannot take it at all, and how many times over it is taken again first. A step is written between two places — `CLI[@ACCOUNT]/MODEL` — rather than on the account, which `providers` already answers for. Names `backends` and nothing else. | `Falls`, `falls`, `points`, `retrying`, `tried`, `clear`, `chain`, `spec`, `reads`, `waits`, `POLICIES` |
| `runtime/epic.py` | One run of one flow as a directory: the journal, the links to each session's log, and what a flow that can be picked up left behind. Written by `runner`, read by `tracing`, `cli` and `tui`. | `Epic`, `epics`, `read`, `opened`, `state`, `resumed` |
| `runtime/runner.py` | Handing a flow the drivers its roles are filled with, and running it under an epic. Also reads the `hmz exec` line, which the interface starts a flow from too. | `Runner`, `flow_and_agents`, `read_agent`, `set_up_from` |
| `runtime/runner.py` | Handing a flow the drivers its roles are filled with, and running it under an epic. Also reads the `hmz exec` line, which the interface starts a flow from too. | `Runner`, `Recorder`, `Refused`, `Line`, `read_line` |
| `runtime/tracing/` | Reading the backends' logs back — and, for a profiled run, sampling the programs its agents start — and rendering both as one Chrome trace. | `collect`, `profile.Profiler` |
| `runtime/doing/` | humanize as one object, and the front door `hmz.runtime` hands through. A workspace, what is remembered about it, the flows there are, the agents and accounts they run as, the runs already made and the run being made now. It composes the layers and restates none of them, and it reaches each of them from inside the call that needs it — which is what lets a caller name it without paying for the tracer. | `Hmz`, `Run` |
| `tui/` | The terminal interface. It reaches the runtime through the daemon holding the run it is drawing. | `Humanize` |
Expand Down Expand Up @@ -106,9 +105,7 @@ runtime/flowing/
├── fakes.py in-memory drivers for every seam, to test a flow on
├── finding.py a flow by name, nearest first
├── skills.py the skills a flow brings, its own and the ones it named
├── verses.py where flows come from when they come from somewhere else
└── checking.py driving.py prophecy.py prophesying.py stepping.py proving.py
the previous flow API's machinery, over _legacy_flows, and going with it
└── verses.py where flows come from when they come from somewhere else
```

The line between those two is the point of them. A flow is somebody else's repository, so
Expand Down
Loading
Loading