tamfis-code 0.6.4__tar.gz → 0.6.5__tar.gz

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.
Files changed (127) hide show
  1. {tamfis_code-0.6.4/tamfis_code.egg-info → tamfis_code-0.6.5}/PKG-INFO +1 -1
  2. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/pyproject.toml +1 -1
  3. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/__init__.py +1 -1
  4. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/runner_local.py +19 -1
  5. {tamfis_code-0.6.4 → tamfis_code-0.6.5/tamfis_code.egg-info}/PKG-INFO +1 -1
  6. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_runner_local.py +23 -0
  7. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/MANIFEST.in +0 -0
  8. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/README.md +0 -0
  9. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/USAGE_INSTALL_RELEASE.md +0 -0
  10. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/setup.cfg +0 -0
  11. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/__main__.py +0 -0
  12. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/agent_definitions.py +0 -0
  13. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/agents.py +0 -0
  14. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/api_client.py +0 -0
  15. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/cli.py +0 -0
  16. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/clipboard.py +0 -0
  17. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/completion.py +0 -0
  18. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/config.py +0 -0
  19. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/custom_commands.py +0 -0
  20. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/doctor.py +0 -0
  21. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/enforcer.py +0 -0
  22. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/evidence.py +0 -0
  23. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/hooks.py +0 -0
  24. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/indexer.py +0 -0
  25. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/instructions.py +0 -0
  26. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/interactive.py +0 -0
  27. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/live_input.py +0 -0
  28. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/local_chat.py +0 -0
  29. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/local_tools.py +0 -0
  30. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/mcp.py +0 -0
  31. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/mcp_stdio_server.py +0 -0
  32. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/metrics.py +0 -0
  33. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/model_registry.py +0 -0
  34. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/__init__.py +0 -0
  35. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/agent.py +0 -0
  36. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/agent_server.py +0 -0
  37. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/automation.py +0 -0
  38. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/compat.py +0 -0
  39. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/conversation.py +0 -0
  40. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/delegation.py +0 -0
  41. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/events.py +0 -0
  42. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/leases.py +0 -0
  43. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/security.py +0 -0
  44. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/skills.py +0 -0
  45. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/tools.py +0 -0
  46. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/openhands/workspace.py +0 -0
  47. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/orchestrator/__init__.py +0 -0
  48. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/orchestrator/context.py +0 -0
  49. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/orchestrator/engine.py +0 -0
  50. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/orchestrator/planner.py +0 -0
  51. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/orchestrator/protocols.py +0 -0
  52. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/orchestrator/validator.py +0 -0
  53. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/project.py +0 -0
  54. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/provider_protocols.py +0 -0
  55. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/providers.py +0 -0
  56. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/pty.py +0 -0
  57. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/references.py +0 -0
  58. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/render.py +0 -0
  59. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/routing.py +0 -0
  60. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/runner.py +0 -0
  61. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/safety.py +0 -0
  62. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/screenshot.py +0 -0
  63. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/sessions.py +0 -0
  64. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/state.py +0 -0
  65. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/swarm.py +0 -0
  66. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/tasks.py +0 -0
  67. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/tool_policy.py +0 -0
  68. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code/workspace.py +0 -0
  69. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code.egg-info/SOURCES.txt +0 -0
  70. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code.egg-info/dependency_links.txt +0 -0
  71. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code.egg-info/entry_points.txt +0 -0
  72. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code.egg-info/requires.txt +0 -0
  73. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tamfis_code.egg-info/top_level.txt +0 -0
  74. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_agent_definitions.py +0 -0
  75. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_agents.py +0 -0
  76. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_agents_delegation.py +0 -0
  77. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_build_installation.py +0 -0
  78. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_cli_commands.py +0 -0
  79. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_clipboard.py +0 -0
  80. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_completion.py +0 -0
  81. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_context_rollover.py +0 -0
  82. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_custom_commands.py +0 -0
  83. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_cwd_validation.py +0 -0
  84. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_doctor_session_diagnostics.py +0 -0
  85. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_enforcer.py +0 -0
  86. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_fake_tool_detection.py +0 -0
  87. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_find_references.py +0 -0
  88. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_hooks.py +0 -0
  89. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_indexer.py +0 -0
  90. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_instructions.py +0 -0
  91. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_integration_new.py +0 -0
  92. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_interactive_standalone.py +0 -0
  93. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_live_input.py +0 -0
  94. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_local_pty.py +0 -0
  95. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_mcp.py +0 -0
  96. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_mcp_search_bounds.py +0 -0
  97. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_mcp_standalone_degradation.py +0 -0
  98. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_mcp_stdio_server.py +0 -0
  99. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_metrics.py +0 -0
  100. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_openhands_runtime.py +0 -0
  101. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_openrouter_cost_routing.py +0 -0
  102. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_orchestrator.py +0 -0
  103. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_plan_mode_gate.py +0 -0
  104. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_plan_steps_and_attempts.py +0 -0
  105. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_provider_protocols.py +0 -0
  106. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_reasoning_effort_capability.py +0 -0
  107. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_reasoning_plan.py +0 -0
  108. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_references.py +0 -0
  109. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_render_task_diagnostics.py +0 -0
  110. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_routing.py +0 -0
  111. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_runner_helpers.py +0 -0
  112. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_safety.py +0 -0
  113. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_safety_manifest.py +0 -0
  114. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_sessions.py +0 -0
  115. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_swarm.py +0 -0
  116. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_api_client.py +0 -0
  117. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_approval.py +0 -0
  118. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_approval_flow.py +0 -0
  119. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_config.py +0 -0
  120. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_intent.py +0 -0
  121. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_render.py +0 -0
  122. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_repl_exit.py +0 -0
  123. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_tasks.py +0 -0
  124. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_tamfis_code_workspace.py +0 -0
  125. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_version_consistency.py +0 -0
  126. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_workspace_discovery_gaps.py +0 -0
  127. {tamfis_code-0.6.4 → tamfis_code-0.6.5}/tests/test_workspace_scope.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tamfis-code
3
- Version: 0.6.4
3
+ Version: 0.6.5
4
4
  Summary: TamfisGPT Code -- portable subscription-backed terminal coding agent with local tools, PTY, plans, queues, and approvals
5
5
  Project-URL: Homepage, https://github.com/tamfitronics/tamfis-code
6
6
  Project-URL: Repository, https://github.com/tamfitronics/tamfis-code
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "tamfis-code"
3
- version = "0.6.4"
3
+ version = "0.6.5"
4
4
  description = "TamfisGPT Code -- portable subscription-backed terminal coding agent with local tools, PTY, plans, queues, and approvals"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -17,7 +17,7 @@ See docs/REMOTE_AGENT_MASTER_SPEC.md, Phase 21, for the original --remote
17
17
  architecture's spec.
18
18
  """
19
19
 
20
- __version__ = "0.6.4"
20
+ __version__ = "0.6.5"
21
21
 
22
22
  # Bumped whenever a CLI release requires a minimum backend Remote API
23
23
  # contract version. Only meaningful for --remote; the standalone path has no
@@ -1183,6 +1183,14 @@ def _legacy_resume_messages(state, incoming_objective: str) -> tuple[list[dict[s
1183
1183
  # the tail of the accumulated text, and triggers within a couple KB of a
1184
1184
  # genuine loop, long before the content can grow large enough to matter.
1185
1185
  _DEGENERATE_REPETITION_RE = re.compile(r"(.{6,200}?)\1{4,}", re.DOTALL)
1186
+ # A separate guard for a common context-confusion failure: the model starts
1187
+ # replaying a synthetic transcript ("then the user said ... then the
1188
+ # assistant responded ...") instead of answering the current task. The
1189
+ # individual paragraphs are often too long or slightly varied for the
1190
+ # contiguous backreference above, so count the unmistakable transcript
1191
+ # markers in the rolling tail.
1192
+ _CONVERSATION_ECHO_USER_MARKER = re.compile(r"\bthen\s+the\s+user\s+said\b", re.IGNORECASE)
1193
+ _CONVERSATION_ECHO_ASSISTANT_MARKER = re.compile(r"\bthen\s+the\s+assistant\s+(?:said|responded)\b", re.IGNORECASE)
1186
1194
  _DEGENERATE_REPETITION_TAIL_WINDOW = 8_000
1187
1195
  _STREAM_QUALITY_LAG_CHARS = 1_024
1188
1196
  _CORRUPTED_STREAM_MIN_CHARS = 600
@@ -2277,6 +2285,12 @@ async def _stream_one_completion(
2277
2285
  if _DEGENERATE_REPETITION_RE.search(tail_buffer):
2278
2286
  quality_failure_reason = "degenerate_repetition"
2279
2287
  break
2288
+ if (
2289
+ len(_CONVERSATION_ECHO_USER_MARKER.findall(tail_buffer)) >= 3
2290
+ and len(_CONVERSATION_ECHO_ASSISTANT_MARKER.findall(tail_buffer)) >= 3
2291
+ ):
2292
+ quality_failure_reason = "conversation_echo"
2293
+ break
2280
2294
  if _corrupted_lexical_stream_index(tail_buffer) is not None:
2281
2295
  quality_failure_reason = "corrupted_output"
2282
2296
  break
@@ -2308,6 +2322,8 @@ async def _stream_one_completion(
2308
2322
  diagnosis = (
2309
2323
  "Detected corrupted provider token output; discarding it and requesting a clean route."
2310
2324
  if quality_failure_reason == "corrupted_output"
2325
+ else "Detected a repeated conversation transcript; discarding it and requesting a clean route."
2326
+ if quality_failure_reason == "conversation_echo"
2311
2327
  else "Detected the model repeating itself in a loop; discarding that completion."
2312
2328
  )
2313
2329
  renderer.handle_event({
@@ -3634,7 +3650,7 @@ async def run_local_agent_turn(
3634
3650
  renderer.handle_event({"event_type": "ai_task_failed", "payload": {"error": message}})
3635
3651
  return TaskOutcome(status="failed", error=message)
3636
3652
 
3637
- if finish_reason in {"degenerate_repetition", "corrupted_output"}:
3653
+ if finish_reason in {"degenerate_repetition", "conversation_echo", "corrupted_output"}:
3638
3654
  failed_quality_provider = resolved_provider
3639
3655
  quality_failed_providers.add(failed_quality_provider)
3640
3656
  checkpoint_partial_parts.clear()
@@ -3677,6 +3693,8 @@ async def run_local_agent_turn(
3677
3693
  reason_text = (
3678
3694
  "corrupted token output"
3679
3695
  if finish_reason == "corrupted_output"
3696
+ else "a repeated conversation transcript"
3697
+ if finish_reason == "conversation_echo"
3680
3698
  else "a degenerate repetition loop"
3681
3699
  )
3682
3700
  error = (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tamfis-code
3
- Version: 0.6.4
3
+ Version: 0.6.5
4
4
  Summary: TamfisGPT Code -- portable subscription-backed terminal coding agent with local tools, PTY, plans, queues, and approvals
5
5
  Project-URL: Homepage, https://github.com/tamfitronics/tamfis-code
6
6
  Project-URL: Repository, https://github.com/tamfitronics/tamfis-code
@@ -767,6 +767,29 @@ class RunLocalAgentTurnTests(_StatePatchMixin, unittest.TestCase):
767
767
  )
768
768
  self.assertNotIn(looping_phrase, visible)
769
769
 
770
+ def test_repeated_conversation_transcript_is_stopped_early(self):
771
+ with tempfile.TemporaryDirectory() as ws:
772
+ rounds = [[
773
+ _chunk(_delta(content=(
774
+ 'Then the user said "audit the site". Then the assistant responded '
775
+ "with a long analysis. " if index % 2 else
776
+ 'Then the user said "continue until fixed". Then the assistant responded '
777
+ "with another long analysis. "
778
+ ))) for index in range(20)
779
+ ]]
780
+ client = _FakeClient(rounds)
781
+ manager = _FakeManager(client)
782
+ renderer = _RecordingRenderer()
783
+ outcome = asyncio.run(run_local_agent_turn(
784
+ manager, ProviderType.NVIDIA, None,
785
+ [{"role": "user", "content": "summarize the site"}],
786
+ self._console(), renderer,
787
+ workspace_root=ws, session_id=1, approval_policy="auto", interactive=False,
788
+ ))
789
+ self.assertEqual(outcome.status, "failed")
790
+ self.assertIn("repeated conversation transcript", outcome.error)
791
+ self.assertEqual(len(client.calls), 1)
792
+
770
793
  def test_change_request_completed_with_no_mutation_gets_a_caveat(self):
771
794
  """Confirmed live: a weak model can narrate "I'll fix this" -- complete
772
795
  with a fabricated "corrected" code block -- without ever calling
File without changes
File without changes
File without changes