prizmkit 1.1.152 → 1.1.153

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.1.152",
3
- "bundledAt": "2026-07-26T05:11:00.580Z",
4
- "bundledFrom": "4db7f74"
2
+ "frameworkVersion": "1.1.153",
3
+ "bundledAt": "2026-07-26T05:44:00.463Z",
4
+ "bundledFrom": "54bad91"
5
5
  }
@@ -820,24 +820,22 @@ class ProgressTracker:
820
820
  self.message_count += 1
821
821
  elif event_type in {"message_update", "message_end"}:
822
822
  assistant_event = event.get("assistantMessageEvent")
823
+ message = event.get("message")
823
824
  text = ""
824
825
  if isinstance(assistant_event, dict):
825
826
  text = str(assistant_event.get("delta") or assistant_event.get("text") or "")
826
- if not text:
827
- message = event.get("message")
828
- if isinstance(message, dict):
829
- content = message.get("content")
830
- if isinstance(content, str):
831
- text = content
832
- elif isinstance(content, list):
833
- text = "\n".join(
834
- str(item.get("text") or "")
835
- for item in content if isinstance(item, dict)
836
- )
827
+ if not text and isinstance(message, dict):
828
+ content = message.get("content")
829
+ if isinstance(content, str):
830
+ text = content
831
+ elif isinstance(content, list):
832
+ text = "\n".join(
833
+ str(item.get("text") or "")
834
+ for item in content if isinstance(item, dict)
835
+ )
837
836
  if text.strip():
838
837
  self.last_text_snippet = text.strip()[-120:]
839
838
  self._detect_phase(text)
840
- self._detect_terminal_error(text, require_error_context=True)
841
839
  if (
842
840
  event_type == "message_end"
843
841
  and isinstance(message, dict)
@@ -1017,6 +1017,31 @@ def test_progress_parser_keeps_pi_length_as_nonfatal_diagnostic_metadata():
1017
1017
  assert data["terminal_success_at"]
1018
1018
 
1019
1019
 
1020
+ @pytest.mark.parametrize("role", ("assistant", "toolResult"))
1021
+ def test_progress_parser_does_not_promote_pi_diagnostic_content_to_fatal_error(role):
1022
+ module = _load_progress_parser_module()
1023
+ tracker = module.ProgressTracker()
1024
+ tracker.process_event({"type": "session", "version": 3, "id": "pi-session", "cwd": "/tmp/project"})
1025
+ tracker.process_event({"type": "agent_start"})
1026
+ tracker.process_event({
1027
+ "type": "message_end",
1028
+ "message": {
1029
+ "role": role,
1030
+ "content": [{
1031
+ "type": "text",
1032
+ "text": 'continuation_reason = "context_overflow"\nerror = _error_text(result)',
1033
+ }],
1034
+ "stopReason": "toolUse",
1035
+ },
1036
+ })
1037
+
1038
+ data = tracker.to_dict()
1039
+
1040
+ assert data["api_error_code"] == ""
1041
+ assert data["fatal_error_code"] == ""
1042
+ assert data["last_result_is_error"] is False
1043
+
1044
+
1020
1045
  def test_progress_parser_recovers_from_retrying_pi_attempt_before_final_success():
1021
1046
  module = _load_progress_parser_module()
1022
1047
  tracker = module.ProgressTracker()
@@ -1677,6 +1702,57 @@ def test_session_persists_normalized_stream_without_raw_history(tmp_path, monkey
1677
1702
  assert not backup_log.exists()
1678
1703
 
1679
1704
 
1705
+ def test_pi_session_diagnostic_tool_output_does_not_trigger_fatal_termination(tmp_path):
1706
+ import prizmkit_runtime.sessions as sessions
1707
+
1708
+ fake_cli = tmp_path / "pi_diagnostic_cli.py"
1709
+ fake_cli.write_text(
1710
+ "#!/usr/bin/env python3\n"
1711
+ "import json, sys, time\n"
1712
+ "_prompt = sys.stdin.read()\n"
1713
+ "source = 'continuation_reason = \\\"context_overflow\\\"\\nerror = _error_text(result)'\n"
1714
+ "events = [\n"
1715
+ " {'type':'session','id':'s1'},\n"
1716
+ " {'type':'agent_start'},\n"
1717
+ " {'type':'turn_start'},\n"
1718
+ " {'type':'tool_execution_start','toolCallId':'c1','toolName':'read','args':{'path':'runtime.py'}},\n"
1719
+ " {'type':'tool_execution_end','toolCallId':'c1','toolName':'read','result':{'content':[{'type':'text','text':source}]},'isError':False},\n"
1720
+ " {'type':'message_end','message':{'role':'toolResult','toolCallId':'c1','content':[{'type':'text','text':source}],'stopReason':'toolUse'}},\n"
1721
+ "]\n"
1722
+ "for event in events: print(json.dumps(event), flush=True)\n"
1723
+ "time.sleep(1.5)\n"
1724
+ "message = {'role':'assistant','content':[{'type':'text','text':'Done'}],'stopReason':'stop'}\n"
1725
+ "print(json.dumps({'type':'message_end','message':message}), flush=True)\n"
1726
+ "print(json.dumps({'type':'agent_end','willRetry':False,'messages':[message]}), flush=True)\n",
1727
+ encoding="utf-8",
1728
+ )
1729
+ fake_cli.chmod(0o755)
1730
+ prompt = tmp_path / "prompt.md"
1731
+ prompt.write_text("hello", encoding="utf-8")
1732
+ session_log = tmp_path / "state" / "sessions" / "sess-diagnostic" / "logs" / "session.log"
1733
+ progress = session_log.with_name("progress.json")
1734
+
1735
+ result = sessions.AISessionLauncher(
1736
+ sessions.AISessionConfig(
1737
+ cli_command=str(fake_cli),
1738
+ platform="pi",
1739
+ model=None,
1740
+ prompt_path=prompt,
1741
+ cwd=tmp_path,
1742
+ log_path=session_log,
1743
+ progress_path=progress,
1744
+ )
1745
+ ).run()
1746
+
1747
+ progress_data = json.loads(progress.read_text(encoding="utf-8"))
1748
+ assert result.exit_code == 0
1749
+ assert result.fatal_error_code == ""
1750
+ assert result.progress_summary.result_subtype == "success"
1751
+ assert progress_data["fatal_error_code"] == ""
1752
+ assert not session_log.with_name("fatal-error.json").exists()
1753
+ assert not session_log.with_name("stale-kill.json").exists()
1754
+
1755
+
1680
1756
  def test_custom_session_launch_writes_existing_logs_and_progress(tmp_path):
1681
1757
  from prizmkit_runtime.launch_profiles import HeadlessLaunchProfile
1682
1758
  from prizmkit_runtime.sessions import AISessionConfig, AISessionLauncher
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.152",
2
+ "version": "1.1.153",
3
3
  "skills": {
4
4
  "prizmkit": {
5
5
  "description": "Framework introduction and navigation for the formal single-requirement lifecycle, project initialization, Prizm docs, and independent deployment.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.152",
3
+ "version": "1.1.153",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {