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: 2 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ OPENROUTER_API_KEY=replace-with-your-openrouter-key
TYPESAFE_API_KEY=replace-with-your-typesafe-key

# The scripted provider is exclusively for deterministic automation. Normal
# interactive development must leave this unset so every turn uses OpenRouter.
# interactive development must leave this unset to use OpenRouter planning
# and TypeSafe Jev workers.
# HEXZERO_PROVIDER=scripted
# Deprecated compatibility alias (HEXZERO_PROVIDER takes precedence):
# AGENTBORNE_PROVIDER=scripted
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
node_modules/
.pnpm-store/
.next/
apps/world-lab/next-env.d.ts
dist/
coverage/
playwright-report/
Expand All @@ -15,3 +14,6 @@ test-results/
logs/
.agentborne/
.hexzero/
.claude/
.codex/
**/next-env.d.ts
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
**/next-env.d.ts
logs/
.claude/
.codex/
241 changes: 147 additions & 94 deletions README.md

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ architecture and removed all legacy infrastructure:
The retirement case is structural rather than measured: the legacy path made one
full generative provider call per active agent per tick, so provider attempts,
cost, and tick latency all scaled linearly with roster size. The zero-swarm path
makes one Agent Zero planning call per tick regardless of roster size. No run in
makes at most one initial Agent Zero planning call when replanning is required,
regardless of roster size; other ticks reuse the current directives. No run in
this repository has compared legacy cognition against zero-swarm cognition on
real providers for cost, latency, or quality; that difference follows from the
call pattern itself. See ADR 0033 for the full record.
Expand All @@ -54,8 +55,9 @@ implementation history.

## Agent Zero planner

Agent Zero is the sole generative planner. It makes one OpenRouter call per
tick regardless of roster size, under the versioned contract `swarm-planner-v1`.
Agent Zero is the sole generative planner. It makes an OpenRouter planning call
only when strategic replanning is required, regardless of roster size, under
the versioned contract `swarm-planner-v1`.
Each plan carries a strategy summary and one directive per active worker;
directives persist across ticks and are reused when no replan is triggered.
Agent Zero participates in the same frozen-world, simultaneous-tick transaction
Expand Down
156 changes: 8 additions & 148 deletions apps/world-lab/src/app/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@
.operator-workspace {
grid-template-columns: 220px minmax(0, 1fr) 300px;
}
.status-popover,
.failed-turn-controls.inactive {
.status-popover {
display: none;
}
.command-navbar {
Expand Down Expand Up @@ -282,7 +281,7 @@ body {
display: grid;
grid-template-rows: auto auto minmax(0, 1fr) clamp(160px, 22dvh, 210px);
}
.world-lab-shell.chat-collapsed {
.world-lab-shell.activity-collapsed {
grid-template-rows: auto auto minmax(0, 1fr) 54px;
}
button,
Expand Down Expand Up @@ -802,14 +801,6 @@ h2 {
background: #2e684b;
color: #f4fff8;
}
.failed-turn-controls {
display: inline-flex;
gap: 4px;
min-width: 132px;
}
.failed-turn-controls.inactive {
visibility: hidden;
}
.dock-heading {
display: flex;
align-items: flex-start;
Expand All @@ -833,8 +824,7 @@ h2 {
margin: 14px 0;
}
.model-filters label,
.model-select-label,
.agent-model-overrides label {
.model-select-label {
display: grid;
gap: 5px;
color: #aebdb8;
Expand All @@ -843,8 +833,7 @@ h2 {
.model-console input,
.model-console select,
.model-console button,
.dock-heading button,
.new-message-button {
.dock-heading button {
padding: 7px 9px;
border: 1px solid #465752;
border-radius: 5px;
Expand All @@ -864,27 +853,10 @@ h2 {
.model-facts div {
grid-template-columns: 75px minmax(0, 1fr);
}
.agent-model-overrides {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 14px;
}
.agent-model-overrides > strong {
grid-column: 1 / -1;
}
.agent-model-override {
display: grid;
gap: 6px;
padding: 7px;
border: 1px solid #34433f;
border-radius: 5px;
}
.model-dialog {
width: min(760px, calc(100vw - 28px));
}
.model-dialog .model-select-label select,
.model-dialog .agent-model-override select,
.export-dialog select,
.export-dialog input[type='number'] {
width: 100%;
Expand Down Expand Up @@ -984,11 +956,6 @@ h2 {
text-overflow: ellipsis;
white-space: nowrap;
}
.details-sidebar > .controls-panel,
.details-sidebar > .world-chat-panel,
.details-sidebar > .event-panel {
display: none;
}
.bottom-dock {
min-height: 0;
height: auto;
Expand Down Expand Up @@ -1019,33 +986,11 @@ h2 {
min-height: 0;
overflow-y: auto;
}
.bottom-dock .world-chat-feed {
min-height: 0;
max-height: none;
flex: 1;
margin-top: 6px;
}
.bottom-dock .world-chat-panel {
display: flex;
min-height: 0;
flex-direction: column;
}
.bottom-dock .world-chat-panel.chat-collapsed {
justify-content: center;
}
.bottom-dock .event-panel.dock-collapsed {
justify-content: center;
}
.bottom-dock .dock-heading {
min-height: 37px;
flex: 0 0 auto;
overflow: visible;
}
.new-message-button {
margin-top: 7px;
color: #a9e7c4;
cursor: pointer;
}
.panel {
padding: 14px;
border-bottom: 1px solid #2d3835;
Expand Down Expand Up @@ -1287,7 +1232,6 @@ dd {
border-color: #fff2d3;
box-shadow: 0 0 0 2px #fff2d344;
}
.controls-panel h2,
.event-panel h2 {
color: #e6ece8;
margin-bottom: 11px;
Expand Down Expand Up @@ -1452,10 +1396,7 @@ dd {
color: #ffafa3 !important;
font-size: 0.74rem !important;
}
.agent-inspector > p,
.turn-detail p,
.turn-detail details,
.compact-history {
.agent-inspector > p {
color: #bcc9c5;
font-size: 0.77rem;
line-height: 1.5;
Expand All @@ -1466,81 +1407,9 @@ dd {
border: 2px solid #e6ece8;
border-radius: 50%;
}
.outcome {
display: inline-block;
padding: 2px 6px;
border-radius: 4px;
text-transform: uppercase;
font-size: 0.67rem !important;
font-weight: 750;
}
.outcome.accepted {
background: #214b39;
color: #8ff1ba;
}
.outcome.rejected,
.outcome.provider-error,
.outcome.lost-tick,
.outcome.operator-skipped {
background: #512b27;
color: #ffafa3;
}
.provider-meta,
.muted {
color: #81928c !important;
}
.turn-detail details {
margin-top: 10px;
}
.turn-detail details p {
margin-top: 6px;
overflow-wrap: anywhere;
}
.observation-note {
color: #8fa19b !important;
font-style: italic;
}
.observation-difference {
color: #ffd58a !important;
}
.compact-history {
margin: 0;
padding-left: 18px;
}
.world-chat-feed small {
color: #82938e;
}
.world-chat-feed {
list-style: none;
max-height: 260px;
overflow-y: auto;
margin: 12px 0 0;
padding: 0 4px 0 0;
}
.world-chat-feed li {
border-left: 3px solid transparent;
border-bottom: 1px solid #26332f;
padding: 6px 0 6px 7px;
font-size: 13px;
line-height: 1.35;
}
.world-chat-feed li:last-child {
border-bottom: 0;
}
.world-chat-feed div {
display: flex;
justify-content: space-between;
gap: 10px;
}
.world-chat-feed p {
margin: 2px 0 0;
overflow-wrap: anywhere;
white-space: pre-wrap;
}
.world-chat-feed small {
font-size: 11px;
line-height: 1.3;
}
.component-result {
border-left: 2px solid #4e766a;
padding-left: 8px;
Expand Down Expand Up @@ -1665,7 +1534,6 @@ dd {
.modal-body {
padding: 12px;
}
.agent-model-overrides,
.model-global-grid,
.model-filters,
.range-row {
Expand Down Expand Up @@ -1973,13 +1841,7 @@ summary:focus-visible {
color: var(--text-muted);
font-size: 0.66rem;
}
.world-chat-feed strong {
text-shadow:
0 1px 2px #000,
0 0 4px #000;
}
.cancel-request-slot.inactive,
.failed-turn-controls.inactive {
.cancel-request-slot.inactive {
visibility: hidden;
}
.overflow-menu summary {
Expand Down Expand Up @@ -2070,8 +1932,7 @@ textarea,
.model-console input,
.model-console select,
.model-console button,
.dock-heading button,
.new-message-button {
.dock-heading button {
border-color: var(--line);
background: var(--surface-raised);
color: var(--text);
Expand All @@ -2081,8 +1942,7 @@ dt,
.catalog-state,
.modal-header p,
.model-filters label,
.model-select-label,
.agent-model-overrides label {
.model-select-label {
color: var(--text-muted) !important;
}
.primary-action:not(:disabled) {
Expand Down
30 changes: 24 additions & 6 deletions apps/world-lab/src/components/map-config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
export const DARK_TILE_URLS = [
'https://a.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
'https://b.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
'https://c.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}@2x.png',
] as const;
import type { StyleSpecification } from 'maplibre-gl';

export const DARK_TILE_ATTRIBUTION = '© OpenStreetMap contributors © CARTO';
type RasterSourceSpecification = Extract<
StyleSpecification['sources'][string],
{ type: 'raster' }
>;
type RasterLayerSpecification = Extract<
StyleSpecification['layers'][number],
{ type: 'raster' }
>;

export const OSM_RASTER_SOURCE = {
type: 'raster',
tiles: ['https://tile.openstreetmap.org/{z}/{x}/{y}.png'],
tileSize: 256,
maxzoom: 19,
attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>',
} satisfies RasterSourceSpecification;

export const DARK_RASTER_PAINT = {
'raster-saturation': -1,
'raster-brightness-min': 0.9,
'raster-brightness-max': 0.08,
} satisfies NonNullable<RasterLayerSpecification['paint']>;
8 changes: 3 additions & 5 deletions apps/world-lab/src/components/model-options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@ const model = (id: string, name: string, price = '0'): CompatibleModel => ({
});

describe('shared model options', () => {
it('deduplicates and orders global and per-agent options identically', () => {
it('deduplicates and orders model options consistently', () => {
const catalog = [
model('zeta/model', 'Alpha'),
model('Acme/model-2', 'Zulu', '0.000001'),
model('acme/model-1', 'Beta'),
model('zeta/model', 'Duplicate ignored'),
];
const globalOptions = buildModelOptions(catalog);
const agentOptions = buildModelOptions(catalog);
const options = buildModelOptions(catalog);

expect(agentOptions).toEqual(globalOptions);
expect(globalOptions.map(({ value }) => value)).toEqual([
expect(options.map(({ value }) => value)).toEqual([
'acme/model-1',
'Acme/model-2',
'zeta/model',
Expand Down
Loading
Loading