refactor(events): deduplicate ConversationStateUpdateEvent definition#249
refactor(events): deduplicate ConversationStateUpdateEvent definition#249VascoSch92 wants to merge 3 commits into
Conversation
ConversationStateUpdateEvent was defined twice: the canonical one in events/types.ts (extends BaseEvent, value: unknown, has previous_value) and a divergent local copy in conversation/remote-state.ts (extends Event, value: any, no previous_value). Remove the local copy and import the canonical type from events/types. Nothing imported the remote-state copy (index.ts re-exports the RemoteState class only, and the type already comes from events/types), so this is non-breaking. The snapshot accessor keeps reading value.full_state via a cast, matching the surrounding `as any` style now that value is the stricter `unknown`. Closes #112
Endpoint audit❌ 6 off-contract call(s) — not on the agent-server · classifiers: cloud
❌ Not on agent-server (gated, 6)⛔ (no known backend) — served by no backend we can see (5)
|
Co-authored-by: openhands <openhands@all-hands.dev>
|
@OpenHands /roast-codereview |
|
I'm on it! VascoSch92 can track my progress at all-hands.dev |
|
I’ll re-run the PR fetch using the injected GitHub token. |
/roast-codereviewYou fixed the root problem (two competing definitions) and you did it the right way: delete the local snowflake, import the canonical type, and add a focused test so this doesn’t silently regress later. Nice. Now the roast: 1) You eliminated the duplicate type… but still has a stealthystill does . So the PR message says ‘no more here’, but the file still relies on one. It’s pre-existing, sure, but it undercuts the “we’re being strict about unknown” story. If you want this to be airtight, mirror the guard you used in :
2) will happily accept garbageIn , is still . If a server ever sends a malformed event (or is not an object), will coerce primitives and do weird things (e.g., strings become indexed properties). It won’t throw, but it will produce nonsense. A tiny hardening would be:
3) The new test is good, but the async callback test is a bit “trust me bro”works, but it’s the classic flaky pattern when CI is slow. If you can, prefer a deterministic flush (e.g., await the promise returned by , or expose a callback that returns a promise, or use a helper). 4) Minor nit: the test mutates directlyIt’s fine in Jest, but it’s global shared state. If another test file assumes is untouched and runs interleaved (parallelism settings change), you get fun nondeterminism. A wrapper is already there, so you’re mostly safe — just be aware this is the kind of thing that causes “only fails on CI” later. Net: the dedupe is a solid refactor and the new guard for is the right direction. I’d just tighten the remaining “unwrap full_state” path and harden to avoid silently corrupting the cache on bad input. This comment was generated by an AI agent (OpenHands) on behalf of the user. |
Problem
ConversationStateUpdateEventwas defined in two places with different shapes:src/events/types.ts:extends BaseEvent,value: unknown, includesprevious_value.src/conversation/remote-state.ts:extends Event,value: any, missingprevious_value.Different base types, different value types, and a missing field — a source of confusion and drift.
Closes #112.
Change
remote-state.ts.ConversationStateUpdateEventfrom../events/types.__full_state__snapshot path now readsvalue.full_statethrough a cast (matching the adjacent(this.cachedState as any)style) since the canonicalvalueis the stricterunknown.Non-breaking: nothing imported the remote-state copy —
index.tsre-exports only theRemoteStateclass, and the type is already exported fromevents/types.local-conversation.tsalready imports the canonical type.tscconfirms theevent as ConversationStateUpdateEventdowncast still holds (BaseEvent extends Event).Tests
New
src/__tests__/remote-state-events.test.tsdrivesupdateStateFromEventwith the canonical type (including the newprevious_valuefield):__full_state__snapshot event is applied and served from cache (no network);createStateUpdateCallback.Full unit suite green (274 tests),
tscbuild clean, eslint (no new warnings vs. the removedvalue: any) + prettier clean.