feat(simulation): deliver event_config.scheduled_events end to end - #780
Open
conradorebuffo wants to merge 3 commits into
Open
feat(simulation): deliver event_config.scheduled_events end to end#780conradorebuffo wants to merge 3 commits into
conradorebuffo wants to merge 3 commits into
Conversation
`event_config.scheduled_events` was declared on the EventConfig dataclass but never reached the simulation: the event-config prompt did not ask for it, `_parse_event_config` overwrote whatever the LLM returned with a hardcoded `[]`, and neither runner read the key. The README advertises injecting variables mid-simulation from a "God's-eye view", which is exactly this field. This wires the existing mechanism rather than inventing a new one. Initial posts are already published through `ManualAction(CREATE_POST)` in a single `env.step()` before the round loop; a scheduled event is the same publication fired from inside the loop at its target round. - ask for `scheduled_events` in the event-config prompt, constraining `round` to the simulation horizon, and keep the failure-path dict the same shape - stop discarding the parsed value in `_parse_event_config` - generalize `_assign_initial_post_agents` into `_assign_agents_to_posts`, so initial posts and scheduled events share one type index, one alias table and one anti-repetition counter instead of duplicating the matching logic - read and group the events by round in both the Reddit and Twitter runners, and publish them at the top of each round before agents act; a malformed event logs a warning and is skipped rather than aborting the run - thread `stance` / `sentiment_bias` into the persona prompt builders, since the persona text is the only channel that reaches the model Backwards compatible: with an empty `scheduled_events` the execution path is identical to today, so existing configs are unaffected. Co-Authored-By: Claude Code <noreply@anthropic.com>
…peline The persona prompt builders now threaded `stance` / `sentiment_bias`, and `generate_profile_from_entity` read them off a new `agent_activity_map`. But no caller ever supplies that map, so every agent kept the `neutral` / `0.0` defaults and the values never reached the model. That is not an oversight in the call chain, it is the pipeline order: `prepare_simulation` generates the profiles before it generates `simulation_config.json`, and the per-agent stance only exists in the latter. Making it reachable means either reordering an existing pipeline or rewriting the generated profile artifact at run time -- both far beyond the scope of this change, and both would mask the point rather than make it. `stance` and `sentiment_bias` are therefore reported as inert, like the other config fields no runner consumes, instead of being wired with plumbing that cannot carry a value. This leaves the change to what is verified end to end: `scheduled_events`. Co-Authored-By: Claude Code <noreply@anthropic.com>
`total_rounds` is derived from the time config, then truncated by `--max-rounds`. The event-config prompt asks the model to keep each `round` inside the simulation horizon, but it sees the untruncated horizon: a run configured for 72 rounds and started with `--max-rounds 24` can be handed events for round 40. Those events were kept in the by-round index and simply never popped, so they disappeared without a trace -- the same silent discard this change set out to fix, reintroduced one level down. Both runners now report the out-of-range rounds up front, next to the existing warning for a malformed `round`. Nothing is dropped differently; it is just no longer dropped quietly. Co-Authored-By: Claude Code <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #779
event_config.scheduled_eventsis declared on theEventConfigdataclass but never reaches thesimulation: the event-config prompt does not ask for it,
_parse_event_configoverwrites whateverthe model returned with a hardcoded
[], and no runner reads the key. The README advertisesinjecting variables mid-simulation from a "God's-eye view", which is exactly this field.
This wires the existing mechanism rather than inventing a new one.
Goals
event_config.scheduled_eventsreach the simulation, so the README's mid-run"God's-eye view" injection is backed by code.
execution path must be indistinguishable from current behaviour.
Non-goals
not here — see "Not included, on purpose" below.
camel-oasis.prepare_simulation. That is a maintainer decision, not an outside PR.Acceptance criteria
round: Nis published in round N, by an agent whoseposter_typematches therequest, and before the agents act in that round.
code with the same config.
scheduled_events: []: no event log lines, same round count, same normalised log flow andsame initial posts as before the change.
roundlogs a warning and is skipped — the run continues rather than aborting.dropped silently (
total_roundscan be truncated by--max-rounds).cd backend && python -m pytest tests -qis green.All six were checked on a clean
b5b53acccheckout; evidence in Testing below.Why this is mergeable: it is the same publication path, moved inside the loop
initial_postsis already published throughManualAction(action_type=ActionType.CREATE_POST)in asingle
env.step()before the round loop (run_reddit_simulation.py:597-620). A scheduled event isthat same publication, fired from inside the loop at its target round.
With an empty
scheduled_eventsthe execution path is identical to today. That is not anargument, it is measured: two runs from the same config, one with events and one with
[], producedthe same number of
env.step()calls per round, the same log flow and the same initial posts. Sincethe current generator always emits
[], existing configs are unaffected.Changes
backend/app/services/simulation_config_generator.pyscheduled_eventsin the event-config prompt, constrainingroundto the simulationhorizon, and keep the failure-path dict the same shape
_parse_event_config_assign_initial_post_agentsinto_assign_agents_to_posts, so initial posts andscheduled events share one type index, one alias table and one anti-repetition counter
instead of duplicating the matching logic
backend/scripts/run_reddit_simulation.py,backend/scripts/run_twitter_simulation.pyroundlogs a warning and is skipped rather than aborting the runtotal_roundscan be truncatedby
--max-rounds, and such events would otherwise be dropped silentlybackend/tests/test_scheduled_event_assignment.py— four tests for the shared assignment helper:resolution across both lists, anti-repetition carrying across them, empty lists as a no-op, and the
unknown-
poster_typefallback.Both platforms are changed, symmetrically: a fix that repairs one and leaves the other broken is an
easy excuse to close the PR.
Testing
cd backend && python -m pytest tests -q→ 133 passed (129 existing + 4 new)b5b53acccheckout: a config with one event atround: 3produced thatpost in round 3, published by an agent of the requested
poster_type, and absent from rounds 1and 2 — with the same config on unpatched code producing nothing.
scheduled_events: []→ no event log lines, same round count, sameexecution flow.
assigned to a distinct agent matching its requested
poster_type, and all four fired in theirround.
One design question
The trigger is the round number, as described in #779. I raised the alternative there — the
simulated clock would allow "at simulated hour N" — and said I would follow your preference. With no
answer yet I am shipping
round, since it is what the loop already indexes and what the generatorcan reason about directly. Switching to the clock is a small change confined to the assignment
helper, and I will make it if you prefer.
Relationship to #573
#573 (Narrative Layer / God Mode) lists "Mid-sim OASIS prompt injection" among its explicit
non-goals, since it deliberately stays out of the OASIS core. This PR does that injection inside the
simulation, so the two are complementary: if #573 lands, its God Mode would have a real mechanism to
push events into rather than only the prose layer. There is no file overlap between them.
Not included, on purpose (the non-goals, in detail)
The issue lists five other fields that no runner reads. I left them out:
stance/sentiment_bias— reachable only by reorderingprepare_simulation, which is your callrecency_weight— its counterpart lives incamel-oasis, not in this repoecho_chamber_strength— no destination underrecsys_type='reddit'I would rather ship the one that is verified end to end than bundle four that are not.
No rush on this — I will rebase if it goes stale.