Skip to content

fix(agent): copy conversation_history to avoid mutating caller's list - #229

Merged
teknium1 merged 1 commit into
NousResearch:mainfrom
Farukest:fix/conversation-history-mutation
Mar 2, 2026
Merged

fix(agent): copy conversation_history to avoid mutating caller's list#229
teknium1 merged 1 commit into
NousResearch:mainfrom
Farukest:fix/conversation-history-mutation

Conversation

@Farukest

@Farukest Farukest commented Mar 1, 2026

Copy link
Copy Markdown
Contributor

Changed messages = conversation_history or [] to messages = list(conversation_history) if conversation_history else [] in run_conversation(). This creates a shallow copy so the caller's list is never mutated.

The result dict already returns the updated messages list, so callers who need the full conversation can use result["messages"].

Test

Added TestConversationHistoryNotMutated to tests/test_run_agent.py that passes a 2-item history list, runs a conversation, and verifies the original list still has exactly 2 items. Without the fix, it grows to 4 (the 2 originals + new user message + assistant response).

Closes #228

@teknium1

teknium1 commented Mar 2, 2026

Copy link
Copy Markdown
Contributor

Merged in 56b53bf — clean fix with a good test. Thanks!

angelburgosrosado pushed a commit to angelburgosrosado/hermes-agent that referenced this pull request Apr 27, 2026
…void mutating caller's list

Authored by Farukest. Fixes NousResearch#228.

# Conflicts:
#	tests/test_run_agent.py
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…void mutating caller's list

Authored by Farukest. Fixes NousResearch#228.

# Conflicts:
#	tests/test_run_agent.py
teddyjfpender added a commit to teddyjfpender/superforecasting-agent that referenced this pull request Jul 5, 2026
Task NousResearch#229 (review item #9), landed on the seam B1 left open, BEFORE the
next autonomous tier rather than after.

- RunMode {interactive, cycle, cron} x ActionClass {ledger_writes,
  network, llm_spend, subprocess} -> Decision {auto, ask, never}. Every
  cell defaults AUTO — the zero-behavior-change contract (today's runtime
  runs every job regardless of mode; the only brakes are the existing
  caps) — pinned by test. The bounded cells ((cycle|cron) x llm_spend)
  record WHICH cap governs the spend (reforecast batch cap,
  cap_preset_by_calls, the paid-tier budget) in the audit entry. Operator
  tightening via additive appconfig keys FORECAST_POLICY_<MODE>_<CLASS>.
- ctx.authorize(class, detail): auto -> proceed + LOG (resolved_policy +
  policy_decisions[] land in the JobRecord — the autonomy audit trail);
  never -> PolicyRefused teaching error naming the config key; ask ->
  an 'approval required:' alert (riding the proposals pattern, deduped),
  the job parks at the new awaiting_approval status, and
  policy.approve_job() grants + acks + re-runs to completion.
- Every type authorizes at its REAL action points: reforecast/task/
  quorum (llm_spend + ledger_writes), refresh (ledger_writes only — it
  is LLM-free by contract), warnings (the paid seam), backup (none).
- JobRecord/DTO gain the 3 audit fields; generated.ts regenerated.
- Named follow-ups (files owned by the concurrent carve): the
  forecast jobs approve CLI verb + gateway RPC over approve_job.

23 policy tests + jobs/gateway/protocol suites (133 + 131 + 358) green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

run_conversation() mutates the caller's conversation_history list

2 participants