"""The journal must capture both halves of a turn. Regression test for a placement bug: the journal originally sat at the end of the pipeline, where the user aggregator has already consumed the transcript, so it never recorded anything at all. """ import asyncio, json, sys, tempfile from pathlib import Path sys.path.insert(0, str(Path(__file__).parent)) from journal import Journal, recent_prompt from pipecat.frames.frames import EndFrame, TranscriptionFrame from pipecat.pipeline.pipeline import Pipeline from pipecat.pipeline.worker import PipelineWorker from pipecat.processors.aggregators.llm_context import LLMContext from pipecat.processors.aggregators.llm_response_universal import ( LLMContextAggregatorPair, LLMUserAggregatorParams) from pipecat.turns.user_start.external_user_turn_start_strategy import ExternalUserTurnStartStrategy from pipecat.turns.user_stop.external_user_turn_stop_strategy import ExternalUserTurnStopStrategy from pipecat.turns.user_turn_strategies import UserTurnStrategies from pipecat.utils.time import time_now_iso8601 from pipecat.workers.runner import WorkerRunner def test_recent_prompt_reads_last_ten_entries(): path = Path(tempfile.mkdtemp()) / "journal.jsonl" rows = [ json.dumps({"heard": f"question {i}", "reply": f"answer {i}"}) for i in range(12) ] path.write_text("\n".join(rows[:3]) + "\nnot json\n" + "\n".join(rows[3:])) prompt = recent_prompt(path) assert "User: question 0\n" not in prompt assert "User: question 1\n" not in prompt assert "User: question 2\n" in prompt assert "User: question 11\n" in prompt assert prompt.index("User: question 2\n") < prompt.index("User: question 11\n") async def main(): path = Path(tempfile.mkdtemp()) / "journal.jsonl" journal = Journal(path) ctx = LLMContext() ua, _ = LLMContextAggregatorPair(ctx, user_params=LLMUserAggregatorParams( user_turn_strategies=UserTurnStrategies( start=[ExternalUserTurnStartStrategy()], stop=[ExternalUserTurnStopStrategy()]))) worker = PipelineWorker(Pipeline([journal, ua])) runner = WorkerRunner(handle_sigint=False) await runner.add_workers(worker) task = asyncio.create_task(runner.run()) await asyncio.sleep(0.3) await worker.queue_frames([ TranscriptionFrame("what is the sample rate", "u", time_now_iso8601(), None)]) await asyncio.sleep(0.5) journal.record_reply("Sixteen kilohertz.") await asyncio.sleep(0.3) await worker.queue_frames([EndFrame()]) await task rows = [json.loads(l) for l in path.read_text().splitlines() if l.strip()] print(f" {'PASS' if rows else 'FAIL'} journal file written ({len(rows)} entries)") if rows: r = rows[0] print(f" {'PASS' if r['heard'] else 'FAIL'} captured what was heard: {r['heard']!r}") print(f" {'PASS' if r['reply'] else 'FAIL'} captured the reply: {r['reply']!r}") asyncio.run(main())