Useful Standard Library
Use datetime, Counter, defaultdict, islice, sha256, uuid, and copy. Know that time.sleep blocks the whole program.
The standard library is the set of modules that come with Python. You do not need pip for these. They run in Joeven. Look here before you add a package. Agent code leans on a small set: time stamps, counts, copies, ids, and hashes.
You already used json, pathlib, copy, math, and re (next lesson). This page is a map of a few more that show up in traces and tests. It is not a tour of every stdlib module. http.client exists; we still will not hit the network here.
These modules come with Python. Stamp time, count tools, id a run. Do not sleep for long.
A few stdlib toolsCheat sheet
| Module | Job |
|---|---|
datetime | When did this step happen? |
collections.Counter | How often did each tool run? |
collections.defaultdict | Group rows without a KeyError |
itertools.islice | Take the first n items |
hashlib.sha256 | Fingerprint bytes; .hexdigest() is hex text |
uuid.uuid4 | A unique id |
copy | Copy a list or dict |
time.sleep | Wait. This blocks. |
time.time | A clock number you can print |
datetime
Store time in UTC. Use .isoformat() when you put a timestamp in a trace. Local time depends on the machine. UTC is comparable.
timedelta is a duration, like five minutes. Add it to a datetime to get a later time. Useful for “this observation is stale.” Do not parse model-written dates with guesswork if you can store ISO strings you created.
datetime.now(timezone.utc) is the current UTC time. Naive datetimes (no timezone) cause bugs when you compare. Prefer timezone-aware.
Counter and defaultdict
Counter counts hashable items. Tool names, error words, status flags. Counter(tools)["search"] is how many times search ran. Counter is a dict subclass. Missing keys look like 0 when you index, which is handy. Still .get if you want.
defaultdict(list) makes a new list when a key is new. You can append without checking if key in d first. defaultdict(int) is a manual counter. Counter is clearer for counts.
Do not defaultdict(list) as a transcript. You would still need an order of keys. Use a list of rows for order, then group with defaultdict when you report.
islice, sha256, uuid, copy
islice(items, n) takes the first n items. Useful when a trace is long and you only want a prefix. For a suffix, slice the list: items[-n:]. islice shines on lazy iterators. On a list, a slice is fine.
hashlib.sha256(data).hexdigest() turns bytes into a hex string. Use it to see if text changed. Pass bytes, like b"hello" or text.encode("utf-8"). Do not hash secrets into a public log if the secret can be guessed. Hash prompts to detect “same prompt as last time,” not passwords.
uuid.uuid4() makes a random unique id. Turn it into text with str(...). Good for a run id. Not good as a security token by itself in every system, but fine as a log correlation id.
copy.copy copies the outer object. Nested dicts are still shared. copy.deepcopy copies nested objects too. You saw this in mutability. It lives in stdlib, so it belongs on the map.
time.sleep blocks
Blocks means the program waits and does nothing else. A long time.sleep(30) freezes that wait. In Joeven it would freeze the page. In an agent loop it would stall every other step.
Mention sleep. Do not sleep for a long time here. If you need a pause on a real server, keep it short and log why. Retries should print “would wait” in this editor. The next agent lesson on retries follows that rule.
Do not call a long time.sleep in a Try it box. The page waits until it finishes.
random.choice is also stdlib and useful for a fake model that picks a canned line. random is not a substitute for tests. urllib exists and still needs a network. Skip it here. argparse builds command-line flags for a laptop main. Skip it here. The table above is the set you will actually type in traces.
When you group with defaultdict(list), convert to dict(grouped) before you JSON-dump if you want a plain object. json.dumps can dump a defaultdict, but tests that compare to a literal dict are easier with a plain dict. Counter dumps as an object of counts. Good for a report row.
Common mistakes
- Naive datetime vs UTC.
- Hashing a str without
.encode. time.sleepin the agent loop as “backoff” with huge numbers.defaultdicthiding missing-key bugs you needed to see.- Using
uuidas a substitute for checking allowlists.
Run to execute this in your browser. Nothing is sent to a server.
Read counts as a policy report: search ran more than read. That report is how you catch a loop that hammers one tool.
How agents use this
Stamp each trace row with UTC time. Count tool names with Counter. Group errors with defaultdict. Take the last few steps with islice (or a slice on a list). Hash a prompt to see if it changed. Give each run a uuid4 id. Copy state before a risky step. Do not sleep for a long time in the loop — that blocks everything else.
A run id in every log line lets you grep one conversation out of a file of many. A hash of the assembled prompt lets you notice “we sent the same 8k characters again.” A Counter in a weekly report lets you see that search is 90% of calls. None of that needs a third-party package.
When you later install httpx on a laptop, you still keep these modules. The stdlib is the floor. Packages are extra. Joeven’s sandbox is that floor on purpose.
Check your understanding