Repository navigation
Commit 4300a84
authored
Owner: Dev2
Reviewer: Reviewer
Written-by: Dev2
Pushed-by: Dev2 (INC 补件 + rebase)
Fixes #796
Tip SHA: a552d6a
#796 asked where a turn's input tokens go. The [2026-10-25
page](https://github.com/ThinkFlowLab/FlyBot/blob/main/docs/reports/2026-10-25-token-spend.md)
answered the ledger questions and said the composition was **not
measured**, because the ledger's JSON holds no request. This PR measures
it: the Session logs carry the provider's own `usage` per call and the
exact surface that call sent, so the split can be read without a replay.
## Reproduce
- Sample: `session-2413164c`, turn 62 — Dev2 in group **FlyBot 交付组**,
`2026-10-25T10:01:33.511Z .. 10:14:17.073Z` (12.7 minutes), 124 calls,
125 tool calls (117 `bash`), opened by a 225-character `[Continue task]`
card.
- `node core/dev/turn-split.mjs --sessions /data/dsh/sessions --session
session-2413164c --turn 62 --top 1` → prompt **17,538,593**; fixed
**41.0%**, history **29.0%**, tool results **24.1%**, task **6.0%**;
first call 215,263, largest 248,706, last 156,754.
- `node core/dev/turn-split.mjs --sessions /data/dsh/sessions --tz
Asia/Shanghai --days` → 2026-10-25: 11,131 calls, **1,645,130,705**
prompt, **36.5%** of it the fixed block.
- The finding: the fixed block is 48,583 tokens per call at p50 and is
re-sent on every call; one 12.7-minute turn paid it 124 times. The group
notice + roster + speaking order is 2,588 characters — 1.8% of the block
— while the tool schemas are 79%.
## What changed
- `core/dev/turn-split.mjs`: folds a Session's events into the surface
each call sent (system prompt, `request/header` tools, messages,
`tool/result`) and splits the provider-reported prompt. The fixed block
is the intercept of `prompt = fixed + k × messageChars` over the same
Session's calls, so it is measured rather than assumed; `--days` prints
the per-day table, `--json` the same as JSON.
- `core/test/turn-split.test.js`: 10 tests — a tool result is never
history, a turn's own messages are its task, the fit recovers a known
intercept, a split never claims the fixed block twice, the frame walker
reads a concatenated log, the CLI's two modes (`--days` and one turn's
split), its missing-root error, and the report's provenance rule.
- `docs/reports/2026-10-26-turn-input-split.md`: the measurement, the
method and every number's provenance.
- `docs/subsystems/ds-bot-core.md`: names the script (`core/dev/` is
owned by that page).
- `patches/ds-bot/files/dev/turn-split.mjs`,
`patches/ds-bot/files/test/turn-split.test.js`: whole-file mirrors,
which `check` requires.
## What I ran
- `node --test core/test/turn-split.test.js` → `# tests 10 / # pass 10 /
# fail 0`.
- Rebased onto `2d3eb88c` (main) with no conflict — main’s nine merges
since `d04712bb` touch none of this PR’s six files.
- `node scripts/ds-bot-patches.mjs check` → `skipped pin (no git)`, `ok
10 patches apply cleanly in order`, `ok core/ equals ds-bot/ +
patches/ds-bot/`.
- `node .github/scripts/check-mojibake.mjs --check` → 0 occurrences of
U+FFFD in 1,071 text files.
- oxlint (97 rules) on the two new files → 0 warnings, 0 errors.
- Both CLI modes against this host's real logs, at the tip: the numbers
in §Reproduce.
## Red without the source change
- Knife 1: `splitStep` returns `fixed = 0` → tests 5 and 8 red (`a split
accounts for the whole prompt and never claims the fixed block twice`,
`the --days table divides each day by the same measured fixed block`), 8
pass / 2 fail.
- Knife 2: a `tool/result` counted as history → tests 1 and 2 red, 8
pass / 2 fail.
- Knife 3, the one the INC added: `row.fixed += 0` in the `--days` loop
→ `not ok 8`, `0.0% !== 96.1%`, 9 pass / 1 fail.
- Restored → 10/10.
## Not run
- `npm run verify` and the full core suite: this host has no `git` and
cannot install the harness (`npm ci` fails on esbuild here), so the core
suite, `build-client --check` and the pack check were not run. CI runs
them.
- An ablated replay through `core/dev/llm-tap.mjs` per category: each
variant is a real provider call. The per-part token figures are
therefore `derived` from character share and labelled so in the report;
the totals and the fixed block are provider-reported.
## Risk
- Read-only tooling plus a report: no runtime path, no prompt, no
workflow, no user-visible change.
- The split inside one call is derived, not ablated; the report says
which rows are which, and the provenance test fails if a row loses its
source.
- The clamp in `splitStep` keeps a prompt smaller than the fitted fixed
block from producing a negative remainder; a Session whose system prompt
shrank mid-run gets a slightly conservative fixed block.
## Deferred from the INC, non-blocking — tracked in #1259
- §2's fixed characters per call use each Session's **first** call
surface while §4 counts the sample turn's **last** call; one clause
naming the two moments.
- §5, §7 and §8 have no rerun command in the repo; a `--json` note or a
second mode would give them one.
- `fitFixed` can return `charsPerToken: null` and the turns-mode summary
calls `.toFixed(2)` on the median, and `localDay` throws an uncaught
`RangeError` on an unknown `--tz`.
## Checkpoint
<!-- flybot:checkpoint -->
```json
{
"pr": 1241,
"claim": "Dev2",
"issue": 796,
"summary": "#796's composition is now measured from the Session logs rather than declared unmeasurable. core/dev/turn-split.mjs folds each call's surface and splits the provider-reported prompt into the fixed block, history, tool results and task, with the fixed block taken as each Session's fit intercept. The report records one real 12.7-minute turn at 17,538,593 prompt tokens, 41% of it the same fixed block re-sent, plus the day and fan-out tables. A 10-test suite pins the split rules and the report's provenance.",
"files": [
"core/dev/turn-split.mjs",
"core/test/turn-split.test.js",
"docs/reports/2026-10-26-turn-input-split.md",
"docs/subsystems/ds-bot-core.md"
],
"checks": { "ran": "node --test core/test/turn-split.test.js; node scripts/ds-bot-patches.mjs check; node .github/scripts/check-mojibake.mjs --check", "result": "green", "at": "a552d6a6dcc72e223bf445c96f7c711231023496" },
"next": "INC at ef94803 answered: the --days path now has a test that fails 0.0% !== 96.1% without it; ready for a fresh verdict at this tip"
}
```
<!-- /flybot:checkpoint -->
1 parent 2d3eb88 commit 4300a84
6 files changed
Lines changed: 1604 additions & 0 deletions
File tree
- core
- dev
- test
- docs
- reports
- subsystems
- patches/ds-bot/files
- dev
- test
0 commit comments