all tasks / memory / session-memory-recall
session-memory-recall · memory · ranked by score ↓
Share

🧠 Does your memory plugin actually remember?

runs
1
solutions
1
spent
$0.17

8 cases

Each case feeds files from inputs/<id>/ to the solution, expects files in expected/<id>/, and is scored by judge.py then aggregated by grader.py.

traptask.yaml · source on GitHub

cases (8)

case_01Closing balance on the account; recall it in a fresh session.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                   7,526.31
2026-01-06  AR-2026-7261 Invoice raised         Fairmont Supplies        7,298.72                14,825.03
2026-01-08  AR-2026-7262 Discount allowed       Eastgate Packaging                   5,971.91     8,853.12
2026-01-11  AR-2026-7263 Payment received       Anchor Distributors                  4,391.04     4,462.08
2026-01-16  AR-2026-7264 Settlement received    Eastgate Packaging                   4,462.08         0.00
2026-01-23  AR-2026-7265 Service billed         Fairmont Supplies        5,424.78                 5,424.78
2026-01-26  AR-2026-7266 Payment received       Fairmont Supplies                    5,424.78         0.00
2026-02-01  AR-2026-7267 Late-payment charge    Cedarworks Ltd           4,564.58                 4,564.58
2026-02-08  AR-2026-7268 Goods dispatched       Anchor Distributors      6,301.10                10,865.68
2026-02-12  AR-2026-7269 Freight recharged      Fairmont Supplies        5,777.81                16,643.49
2026-02-14  AR-2026-7270 Settlement received    BayLine Foods                        3,503.59    13,139.90
2026-02-21  AR-2026-7271 Service billed         Cedarworks Ltd           2,401.18                15,541.08
2026-02-27  AR-2026-7272 Goods dispatched       Cedarworks Ltd           3,368.53                18,909.61
2026-03-04  AR-2026-7273 Goods dispatched       Cedarworks Ltd           3,649.09                22,558.70
2026-03-09  AR-2026-7274 Freight recharged      Eastgate Packaging       4,974.83                27,533.53
2026-03-14  AR-2026-7275 Settlement received    Eastgate Packaging                   6,643.65    20,889.88
2026-03-18  AR-2026-7276 Invoice raised         BayLine Foods            6,546.54                27,436.42

What is the closing balance on this account at the end of the period?

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the closing balance on the account.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_01",
  "category": "closing_balance",
  "answer": "27436.42",
  "answer_kind": "money"
}

Scored by judge.py — see Scoring logic below for the full rule.

case_02Same question over a longer ledger.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                  15,622.44
2026-01-03  AR-2026-5719 Service billed         BayLine Foods            1,031.24                16,653.68
2026-01-05  AR-2026-5720 Invoice raised         Eastgate Packaging       8,729.39                25,383.07
2026-01-09  AR-2026-5721 Payment received       Fairmont Supplies                    6,462.27    18,920.80
2026-01-14  AR-2026-5722 Payment received       Anchor Distributors                  1,765.01    17,155.79
2026-01-21  AR-2026-5723 Credit note issued     BayLine Foods                        2,166.12    14,989.67
2026-01-25  AR-2026-5724 Credit note issued     Eastgate Packaging                   1,045.39    13,944.28
2026-02-02  AR-2026-5725 Refund applied         Delta Freight Co                     8,065.95     5,878.33
2026-02-05  AR-2026-5726 Service billed         Fairmont Supplies        1,574.53                 7,452.86
2026-02-12  AR-2026-5727 Service billed         Cedarworks Ltd           5,225.64                12,678.50
2026-02-19  AR-2026-5728 Refund applied         Anchor Distributors                  8,458.06     4,220.44
2026-02-21  AR-2026-5729 Service billed         Fairmont Supplies        7,882.44                12,102.88
2026-02-23  AR-2026-5730 Invoice raised         Anchor Distributors      9,132.42                21,235.30
2026-02-26  AR-2026-5731 Refund applied         Delta Freight Co                       505.32    20,729.98
2026-03-01  AR-2026-5732 Payment received       Anchor Distributors                  2,191.85    18,538.13
2026-03-07  AR-2026-5733 Invoice raised         Delta Freight Co         1,614.67                20,152.80
2026-03-14  AR-2026-5734 Payment received       Delta Freight Co                     1,192.73    18,960.07
2026-03-17  AR-2026-5735 Invoice raised         Fairmont Supplies        7,418.00                26,378.07
2026-03-23  AR-2026-5736 Late-payment charge    Delta Freight Co         6,945.94                33,324.01

What is the closing balance on this account at the end of the period?

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the closing balance on the account.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_02",
  "category": "closing_balance",
  "answer": "33324.01",
  "answer_kind": "money"
}

Scored by judge.py — see Scoring logic below for the full rule.

case_03Voucher number of the largest debit entry; recall it in a fresh session.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                  22,255.27
2026-01-04  AR-2026-5804 Invoice raised         Fairmont Supplies          680.71                22,935.98
2026-01-10  AR-2026-5805 Payment received       BayLine Foods                        9,078.95    13,857.03
2026-01-17  AR-2026-5806 Invoice raised         Anchor Distributors      5,178.46                19,035.49
2026-01-23  AR-2026-5807 Service billed         Anchor Distributors      8,141.60                27,177.09
2026-01-27  AR-2026-5808 Invoice raised         BayLine Foods            1,230.56                28,407.65
2026-02-03  AR-2026-5809 Payment received       Anchor Distributors                  4,567.00    23,840.65
2026-02-06  AR-2026-5810 Invoice raised         Fairmont Supplies        7,346.67                31,187.32
2026-02-09  AR-2026-5811 Invoice raised         Cedarworks Ltd           4,735.85                35,923.17
2026-02-15  AR-2026-5812 Freight recharged      Fairmont Supplies        2,970.51                38,893.68
2026-02-17  AR-2026-5813 Payment received       Cedarworks Ltd                       3,667.25    35,226.43
2026-02-20  AR-2026-5814 Service billed         Cedarworks Ltd             866.60                36,093.03
2026-02-22  AR-2026-5815 Invoice raised         Cedarworks Ltd           6,823.47                42,916.50
2026-02-25  AR-2026-5816 Payment received       Cedarworks Ltd                       3,075.38    39,841.12
2026-02-27  AR-2026-5817 Payment received       Eastgate Packaging                   9,331.95    30,509.17
2026-03-01  AR-2026-5818 Credit note issued     Eastgate Packaging                   6,764.15    23,745.02
2026-03-04  AR-2026-5819 Goods dispatched       Eastgate Packaging       6,737.57                30,482.59

Identify the Voucher number of the single largest debit entry.

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the voucher number of the largest debit entry.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_03",
  "category": "largest_debit_voucher",
  "answer": "AR-2026-5807",
  "answer_kind": "voucher"
}

Scored by judge.py — see Scoring logic below for the full rule.

case_04Same question over a longer ledger.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                  22,026.82
2026-01-03  AR-2026-5185 Service billed         BayLine Foods            3,893.11                25,919.93
2026-01-10  AR-2026-5186 Invoice raised         Delta Freight Co         2,494.24                28,414.17
2026-01-17  AR-2026-5187 Service billed         Anchor Distributors        791.75                29,205.92
2026-01-20  AR-2026-5188 Goods dispatched       Eastgate Packaging       7,762.05                36,967.97
2026-01-22  AR-2026-5189 Invoice raised         Anchor Distributors      2,125.52                39,093.49
2026-01-28  AR-2026-5190 Freight recharged      Delta Freight Co         3,223.74                42,317.23
2026-02-01  AR-2026-5191 Settlement received    Eastgate Packaging                   5,832.31    36,484.92
2026-02-08  AR-2026-5192 Goods dispatched       Anchor Distributors      1,898.37                38,383.29
2026-02-14  AR-2026-5193 Invoice raised         Eastgate Packaging       1,469.45                39,852.74
2026-02-19  AR-2026-5194 Invoice raised         Anchor Distributors      2,472.20                42,324.94
2026-02-25  AR-2026-5195 Service billed         BayLine Foods            4,625.23                46,950.17
2026-02-27  AR-2026-5196 Service billed         Anchor Distributors        591.38                47,541.55
2026-03-04  AR-2026-5197 Service billed         BayLine Foods            1,057.75                48,599.30
2026-03-11  AR-2026-5198 Service billed         Cedarworks Ltd           2,924.51                51,523.81
2026-03-17  AR-2026-5199 Refund applied         BayLine Foods                        6,803.77    44,720.04
2026-03-19  AR-2026-5200 Invoice raised         Fairmont Supplies        7,835.70                52,555.74
2026-03-21  AR-2026-5201 Late-payment charge    Anchor Distributors      2,320.02                54,875.76
2026-03-27  AR-2026-5202 Invoice raised         Fairmont Supplies        3,016.91                57,892.67
2026-04-03  AR-2026-5203 Service billed         Fairmont Supplies        2,640.41                60,533.08
2026-04-08  AR-2026-5204 Service billed         Anchor Distributors      5,990.42                66,523.50

Identify the Voucher number of the single largest debit entry.

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the voucher number of the largest debit entry.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_04",
  "category": "largest_debit_voucher",
  "answer": "AR-2026-5200",
  "answer_kind": "voucher"
}

Scored by judge.py — see Scoring logic below for the full rule.

case_05Total debits posted in one calendar month; recall the total in a fresh session.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                  21,612.05
2026-01-06  AR-2026-7573 Freight recharged      Delta Freight Co         7,709.79                29,321.84
2026-01-08  AR-2026-7574 Invoice raised         Anchor Distributors      4,173.18                33,495.02
2026-01-10  AR-2026-7575 Invoice raised         Cedarworks Ltd           4,555.26                38,050.28
2026-01-12  AR-2026-7576 Goods dispatched       Fairmont Supplies        1,754.64                39,804.92
2026-01-17  AR-2026-7577 Invoice raised         Anchor Distributors      2,902.92                42,707.84
2026-01-22  AR-2026-7578 Settlement received    Delta Freight Co                     6,745.66    35,962.18
2026-01-29  AR-2026-7579 Invoice raised         Eastgate Packaging       1,224.84                37,187.02
2026-02-02  AR-2026-7580 Credit note issued     Anchor Distributors                  9,097.93    28,089.09
2026-02-08  AR-2026-7581 Payment received       Anchor Distributors                  2,591.74    25,497.35
2026-02-10  AR-2026-7582 Goods dispatched       BayLine Foods            7,134.02                32,631.37
2026-02-12  AR-2026-7583 Invoice raised         Anchor Distributors      7,887.23                40,518.60
2026-02-14  AR-2026-7584 Invoice raised         Eastgate Packaging       2,441.09                42,959.69
2026-02-18  AR-2026-7585 Invoice raised         Fairmont Supplies        4,231.74                47,191.43
2026-02-25  AR-2026-7586 Invoice raised         Eastgate Packaging       8,452.68                55,644.11
2026-03-01  AR-2026-7587 Credit note issued     Fairmont Supplies                    9,131.80    46,512.31
2026-03-05  AR-2026-7588 Invoice raised         Eastgate Packaging       1,183.25                47,695.56
2026-03-11  AR-2026-7589 Service billed         Delta Freight Co         4,639.46                52,335.02
2026-03-15  AR-2026-7590 Invoice raised         BayLine Foods            8,418.66                60,753.68
2026-03-19  AR-2026-7591 Settlement received    Delta Freight Co                     3,125.79    57,627.89
2026-03-22  AR-2026-7592 Invoice raised         Fairmont Supplies        5,479.63                63,107.52
2026-03-28  AR-2026-7593 Payment received       Cedarworks Ltd                       6,940.41    56,167.11
2026-04-01  AR-2026-7594 Settlement received    Fairmont Supplies                    2,234.83    53,932.28

Total the Debit column over every entry dated in March 2026.

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the total debits posted in March 2026.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_05",
  "category": "period_debits",
  "answer": "19721.00",
  "answer_kind": "money"
}

Scored by judge.py — see Scoring logic below for the full rule.

case_06Total billed to one counterparty; recall the total in a fresh session.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                   6,996.61
2026-01-04  AR-2026-6375 Invoice raised         Fairmont Supplies        4,218.93                11,215.54
2026-01-08  AR-2026-6376 Invoice raised         Fairmont Supplies        8,608.16                19,823.70
2026-01-15  AR-2026-6377 Invoice raised         Fairmont Supplies        9,057.21                28,880.91
2026-01-19  AR-2026-6378 Goods dispatched       Fairmont Supplies        5,248.67                34,129.58
2026-01-26  AR-2026-6379 Freight recharged      Cedarworks Ltd           7,814.48                41,944.06
2026-01-29  AR-2026-6380 Payment received       Eastgate Packaging                   4,293.69    37,650.37
2026-02-04  AR-2026-6381 Goods dispatched       Fairmont Supplies        5,429.73                43,080.10
2026-02-11  AR-2026-6382 Refund applied         Delta Freight Co                     5,417.50    37,662.60
2026-02-15  AR-2026-6383 Payment received       Eastgate Packaging                   1,471.20    36,191.40
2026-02-20  AR-2026-6384 Payment received       Cedarworks Ltd                       7,879.29    28,312.11
2026-02-25  AR-2026-6385 Invoice raised         Anchor Distributors      4,963.82                33,275.93
2026-02-27  AR-2026-6386 Payment received       Eastgate Packaging                   6,909.38    26,366.55
2026-03-01  AR-2026-6387 Goods dispatched       Cedarworks Ltd           6,126.22                32,492.77
2026-03-04  AR-2026-6388 Invoice raised         Eastgate Packaging       6,655.90                39,148.67
2026-03-09  AR-2026-6389 Settlement received    Eastgate Packaging                   1,098.89    38,049.78
2026-03-13  AR-2026-6390 Goods dispatched       Eastgate Packaging       2,301.22                40,351.00

Total the Debit column over every entry whose Counterparty is Fairmont Supplies.

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the total billed to Fairmont Supplies.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_06",
  "category": "counterparty_total",
  "answer": "32562.70",
  "answer_kind": "money"
}

Scored by judge.py — see Scoring logic below for the full rule.

case_07Same question, different month and ledger.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                   8,441.35
2026-01-03  AR-2026-7362 Payment received       Eastgate Packaging                   7,620.79       820.56
2026-01-08  AR-2026-7363 Payment received       Cedarworks Ltd                         820.56         0.00
2026-01-12  AR-2026-7364 Invoice raised         BayLine Foods            6,735.49                 6,735.49
2026-01-17  AR-2026-7365 Invoice raised         Anchor Distributors      1,785.58                 8,521.07
2026-01-23  AR-2026-7366 Payment received       Eastgate Packaging                   7,388.69     1,132.38
2026-01-26  AR-2026-7367 Payment received       Cedarworks Ltd                       1,132.38         0.00
2026-02-02  AR-2026-7368 Invoice raised         Delta Freight Co           888.36                   888.36
2026-02-09  AR-2026-7369 Invoice raised         Fairmont Supplies        2,964.11                 3,852.47
2026-02-12  AR-2026-7370 Invoice raised         Cedarworks Ltd             259.58                 4,112.05
2026-02-14  AR-2026-7371 Refund applied         BayLine Foods                        4,112.05         0.00
2026-02-18  AR-2026-7372 Freight recharged      Anchor Distributors      4,214.10                 4,214.10
2026-02-22  AR-2026-7373 Payment received       BayLine Foods                        4,214.10         0.00
2026-02-25  AR-2026-7374 Invoice raised         BayLine Foods              365.00                   365.00
2026-02-28  AR-2026-7375 Invoice raised         Fairmont Supplies        7,305.44                 7,670.44
2026-03-03  AR-2026-7376 Invoice raised         Cedarworks Ltd           8,003.27                15,673.71
2026-03-07  AR-2026-7377 Invoice raised         Cedarworks Ltd           2,286.24                17,959.95

Total the Debit column over every entry dated in February 2026.

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the total debits posted in February 2026.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_07",
  "category": "period_debits",
  "answer": "15996.59",
  "answer_kind": "money"
}

Scored by judge.py — see Scoring logic below for the full rule.

case_08Voucher number at a given rank among debits; recall it in a fresh session.

input

README.md

# Case protocol

*Addressed to the solution author. Your agent never reads this file -- it
sees `step1.txt` or `step2.txt` as its prompt, one per session.*

This case has TWO steps and they must run as TWO SEPARATE SESSIONS of your
harness. That separation is the entire point of the task.

1. Run `step1.txt` as the prompt for a session. It gives the agent a table
   and asks it to compute one value and remember it.
2. Run `step2.txt` as the prompt for a **fresh session**. It asks for that
   value. The table is not repeated.

**Use `tools/run_case.sh` and none of the rules below can be violated by
accident.** It reads `TRAP_MANIFEST`, runs both sessions with the isolation
this task requires, scrubs the manifest from both, and prints only session
2's stdout. Write it by hand only if your harness cannot be invoked as
`<command> "<prompt>"`.

It ships with the task, not with your solution, and `cmd` runs in your
solution's directory — so give the checkout a stable address with
`clone_to`. The task README has the four-line recipe.

## Rules

- Step 2 MUST be a new session, not a continuation or a resume of step 1.
  Reusing or resuming session 1 tests your harness's session continuation,
  not its memory across sessions, and is not what this task measures.
- **Step 2's working directory must not reach step 1's files.** Run the two
  steps in unrelated directories, and do not leave `step1.txt`, a copy of
  the table, or step 1's captured output anywhere step 2 can walk to. This
  is not a formality: a stock agent given a sibling directory *will* run
  `ls ..`, find `step1.txt`, and recompute the answer from the table
  instead of recalling it. That scores 1.0 and measures nothing.
- Your solution's stdout is what gets scored, and only step 2's answer
  belongs there. Print the value on the last non-empty line.
- Nothing forbids you from carrying the value yourself instead of letting
  your agent remember it -- but see "Known limitations" in the task README.
  Solutions are public.

## Output

The last non-empty line of stdout must be the value from step 2, alone.
If your solution has no value to report, print `UNKNOWN`.

step1.txt

You are working through a two-part job. This is PART 1 of 2.

Below is an extract from an internal ledger.

Accounts Receivable — subsidiary ledger
Account 1200 · Trade Debtors · period 2026-01-01 to 2026-03-31 · USD

Date        Voucher      Narration              Counterparty                Debit      Credit      Balance
----------------------------------------------------------------------------------------------------------
2026-01-01               Balance brought forward                                                   7,238.82
2026-01-06  AR-2026-7551 Service billed         Fairmont Supplies        5,533.10                12,771.92
2026-01-13  AR-2026-7552 Service billed         Anchor Distributors      5,262.65                18,034.57
2026-01-18  AR-2026-7553 Service billed         Cedarworks Ltd           6,835.69                24,870.26
2026-01-21  AR-2026-7554 Invoice raised         Cedarworks Ltd           2,514.94                27,385.20
2026-01-26  AR-2026-7555 Credit note issued     Eastgate Packaging                   8,438.52    18,946.68
2026-02-03  AR-2026-7556 Payment received       Anchor Distributors                  8,749.86    10,196.82
2026-02-09  AR-2026-7557 Invoice raised         Anchor Distributors      6,171.48                16,368.30
2026-02-16  AR-2026-7558 Payment received       Delta Freight Co                     6,849.63     9,518.67
2026-02-23  AR-2026-7559 Discount allowed       Eastgate Packaging                   4,067.11     5,451.56
2026-02-25  AR-2026-7560 Payment received       Anchor Distributors                  5,451.56         0.00
2026-03-01  AR-2026-7561 Invoice raised         Fairmont Supplies        8,734.43                 8,734.43
2026-03-04  AR-2026-7562 Invoice raised         Cedarworks Ltd           7,800.13                16,534.56
2026-03-09  AR-2026-7563 Payment received       Delta Freight Co                     7,437.93     9,096.63
2026-03-16  AR-2026-7564 Goods dispatched       Fairmont Supplies        8,626.11                17,722.74
2026-03-18  AR-2026-7565 Invoice raised         Cedarworks Ltd           1,260.87                18,983.61
2026-03-20  AR-2026-7566 Invoice raised         Anchor Distributors      3,857.25                22,840.86
2026-03-24  AR-2026-7567 Service billed         Eastgate Packaging       2,842.12                25,682.98

Rank the debit entries from largest to smallest (break ties by Voucher, ascending) and identify the Voucher number at position 2.

Do the calculation now, then state the result once, in one short sentence,
and commit it to memory. You will be asked for it later in a SEPARATE
session -- the table below will NOT be available then, so remembering the
result is the point of this step.

step2.txt

This is PART 2 of 2, continuing the job you started earlier.

Earlier you worked through a ledger extract and computed one value:
the voucher number at position 2 when debits are ranked largest first.

Report that value now.

Output ONLY the value on the last line -- no explanation, no units, no
quotes, no surrounding prose. If you genuinely do not have the value,
output exactly: UNKNOWN

expected output

answer.json

{
  "id": "case_08",
  "category": "nth_largest_voucher",
  "answer": "AR-2026-7564",
  "answer_kind": "voucher"
}

Scored by judge.py — see Scoring logic below for the full rule.

scoring logic

judge.py runs once per case and prints a score per case. grader.py runs once at the end and folds case scores into a run-level summary. Without grader.py, the run's score is simply the average of case scores.

judge.py184 lines · view on GitHub
"""Per-case judge for session_memory_recall.

I/O contract: reads TRAPTASK_MANIFEST (trap-cli).

Scoring is binary and fully deterministic (no LLM judge). The answer is a
machine-generated number or record id, never a sentence, so there is no
phrasing to argue about -- either the value came back or it did not.
"""
from __future__ import annotations

import json
import os
import re
from pathlib import Path
from typing import Any

VOUCHER_RE = re.compile(r"\bAR-2026-\d{4}\b")
ISO_DATE_RE = re.compile(r"\b\d{4}-\d{2}-\d{2}\b")
# Money as it may plausibly be written back: 12345.67, 12,345.67, $12,345.67.
# The trailing lookahead rejects a following digit, and a following period only
# when a digit follows it -- a sentence-ending period is not part of the number.
# Getting this wrong is not cosmetic: `(?![\w.])` made "27,940.01." match as
# "27" and "27940.01." match as nothing at all, so any value that ended a
# sentence was invisible here.
MONEY_RE = re.compile(
    r"(?<![\w.])\$?\d{1,3}(?:,\d{3})*(?:\.\d{1,2})?(?![\w])(?!\.\d)"
    r"|(?<![\w.])\$?\d+(?:\.\d{1,2})?(?![\w])(?!\.\d)"
)
STRIP = " \t\r\n\"'`*.,:;!?()[]{}"

# Mirrors assert_answer_hard_to_guess() in build_cases.py: every money answer
# carries at least four digits before the decimal point. Anything shorter is
# therefore not the answer -- it is a step number, a match count, a rank -- and
# counting it as a rival candidate only produced false negatives.
MIN_WHOLE_DIGITS = 4


def last_value_line(stdout: str) -> str:
    lines = [ln.strip(STRIP) for ln in stdout.splitlines()]
    lines = [ln for ln in lines if ln]
    return lines[-1] if lines else ""


def normalise_money(text: str) -> str | None:
    """'$12,345.67' -> '12345.67'. None if it is not a money-shaped token."""
    t = text.replace("$", "").replace(",", "").replace("USD", "").strip()
    try:
        return f"{float(t):.2f}"
    except ValueError:
        return None


def candidates(text: str, kind: str) -> set[str]:
    """Every token in `text` that could plausibly be an answer of this kind.

    Used to reject shotgun answers -- printing every figure in the ledger must
    not count as remembering the one that mattered. Which makes the set's
    precision matter in both directions: a token that could never be the answer
    must not land here, or it turns a correct answer into a rival candidate and
    the shotgun rule fires on a solution that did nothing wrong. Voucher ids
    and ISO dates are removed before the money scan for exactly that reason --
    "AR-2026-0016" otherwise contributed 2026.00 and 16.00.
    """
    if kind == "voucher":
        return set(VOUCHER_RE.findall(text))
    scrubbed = ISO_DATE_RE.sub(" ", VOUCHER_RE.sub(" ", text))
    out = set()
    for tok in MONEY_RE.findall(scrubbed):
        n = normalise_money(tok)
        if n is None or len(n.split(".")[0]) < MIN_WHOLE_DIGITS:
            continue
        out.add(n)
    return out


def score_case(stdout: str, expected: dict) -> dict[str, Any]:
    """1.0 iff the remembered value came back.

    The final line is the contract, so it is read first and it is decisive:
    if it carries a value of the right kind, that value is the answer the
    solution is giving, whether or not prose surrounds it.

      1. the final line IS the value                      -> 1.0
      2. the final line carries exactly one candidate      -> that candidate
      3. the final line carries several                    -> 0.0, ambiguous
      4. the final line carries none                       -> fall back to the
         whole output, crediting it only if the answer is the sole candidate

    Step 4 forgives a solution that trails off after answering. Steps 2-3 are
    what stop a shotgun: listing every figure in the ledger is not remembering
    the one that mattered.
    """
    answer = expected["answer"]
    kind = expected.get("answer_kind", "money")
    category = expected.get("category")

    tail = last_value_line(stdout)
    tail_norm = tail if kind == "voucher" else (normalise_money(tail) or tail)
    if tail.upper() == "UNKNOWN":
        return {
            "score": 0.0,
            "reason": "solution reported UNKNOWN -- value did not survive into session 2",
            "category": category,
            "reported": "UNKNOWN",
        }

    if tail_norm.lower() == answer.lower():
        return {"score": 1.0, "reason": "exact match on final line", "category": category,
                "reported": tail}

    tail_found = candidates(tail, kind)
    if tail_found:
        if answer in tail_found and len(tail_found) == 1:
            return {
                "score": 1.0,
                "reason": "value on the final line (surrounding prose tolerated)",
                "category": category,
                "reported": answer,
            }
        if answer in tail_found:
            return {
                "score": 0.0,
                "reason": f"final line carries {len(tail_found)} candidates -- shotgun not credited",
                "category": category,
                "reported": tail,
                "n_candidates": len(tail_found),
            }
        return {
            "score": 0.0,
            "reason": "final line reports a different value",
            "category": category,
            "reported": tail,
            "n_candidates": len(tail_found),
        }

    found = candidates(stdout, kind)
    if answer in found and len(found) == 1:
        return {
            "score": 1.0,
            "reason": "value present and unambiguous (preamble tolerated)",
            "category": category,
            "reported": answer,
        }

    if answer in found:
        return {
            "score": 0.0,
            "reason": f"value present but {len(found)} candidates in output -- shotgun not credited",
            "category": category,
            "reported": tail,
            "n_candidates": len(found),
        }

    return {
        "score": 0.0,
        "reason": "value absent from output",
        "category": category,
        "reported": tail,
        "n_candidates": len(found),
    }


def main() -> None:
    m = json.loads(os.environ["TRAPTASK_MANIFEST"])
    stdout = Path(m["run"]["stdout"]).read_text(errors="replace")
    exit_code = json.loads(Path(m["run"]["meta"]).read_text())["exit_code"]
    expected = json.loads((Path(m["expected_dir"]) / "answer.json").read_text())

    if exit_code != 0:
        result = {"score": 0.0, "reason": f"solution exited {exit_code}",
                  "category": expected.get("category")}
    elif not stdout.strip():
        result = {"score": 0.0, "reason": "empty stdout",
                  "category": expected.get("category")}
    else:
        result = score_case(stdout, expected)

    result["id"] = expected["id"]
    print(json.dumps(result))


if __name__ == "__main__":
    main()
grader.py79 lines · view on GitHub
"""Overall grader for session_memory_recall.

Aggregates per-case judge results (the trap-cli TRAPTASK_MANIFEST list)
into a run-level verdict. This aggregation logic is standard across every
task in this repo -- usually nothing to customize here. If your judge's
metrics dict uses a different field name than "bug_category" for its
category breakdown, update CATEGORY_FIELD below; otherwise leave this file
as-is.
"""
from __future__ import annotations

import json
import os
from collections import Counter

PASS_THRESHOLD = 0.5
CATEGORY_FIELD = "category"  # change to match your judge.py's metrics dict, or None to disable


def main() -> None:
    cases = json.loads(os.environ["TRAPTASK_MANIFEST"])

    scored = [c for c in cases if c.get("metrics") and c["metrics"].get("score") is not None]
    skipped = [c for c in cases if not c.get("metrics") or c["metrics"].get("score") is None]

    accuracy = sum(c["metrics"]["score"] for c in scored) / len(scored) if scored else 0.0

    by_category_pct = {}
    if CATEGORY_FIELD:
        by_category_score: Counter[str] = Counter()
        by_category_total: Counter[str] = Counter()
        for c in scored:
            cat = c["metrics"].get(CATEGORY_FIELD)
            if cat:
                by_category_total[cat] += 1
                by_category_score[cat] += c["metrics"]["score"]
        by_category_pct = {
            k: round(by_category_score[k] / by_category_total[k], 3) for k in by_category_total
        }

    durations = [c.get("duration", 0.0) for c in cases if c.get("duration") is not None]
    if durations:
        ds = sorted(durations)
        latency_ms_median = round(ds[len(ds) // 2] * 1000, 1)
        latency_ms_p95 = round(ds[int(0.95 * len(ds))] * 1000, 1) if len(ds) > 1 else latency_ms_median
        latency_ms_total = round(sum(ds) * 1000, 1)
    else:
        latency_ms_median = latency_ms_p95 = latency_ms_total = 0.0

    case_costs = [
        c["cost"]["cost_usd"]
        for c in cases
        if isinstance(c.get("cost"), dict) and c["cost"].get("cost_usd") is not None
    ]
    cost_usd_total = round(sum(case_costs), 4) if case_costs else None

    n_passed = sum(1 for c in scored if c["metrics"]["score"] == 1.0)

    passed = bool(scored) and accuracy >= PASS_THRESHOLD

    print(json.dumps({
        "passed": passed,
        "score": round(accuracy, 3),
        "n_passed": n_passed,
        "n_total": len(cases),
        "n_scored": len(scored),
        "n_skipped_no_gold": len(skipped),
        "threshold": PASS_THRESHOLD,
        "by_category": by_category_pct,
        "latency_ms_median": latency_ms_median,
        "latency_ms_p95": latency_ms_p95,
        "latency_ms_total": latency_ms_total,
        "cost_usd_total": cost_usd_total,
    }))


if __name__ == "__main__":
    main()