Add interactive trace-grounded CID mechanism replay
Browse files- .gitignore +4 -0
- README.md +7 -0
- cid_demo/assets/mechanism.css +625 -0
- cid_demo/assets/mechanism.html +62 -0
- cid_demo/assets/mechanism.js +782 -0
- cid_demo/assets/styles.css +6 -0
- cid_demo/mechanism.py +48 -0
- cid_demo/runtime.py +2 -0
- cid_demo/ui.py +6 -1
- tests/mechanism-state.test.cjs +94 -0
- tests/test_mechanism.py +35 -0
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
__pycache__/
|
| 2 |
+
*.py[cod]
|
| 3 |
+
.pytest_cache/
|
| 4 |
+
.ruff_cache/
|
README.md
CHANGED
|
@@ -24,6 +24,8 @@ Interactive Hugging Face Space for the 398.8M-parameter `fwerkor/CID-v1-0.4B` ch
|
|
| 24 |
|
| 25 |
The demo exposes CID's revisable Display and runtime trace with example prompts for the released 0.4B checkpoint. `calculator`, `symbolic_math`, and the task-local workspace are enabled explicitly from the UI. The workspace editor is disabled until its tool switch is enabled; document-backed examples enable it automatically. Workspace mode exposes read-only `workspace_search` and `workspace_read` information needs while reasoning.
|
| 26 |
|
|
|
|
|
|
|
| 27 |
The model is mechanism-focused, with general-purpose chat outside the primary evaluation target. The Space uses the published unified checkpoint and pins the CID runtime implementation to commit `49c02313044278c93e929834261bebebf3f66bf5`.
|
| 28 |
|
| 29 |
**Paper:** [Continuous Interaction Diffusion](https://arxiv.org/abs/2608.10438)
|
|
@@ -38,3 +40,8 @@ The model is mechanism-focused, with general-purpose chat outside the primary ev
|
|
| 38 |
- `cid_demo/workspace.py` — task-local document parsing.
|
| 39 |
- `cid_demo/examples.py` — public examples and workspace fixtures.
|
| 40 |
- `cid_demo/presentation.py` and `cid_demo/assets/styles.css` — display formatting, HTML, and styling.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
|
| 25 |
The demo exposes CID's revisable Display and runtime trace with example prompts for the released 0.4B checkpoint. `calculator`, `symbolic_math`, and the task-local workspace are enabled explicitly from the UI. The workspace editor is disabled until its tool switch is enabled; document-backed examples enable it automatically. Workspace mode exposes read-only `workspace_search` and `workspace_read` information needs while reasoning.
|
| 26 |
|
| 27 |
+
The **CID in motion** replay sits between the result and detailed inspection tabs. Play or scrub through the current run, jump to tool returns and evidence projections, inspect observed TCT cell states, and compare successive Display snapshots. The shared clock uses measured trace timestamps; playback speed is adjustable. The visualization uses the full runtime events, including asynchronous completion callbacks, without additional model calls. Cell semantics and unrecorded tool contents are not inferred.
|
| 28 |
+
|
| 29 |
The model is mechanism-focused, with general-purpose chat outside the primary evaluation target. The Space uses the published unified checkpoint and pins the CID runtime implementation to commit `49c02313044278c93e929834261bebebf3f66bf5`.
|
| 30 |
|
| 31 |
**Paper:** [Continuous Interaction Diffusion](https://arxiv.org/abs/2608.10438)
|
|
|
|
| 40 |
- `cid_demo/workspace.py` — task-local document parsing.
|
| 41 |
- `cid_demo/examples.py` — public examples and workspace fixtures.
|
| 42 |
- `cid_demo/presentation.py` and `cid_demo/assets/styles.css` — display formatting, HTML, and styling.
|
| 43 |
+
- `cid_demo/mechanism.py` and `cid_demo/assets/mechanism.*` — isolated interactive trace replay, event reducer, and responsive mechanism view.
|
| 44 |
+
|
| 45 |
+
## Frontend checks
|
| 46 |
+
|
| 47 |
+
Run `python -m pytest tests` and `node --test tests/mechanism-state.test.cjs`. These cover trace preservation, text isolation, asynchronous ordering, lifecycle reconstruction, failure/cancellation, and non-converged runs. The `/run_cid` API retains its first four outputs and appends the replay HTML as its fifth output.
|
cid_demo/assets/mechanism.css
ADDED
|
@@ -0,0 +1,625 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root {
|
| 2 |
+
color-scheme: light dark;
|
| 3 |
+
--bg: #fff;
|
| 4 |
+
--soft: #f7f8fc;
|
| 5 |
+
--ink: #20263b;
|
| 6 |
+
--muted: #6c7387;
|
| 7 |
+
--line: #e5e8f1;
|
| 8 |
+
--indigo: #6256db;
|
| 9 |
+
--teal: #078b83;
|
| 10 |
+
--amber: #ba7515;
|
| 11 |
+
--purple: #8960c8;
|
| 12 |
+
--active: #7563df;
|
| 13 |
+
--waiting: #e4a443;
|
| 14 |
+
--stable: #37a797;
|
| 15 |
+
--retired: #a8afbf;
|
| 16 |
+
}
|
| 17 |
+
* {
|
| 18 |
+
box-sizing: border-box;
|
| 19 |
+
}
|
| 20 |
+
body {
|
| 21 |
+
margin: 0;
|
| 22 |
+
background: transparent;
|
| 23 |
+
color: var(--ink);
|
| 24 |
+
font:
|
| 25 |
+
14px/1.5 system-ui,
|
| 26 |
+
-apple-system,
|
| 27 |
+
BlinkMacSystemFont,
|
| 28 |
+
"Segoe UI",
|
| 29 |
+
sans-serif;
|
| 30 |
+
}
|
| 31 |
+
.replay {
|
| 32 |
+
padding: 25px 26px 18px;
|
| 33 |
+
border: 1px solid var(--line);
|
| 34 |
+
border-radius: 20px;
|
| 35 |
+
background: var(--bg);
|
| 36 |
+
overflow: hidden;
|
| 37 |
+
}
|
| 38 |
+
.heading {
|
| 39 |
+
display: flex;
|
| 40 |
+
align-items: flex-start;
|
| 41 |
+
justify-content: space-between;
|
| 42 |
+
gap: 16px;
|
| 43 |
+
}
|
| 44 |
+
.eyebrow {
|
| 45 |
+
font-size: 10px;
|
| 46 |
+
letter-spacing: 0.16em;
|
| 47 |
+
font-weight: 750;
|
| 48 |
+
color: var(--indigo);
|
| 49 |
+
}
|
| 50 |
+
h2 {
|
| 51 |
+
font-size: 27px;
|
| 52 |
+
letter-spacing: -0.035em;
|
| 53 |
+
margin: 3px 0 4px;
|
| 54 |
+
line-height: 1.2;
|
| 55 |
+
}
|
| 56 |
+
p {
|
| 57 |
+
margin: 0;
|
| 58 |
+
color: var(--muted);
|
| 59 |
+
}
|
| 60 |
+
.heading p {
|
| 61 |
+
font-size: 13px;
|
| 62 |
+
}
|
| 63 |
+
.badge {
|
| 64 |
+
font-size: 11px;
|
| 65 |
+
white-space: nowrap;
|
| 66 |
+
border: 1px solid var(--line);
|
| 67 |
+
padding: 5px 10px;
|
| 68 |
+
border-radius: 30px;
|
| 69 |
+
color: var(--muted);
|
| 70 |
+
}
|
| 71 |
+
.question {
|
| 72 |
+
font-size: 13px;
|
| 73 |
+
line-height: 1.5;
|
| 74 |
+
margin: 16px 0;
|
| 75 |
+
color: var(--muted);
|
| 76 |
+
white-space: pre-wrap;
|
| 77 |
+
max-height: 65px;
|
| 78 |
+
overflow: auto;
|
| 79 |
+
overflow-wrap: anywhere;
|
| 80 |
+
padding-left: 11px;
|
| 81 |
+
border-left: 2px solid var(--line);
|
| 82 |
+
}
|
| 83 |
+
.transport {
|
| 84 |
+
display: flex;
|
| 85 |
+
gap: 7px;
|
| 86 |
+
align-items: center;
|
| 87 |
+
}
|
| 88 |
+
button,
|
| 89 |
+
select {
|
| 90 |
+
font: inherit;
|
| 91 |
+
color: var(--ink);
|
| 92 |
+
background: var(--bg);
|
| 93 |
+
border: 1px solid var(--line);
|
| 94 |
+
border-radius: 8px;
|
| 95 |
+
min-height: 32px;
|
| 96 |
+
padding: 5px 11px;
|
| 97 |
+
cursor: pointer;
|
| 98 |
+
}
|
| 99 |
+
button:hover:enabled,
|
| 100 |
+
select:hover {
|
| 101 |
+
border-color: var(--indigo);
|
| 102 |
+
}
|
| 103 |
+
button:disabled {
|
| 104 |
+
opacity: 0.4;
|
| 105 |
+
cursor: default;
|
| 106 |
+
}
|
| 107 |
+
button.primary {
|
| 108 |
+
background: var(--indigo);
|
| 109 |
+
color: white;
|
| 110 |
+
border-color: var(--indigo);
|
| 111 |
+
min-width: 90px;
|
| 112 |
+
}
|
| 113 |
+
button:focus-visible,
|
| 114 |
+
select:focus-visible,
|
| 115 |
+
input:focus-visible,
|
| 116 |
+
summary:focus-visible {
|
| 117 |
+
outline: 2px solid var(--indigo);
|
| 118 |
+
outline-offset: 3px;
|
| 119 |
+
}
|
| 120 |
+
.speed {
|
| 121 |
+
font-size: 11px;
|
| 122 |
+
color: var(--muted);
|
| 123 |
+
display: flex;
|
| 124 |
+
gap: 6px;
|
| 125 |
+
align-items: center;
|
| 126 |
+
margin-left: 6px;
|
| 127 |
+
}
|
| 128 |
+
.speed select {
|
| 129 |
+
font-size: 12px;
|
| 130 |
+
padding: 3px 5px;
|
| 131 |
+
}
|
| 132 |
+
.position {
|
| 133 |
+
margin-left: auto;
|
| 134 |
+
display: flex;
|
| 135 |
+
gap: 12px;
|
| 136 |
+
align-items: baseline;
|
| 137 |
+
font-variant-numeric: tabular-nums;
|
| 138 |
+
}
|
| 139 |
+
.position strong {
|
| 140 |
+
font-size: 13px;
|
| 141 |
+
}
|
| 142 |
+
.position span {
|
| 143 |
+
font-size: 11px;
|
| 144 |
+
color: var(--muted);
|
| 145 |
+
}
|
| 146 |
+
#scrubber {
|
| 147 |
+
width: 100%;
|
| 148 |
+
accent-color: var(--indigo);
|
| 149 |
+
margin: 12px 0 3px;
|
| 150 |
+
cursor: pointer;
|
| 151 |
+
}
|
| 152 |
+
.scene {
|
| 153 |
+
position: relative;
|
| 154 |
+
display: grid;
|
| 155 |
+
grid-template-columns: 26% 34% 28%;
|
| 156 |
+
justify-content: space-between;
|
| 157 |
+
padding: 20px 0 14px;
|
| 158 |
+
min-height: 330px;
|
| 159 |
+
}
|
| 160 |
+
.connections {
|
| 161 |
+
position: absolute;
|
| 162 |
+
inset: 72px 0 0;
|
| 163 |
+
width: 100%;
|
| 164 |
+
height: 230px;
|
| 165 |
+
pointer-events: none;
|
| 166 |
+
z-index: 0;
|
| 167 |
+
overflow: visible;
|
| 168 |
+
}
|
| 169 |
+
.connections text {
|
| 170 |
+
font-size: 9px;
|
| 171 |
+
fill: var(--muted);
|
| 172 |
+
}
|
| 173 |
+
.path {
|
| 174 |
+
fill: none;
|
| 175 |
+
stroke: var(--line);
|
| 176 |
+
stroke-width: 1.5;
|
| 177 |
+
stroke-dasharray: 4 4;
|
| 178 |
+
}
|
| 179 |
+
.path.lit {
|
| 180 |
+
stroke-width: 2.5;
|
| 181 |
+
stroke-dasharray: 7 5;
|
| 182 |
+
}
|
| 183 |
+
.playing .path.lit {
|
| 184 |
+
animation: flow 1s linear infinite;
|
| 185 |
+
}
|
| 186 |
+
.need.lit {
|
| 187 |
+
stroke: var(--amber);
|
| 188 |
+
}
|
| 189 |
+
.evidence.lit {
|
| 190 |
+
stroke: var(--teal);
|
| 191 |
+
}
|
| 192 |
+
.display.lit {
|
| 193 |
+
stroke: var(--purple);
|
| 194 |
+
}
|
| 195 |
+
@keyframes flow {
|
| 196 |
+
to {
|
| 197 |
+
stroke-dashoffset: -24;
|
| 198 |
+
}
|
| 199 |
+
}
|
| 200 |
+
.scene section {
|
| 201 |
+
position: relative;
|
| 202 |
+
z-index: 1;
|
| 203 |
+
min-width: 0;
|
| 204 |
+
}
|
| 205 |
+
.channel-label {
|
| 206 |
+
font-size: 10px;
|
| 207 |
+
font-weight: 750;
|
| 208 |
+
letter-spacing: 0.1em;
|
| 209 |
+
display: flex;
|
| 210 |
+
align-items: center;
|
| 211 |
+
gap: 7px;
|
| 212 |
+
}
|
| 213 |
+
.dot {
|
| 214 |
+
width: 7px;
|
| 215 |
+
height: 7px;
|
| 216 |
+
display: inline-block;
|
| 217 |
+
border-radius: 50%;
|
| 218 |
+
flex-shrink: 0;
|
| 219 |
+
}
|
| 220 |
+
.tool {
|
| 221 |
+
background: var(--teal);
|
| 222 |
+
}
|
| 223 |
+
.thought,
|
| 224 |
+
.active {
|
| 225 |
+
background: var(--active);
|
| 226 |
+
}
|
| 227 |
+
.display {
|
| 228 |
+
background: var(--purple);
|
| 229 |
+
}
|
| 230 |
+
.waiting {
|
| 231 |
+
background: var(--waiting);
|
| 232 |
+
}
|
| 233 |
+
.stable {
|
| 234 |
+
background: var(--stable);
|
| 235 |
+
}
|
| 236 |
+
.retired {
|
| 237 |
+
background: var(--retired);
|
| 238 |
+
}
|
| 239 |
+
h3 {
|
| 240 |
+
font-size: 13px;
|
| 241 |
+
font-weight: 600;
|
| 242 |
+
margin: 6px 0 12px;
|
| 243 |
+
}
|
| 244 |
+
.tools {
|
| 245 |
+
display: flex;
|
| 246 |
+
flex-direction: column;
|
| 247 |
+
gap: 7px;
|
| 248 |
+
max-height: 204px;
|
| 249 |
+
overflow: auto;
|
| 250 |
+
}
|
| 251 |
+
.tool-row {
|
| 252 |
+
background: var(--soft);
|
| 253 |
+
border: 1px solid var(--line);
|
| 254 |
+
border-radius: 10px;
|
| 255 |
+
padding: 9px 10px;
|
| 256 |
+
}
|
| 257 |
+
.tool-row strong {
|
| 258 |
+
display: block;
|
| 259 |
+
font-size: 12px;
|
| 260 |
+
overflow-wrap: anywhere;
|
| 261 |
+
}
|
| 262 |
+
.tool-row span {
|
| 263 |
+
font-size: 11px;
|
| 264 |
+
color: var(--muted);
|
| 265 |
+
}
|
| 266 |
+
.tool-row.busy {
|
| 267 |
+
border-color: var(--amber);
|
| 268 |
+
}
|
| 269 |
+
.tool-row.ready,
|
| 270 |
+
.tool-row.projected {
|
| 271 |
+
border-color: var(--teal);
|
| 272 |
+
}
|
| 273 |
+
.tool-row small {
|
| 274 |
+
display: block;
|
| 275 |
+
font-size: 10px;
|
| 276 |
+
color: var(--muted);
|
| 277 |
+
margin-top: 3px;
|
| 278 |
+
}
|
| 279 |
+
.empty {
|
| 280 |
+
color: var(--muted);
|
| 281 |
+
font-size: 12px;
|
| 282 |
+
padding: 18px 8px;
|
| 283 |
+
border: 1px dashed var(--line);
|
| 284 |
+
border-radius: 10px;
|
| 285 |
+
}
|
| 286 |
+
.field-wrap {
|
| 287 |
+
position: relative;
|
| 288 |
+
}
|
| 289 |
+
.field-wrap svg {
|
| 290 |
+
width: 100%;
|
| 291 |
+
max-height: 217px;
|
| 292 |
+
display: block;
|
| 293 |
+
}
|
| 294 |
+
.field-shell {
|
| 295 |
+
fill: var(--soft);
|
| 296 |
+
stroke: var(--line);
|
| 297 |
+
stroke-width: 1;
|
| 298 |
+
}
|
| 299 |
+
.field-inner {
|
| 300 |
+
fill: none;
|
| 301 |
+
stroke: var(--line);
|
| 302 |
+
stroke-dasharray: 3 6;
|
| 303 |
+
}
|
| 304 |
+
.field-wrap text {
|
| 305 |
+
fill: var(--muted);
|
| 306 |
+
font-size: 11px;
|
| 307 |
+
}
|
| 308 |
+
.cell {
|
| 309 |
+
stroke: var(--bg);
|
| 310 |
+
stroke-width: 2;
|
| 311 |
+
transition:
|
| 312 |
+
fill 0.15s,
|
| 313 |
+
opacity 0.15s;
|
| 314 |
+
cursor: pointer;
|
| 315 |
+
}
|
| 316 |
+
.cell.changed {
|
| 317 |
+
stroke: var(--ink);
|
| 318 |
+
stroke-width: 2.3;
|
| 319 |
+
}
|
| 320 |
+
.cell-label {
|
| 321 |
+
font-size: 7px !important;
|
| 322 |
+
fill: var(--bg) !important;
|
| 323 |
+
pointer-events: none;
|
| 324 |
+
font-weight: 600;
|
| 325 |
+
}
|
| 326 |
+
.model-state {
|
| 327 |
+
position: absolute;
|
| 328 |
+
bottom: 1px;
|
| 329 |
+
left: 50%;
|
| 330 |
+
transform: translateX(-50%);
|
| 331 |
+
font-size: 10px;
|
| 332 |
+
border: 1px solid var(--line);
|
| 333 |
+
border-radius: 20px;
|
| 334 |
+
padding: 2px 9px;
|
| 335 |
+
background: var(--bg);
|
| 336 |
+
white-space: nowrap;
|
| 337 |
+
}
|
| 338 |
+
.legend {
|
| 339 |
+
display: flex;
|
| 340 |
+
justify-content: center;
|
| 341 |
+
gap: 8px;
|
| 342 |
+
flex-wrap: wrap;
|
| 343 |
+
margin: 10px 0 4px;
|
| 344 |
+
font-size: 10px;
|
| 345 |
+
color: var(--muted);
|
| 346 |
+
}
|
| 347 |
+
.legend span {
|
| 348 |
+
display: flex;
|
| 349 |
+
align-items: center;
|
| 350 |
+
gap: 4px;
|
| 351 |
+
}
|
| 352 |
+
.micro {
|
| 353 |
+
font-size: 10px;
|
| 354 |
+
color: var(--muted);
|
| 355 |
+
margin-top: 7px;
|
| 356 |
+
line-height: 1.5;
|
| 357 |
+
}
|
| 358 |
+
.thought-area .micro {
|
| 359 |
+
text-align: center;
|
| 360 |
+
}
|
| 361 |
+
.answer {
|
| 362 |
+
border-top: 2px solid var(--purple);
|
| 363 |
+
padding: 13px 0 8px;
|
| 364 |
+
min-height: 98px;
|
| 365 |
+
max-height: 170px;
|
| 366 |
+
overflow: auto;
|
| 367 |
+
white-space: pre-wrap;
|
| 368 |
+
overflow-wrap: anywhere;
|
| 369 |
+
font-size: 23px;
|
| 370 |
+
line-height: 1.4;
|
| 371 |
+
font-weight: 620;
|
| 372 |
+
letter-spacing: -0.02em;
|
| 373 |
+
}
|
| 374 |
+
.answer mark {
|
| 375 |
+
background: #ebe4ff;
|
| 376 |
+
color: inherit;
|
| 377 |
+
border-radius: 3px;
|
| 378 |
+
}
|
| 379 |
+
.tokens {
|
| 380 |
+
display: flex;
|
| 381 |
+
gap: 3px;
|
| 382 |
+
flex-wrap: wrap;
|
| 383 |
+
max-height: 40px;
|
| 384 |
+
overflow: auto;
|
| 385 |
+
margin-top: 10px;
|
| 386 |
+
}
|
| 387 |
+
.token {
|
| 388 |
+
width: 6px;
|
| 389 |
+
height: 12px;
|
| 390 |
+
border-radius: 2px;
|
| 391 |
+
background: var(--line);
|
| 392 |
+
}
|
| 393 |
+
.token.changed {
|
| 394 |
+
background: var(--purple);
|
| 395 |
+
}
|
| 396 |
+
.event-story {
|
| 397 |
+
display: flex;
|
| 398 |
+
align-items: center;
|
| 399 |
+
gap: 13px;
|
| 400 |
+
background: var(--soft);
|
| 401 |
+
padding: 13px 16px;
|
| 402 |
+
border-radius: 11px;
|
| 403 |
+
min-height: 82px;
|
| 404 |
+
border-left: 3px solid var(--indigo);
|
| 405 |
+
}
|
| 406 |
+
.event-icon {
|
| 407 |
+
font-size: 24px;
|
| 408 |
+
color: var(--indigo);
|
| 409 |
+
min-width: 28px;
|
| 410 |
+
text-align: center;
|
| 411 |
+
}
|
| 412 |
+
.event-story strong {
|
| 413 |
+
font-size: 13px;
|
| 414 |
+
}
|
| 415 |
+
.event-story p {
|
| 416 |
+
font-size: 12px;
|
| 417 |
+
margin-top: 3px;
|
| 418 |
+
overflow-wrap: anywhere;
|
| 419 |
+
}
|
| 420 |
+
.timeline-area {
|
| 421 |
+
margin-top: 20px;
|
| 422 |
+
}
|
| 423 |
+
.timeline-heading {
|
| 424 |
+
display: flex;
|
| 425 |
+
justify-content: space-between;
|
| 426 |
+
gap: 10px;
|
| 427 |
+
font-size: 11px;
|
| 428 |
+
}
|
| 429 |
+
.timeline-heading span {
|
| 430 |
+
color: var(--muted);
|
| 431 |
+
font-size: 10px;
|
| 432 |
+
}
|
| 433 |
+
#timeline {
|
| 434 |
+
display: block;
|
| 435 |
+
width: 100%;
|
| 436 |
+
height: 116px;
|
| 437 |
+
margin-top: 8px;
|
| 438 |
+
overflow: visible;
|
| 439 |
+
}
|
| 440 |
+
#timeline text {
|
| 441 |
+
fill: var(--muted);
|
| 442 |
+
font-size: 10px;
|
| 443 |
+
}
|
| 444 |
+
#timeline .tick {
|
| 445 |
+
cursor: pointer;
|
| 446 |
+
}
|
| 447 |
+
#timeline .cursor {
|
| 448 |
+
stroke: var(--ink);
|
| 449 |
+
stroke-width: 1.4;
|
| 450 |
+
}
|
| 451 |
+
.timeline-footer {
|
| 452 |
+
display: flex;
|
| 453 |
+
justify-content: space-between;
|
| 454 |
+
color: var(--muted);
|
| 455 |
+
font-size: 10px;
|
| 456 |
+
gap: 12px;
|
| 457 |
+
}
|
| 458 |
+
.jumps {
|
| 459 |
+
display: flex;
|
| 460 |
+
gap: 6px;
|
| 461 |
+
flex-wrap: wrap;
|
| 462 |
+
margin-top: 14px;
|
| 463 |
+
}
|
| 464 |
+
.jumps button {
|
| 465 |
+
font-size: 11px;
|
| 466 |
+
min-height: 27px;
|
| 467 |
+
padding: 3px 9px;
|
| 468 |
+
}
|
| 469 |
+
details {
|
| 470 |
+
margin-top: 13px;
|
| 471 |
+
font-size: 11px;
|
| 472 |
+
color: var(--muted);
|
| 473 |
+
}
|
| 474 |
+
summary {
|
| 475 |
+
cursor: pointer;
|
| 476 |
+
width: fit-content;
|
| 477 |
+
}
|
| 478 |
+
pre {
|
| 479 |
+
font-size: 11px;
|
| 480 |
+
max-height: 190px;
|
| 481 |
+
overflow: auto;
|
| 482 |
+
background: var(--soft);
|
| 483 |
+
padding: 12px;
|
| 484 |
+
border-radius: 8px;
|
| 485 |
+
white-space: pre-wrap;
|
| 486 |
+
overflow-wrap: anywhere;
|
| 487 |
+
}
|
| 488 |
+
.footnote {
|
| 489 |
+
font-size: 10px;
|
| 490 |
+
line-height: 1.5;
|
| 491 |
+
margin-top: 11px;
|
| 492 |
+
}
|
| 493 |
+
@media (prefers-color-scheme: dark) {
|
| 494 |
+
:root {
|
| 495 |
+
--bg: #111727;
|
| 496 |
+
--soft: #192134;
|
| 497 |
+
--ink: #e5e9f5;
|
| 498 |
+
--muted: #9aa5bd;
|
| 499 |
+
--line: #2b354b;
|
| 500 |
+
--indigo: #978bfa;
|
| 501 |
+
--teal: #43c3b8;
|
| 502 |
+
--amber: #e8b15a;
|
| 503 |
+
--purple: #b498ee;
|
| 504 |
+
}
|
| 505 |
+
.answer mark {
|
| 506 |
+
background: #433761;
|
| 507 |
+
}
|
| 508 |
+
button.primary {
|
| 509 |
+
color: #111727;
|
| 510 |
+
}
|
| 511 |
+
}
|
| 512 |
+
@media (max-width: 650px) {
|
| 513 |
+
.replay {
|
| 514 |
+
padding: 18px 14px 14px;
|
| 515 |
+
border-radius: 14px;
|
| 516 |
+
}
|
| 517 |
+
.heading {
|
| 518 |
+
gap: 7px;
|
| 519 |
+
}
|
| 520 |
+
h2 {
|
| 521 |
+
font-size: 24px;
|
| 522 |
+
}
|
| 523 |
+
.heading p {
|
| 524 |
+
font-size: 12px;
|
| 525 |
+
}
|
| 526 |
+
.badge {
|
| 527 |
+
font-size: 9px;
|
| 528 |
+
padding: 4px 7px;
|
| 529 |
+
}
|
| 530 |
+
.position {
|
| 531 |
+
display: block;
|
| 532 |
+
text-align: right;
|
| 533 |
+
}
|
| 534 |
+
.position span {
|
| 535 |
+
display: block;
|
| 536 |
+
font-size: 9px;
|
| 537 |
+
}
|
| 538 |
+
.speed {
|
| 539 |
+
margin-left: 0;
|
| 540 |
+
}
|
| 541 |
+
.transport {
|
| 542 |
+
gap: 4px;
|
| 543 |
+
}
|
| 544 |
+
button {
|
| 545 |
+
padding: 5px 8px;
|
| 546 |
+
}
|
| 547 |
+
.primary {
|
| 548 |
+
min-width: 70px !important;
|
| 549 |
+
}
|
| 550 |
+
.scene {
|
| 551 |
+
grid-template-columns: 43% 53%;
|
| 552 |
+
padding-top: 16px;
|
| 553 |
+
gap: 10px;
|
| 554 |
+
min-height: 0;
|
| 555 |
+
}
|
| 556 |
+
.thought-area {
|
| 557 |
+
grid-column: 2;
|
| 558 |
+
}
|
| 559 |
+
.tool-area {
|
| 560 |
+
grid-column: 1;
|
| 561 |
+
}
|
| 562 |
+
.display-area {
|
| 563 |
+
grid-column: 1/-1;
|
| 564 |
+
border-top: 1px solid var(--line);
|
| 565 |
+
padding-top: 14px;
|
| 566 |
+
}
|
| 567 |
+
.connections {
|
| 568 |
+
display: none;
|
| 569 |
+
}
|
| 570 |
+
.field-wrap svg {
|
| 571 |
+
max-height: 176px;
|
| 572 |
+
}
|
| 573 |
+
.legend {
|
| 574 |
+
gap: 5px;
|
| 575 |
+
font-size: 9px;
|
| 576 |
+
}
|
| 577 |
+
.answer {
|
| 578 |
+
min-height: 60px;
|
| 579 |
+
max-height: 130px;
|
| 580 |
+
font-size: 23px;
|
| 581 |
+
}
|
| 582 |
+
.display-area h3 {
|
| 583 |
+
margin-bottom: 7px;
|
| 584 |
+
}
|
| 585 |
+
.timeline-heading {
|
| 586 |
+
display: block;
|
| 587 |
+
}
|
| 588 |
+
.timeline-heading span {
|
| 589 |
+
display: block;
|
| 590 |
+
margin-top: 3px;
|
| 591 |
+
}
|
| 592 |
+
.timeline-footer {
|
| 593 |
+
font-size: 9px;
|
| 594 |
+
}
|
| 595 |
+
.event-story {
|
| 596 |
+
margin-top: 12px;
|
| 597 |
+
padding: 12px;
|
| 598 |
+
}
|
| 599 |
+
.event-story p {
|
| 600 |
+
font-size: 11px;
|
| 601 |
+
}
|
| 602 |
+
.tools {
|
| 603 |
+
max-height: 175px;
|
| 604 |
+
}
|
| 605 |
+
.tool-row {
|
| 606 |
+
padding: 8px;
|
| 607 |
+
}
|
| 608 |
+
.channel-label {
|
| 609 |
+
font-size: 9px;
|
| 610 |
+
}
|
| 611 |
+
.scene h3 {
|
| 612 |
+
font-size: 12px;
|
| 613 |
+
}
|
| 614 |
+
.footnote {
|
| 615 |
+
font-size: 9px;
|
| 616 |
+
}
|
| 617 |
+
}
|
| 618 |
+
@media (prefers-reduced-motion: reduce) {
|
| 619 |
+
*,
|
| 620 |
+
*::before,
|
| 621 |
+
*::after {
|
| 622 |
+
animation: none !important;
|
| 623 |
+
transition: none !important;
|
| 624 |
+
}
|
| 625 |
+
}
|
cid_demo/assets/mechanism.html
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!doctype html>
|
| 2 |
+
<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
| 3 |
+
<style>/* REPLAY_CSS */</style></head>
|
| 4 |
+
<body>
|
| 5 |
+
<main class="replay" aria-label="CID mechanism replay">
|
| 6 |
+
<header class="heading"><div><div class="eyebrow">INSIDE THE RUN</div><h2>CID in motion</h2>
|
| 7 |
+
<p>Follow the cognitive cells, tool activity and revisable answer through this run.</p></div>
|
| 8 |
+
<span class="badge" id="run-badge">Awaiting a run</span></header>
|
| 9 |
+
<div class="question" id="question">Run a prompt above to explore its actual trajectory.</div>
|
| 10 |
+
<div class="transport">
|
| 11 |
+
<button id="play" class="primary" disabled aria-label="Play replay">▶ Play</button>
|
| 12 |
+
<button id="prev" aria-label="Previous event" disabled>←</button>
|
| 13 |
+
<button id="next" aria-label="Next event" disabled>→</button>
|
| 14 |
+
<label class="speed">Pace <select id="speed" aria-label="Playback pace"><option value="900">Slow</option><option value="380" selected>Normal</option><option value="120">Fast</option></select></label>
|
| 15 |
+
<div class="position"><strong id="step-label">Step —</strong><span id="time-label">0.000 s · event —</span></div>
|
| 16 |
+
</div>
|
| 17 |
+
<input id="scrubber" aria-label="Runtime event" type="range" min="0" max="0" value="0" disabled>
|
| 18 |
+
<div class="scene">
|
| 19 |
+
<svg class="connections" viewBox="0 0 1000 290" preserveAspectRatio="none" aria-hidden="true">
|
| 20 |
+
<defs><marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="5" markerHeight="5" orient="auto-start-reverse"><path d="M 0 0 L 10 5 L 0 10 z" fill="context-stroke"/></marker></defs>
|
| 21 |
+
<path id="request-path" class="path need" d="M 420 86 C 340 50 306 58 246 86" marker-end="url(#arrow)"/>
|
| 22 |
+
<path id="return-path" class="path evidence" d="M 246 191 C 319 221 355 221 420 191" marker-end="url(#arrow)"/>
|
| 23 |
+
<path id="display-path" class="path display" d="M 586 140 C 646 140 665 140 724 140" marker-end="url(#arrow)"/>
|
| 24 |
+
<text x="326" y="51" text-anchor="middle">information need</text>
|
| 25 |
+
<text x="326" y="242" text-anchor="middle">evidence → projection</text>
|
| 26 |
+
<text x="656" y="123" text-anchor="middle">materialize</text>
|
| 27 |
+
</svg>
|
| 28 |
+
<section class="tool-area"><div class="channel-label"><i class="dot tool"></i>EXTERNAL TOOLS</div>
|
| 29 |
+
<h3>Reach for information</h3>
|
| 30 |
+
<div id="tools" class="tools"><div class="empty">Tool activity will appear here.</div></div>
|
| 31 |
+
<div id="tool-count" class="micro">Requests and returns from the trace</div>
|
| 32 |
+
</section>
|
| 33 |
+
<section class="thought-area"><div class="channel-label"><i class="dot thought"></i>T · THOUGHT</div>
|
| 34 |
+
<h3>A field of cognitive cells</h3>
|
| 35 |
+
<div class="field-wrap"><svg id="field" viewBox="0 0 300 235" role="img" aria-label="Observed TCT cell lifecycle states">
|
| 36 |
+
<ellipse class="field-shell" cx="150" cy="119" rx="140" ry="108"/>
|
| 37 |
+
<ellipse class="field-inner" cx="150" cy="119" rx="118" ry="89"/>
|
| 38 |
+
<g id="cells"></g><text id="field-empty" x="150" y="122" text-anchor="middle">No cells recorded yet</text>
|
| 39 |
+
</svg><span id="model-state" class="model-state">Waiting to begin</span></div>
|
| 40 |
+
<div class="legend"><span><i class="dot active"></i>Active</span><span><i class="dot waiting"></i>Waiting</span><span><i class="dot stable"></i>Stable</span><span><i class="dot retired"></i>Retired</span></div>
|
| 41 |
+
<div class="micro" id="cell-count">Cell colors follow recorded lifecycle events.</div>
|
| 42 |
+
</section>
|
| 43 |
+
<section class="display-area"><div class="channel-label"><i class="dot display"></i>D · DISPLAY</div>
|
| 44 |
+
<h3>An answer that can change</h3>
|
| 45 |
+
<div id="answer" class="answer">No Display materialized yet.</div>
|
| 46 |
+
<div class="micro" id="display-meta">Newly changed text is highlighted.</div>
|
| 47 |
+
<div id="tokens" class="tokens" aria-label="Recorded Display token positions"></div>
|
| 48 |
+
<div class="micro" id="token-caption"></div>
|
| 49 |
+
</section>
|
| 50 |
+
</div>
|
| 51 |
+
<div class="event-story" aria-live="polite" aria-atomic="true"><span class="event-icon" id="event-icon">○</span><div><strong id="event-title">Your run, made visible</strong><p id="event-copy">Play, pause or scrub through the events after a run finishes.</p></div></div>
|
| 52 |
+
<section class="timeline-area"><div class="timeline-heading"><strong>One shared clock</strong><span>Model work & tools can overlap · click a mark to inspect</span></div>
|
| 53 |
+
<svg id="timeline" viewBox="0 0 1000 116" role="img" aria-label="Model, tool, TCT and Display events on the recorded wall clock"></svg>
|
| 54 |
+
<div class="timeline-footer"><span id="duration-label">Recorded wall time</span><span>Playback pace is illustrative; timestamps are measured.</span></div>
|
| 55 |
+
</section>
|
| 56 |
+
<div class="jumps" id="jumps"></div>
|
| 57 |
+
<details id="event-details"><summary>Inspect this event</summary><pre id="raw-event">No runtime event selected.</pre></details>
|
| 58 |
+
<p class="footnote">Cells show observed lifecycle states, not decoded thoughts. Connections highlight recorded event types; the trace does not expose cell-to-cell semantic links.</p>
|
| 59 |
+
</main>
|
| 60 |
+
<script id="replay-data" type="application/json">/* REPLAY_DATA */</script>
|
| 61 |
+
<script>/* REPLAY_JS */</script>
|
| 62 |
+
</body></html>
|
cid_demo/assets/mechanism.js
ADDED
|
@@ -0,0 +1,782 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* Pure event reducer is also exercised by the Node regression tests. */
|
| 2 |
+
function buildReplay(events) {
|
| 3 |
+
let state = {
|
| 4 |
+
cells: {},
|
| 5 |
+
bindings: {},
|
| 6 |
+
jobs: {},
|
| 7 |
+
display: null,
|
| 8 |
+
previousDisplay: null,
|
| 9 |
+
model: "Waiting to begin",
|
| 10 |
+
needs: 0,
|
| 11 |
+
returns: 0,
|
| 12 |
+
projections: 0,
|
| 13 |
+
done: false,
|
| 14 |
+
};
|
| 15 |
+
const frames = [];
|
| 16 |
+
for (let i = 0; i < events.length; i++) {
|
| 17 |
+
const e = events[i],
|
| 18 |
+
p = e.payload || {},
|
| 19 |
+
k = e.kind;
|
| 20 |
+
state = {
|
| 21 |
+
...state,
|
| 22 |
+
cells: { ...state.cells },
|
| 23 |
+
bindings: { ...state.bindings },
|
| 24 |
+
jobs: { ...state.jobs },
|
| 25 |
+
};
|
| 26 |
+
const binding = (id, patch) => {
|
| 27 |
+
if (id)
|
| 28 |
+
state.bindings[id] = {
|
| 29 |
+
...(state.bindings[id] || { source: "Unknown source" }),
|
| 30 |
+
...Object.fromEntries(
|
| 31 |
+
Object.entries(patch).filter(([, v]) => v !== undefined),
|
| 32 |
+
),
|
| 33 |
+
};
|
| 34 |
+
};
|
| 35 |
+
const forWork = (key, patch) => {
|
| 36 |
+
if (key)
|
| 37 |
+
for (const [id, b] of Object.entries(state.bindings))
|
| 38 |
+
if (b.work_key === key) binding(id, patch);
|
| 39 |
+
};
|
| 40 |
+
if (k === "cell_allocated")
|
| 41 |
+
state.cells[p.cell_id] = { lifecycle: p.lifecycle, event: i };
|
| 42 |
+
if (k === "lifecycle_transition")
|
| 43 |
+
state.cells[p.cell_id] = { lifecycle: p.current, event: i };
|
| 44 |
+
if (k === "cell_reclaimed") delete state.cells[p.cell_id];
|
| 45 |
+
if (k === "model_step_started") state.model = "Refining";
|
| 46 |
+
if (k === "model_step_finished") {
|
| 47 |
+
state.model = p.converged
|
| 48 |
+
? "Convergence proposed"
|
| 49 |
+
: p.equilibrium
|
| 50 |
+
? "At equilibrium"
|
| 51 |
+
: "Step complete";
|
| 52 |
+
if (Object.hasOwn(p, "display_materialized_text")) {
|
| 53 |
+
state.previousDisplay = state.display;
|
| 54 |
+
state.display = {
|
| 55 |
+
text: p.display_materialized_text,
|
| 56 |
+
ids: p.display_token_ids || null,
|
| 57 |
+
step: e.step,
|
| 58 |
+
unresolved: p.display_unresolved,
|
| 59 |
+
};
|
| 60 |
+
}
|
| 61 |
+
}
|
| 62 |
+
if (k === "information_need") state.needs++;
|
| 63 |
+
if (k === "binding_active")
|
| 64 |
+
binding(p.binding_id, {
|
| 65 |
+
source: p.source,
|
| 66 |
+
need_id: p.need_id,
|
| 67 |
+
...(!state.bindings[p.binding_id] ? { status: "Bound" } : {}),
|
| 68 |
+
});
|
| 69 |
+
if (k === "external_refresh_started" || k === "job_started") {
|
| 70 |
+
binding(p.binding_id, { status: "Running", work_key: p.work_key });
|
| 71 |
+
if (p.work_key)
|
| 72 |
+
state.jobs[p.work_key] = {
|
| 73 |
+
binding_id: p.binding_id,
|
| 74 |
+
status: "Running",
|
| 75 |
+
};
|
| 76 |
+
}
|
| 77 |
+
if (k === "external_refresh_ready") {
|
| 78 |
+
binding(p.binding_id, {
|
| 79 |
+
status: p.success === false ? "Failed" : "Returned",
|
| 80 |
+
work_key: p.work_key,
|
| 81 |
+
});
|
| 82 |
+
if (p.work_key)
|
| 83 |
+
state.jobs[p.work_key] = {
|
| 84 |
+
...(state.jobs[p.work_key] || {}),
|
| 85 |
+
status: p.success === false ? "Failed" : "Returned",
|
| 86 |
+
};
|
| 87 |
+
}
|
| 88 |
+
if (k === "external_refresh_finished" || k === "job_finished") {
|
| 89 |
+
forWork(p.work_key, { status: "Read complete" });
|
| 90 |
+
state.returns++;
|
| 91 |
+
}
|
| 92 |
+
if (k === "binding_observation_updated" || k === "observation_available")
|
| 93 |
+
binding(p.binding_id, {
|
| 94 |
+
status: "Evidence available",
|
| 95 |
+
work_key: p.work_key,
|
| 96 |
+
version: p.version,
|
| 97 |
+
});
|
| 98 |
+
if (k === "cache_hit") binding(p.binding_id, { status: "Cached evidence" });
|
| 99 |
+
if (k === "cognitive_projection") {
|
| 100 |
+
binding(p.binding_id, { status: "Projected", projection: p.index });
|
| 101 |
+
state.projections++;
|
| 102 |
+
}
|
| 103 |
+
if (k === "job_deduplicated")
|
| 104 |
+
binding(p.binding_id, { status: "Shared job" });
|
| 105 |
+
if (k === "external_refresh_cancelled" || k === "stream_cancelled")
|
| 106 |
+
forWork(p.work_key, { status: "Cancelled" });
|
| 107 |
+
if (k === "quiescence_started") state.model = "Waiting for evidence";
|
| 108 |
+
if (k === "quiescence_resumed") state.model = "Resuming";
|
| 109 |
+
if (k === "loop_escape_applied") state.model = "Re-diffusing";
|
| 110 |
+
if (k === "trajectory_finalized") state.model = "Converged";
|
| 111 |
+
if (k === "trajectory_finished") {
|
| 112 |
+
state.model = p.converged ? "Converged" : "Stopped";
|
| 113 |
+
state.done = true;
|
| 114 |
+
}
|
| 115 |
+
frames.push(state);
|
| 116 |
+
}
|
| 117 |
+
return frames;
|
| 118 |
+
}
|
| 119 |
+
if (typeof module !== "undefined") module.exports = { buildReplay };
|
| 120 |
+
|
| 121 |
+
if (typeof document !== "undefined")
|
| 122 |
+
(() => {
|
| 123 |
+
"use strict";
|
| 124 |
+
const data = JSON.parse(document.getElementById("replay-data").textContent);
|
| 125 |
+
const events = data.events || [],
|
| 126 |
+
frames = buildReplay(events),
|
| 127 |
+
$ = (id) => document.getElementById(id);
|
| 128 |
+
const esc = (x) =>
|
| 129 |
+
String(x ?? "").replace(
|
| 130 |
+
/[&<>"']/g,
|
| 131 |
+
(c) =>
|
| 132 |
+
({
|
| 133 |
+
"&": "&",
|
| 134 |
+
"<": "<",
|
| 135 |
+
">": ">",
|
| 136 |
+
'"': """,
|
| 137 |
+
"'": "'",
|
| 138 |
+
})[c],
|
| 139 |
+
);
|
| 140 |
+
const colors = {
|
| 141 |
+
active: "var(--active)",
|
| 142 |
+
waiting: "var(--waiting)",
|
| 143 |
+
stable: "var(--stable)",
|
| 144 |
+
retired: "var(--retired)",
|
| 145 |
+
empty: "var(--line)",
|
| 146 |
+
};
|
| 147 |
+
let index = 0,
|
| 148 |
+
timer = null,
|
| 149 |
+
selectedCell = null;
|
| 150 |
+
const lastTime = Math.max(
|
| 151 |
+
0,
|
| 152 |
+
...events.map((e) => Number(e.timestamp_s) || 0),
|
| 153 |
+
);
|
| 154 |
+
const timeX = (t) => 100 + (884 * (Number(t) || 0)) / (lastTime || 1);
|
| 155 |
+
const lane = (k) =>
|
| 156 |
+
/external|binding|information_need|cache_hit|projection|job_|stream_|observation/.test(
|
| 157 |
+
k,
|
| 158 |
+
)
|
| 159 |
+
? 1
|
| 160 |
+
: /cell_|lifecycle|compaction|loop_/.test(k)
|
| 161 |
+
? 2
|
| 162 |
+
: k === "model_step_finished"
|
| 163 |
+
? 3
|
| 164 |
+
: 0;
|
| 165 |
+
const laneColor = (n) =>
|
| 166 |
+
["var(--indigo)", "var(--teal)", "var(--amber)", "var(--purple)"][n];
|
| 167 |
+
function story(e, s) {
|
| 168 |
+
const p = e.payload || {},
|
| 169 |
+
source = p.source || s.bindings[p.binding_id]?.source || "the tool";
|
| 170 |
+
const known = {
|
| 171 |
+
trajectory_started: [
|
| 172 |
+
"◎",
|
| 173 |
+
"The trajectory begins",
|
| 174 |
+
"The runtime starts iterative refinement for this prompt.",
|
| 175 |
+
],
|
| 176 |
+
model_step_started: [
|
| 177 |
+
"↻",
|
| 178 |
+
"Refining the current state",
|
| 179 |
+
p.percepts
|
| 180 |
+
? String(p.percepts) + " recorded percept(s) enter this model step."
|
| 181 |
+
: "The model updates its cognitive field and Display.",
|
| 182 |
+
],
|
| 183 |
+
model_step_finished: [
|
| 184 |
+
"✦",
|
| 185 |
+
"The Display is materialized",
|
| 186 |
+
String(p.needs ?? 0) +
|
| 187 |
+
" information need(s) proposed. " +
|
| 188 |
+
(p.converged
|
| 189 |
+
? "The model proposes convergence; the runtime still checks outstanding work."
|
| 190 |
+
: p.equilibrium
|
| 191 |
+
? "The model reports equilibrium for its current information."
|
| 192 |
+
: "Compare this snapshot with the previous model step."),
|
| 193 |
+
],
|
| 194 |
+
information_need: [
|
| 195 |
+
"↗",
|
| 196 |
+
"An information need emerges",
|
| 197 |
+
source +
|
| 198 |
+
" · confidence " +
|
| 199 |
+
(Number.isFinite(p.confidence)
|
| 200 |
+
? p.confidence.toFixed(3)
|
| 201 |
+
: "not recorded") +
|
| 202 |
+
". " +
|
| 203 |
+
(p.executable
|
| 204 |
+
? "This need has the required tool arguments."
|
| 205 |
+
: "This need is not executable at this event."),
|
| 206 |
+
],
|
| 207 |
+
binding_active: [
|
| 208 |
+
"⇄",
|
| 209 |
+
"A need is bound to a source",
|
| 210 |
+
source + " is bound to " + (p.need_id || "the recorded need") + ".",
|
| 211 |
+
],
|
| 212 |
+
external_refresh_started: [
|
| 213 |
+
"↗",
|
| 214 |
+
"External work starts",
|
| 215 |
+
"A read is launched for " +
|
| 216 |
+
source +
|
| 217 |
+
". Subsequent model steps and this read have separate events on the clock.",
|
| 218 |
+
],
|
| 219 |
+
external_refresh_ready: [
|
| 220 |
+
"↙",
|
| 221 |
+
p.success === false
|
| 222 |
+
? "The tool read failed"
|
| 223 |
+
: "The tool has returned",
|
| 224 |
+
p.success === false
|
| 225 |
+
? "The completion callback reports failure."
|
| 226 |
+
: "The asynchronous read is ready. The runtime must still collect and project its observation.",
|
| 227 |
+
],
|
| 228 |
+
external_refresh_finished: [
|
| 229 |
+
"✓",
|
| 230 |
+
"The runtime collects a result",
|
| 231 |
+
"The completed external read is drained; observation updates identify the receiving bindings.",
|
| 232 |
+
],
|
| 233 |
+
binding_observation_updated: [
|
| 234 |
+
"↓",
|
| 235 |
+
"Evidence becomes available",
|
| 236 |
+
source +
|
| 237 |
+
" now has a recorded observation. A projection event shows when it is fed into the model.",
|
| 238 |
+
],
|
| 239 |
+
cognitive_projection: [
|
| 240 |
+
"→",
|
| 241 |
+
"Evidence enters the cognitive field",
|
| 242 |
+
source +
|
| 243 |
+
" · projection " +
|
| 244 |
+
(p.index ?? "—") +
|
| 245 |
+
". The observation is included in the next model context.",
|
| 246 |
+
],
|
| 247 |
+
cache_hit: [
|
| 248 |
+
"↙",
|
| 249 |
+
"A cached observation is reused",
|
| 250 |
+
"An existing observation satisfies this binding without a new external read.",
|
| 251 |
+
],
|
| 252 |
+
job_deduplicated: [
|
| 253 |
+
"⇄",
|
| 254 |
+
"Bindings share external work",
|
| 255 |
+
"This need reuses an already running job.",
|
| 256 |
+
],
|
| 257 |
+
cell_allocated: [
|
| 258 |
+
"●",
|
| 259 |
+
"A cognitive cell is allocated",
|
| 260 |
+
(p.cell_id || "Cell") +
|
| 261 |
+
" enters the " +
|
| 262 |
+
(p.lifecycle || "recorded") +
|
| 263 |
+
" state.",
|
| 264 |
+
],
|
| 265 |
+
lifecycle_transition: [
|
| 266 |
+
"◉",
|
| 267 |
+
"A cognitive cell changes state",
|
| 268 |
+
(p.cell_id || "Cell") + ": " + p.previous + " → " + p.current + ".",
|
| 269 |
+
],
|
| 270 |
+
cell_reclaimed: [
|
| 271 |
+
"○",
|
| 272 |
+
"A retired cell is reclaimed",
|
| 273 |
+
(p.cell_id || "Cell") + " is archived and its slot becomes reusable.",
|
| 274 |
+
],
|
| 275 |
+
cognitive_compaction: [
|
| 276 |
+
"⋮",
|
| 277 |
+
"The cognitive field is compacted",
|
| 278 |
+
String(p.reclaimed ?? 0) +
|
| 279 |
+
" cell(s) reclaimed; " +
|
| 280 |
+
String(p.empty_slots ?? "—") +
|
| 281 |
+
" empty slots reported.",
|
| 282 |
+
],
|
| 283 |
+
quiescence_started: [
|
| 284 |
+
"Ⅱ",
|
| 285 |
+
"Model computation pauses",
|
| 286 |
+
"The runtime waits for external progress. Reason: " +
|
| 287 |
+
(p.reason || "not recorded") +
|
| 288 |
+
".",
|
| 289 |
+
],
|
| 290 |
+
quiescence_resumed: [
|
| 291 |
+
"↻",
|
| 292 |
+
"External progress resumes the loop",
|
| 293 |
+
"Reason: " +
|
| 294 |
+
(p.reason || "not recorded") +
|
| 295 |
+
". The next recorded model step shows the continuation.",
|
| 296 |
+
],
|
| 297 |
+
loop_detected: [
|
| 298 |
+
"↻",
|
| 299 |
+
"A repeated pattern is detected",
|
| 300 |
+
"The runtime records a " +
|
| 301 |
+
(p.mode || "") +
|
| 302 |
+
" cycle of period " +
|
| 303 |
+
(p.period ?? "—") +
|
| 304 |
+
".",
|
| 305 |
+
],
|
| 306 |
+
loop_escape_applied: [
|
| 307 |
+
"↻",
|
| 308 |
+
"The runtime re-diffuses selected positions",
|
| 309 |
+
"This is a recovery event. The next model snapshot reveals the updated Display.",
|
| 310 |
+
],
|
| 311 |
+
trajectory_finalized: [
|
| 312 |
+
"✓",
|
| 313 |
+
"The runtime accepts convergence",
|
| 314 |
+
"The finalization conditions are satisfied.",
|
| 315 |
+
],
|
| 316 |
+
trajectory_finished: [
|
| 317 |
+
s.model === "Converged" ? "✓" : "■",
|
| 318 |
+
s.model === "Converged"
|
| 319 |
+
? "The run has converged"
|
| 320 |
+
: "The run stopped without convergence",
|
| 321 |
+
"The replay has reached the recorded end of model execution.",
|
| 322 |
+
],
|
| 323 |
+
total_compute_budget_exhausted: [
|
| 324 |
+
"■",
|
| 325 |
+
"The model-step budget is reached",
|
| 326 |
+
"The run stops at its configured total compute limit.",
|
| 327 |
+
],
|
| 328 |
+
compute_budget_exhausted: [
|
| 329 |
+
"■",
|
| 330 |
+
"The compute budget is reached",
|
| 331 |
+
"The runtime records a compute-budget stop.",
|
| 332 |
+
],
|
| 333 |
+
wall_clock_budget_exhausted: [
|
| 334 |
+
"■",
|
| 335 |
+
"The wall-time budget is reached",
|
| 336 |
+
"The run stops at its configured wall-time limit.",
|
| 337 |
+
],
|
| 338 |
+
loop_escape_exhausted: [
|
| 339 |
+
"■",
|
| 340 |
+
"Recovery attempts are exhausted",
|
| 341 |
+
"The runtime stops after its configured loop-escape attempts.",
|
| 342 |
+
],
|
| 343 |
+
};
|
| 344 |
+
return (
|
| 345 |
+
known[e.kind] || [
|
| 346 |
+
"·",
|
| 347 |
+
e.kind.replaceAll("_", " "),
|
| 348 |
+
"Inspect the exact recorded payload below.",
|
| 349 |
+
]
|
| 350 |
+
);
|
| 351 |
+
}
|
| 352 |
+
function displayMarkup(now, before) {
|
| 353 |
+
if (now === null || now === undefined)
|
| 354 |
+
return "No Display materialized yet.";
|
| 355 |
+
if (!now) return '<span class="micro">(empty Display)</span>';
|
| 356 |
+
const a = Array.from(now),
|
| 357 |
+
b = Array.from(before || "");
|
| 358 |
+
let start = 0,
|
| 359 |
+
end = 0;
|
| 360 |
+
while (start < a.length && start < b.length && a[start] === b[start])
|
| 361 |
+
start++;
|
| 362 |
+
while (
|
| 363 |
+
end < a.length - start &&
|
| 364 |
+
end < b.length - start &&
|
| 365 |
+
a[a.length - 1 - end] === b[b.length - 1 - end]
|
| 366 |
+
)
|
| 367 |
+
end++;
|
| 368 |
+
return (
|
| 369 |
+
esc(a.slice(0, start).join("")) +
|
| 370 |
+
(a.length - start - end
|
| 371 |
+
? "<mark>" + esc(a.slice(start, a.length - end).join("")) + "</mark>"
|
| 372 |
+
: "") +
|
| 373 |
+
esc(end ? a.slice(-end).join("") : "")
|
| 374 |
+
);
|
| 375 |
+
}
|
| 376 |
+
function renderCells(s, e) {
|
| 377 |
+
const entries = Object.entries(s.cells),
|
| 378 |
+
count = entries.length;
|
| 379 |
+
$("field-empty").style.display = count ? "none" : "";
|
| 380 |
+
$("cells").innerHTML = entries
|
| 381 |
+
.map(([id, c], n) => {
|
| 382 |
+
const angle = n * 2.3999632297,
|
| 383 |
+
r = Math.sqrt((n + 0.5) / Math.max(count, 1));
|
| 384 |
+
const x = 150 + 112 * r * Math.cos(angle),
|
| 385 |
+
y = 112 + 82 * r * Math.sin(angle),
|
| 386 |
+
radius = Math.min(16, Math.max(4.5, 67 / Math.sqrt(count)));
|
| 387 |
+
return (
|
| 388 |
+
'<g data-cell="' +
|
| 389 |
+
esc(id) +
|
| 390 |
+
'" tabindex="0" role="button" aria-label="' +
|
| 391 |
+
esc(id) +
|
| 392 |
+
": " +
|
| 393 |
+
esc(c.lifecycle) +
|
| 394 |
+
'"><title>' +
|
| 395 |
+
esc(id) +
|
| 396 |
+
" · " +
|
| 397 |
+
esc(c.lifecycle) +
|
| 398 |
+
'</title><circle class="cell ' +
|
| 399 |
+
(c.event === index || id === selectedCell ? "changed" : "") +
|
| 400 |
+
'" cx="' +
|
| 401 |
+
x +
|
| 402 |
+
'" cy="' +
|
| 403 |
+
y +
|
| 404 |
+
'" r="' +
|
| 405 |
+
radius +
|
| 406 |
+
'" fill="' +
|
| 407 |
+
(colors[c.lifecycle] || "var(--line)") +
|
| 408 |
+
'" ' +
|
| 409 |
+
(c.lifecycle === "retired" ? 'opacity=".42"' : "") +
|
| 410 |
+
"/>" +
|
| 411 |
+
(count <= 40
|
| 412 |
+
? '<text class="cell-label" x="' +
|
| 413 |
+
x +
|
| 414 |
+
'" y="' +
|
| 415 |
+
(y + 2.6) +
|
| 416 |
+
'" text-anchor="middle">' +
|
| 417 |
+
(n + 1) +
|
| 418 |
+
"</text>"
|
| 419 |
+
: "") +
|
| 420 |
+
"</g>"
|
| 421 |
+
);
|
| 422 |
+
})
|
| 423 |
+
.join("");
|
| 424 |
+
const counts = {};
|
| 425 |
+
entries.forEach(
|
| 426 |
+
([, c]) => (counts[c.lifecycle] = (counts[c.lifecycle] || 0) + 1),
|
| 427 |
+
);
|
| 428 |
+
$("cell-count").textContent = count
|
| 429 |
+
? Object.entries(counts)
|
| 430 |
+
.map(([k, v]) => v + " " + k)
|
| 431 |
+
.join(" · ")
|
| 432 |
+
: "No cell lifecycle events recorded so far.";
|
| 433 |
+
}
|
| 434 |
+
function renderTools(s) {
|
| 435 |
+
const grouped = {};
|
| 436 |
+
for (const [id, b] of Object.entries(s.bindings))
|
| 437 |
+
(grouped[b.source] ??= []).push([id, b]);
|
| 438 |
+
$("tools").innerHTML =
|
| 439 |
+
Object.entries(grouped)
|
| 440 |
+
.map(([source, items]) => {
|
| 441 |
+
const current =
|
| 442 |
+
items.find(([id]) => id === events[index].payload?.binding_id) ||
|
| 443 |
+
items[items.length - 1];
|
| 444 |
+
const b = current[1],
|
| 445 |
+
busy = items.some(([, x]) => x.status === "Running"),
|
| 446 |
+
cls = busy
|
| 447 |
+
? "busy"
|
| 448 |
+
: /Projected|Evidence|Cached|Returned|complete/i.test(b.status)
|
| 449 |
+
? "ready"
|
| 450 |
+
: "";
|
| 451 |
+
return (
|
| 452 |
+
'<div class="tool-row ' +
|
| 453 |
+
cls +
|
| 454 |
+
'"><strong>' +
|
| 455 |
+
esc(source) +
|
| 456 |
+
"</strong><span>" +
|
| 457 |
+
esc(b.status) +
|
| 458 |
+
"</span><small>" +
|
| 459 |
+
items.length +
|
| 460 |
+
" observed binding" +
|
| 461 |
+
(items.length === 1 ? "" : "s") +
|
| 462 |
+
"</small></div>"
|
| 463 |
+
);
|
| 464 |
+
})
|
| 465 |
+
.join("") ||
|
| 466 |
+
'<div class="empty">' +
|
| 467 |
+
(s.done
|
| 468 |
+
? "No tool binding was recorded in this run."
|
| 469 |
+
: "No tool binding recorded yet.") +
|
| 470 |
+
"</div>";
|
| 471 |
+
$("tool-count").textContent =
|
| 472 |
+
s.needs +
|
| 473 |
+
" needs · " +
|
| 474 |
+
s.returns +
|
| 475 |
+
" reads collected · " +
|
| 476 |
+
s.projections +
|
| 477 |
+
" projections";
|
| 478 |
+
}
|
| 479 |
+
function render() {
|
| 480 |
+
if (!events.length) return;
|
| 481 |
+
const e = events[index],
|
| 482 |
+
p = e.payload || {},
|
| 483 |
+
s = frames[index],
|
| 484 |
+
prev = s.previousDisplay;
|
| 485 |
+
$("scrubber").value = index;
|
| 486 |
+
$("step-label").textContent = "Step " + e.step;
|
| 487 |
+
$("time-label").textContent =
|
| 488 |
+
(Number(e.timestamp_s) || 0).toFixed(3) +
|
| 489 |
+
" s · event " +
|
| 490 |
+
(index + 1) +
|
| 491 |
+
"/" +
|
| 492 |
+
events.length;
|
| 493 |
+
$("prev").disabled = index === 0;
|
| 494 |
+
$("next").disabled = index === events.length - 1;
|
| 495 |
+
$("model-state").textContent = s.model;
|
| 496 |
+
$("run-badge").textContent = s.done ? s.model : "Trace replay";
|
| 497 |
+
const showFinal = s.done && typeof data.final_text === "string";
|
| 498 |
+
const text = showFinal ? data.final_text : s.display?.text;
|
| 499 |
+
$("answer").innerHTML = displayMarkup(text, prev?.text);
|
| 500 |
+
$("display-meta").textContent = showFinal
|
| 501 |
+
? "Final runtime Display"
|
| 502 |
+
: s.display
|
| 503 |
+
? "Snapshot at step " +
|
| 504 |
+
s.display.step +
|
| 505 |
+
(text === prev?.text
|
| 506 |
+
? " · unchanged"
|
| 507 |
+
: text?.length < (prev?.text || "").length
|
| 508 |
+
? " · revised / shortened"
|
| 509 |
+
: " · revised")
|
| 510 |
+
: "Awaiting the first recorded model snapshot.";
|
| 511 |
+
$("tokens").innerHTML = (s.display?.ids || [])
|
| 512 |
+
.map(
|
| 513 |
+
(id, i) =>
|
| 514 |
+
'<span class="token ' +
|
| 515 |
+
(id !== prev?.ids?.[i] ? "changed" : "") +
|
| 516 |
+
'" title="Position ' +
|
| 517 |
+
i +
|
| 518 |
+
" · token ID " +
|
| 519 |
+
id +
|
| 520 |
+
'"></span>',
|
| 521 |
+
)
|
| 522 |
+
.join("");
|
| 523 |
+
$("token-caption").textContent = s.display?.ids
|
| 524 |
+
? String(s.display.ids.length) +
|
| 525 |
+
" recorded token positions · colored = changed ID"
|
| 526 |
+
: "";
|
| 527 |
+
renderCells(s, e);
|
| 528 |
+
renderTools(s);
|
| 529 |
+
const need =
|
| 530 |
+
/information_need|binding_active|external_refresh_started/.test(
|
| 531 |
+
e.kind,
|
| 532 |
+
),
|
| 533 |
+
ret =
|
| 534 |
+
/binding_observation_updated|cache_hit|cognitive_projection|external_refresh_ready/.test(
|
| 535 |
+
e.kind,
|
| 536 |
+
);
|
| 537 |
+
$("request-path").classList.toggle("lit", need);
|
| 538 |
+
$("return-path").classList.toggle("lit", ret);
|
| 539 |
+
$("display-path").classList.toggle(
|
| 540 |
+
"lit",
|
| 541 |
+
e.kind === "model_step_finished",
|
| 542 |
+
);
|
| 543 |
+
const [icon, title, copy] = story(e, s);
|
| 544 |
+
$("event-icon").textContent = icon;
|
| 545 |
+
$("event-title").textContent = title;
|
| 546 |
+
$("event-copy").textContent = copy;
|
| 547 |
+
$("raw-event").textContent = JSON.stringify(
|
| 548 |
+
{ event: index + 1, ...e },
|
| 549 |
+
null,
|
| 550 |
+
2,
|
| 551 |
+
);
|
| 552 |
+
const cursor = $("clock-cursor");
|
| 553 |
+
if (cursor) {
|
| 554 |
+
cursor.setAttribute("x1", timeX(e.timestamp_s));
|
| 555 |
+
cursor.setAttribute("x2", timeX(e.timestamp_s));
|
| 556 |
+
}
|
| 557 |
+
resize();
|
| 558 |
+
}
|
| 559 |
+
function pause() {
|
| 560 |
+
clearTimeout(timer);
|
| 561 |
+
timer = null;
|
| 562 |
+
document.querySelector(".replay").classList.remove("playing");
|
| 563 |
+
$("play").textContent =
|
| 564 |
+
index === events.length - 1 ? "↺ Replay" : "▶ Play";
|
| 565 |
+
$("play").setAttribute(
|
| 566 |
+
"aria-label",
|
| 567 |
+
index === events.length - 1 ? "Replay from start" : "Play replay",
|
| 568 |
+
);
|
| 569 |
+
}
|
| 570 |
+
function schedule() {
|
| 571 |
+
document.querySelector(".replay").classList.add("playing");
|
| 572 |
+
timer = setTimeout(
|
| 573 |
+
() => {
|
| 574 |
+
if (index >= events.length - 1) {
|
| 575 |
+
pause();
|
| 576 |
+
return;
|
| 577 |
+
}
|
| 578 |
+
index++;
|
| 579 |
+
render();
|
| 580 |
+
schedule();
|
| 581 |
+
},
|
| 582 |
+
Number($("speed").value),
|
| 583 |
+
);
|
| 584 |
+
}
|
| 585 |
+
function seek(i) {
|
| 586 |
+
pause();
|
| 587 |
+
index = Math.max(0, Math.min(events.length - 1, i));
|
| 588 |
+
render();
|
| 589 |
+
}
|
| 590 |
+
function makeTimeline() {
|
| 591 |
+
const labels = ["Model", "Tools", "TCT", "Display"];
|
| 592 |
+
let markup = labels
|
| 593 |
+
.map(
|
| 594 |
+
(label, n) =>
|
| 595 |
+
'<text x="0" y="' +
|
| 596 |
+
(18 + n * 24) +
|
| 597 |
+
'">' +
|
| 598 |
+
label +
|
| 599 |
+
'</text><line x1="100" x2="984" y1="' +
|
| 600 |
+
(14 + n * 24) +
|
| 601 |
+
'" y2="' +
|
| 602 |
+
(14 + n * 24) +
|
| 603 |
+
'" stroke="var(--line)"/>',
|
| 604 |
+
)
|
| 605 |
+
.join("");
|
| 606 |
+
let pending = null;
|
| 607 |
+
const reads = new Map();
|
| 608 |
+
events.forEach((e, i) => {
|
| 609 |
+
const p = e.payload || {};
|
| 610 |
+
if (e.kind === "external_refresh_started" && p.work_key)
|
| 611 |
+
reads.set(p.work_key, e);
|
| 612 |
+
if (
|
| 613 |
+
(e.kind === "external_refresh_ready" ||
|
| 614 |
+
e.kind === "external_refresh_finished") &&
|
| 615 |
+
reads.has(p.work_key)
|
| 616 |
+
) {
|
| 617 |
+
const start = reads.get(p.work_key);
|
| 618 |
+
reads.delete(p.work_key);
|
| 619 |
+
markup +=
|
| 620 |
+
'<rect x="' +
|
| 621 |
+
timeX(start.timestamp_s) +
|
| 622 |
+
'" y="33" width="' +
|
| 623 |
+
Math.max(1, timeX(e.timestamp_s) - timeX(start.timestamp_s)) +
|
| 624 |
+
'" height="10" rx="2" fill="var(--teal)" opacity=".3"><title>External read · ' +
|
| 625 |
+
(Number(e.timestamp_s) - Number(start.timestamp_s)).toFixed(3) +
|
| 626 |
+
" s</title></rect>";
|
| 627 |
+
}
|
| 628 |
+
if (e.kind === "model_step_started") pending = e;
|
| 629 |
+
if (e.kind === "model_step_finished" && pending) {
|
| 630 |
+
markup +=
|
| 631 |
+
'<rect x="' +
|
| 632 |
+
timeX(pending.timestamp_s) +
|
| 633 |
+
'" y="9" width="' +
|
| 634 |
+
Math.max(1, timeX(e.timestamp_s) - timeX(pending.timestamp_s)) +
|
| 635 |
+
'" height="10" rx="2" fill="var(--indigo)" opacity=".2"/>';
|
| 636 |
+
pending = null;
|
| 637 |
+
}
|
| 638 |
+
const n = lane(e.kind);
|
| 639 |
+
markup +=
|
| 640 |
+
'<circle class="tick" data-event="' +
|
| 641 |
+
i +
|
| 642 |
+
'" tabindex="0" role="button" aria-label="Event ' +
|
| 643 |
+
(i + 1) +
|
| 644 |
+
": " +
|
| 645 |
+
esc(e.kind) +
|
| 646 |
+
'" cx="' +
|
| 647 |
+
timeX(e.timestamp_s) +
|
| 648 |
+
'" cy="' +
|
| 649 |
+
(14 + n * 24) +
|
| 650 |
+
'" r="3" fill="' +
|
| 651 |
+
laneColor(n) +
|
| 652 |
+
'"><title>' +
|
| 653 |
+
esc(e.kind) +
|
| 654 |
+
" · " +
|
| 655 |
+
Number(e.timestamp_s || 0).toFixed(3) +
|
| 656 |
+
" s</title></circle>";
|
| 657 |
+
});
|
| 658 |
+
markup +=
|
| 659 |
+
'<line id="clock-cursor" class="cursor" x1="100" x2="100" y1="1" y2="97"/><text x="100" y="113">0 s</text><text x="984" y="113" text-anchor="end">' +
|
| 660 |
+
lastTime.toFixed(3) +
|
| 661 |
+
" s</text>";
|
| 662 |
+
$("timeline").innerHTML = markup;
|
| 663 |
+
$("duration-label").textContent =
|
| 664 |
+
events.length + " events · " + lastTime.toFixed(3) + " s recorded";
|
| 665 |
+
const jumps = [
|
| 666 |
+
["First need", (e) => e.kind === "information_need"],
|
| 667 |
+
[
|
| 668 |
+
"Tool return",
|
| 669 |
+
(e) =>
|
| 670 |
+
e.kind === "external_refresh_ready" ||
|
| 671 |
+
e.kind === "external_refresh_finished",
|
| 672 |
+
],
|
| 673 |
+
["Evidence in", (e) => e.kind === "cognitive_projection"],
|
| 674 |
+
[
|
| 675 |
+
"First revision",
|
| 676 |
+
(e, i) =>
|
| 677 |
+
e.kind === "model_step_finished" &&
|
| 678 |
+
frames[i].previousDisplay &&
|
| 679 |
+
frames[i].display?.text !== frames[i].previousDisplay?.text,
|
| 680 |
+
],
|
| 681 |
+
["Recovery", (e) => e.kind === "loop_escape_applied"],
|
| 682 |
+
["Run end", (e) => e.kind === "trajectory_finished"],
|
| 683 |
+
];
|
| 684 |
+
$("jumps").innerHTML = jumps
|
| 685 |
+
.map(([label, test]) => {
|
| 686 |
+
const i = events.findIndex(test);
|
| 687 |
+
return i < 0
|
| 688 |
+
? ""
|
| 689 |
+
: '<button data-jump="' + i + '">' + label + "</button>";
|
| 690 |
+
})
|
| 691 |
+
.join("");
|
| 692 |
+
}
|
| 693 |
+
function resize() {
|
| 694 |
+
requestAnimationFrame(() =>
|
| 695 |
+
parent.postMessage(
|
| 696 |
+
{
|
| 697 |
+
type: "cid-replay-height",
|
| 698 |
+
height:
|
| 699 |
+
Math.ceil(
|
| 700 |
+
document.querySelector(".replay").getBoundingClientRect()
|
| 701 |
+
.height,
|
| 702 |
+
) + 2,
|
| 703 |
+
},
|
| 704 |
+
"*",
|
| 705 |
+
),
|
| 706 |
+
);
|
| 707 |
+
}
|
| 708 |
+
$("play").addEventListener("click", () => {
|
| 709 |
+
if (timer) {
|
| 710 |
+
pause();
|
| 711 |
+
return;
|
| 712 |
+
}
|
| 713 |
+
if (index === events.length - 1) index = 0;
|
| 714 |
+
render();
|
| 715 |
+
$("play").textContent = "Ⅱ Pause";
|
| 716 |
+
$("play").setAttribute("aria-label", "Pause replay");
|
| 717 |
+
schedule();
|
| 718 |
+
});
|
| 719 |
+
$("prev").addEventListener("click", () => seek(index - 1));
|
| 720 |
+
$("next").addEventListener("click", () => seek(index + 1));
|
| 721 |
+
$("scrubber").addEventListener("input", () =>
|
| 722 |
+
seek(Number($("scrubber").value)),
|
| 723 |
+
);
|
| 724 |
+
$("speed").addEventListener("change", () => {
|
| 725 |
+
if (timer) {
|
| 726 |
+
clearTimeout(timer);
|
| 727 |
+
schedule();
|
| 728 |
+
}
|
| 729 |
+
});
|
| 730 |
+
$("timeline").addEventListener("click", (e) => {
|
| 731 |
+
const mark = e.target.closest("[data-event]");
|
| 732 |
+
if (mark) seek(Number(mark.dataset.event));
|
| 733 |
+
});
|
| 734 |
+
$("timeline").addEventListener("keydown", (e) => {
|
| 735 |
+
if (e.key === "Enter" || e.key === " ") {
|
| 736 |
+
const mark = e.target.closest("[data-event]");
|
| 737 |
+
if (mark) {
|
| 738 |
+
e.preventDefault();
|
| 739 |
+
seek(Number(mark.dataset.event));
|
| 740 |
+
}
|
| 741 |
+
}
|
| 742 |
+
});
|
| 743 |
+
$("jumps").addEventListener("click", (e) => {
|
| 744 |
+
const b = e.target.closest("[data-jump]");
|
| 745 |
+
if (b) seek(Number(b.dataset.jump));
|
| 746 |
+
});
|
| 747 |
+
function selectCell(e) {
|
| 748 |
+
const g = e.target.closest("[data-cell]");
|
| 749 |
+
if (!g) return;
|
| 750 |
+
selectedCell = g.dataset.cell;
|
| 751 |
+
pause();
|
| 752 |
+
const s = frames[index];
|
| 753 |
+
$("event-title").textContent = "Cognitive cell · " + selectedCell;
|
| 754 |
+
$("event-copy").textContent =
|
| 755 |
+
"Last observed lifecycle: " +
|
| 756 |
+
s.cells[selectedCell].lifecycle +
|
| 757 |
+
". Its latent semantic content is not recorded.";
|
| 758 |
+
renderCells(s, events[index]);
|
| 759 |
+
}
|
| 760 |
+
$("cells").addEventListener("click", selectCell);
|
| 761 |
+
$("cells").addEventListener("keydown", (e) => {
|
| 762 |
+
if (e.key === "Enter" || e.key === " ") {
|
| 763 |
+
e.preventDefault();
|
| 764 |
+
selectCell(e);
|
| 765 |
+
}
|
| 766 |
+
});
|
| 767 |
+
document.addEventListener("visibilitychange", () => {
|
| 768 |
+
if (document.hidden) pause();
|
| 769 |
+
});
|
| 770 |
+
$("event-details").addEventListener("toggle", resize);
|
| 771 |
+
window.addEventListener("resize", resize);
|
| 772 |
+
new ResizeObserver(resize).observe(document.querySelector(".replay"));
|
| 773 |
+
if (events.length) {
|
| 774 |
+
$("question").textContent = data.prompt || "Recorded CID trajectory";
|
| 775 |
+
$("play").disabled = false;
|
| 776 |
+
$("scrubber").disabled = false;
|
| 777 |
+
$("scrubber").max = events.length - 1;
|
| 778 |
+
makeTimeline();
|
| 779 |
+
render();
|
| 780 |
+
}
|
| 781 |
+
resize();
|
| 782 |
+
})();
|
cid_demo/assets/styles.css
CHANGED
|
@@ -188,3 +188,9 @@
|
|
| 188 |
grid-template-columns: repeat(2, minmax(0, 1fr));
|
| 189 |
}
|
| 190 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 188 |
grid-template-columns: repeat(2, minmax(0, 1fr));
|
| 189 |
}
|
| 190 |
}
|
| 191 |
+
|
| 192 |
+
#cid-mechanism { margin-top: 24px; }
|
| 193 |
+
@media (max-width: 480px) {
|
| 194 |
+
#prompt-panel, #result-panel { min-width: 0 !important; }
|
| 195 |
+
#cid-hero .hero-title { font-size: 34px; }
|
| 196 |
+
}
|
cid_demo/mechanism.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Self-contained, trace-grounded CID replay; no model work during playback."""
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import html
|
| 5 |
+
import json
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from typing import Any
|
| 8 |
+
|
| 9 |
+
_ASSETS = Path(__file__).parent / "assets"
|
| 10 |
+
|
| 11 |
+
# The opaque-origin frame can execute only its own bundled visualization code.
|
| 12 |
+
# Match the sending window before accepting its responsive height.
|
| 13 |
+
REPLAY_BRIDGE_JS = """() => {
|
| 14 |
+
if (window.__cidReplayResize) return;
|
| 15 |
+
window.__cidReplayResize = true;
|
| 16 |
+
window.addEventListener("message", (event) => {
|
| 17 |
+
if (event.data?.type !== "cid-replay-height") return;
|
| 18 |
+
for (const frame of document.querySelectorAll("iframe.cid-replay-frame")) {
|
| 19 |
+
if (frame.contentWindow === event.source) {
|
| 20 |
+
const height = Number(event.data.height);
|
| 21 |
+
if (Number.isFinite(height)) frame.style.height = Math.min(2400, Math.max(520, height)) + "px";
|
| 22 |
+
}
|
| 23 |
+
}
|
| 24 |
+
});
|
| 25 |
+
}"""
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def replay_document(events: tuple[dict[str, Any], ...] = (), *, prompt: str = "", final_text: str = "") -> str:
|
| 29 |
+
# Escape script terminators as well as the outer srcdoc attribute. All runtime
|
| 30 |
+
# strings are rendered as text by the client, never inserted as trusted HTML.
|
| 31 |
+
data = json.dumps(
|
| 32 |
+
{"events": list(events), "prompt": prompt, "final_text": final_text},
|
| 33 |
+
ensure_ascii=False, separators=(",", ":"), default=str,
|
| 34 |
+
).replace("&", "\\u0026").replace("<", "\\u003c").replace(">", "\\u003e")
|
| 35 |
+
template = (_ASSETS / "mechanism.html").read_text(encoding="utf-8")
|
| 36 |
+
return (template.replace("/* REPLAY_CSS */", (_ASSETS / "mechanism.css").read_text(encoding="utf-8"))
|
| 37 |
+
.replace("/* REPLAY_JS */", (_ASSETS / "mechanism.js").read_text(encoding="utf-8"))
|
| 38 |
+
.replace("/* REPLAY_DATA */", data))
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def mechanism_html(events: tuple[dict[str, Any], ...] = (), *, prompt: str = "", final_text: str = "") -> str:
|
| 42 |
+
return (
|
| 43 |
+
'<iframe class="cid-replay-frame" title="CID mechanism replay" '
|
| 44 |
+
'sandbox="allow-scripts" referrerpolicy="no-referrer" '
|
| 45 |
+
'style="width:100%;height:820px;border:0;display:block" srcdoc="'
|
| 46 |
+
+ html.escape(replay_document(events, prompt=prompt, final_text=final_text), quote=True)
|
| 47 |
+
+ '"></iframe>'
|
| 48 |
+
)
|
cid_demo/runtime.py
CHANGED
|
@@ -20,6 +20,7 @@ from .config import (
|
|
| 20 |
MODEL_REVISION,
|
| 21 |
)
|
| 22 |
from .model import MODEL_BUNDLE
|
|
|
|
| 23 |
from .presentation import display_evolution, summary_html, trace_rows
|
| 24 |
from .tools import (
|
| 25 |
LIVE_MATH_DESCRIPTORS,
|
|
@@ -184,4 +185,5 @@ def run_cid(
|
|
| 184 |
summary_html(summary),
|
| 185 |
display_evolution(events),
|
| 186 |
trace_rows(events),
|
|
|
|
| 187 |
)
|
|
|
|
| 20 |
MODEL_REVISION,
|
| 21 |
)
|
| 22 |
from .model import MODEL_BUNDLE
|
| 23 |
+
from .mechanism import mechanism_html
|
| 24 |
from .presentation import display_evolution, summary_html, trace_rows
|
| 25 |
from .tools import (
|
| 26 |
LIVE_MATH_DESCRIPTORS,
|
|
|
|
| 185 |
summary_html(summary),
|
| 186 |
display_evolution(events),
|
| 187 |
trace_rows(events),
|
| 188 |
+
mechanism_html(events, prompt=prompt, final_text=result.final_text or ""),
|
| 189 |
)
|
cid_demo/ui.py
CHANGED
|
@@ -13,6 +13,7 @@ from .config import (
|
|
| 13 |
from .examples import EXAMPLES, WORKSPACE_PLACEHOLDER
|
| 14 |
from .presentation import CUSTOM_CSS, FOOTER_HTML, HERO_HTML, READY_SUMMARY_HTML
|
| 15 |
from .runtime import run_cid
|
|
|
|
| 16 |
|
| 17 |
|
| 18 |
@dataclass(frozen=True)
|
|
@@ -36,6 +37,7 @@ class DemoOutputs:
|
|
| 36 |
summary: gr.HTML
|
| 37 |
display_evolution: gr.Markdown
|
| 38 |
trace: gr.Dataframe
|
|
|
|
| 39 |
|
| 40 |
|
| 41 |
def _build_input_panel() -> tuple[DemoInputs, gr.Button]:
|
|
@@ -193,6 +195,7 @@ def build_demo() -> gr.Blocks:
|
|
| 193 |
with gr.Blocks(
|
| 194 |
title="CID · Demo",
|
| 195 |
css=CUSTOM_CSS,
|
|
|
|
| 196 |
theme=gr.themes.Soft(
|
| 197 |
primary_hue=gr.themes.colors.indigo,
|
| 198 |
neutral_hue=gr.themes.colors.slate,
|
|
@@ -206,8 +209,9 @@ def build_demo() -> gr.Blocks:
|
|
| 206 |
with gr.Column(scale=5, min_width=360, elem_id="result-panel"):
|
| 207 |
final_display, summary = _build_result_panel()
|
| 208 |
|
|
|
|
| 209 |
display_evolution, trace = _build_inspection_tabs()
|
| 210 |
-
outputs = DemoOutputs(final_display, summary, display_evolution, trace)
|
| 211 |
|
| 212 |
run_button.click(
|
| 213 |
fn=run_cid,
|
|
@@ -229,6 +233,7 @@ def build_demo() -> gr.Blocks:
|
|
| 229 |
outputs.summary,
|
| 230 |
outputs.display_evolution,
|
| 231 |
outputs.trace,
|
|
|
|
| 232 |
],
|
| 233 |
concurrency_limit=1,
|
| 234 |
api_name="run_cid",
|
|
|
|
| 13 |
from .examples import EXAMPLES, WORKSPACE_PLACEHOLDER
|
| 14 |
from .presentation import CUSTOM_CSS, FOOTER_HTML, HERO_HTML, READY_SUMMARY_HTML
|
| 15 |
from .runtime import run_cid
|
| 16 |
+
from .mechanism import REPLAY_BRIDGE_JS, mechanism_html
|
| 17 |
|
| 18 |
|
| 19 |
@dataclass(frozen=True)
|
|
|
|
| 37 |
summary: gr.HTML
|
| 38 |
display_evolution: gr.Markdown
|
| 39 |
trace: gr.Dataframe
|
| 40 |
+
mechanism: gr.HTML
|
| 41 |
|
| 42 |
|
| 43 |
def _build_input_panel() -> tuple[DemoInputs, gr.Button]:
|
|
|
|
| 195 |
with gr.Blocks(
|
| 196 |
title="CID · Demo",
|
| 197 |
css=CUSTOM_CSS,
|
| 198 |
+
js=REPLAY_BRIDGE_JS,
|
| 199 |
theme=gr.themes.Soft(
|
| 200 |
primary_hue=gr.themes.colors.indigo,
|
| 201 |
neutral_hue=gr.themes.colors.slate,
|
|
|
|
| 209 |
with gr.Column(scale=5, min_width=360, elem_id="result-panel"):
|
| 210 |
final_display, summary = _build_result_panel()
|
| 211 |
|
| 212 |
+
mechanism = gr.HTML(mechanism_html(), elem_id="cid-mechanism")
|
| 213 |
display_evolution, trace = _build_inspection_tabs()
|
| 214 |
+
outputs = DemoOutputs(final_display, summary, display_evolution, trace, mechanism)
|
| 215 |
|
| 216 |
run_button.click(
|
| 217 |
fn=run_cid,
|
|
|
|
| 233 |
outputs.summary,
|
| 234 |
outputs.display_evolution,
|
| 235 |
outputs.trace,
|
| 236 |
+
outputs.mechanism,
|
| 237 |
],
|
| 238 |
concurrency_limit=1,
|
| 239 |
api_name="run_cid",
|
tests/mechanism-state.test.cjs
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const test = require("node:test");
|
| 2 |
+
const assert = require("node:assert/strict");
|
| 3 |
+
const { buildReplay } = require("../cid_demo/assets/mechanism.js");
|
| 4 |
+
const event = (kind, payload = {}, step = 0, timestamp_s = 0) => ({
|
| 5 |
+
kind,
|
| 6 |
+
payload,
|
| 7 |
+
step,
|
| 8 |
+
timestamp_s,
|
| 9 |
+
});
|
| 10 |
+
test("async completion stays in event order even when callback step goes backwards", () => {
|
| 11 |
+
const f = buildReplay([
|
| 12 |
+
event("binding_active", { binding_id: "b", source: "calculator" }),
|
| 13 |
+
event(
|
| 14 |
+
"external_refresh_started",
|
| 15 |
+
{ binding_id: "b", work_key: "w" },
|
| 16 |
+
0,
|
| 17 |
+
0.1,
|
| 18 |
+
),
|
| 19 |
+
event("model_step_started", {}, 1, 0.2),
|
| 20 |
+
event(
|
| 21 |
+
"external_refresh_ready",
|
| 22 |
+
{ binding_id: "b", work_key: "w", success: true },
|
| 23 |
+
0,
|
| 24 |
+
0.3,
|
| 25 |
+
),
|
| 26 |
+
event(
|
| 27 |
+
"binding_observation_updated",
|
| 28 |
+
{ binding_id: "b", work_key: "w" },
|
| 29 |
+
1,
|
| 30 |
+
0.4,
|
| 31 |
+
),
|
| 32 |
+
event("cognitive_projection", { binding_id: "b", index: 1 }, 2, 0.5),
|
| 33 |
+
]);
|
| 34 |
+
assert.equal(f[2].bindings.b.status, "Running");
|
| 35 |
+
assert.equal(f[3].model, "Refining");
|
| 36 |
+
assert.equal(f[3].bindings.b.status, "Returned");
|
| 37 |
+
assert.equal(f[3].projections, 0);
|
| 38 |
+
assert.equal(f[5].projections, 1);
|
| 39 |
+
assert.equal(f[0].bindings.b.status, "Bound");
|
| 40 |
+
});
|
| 41 |
+
test("cell retirement and reclamation preserve earlier snapshots", () => {
|
| 42 |
+
const f = buildReplay([
|
| 43 |
+
event("cell_allocated", { cell_id: "c1", lifecycle: "active" }),
|
| 44 |
+
event("lifecycle_transition", {
|
| 45 |
+
cell_id: "c1",
|
| 46 |
+
previous: "active",
|
| 47 |
+
current: "retired",
|
| 48 |
+
}),
|
| 49 |
+
event("cell_reclaimed", { cell_id: "c1" }),
|
| 50 |
+
]);
|
| 51 |
+
assert.equal(f[0].cells.c1.lifecycle, "active");
|
| 52 |
+
assert.equal(f[1].cells.c1.lifecycle, "retired");
|
| 53 |
+
assert.deepEqual(f[2].cells, {});
|
| 54 |
+
});
|
| 55 |
+
test("failed reads, cache reuse, and cancellation do not create projections", () => {
|
| 56 |
+
const f = buildReplay([
|
| 57 |
+
event("binding_active", { binding_id: "b", source: "calculator" }),
|
| 58 |
+
event("external_refresh_started", { binding_id: "b", work_key: "w" }),
|
| 59 |
+
event("external_refresh_ready", { binding_id: "b", success: false }),
|
| 60 |
+
event("external_refresh_cancelled", { work_key: "w" }),
|
| 61 |
+
event("cache_hit", { binding_id: "b" }),
|
| 62 |
+
]);
|
| 63 |
+
assert.equal(f[2].bindings.b.status, "Failed");
|
| 64 |
+
assert.equal(f[3].bindings.b.status, "Cancelled");
|
| 65 |
+
assert.equal(f[4].bindings.b.status, "Cached evidence");
|
| 66 |
+
assert.equal(f[4].projections, 0);
|
| 67 |
+
});
|
| 68 |
+
test("Display snapshots remain distinct from convergence and final status", () => {
|
| 69 |
+
const f = buildReplay([
|
| 70 |
+
event("model_step_finished", {
|
| 71 |
+
display_materialized_text: "12.",
|
| 72 |
+
display_token_ids: [1, 2],
|
| 73 |
+
converged: true,
|
| 74 |
+
}),
|
| 75 |
+
event("model_step_finished", {
|
| 76 |
+
display_materialized_text: "12",
|
| 77 |
+
display_token_ids: [1],
|
| 78 |
+
converged: false,
|
| 79 |
+
}),
|
| 80 |
+
event("trajectory_finished", { converged: false }),
|
| 81 |
+
]);
|
| 82 |
+
assert.equal(f[0].done, false);
|
| 83 |
+
assert.equal(f[1].previousDisplay.text, "12.");
|
| 84 |
+
assert.equal(f[1].display.text, "12");
|
| 85 |
+
assert.equal(f[2].model, "Stopped");
|
| 86 |
+
assert.equal(f[2].done, true);
|
| 87 |
+
assert.deepEqual(f[2].bindings, {});
|
| 88 |
+
});
|
| 89 |
+
test("empty and unknown events are safe; no fictitious cells or bindings", () => {
|
| 90 |
+
assert.deepEqual(buildReplay([]), []);
|
| 91 |
+
const [f] = buildReplay([event("future_runtime_event", { cell_id: "x" })]);
|
| 92 |
+
assert.deepEqual(f.cells, {});
|
| 93 |
+
assert.deepEqual(f.bindings, {});
|
| 94 |
+
});
|
tests/test_mechanism.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import html
|
| 2 |
+
import json
|
| 3 |
+
from html.parser import HTMLParser
|
| 4 |
+
|
| 5 |
+
from cid_demo.mechanism import mechanism_html, replay_document
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
class FrameParser(HTMLParser):
|
| 9 |
+
def handle_starttag(self, tag, attrs):
|
| 10 |
+
if tag == "iframe":
|
| 11 |
+
self.attrs = dict(attrs)
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def test_full_trace_and_markup_are_isolated():
|
| 15 |
+
value = '</script><img src=x onerror="alert(1)"> & /* REPLAY_JS */'
|
| 16 |
+
events = [{"step": 0, "timestamp_s": 0, "kind": "model_step_finished",
|
| 17 |
+
"payload": {"display_materialized_text": value, "long": "x" * 6000}}]
|
| 18 |
+
frame = FrameParser()
|
| 19 |
+
frame.feed(mechanism_html(events, prompt=value, final_text=value))
|
| 20 |
+
assert frame.attrs["sandbox"] == "allow-scripts"
|
| 21 |
+
doc = frame.attrs["srcdoc"]
|
| 22 |
+
data = doc.split('<script id="replay-data" type="application/json">', 1)[1].split("</script>", 1)[0]
|
| 23 |
+
parsed = json.loads(data)
|
| 24 |
+
assert parsed["events"] == events
|
| 25 |
+
assert parsed["prompt"] == value
|
| 26 |
+
assert parsed["final_text"] == value
|
| 27 |
+
assert "<img" not in doc
|
| 28 |
+
assert "onerror" in data # Preserved as text, never trusted markup.
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def test_empty_trace_has_disabled_controls_and_no_demo_trajectory():
|
| 32 |
+
doc = replay_document()
|
| 33 |
+
assert 'id="play" class="primary" disabled' in doc
|
| 34 |
+
assert '"events":[]' in doc
|
| 35 |
+
assert 'No cells recorded yet' in doc
|