fruxon 2.2.0__tar.gz → 2.2.1__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 (216) hide show
  1. {fruxon-2.2.0 → fruxon-2.2.1}/HISTORY.md +19 -0
  2. {fruxon-2.2.0 → fruxon-2.2.1}/PKG-INFO +1 -1
  3. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/_version.py +2 -2
  4. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_memory.py +30 -7
  5. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/examples.py +8 -2
  6. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/fruxon.py +42 -10
  7. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_client.py +38 -3
  8. {fruxon-2.2.0 → fruxon-2.2.1}/.gitignore +0 -0
  9. {fruxon-2.2.0 → fruxon-2.2.1}/LICENSE +0 -0
  10. {fruxon-2.2.0 → fruxon-2.2.1}/README.md +0 -0
  11. {fruxon-2.2.0 → fruxon-2.2.1}/pyproject.toml +0 -0
  12. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/__init__.py +0 -0
  13. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/__main__.py +0 -0
  14. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/_ssl.py +0 -0
  15. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/checks/__init__.py +0 -0
  16. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/checks/agent.py +0 -0
  17. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/checks/ledger.py +0 -0
  18. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/checks/references.py +0 -0
  19. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/__init__.py +0 -0
  20. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/_crash.py +0 -0
  21. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/_schema.py +0 -0
  22. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/_shared.py +0 -0
  23. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/_stream.py +0 -0
  24. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents.py +0 -0
  25. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_approvals.py +0 -0
  26. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_budget.py +0 -0
  27. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_channels.py +0 -0
  28. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_draft.py +0 -0
  29. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_evaluations.py +0 -0
  30. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_executions.py +0 -0
  31. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_improvements.py +0 -0
  32. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_lifecycle.py +0 -0
  33. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_reply_style.py +0 -0
  34. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_revisions.py +0 -0
  35. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_sandbox.py +0 -0
  36. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_sandbox_test.py +0 -0
  37. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_slots.py +0 -0
  38. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_system_blocks.py +0 -0
  39. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_tests.py +0 -0
  40. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_topics.py +0 -0
  41. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/agents_voice_calls.py +0 -0
  42. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/applications.py +0 -0
  43. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/applications_entry_points.py +0 -0
  44. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/assets.py +0 -0
  45. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/auth.py +0 -0
  46. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/capabilities.py +0 -0
  47. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/completion.py +0 -0
  48. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/config.py +0 -0
  49. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/consult_pins.py +0 -0
  50. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/conversation_imports.py +0 -0
  51. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/dash.py +0 -0
  52. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/describe.py +0 -0
  53. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/doctor.py +0 -0
  54. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/environments.py +0 -0
  55. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/escalations.py +0 -0
  56. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/guides.py +0 -0
  57. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/integrations.py +0 -0
  58. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/keys.py +0 -0
  59. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/knowledge_bases.py +0 -0
  60. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/knowledge_documents.py +0 -0
  61. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/knowledge_notices.py +0 -0
  62. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/knowledge_sources.py +0 -0
  63. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/llm_providers.py +0 -0
  64. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/messages.py +0 -0
  65. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/metrics.py +0 -0
  66. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/participants.py +0 -0
  67. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/pipelines.py +0 -0
  68. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/secrets.py +0 -0
  69. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/skills.py +0 -0
  70. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/storage.py +0 -0
  71. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/tools.py +0 -0
  72. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/triggers.py +0 -0
  73. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/triggers_budget.py +0 -0
  74. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/triggers_check.py +0 -0
  75. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/triggers_ledger.py +0 -0
  76. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/triggers_ledger_stage_tests.py +0 -0
  77. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/triggers_questions.py +0 -0
  78. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/triggers_shape.py +0 -0
  79. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/cli/workspaces.py +0 -0
  80. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/credentials.py +0 -0
  81. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/device_auth.py +0 -0
  82. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/doctor.py +0 -0
  83. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/exceptions.py +0 -0
  84. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/flow_validation.py +0 -0
  85. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/models.py +0 -0
  86. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/output.py +0 -0
  87. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/params.py +0 -0
  88. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/sandbox_scenario.py +0 -0
  89. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/skills/__init__.py +0 -0
  90. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/skills/fruxon-agent-mode/SKILL.md +0 -0
  91. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/skills/fruxon-build-agent/SKILL.md +0 -0
  92. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/skills/fruxon-create-integration/SKILL.md +0 -0
  93. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/skills/fruxon-debug-trace/SKILL.md +0 -0
  94. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/skills/fruxon-meet/SKILL.md +0 -0
  95. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/skills/fruxon-use-integrations/SKILL.md +0 -0
  96. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/telemetry.py +0 -0
  97. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/__init__.py +0 -0
  98. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/app.py +0 -0
  99. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/demo.py +0 -0
  100. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/links.py +0 -0
  101. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/__init__.py +0 -0
  102. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/agent.py +0 -0
  103. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/base.py +0 -0
  104. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/home.py +0 -0
  105. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/ledger.py +0 -0
  106. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/loader.py +0 -0
  107. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/pickers.py +0 -0
  108. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/screens/trace.py +0 -0
  109. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/source.py +0 -0
  110. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/theme.py +0 -0
  111. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/views.py +0 -0
  112. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/tui/widgets.py +0 -0
  113. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/ui.py +0 -0
  114. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/update_check.py +0 -0
  115. {fruxon-2.2.0 → fruxon-2.2.1}/src/fruxon/validation.py +0 -0
  116. {fruxon-2.2.0 → fruxon-2.2.1}/tests/.test_durations.json +0 -0
  117. {fruxon-2.2.0 → fruxon-2.2.1}/tests/__init__.py +0 -0
  118. {fruxon-2.2.0 → fruxon-2.2.1}/tests/conftest.py +0 -0
  119. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_actor.py +0 -0
  120. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_agent_lifecycle.py +0 -0
  121. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_agent_revisions_list.py +0 -0
  122. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_agent_slots.py +0 -0
  123. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_agents_check_cli.py +0 -0
  124. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_agents_revisions_cli.py +0 -0
  125. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_agents_sandbox.py +0 -0
  126. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_applications.py +0 -0
  127. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_approvals.py +0 -0
  128. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_assets.py +0 -0
  129. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_budgets.py +0 -0
  130. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_capabilities.py +0 -0
  131. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_channels.py +0 -0
  132. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_checks_agent.py +0 -0
  133. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_checks_ledger.py +0 -0
  134. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_cli.py +0 -0
  135. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_cli_base_url_routing.py +0 -0
  136. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_cli_crash.py +0 -0
  137. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_cli_root_flags.py +0 -0
  138. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_connect_nudge.py +0 -0
  139. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_consult.py +0 -0
  140. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_conversation_imports.py +0 -0
  141. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_credentials.py +0 -0
  142. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_dash_app.py +0 -0
  143. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_dash_cli.py +0 -0
  144. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_dash_client.py +0 -0
  145. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_dash_links.py +0 -0
  146. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_dash_source.py +0 -0
  147. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_describe.py +0 -0
  148. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_device_auth.py +0 -0
  149. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_docs_commands_exist.py +0 -0
  150. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_doctor.py +0 -0
  151. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_draft_bootstrap.py +0 -0
  152. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_draft_evaluate_cli.py +0 -0
  153. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_draft_pull_shape.py +0 -0
  154. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_draft_run_replay.py +0 -0
  155. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_draft_validate_cli.py +0 -0
  156. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_drafts.py +0 -0
  157. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_entry_points.py +0 -0
  158. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_environments.py +0 -0
  159. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_escalations.py +0 -0
  160. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_evaluations.py +0 -0
  161. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_execution_records.py +0 -0
  162. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_flow_validation.py +0 -0
  163. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_fruxon.py +0 -0
  164. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_guides.py +0 -0
  165. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_improvements.py +0 -0
  166. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_integration_configs_write_cli.py +0 -0
  167. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_integration_triggers_cli.py +0 -0
  168. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_integrations_authorize_cli.py +0 -0
  169. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_integrations_connect_cli.py +0 -0
  170. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_kb_trial_cli.py +0 -0
  171. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_knowledge_bases.py +0 -0
  172. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_knowledge_documents.py +0 -0
  173. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_knowledge_notices.py +0 -0
  174. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_knowledge_sources.py +0 -0
  175. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_llm_provider_configs_cli.py +0 -0
  176. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_llm_providers_connect_cli.py +0 -0
  177. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_managed_by.py +0 -0
  178. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_memory.py +0 -0
  179. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_messages.py +0 -0
  180. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_metrics.py +0 -0
  181. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_online_llm_config_refs.py +0 -0
  182. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_online_prefetch_refs.py +0 -0
  183. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_online_secret_refs.py +0 -0
  184. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_output.py +0 -0
  185. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_params.py +0 -0
  186. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_participants.py +0 -0
  187. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_participants_write.py +0 -0
  188. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_pipelines.py +0 -0
  189. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_reply_style.py +0 -0
  190. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_sandbox_scenario.py +0 -0
  191. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_schema.py +0 -0
  192. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_schema_fetch.py +0 -0
  193. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_secrets.py +0 -0
  194. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_skills.py +0 -0
  195. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_ssl.py +0 -0
  196. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_storage.py +0 -0
  197. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_system_blocks.py +0 -0
  198. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_system_blocks_cli.py +0 -0
  199. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_telemetry.py +0 -0
  200. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_test_chats.py +0 -0
  201. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_topics.py +0 -0
  202. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_trigger_budgets.py +0 -0
  203. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers.py +0 -0
  204. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers_check_cli.py +0 -0
  205. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers_ledger.py +0 -0
  206. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers_ledger_batch_views.py +0 -0
  207. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers_ledger_stage_tests.py +0 -0
  208. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers_questions.py +0 -0
  209. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers_shape.py +0 -0
  210. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_triggers_write.py +0 -0
  211. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_tui_boundary.py +0 -0
  212. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_ui.py +0 -0
  213. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_update_check.py +0 -0
  214. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_validation.py +0 -0
  215. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_voice_calls.py +0 -0
  216. {fruxon-2.2.0 → fruxon-2.2.1}/tests/test_workspaces_cli.py +0 -0
@@ -1,5 +1,24 @@
1
1
  # History
2
2
 
3
+ ## Unreleased — `chat_user` is deprecated: the server ignores it
4
+
5
+ - `execute`, `stream` and `stream_text` no longer send `chat_user` (as
6
+ `chatUser`). The execution endpoints have no field for it, so the server
7
+ dropped it unread: it did not identify the end user to the agent, gave no
8
+ per-user memory and filled no `{{sender.*}}` values. The argument is still
9
+ accepted, so existing calls keep working, but passing it emits a
10
+ `DeprecationWarning`. To give the agent details about the user, pass them in
11
+ `parameters`.
12
+
13
+ ## Unreleased — `agents memory` names a person by participant id or address
14
+
15
+ - `fruxon agents memory forget-subject` and `list --subject` document the
16
+ subject the server takes: the person's participant id, or one of their
17
+ addresses as `provider:identifier` (e.g. `telegram:123456789`). The old
18
+ example, `user_42`, matched nothing. With fruxon-backend's fix either form
19
+ reaches every memory about the person — those filed under the participant
20
+ id since memory follows the person, and older ones filed under an address.
21
+
3
22
  ## Unreleased — whoami and the 403 hint read the role cap off the key
4
23
 
5
24
  - On a server with fruxon-backend #1571, `fruxon whoami` and the 403
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: fruxon
3
- Version: 2.2.0
3
+ Version: 2.2.1
4
4
  Summary: The Fruxon SDK is a lightweight Python client for integrating with the Fruxon platform.
5
5
  Project-URL: bugs, https://github.com/fruxon-ai/fruxon-sdk/issues
6
6
  Project-URL: changelog, https://github.com/fruxon-ai/fruxon-sdk/blob/main/HISTORY.md
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.2.0'
22
- __version_tuple__ = version_tuple = (2, 2, 0)
21
+ __version__ = version = '2.2.1'
22
+ __version_tuple__ = version_tuple = (2, 2, 1)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -51,7 +51,13 @@ def memory_list(
51
51
  agent: Annotated[str, typer.Argument(help="Agent whose memories to list.")],
52
52
  subject: Annotated[
53
53
  str | None,
54
- typer.Option("--subject", help="Only memories about this subject (person / end-user key)."),
54
+ typer.Option(
55
+ "--subject",
56
+ help=(
57
+ "Only memories about this person: their participant id, or a channel address as "
58
+ "provider:identifier (e.g. telegram:123456789)."
59
+ ),
60
+ ),
55
61
  ] = None,
56
62
  query: Annotated[str | None, typer.Option("--query", "-q", help="Full-text filter over title + content.")] = None,
57
63
  scope: Annotated[
@@ -75,10 +81,13 @@ def memory_list(
75
81
  """List what an agent remembers — narrow with --subject / --query / --scope.
76
82
 
77
83
  The filters run server-side, so "what does my agent remember about
78
- user_42" is `--subject user_42`, not a client-side scan.
84
+ the Telegram user 123456789" is `--subject telegram:123456789`, not a
85
+ client-side scan. A subject is the person's participant id or one of
86
+ their addresses as provider:identifier; either matches every memory
87
+ about them.
79
88
 
80
89
  Examples:
81
- fruxon agents memory list my-agent --subject user_42
90
+ fruxon agents memory list my-agent --subject telegram:123456789
82
91
  fruxon agents memory list my-agent --query "dark mode"
83
92
  fruxon agents memory list my-agent --scope AGENT --output id
84
93
  """
@@ -228,7 +237,15 @@ def memory_get(
228
237
  @memory_app.command("forget-subject")
229
238
  def memory_forget_subject(
230
239
  agent: Annotated[str, typer.Argument(help="Agent whose memories to prune.")],
231
- subject: Annotated[str, typer.Argument(help="The subject (person / end-user key) to forget entirely.")],
240
+ subject: Annotated[
241
+ str,
242
+ typer.Argument(
243
+ help=(
244
+ "The person to forget entirely: their participant id, or a channel address as "
245
+ "provider:identifier (e.g. telegram:123456789)."
246
+ )
247
+ ),
248
+ ],
232
249
  yes: Annotated[
233
250
  bool,
234
251
  typer.Option("--yes", "-y", help="Skip the confirmation prompt. REQUIRED under agent mode (CLAUDECODE / CI)."),
@@ -242,11 +259,17 @@ def memory_forget_subject(
242
259
  ):
243
260
  """Forget every memory an agent holds about one subject (GDPR-style).
244
261
 
245
- Irreversible — it deletes all of the subject's memories. Confirms
246
- first, and under agent mode refuses without [bold]--yes[/bold].
262
+ Irreversible — it deletes all of the person's memories, whether they
263
+ are filed under the participant id or under any of the person's
264
+ addresses, and records each deletion in the agent's deletion trail.
265
+ Confirms first, and under agent mode refuses without [bold]--yes[/bold].
266
+
267
+ Name the person by participant id (the `subject` column of
268
+ `agents memory subjects`) or by an address as provider:identifier.
247
269
 
248
270
  Examples:
249
- fruxon agents memory forget-subject my-agent user_42 --yes
271
+ fruxon agents memory forget-subject my-agent telegram:123456789 --yes
272
+ fruxon agents memory forget-subject my-agent 0199f3c2-5b1e-7c4a-9d2e-3f6a8b1c0d4e --yes
250
273
  """
251
274
  output = resolve_output_format(output, human_default="text", agent_default="json")
252
275
  if output not in {"text", "json"}:
@@ -384,10 +384,16 @@ _EXAMPLES: dict[str, list[tuple[str, str]]] = {
384
384
  ),
385
385
  ],
386
386
  "memory": [
387
- ("fruxon agents memory list my-agent --subject user_42", "What the agent remembers about one person"),
387
+ (
388
+ "fruxon agents memory list my-agent --subject telegram:123456789",
389
+ "What the agent remembers about one person (participant id or provider:identifier)",
390
+ ),
388
391
  ("fruxon agents memory list my-agent --query 'dark mode'", "Full-text over its memories"),
389
392
  ("fruxon agents memory subjects my-agent", "Which subjects it has memories about (+ counts)"),
390
- ("fruxon agents memory forget-subject my-agent user_42 --yes", "GDPR-forget everything about a subject"),
393
+ (
394
+ "fruxon agents memory forget-subject my-agent telegram:123456789 --yes",
395
+ "GDPR-forget everything about a person",
396
+ ),
391
397
  ],
392
398
  "metrics": [
393
399
  ("fruxon metrics list", "Browse evaluation metrics (ids for quality checks)"),
@@ -15,6 +15,7 @@ import urllib.error
15
15
  import urllib.parse
16
16
  import urllib.request
17
17
  import uuid
18
+ import warnings
18
19
  from collections.abc import Callable, Iterator
19
20
  from datetime import datetime, timezone
20
21
  from typing import Any, NoReturn
@@ -275,6 +276,21 @@ _STATUS_EXCEPTIONS: dict[int, type[FruxonAPIError]] = {
275
276
  }
276
277
 
277
278
 
279
+ # ``chat_user`` on execute / stream / stream_text. The execution body
280
+ # (``AgentExecutionRequestView``) has no field for it — end-user identity is
281
+ # deliberately not settable there — so the server dropped it unread.
282
+ _CHAT_USER_IGNORED = (
283
+ "chat_user is deprecated and has no effect: the agent execution endpoints have no field for it, "
284
+ "so it does not identify the end user to the agent (no per-user memory, no {{sender.*}} values) "
285
+ "and is no longer sent. To give the agent details about the user, pass them in `parameters`."
286
+ )
287
+
288
+
289
+ def _warn_chat_user_ignored() -> None:
290
+ # stacklevel=3: past this helper and the client method, to the caller.
291
+ warnings.warn(_CHAT_USER_IGNORED, DeprecationWarning, stacklevel=3)
292
+
293
+
278
294
  def _detect_actor() -> str | None:
279
295
  """Identify the tool making the request, for the ``X-Fruxon-Actor`` header.
280
296
 
@@ -376,17 +392,22 @@ class FruxonClient:
376
392
  agent: The agent identifier.
377
393
  parameters: Execution parameters and inputs.
378
394
  attachments: File attachments.
379
- chat_user: Chat user information.
395
+ chat_user: Deprecated, and ignored: it is not sent, and passing it
396
+ emits a :class:`DeprecationWarning`. The execution endpoints
397
+ have no end-user field, so it does not identify the user to
398
+ the agent. Pass what the agent should know about the user in
399
+ ``parameters``.
380
400
  session_id: Session identifier for multi-turn conversations.
381
401
  environment_slug: End-customer environment to attribute this run
382
402
  to (per-environment cost tracking, quota enforcement, and
383
403
  analytics). Sent as ``environmentSlug`` in the request body.
384
404
  """
405
+ if chat_user is not None:
406
+ _warn_chat_user_ignored()
385
407
  url = self._agent_url(agent, ":execute")
386
408
  body = self._build_execution_body(
387
409
  parameters=parameters,
388
410
  attachments=attachments,
389
- chat_user=chat_user,
390
411
  session_id=session_id,
391
412
  environment_slug=environment_slug,
392
413
  )
@@ -411,12 +432,16 @@ class FruxonClient:
411
432
  For the common case of "stream and print the model's text chunks,"
412
433
  prefer :meth:`stream_text`, which yields just the concatenable text
413
434
  pieces.
435
+
436
+ Arguments are those of :meth:`execute`; ``chat_user`` is deprecated
437
+ and ignored there too.
414
438
  """
439
+ if chat_user is not None:
440
+ _warn_chat_user_ignored()
415
441
  url = self._agent_url(agent, ":stream")
416
442
  body = self._build_execution_body(
417
443
  parameters=parameters,
418
444
  attachments=attachments,
419
- chat_user=chat_user,
420
445
  session_id=session_id,
421
446
  environment_slug=environment_slug,
422
447
  )
@@ -438,12 +463,17 @@ class FruxonClient:
438
463
  ``chunk`` payload as a string. Use this when you want to mirror the
439
464
  chat-style streaming UX without dealing with tool calls, step traces,
440
465
  or terminal events.
466
+
467
+ Arguments are those of :meth:`execute`; ``chat_user`` is deprecated
468
+ and ignored there too. Being a generator, it warns on the first
469
+ iteration rather than at the call.
441
470
  """
471
+ if chat_user is not None:
472
+ _warn_chat_user_ignored()
442
473
  for event in self.stream(
443
474
  agent,
444
475
  parameters=parameters,
445
476
  attachments=attachments,
446
- chat_user=chat_user,
447
477
  session_id=session_id,
448
478
  environment_slug=environment_slug,
449
479
  ):
@@ -1406,7 +1436,10 @@ class FruxonClient:
1406
1436
  ``...ListPage`` envelope). The filters answer the question an
1407
1437
  author actually has:
1408
1438
 
1409
- * ``subject`` — only memories about one person/end-user;
1439
+ * ``subject`` — only memories about one person/end-user, named by
1440
+ participant id or by a channel address as ``provider:identifier``
1441
+ (e.g. ``telegram:123456789``); either matches every memory about
1442
+ them;
1410
1443
  * ``query`` — full-text over title/content;
1411
1444
  * ``scope`` — ``AGENT`` (cross-everyone facts) or ``SUBJECT``
1412
1445
  (per-person facts).
@@ -1450,8 +1483,10 @@ class FruxonClient:
1450
1483
  """Forget every memory an agent holds about one subject (GDPR-style).
1451
1484
 
1452
1485
  Hits ``POST .../memories:forgetSubject`` with ``{"subject": …}`` →
1453
- ``{"deletedCount": N}``. Irreversible — the CLI gates it behind a
1454
- confirmation.
1486
+ ``{"deletedCount": N}``. ``subject`` is the person's participant id or
1487
+ a channel address as ``provider:identifier``; either forgets the
1488
+ memories filed under the participant id and under each of their
1489
+ addresses. Irreversible — the CLI gates it behind a confirmation.
1455
1490
  """
1456
1491
  return self._post_json(self._memories_url(agent, ":forgetSubject"), {"subject": subject})
1457
1492
 
@@ -8031,7 +8066,6 @@ class FruxonClient:
8031
8066
  *,
8032
8067
  parameters: dict[str, object] | None,
8033
8068
  attachments: list[dict[str, object]] | None,
8034
- chat_user: dict[str, object] | None,
8035
8069
  session_id: str | None,
8036
8070
  environment_slug: str | None = None,
8037
8071
  ) -> dict[str, object]:
@@ -8040,8 +8074,6 @@ class FruxonClient:
8040
8074
  body["parameters"] = parameters
8041
8075
  if attachments is not None:
8042
8076
  body["attachments"] = attachments
8043
- if chat_user is not None:
8044
- body["chatUser"] = chat_user
8045
8077
  if session_id is not None:
8046
8078
  body["sessionId"] = session_id
8047
8079
  if environment_slug is not None:
@@ -5,6 +5,7 @@ import json
5
5
  import urllib.error
6
6
  import urllib.parse
7
7
  import urllib.request
8
+ import warnings
8
9
 
9
10
  import pytest
10
11
 
@@ -139,7 +140,9 @@ class TestFruxonClientExecute:
139
140
  client.execute("my-agent")
140
141
  assert captured["body"] == {}
141
142
 
142
- def test_maps_chat_user(self, client, monkeypatch):
143
+ def test_chat_user_is_deprecated_and_not_sent(self, client, monkeypatch):
144
+ # The execution body has no end-user field: the server dropped
145
+ # ``chatUser`` unread while the caller believed the user was identified.
143
146
  captured = {}
144
147
 
145
148
  def mock_urlopen(req, timeout=None, context=None):
@@ -148,8 +151,22 @@ class TestFruxonClientExecute:
148
151
 
149
152
  monkeypatch.setattr(urllib.request, "urlopen", mock_urlopen)
150
153
 
151
- client.execute("my-agent", chat_user={"id": "user-1", "name": "Alice"})
152
- assert captured["body"]["chatUser"] == {"id": "user-1", "name": "Alice"}
154
+ with pytest.warns(DeprecationWarning, match="does not identify the end user") as record:
155
+ client.execute("my-agent", parameters={"q": "hi"}, chat_user={"id": "user-1", "name": "Alice"})
156
+
157
+ assert captured["body"] == {"parameters": {"q": "hi"}}
158
+ assert len(record) == 1
159
+ # Attributed to the caller's line, not to the SDK.
160
+ assert record[0].filename == __file__
161
+
162
+ def test_no_warning_without_chat_user(self, client, monkeypatch):
163
+ monkeypatch.setattr(
164
+ urllib.request, "urlopen", lambda req, timeout=None, context=None: _MockResponse(SAMPLE_RESPONSE)
165
+ )
166
+
167
+ with warnings.catch_warnings():
168
+ warnings.simplefilter("error")
169
+ client.execute("my-agent", parameters={"q": "hi"})
153
170
 
154
171
  def test_maps_environment_slug(self, client, monkeypatch):
155
172
  captured = {}
@@ -485,6 +502,24 @@ class TestFruxonClientStream:
485
502
  chunks = list(client.stream_text("my-agent"))
486
503
  assert chunks == ["Hello ", "world"]
487
504
 
505
+ @pytest.mark.parametrize("method", ["stream", "stream_text"])
506
+ def test_chat_user_is_deprecated_and_not_sent(self, client, monkeypatch, method):
507
+ captured = {}
508
+
509
+ def mock_urlopen(req, timeout=None, context=None):
510
+ captured["body"] = json.loads(req.data.decode("utf-8"))
511
+ return self._mock_stream(self._sse_body(("text", '{"chunk": "x"}'), ("done", "{}")))
512
+
513
+ monkeypatch.setattr(urllib.request, "urlopen", mock_urlopen)
514
+
515
+ with pytest.warns(DeprecationWarning, match="does not identify the end user") as record:
516
+ list(getattr(client, method)("my-agent", parameters={"q": "hi"}, chat_user={"id": "user-1"}))
517
+
518
+ assert captured["body"] == {"parameters": {"q": "hi"}}
519
+ # stream_text rides on stream, but warns once, and from the caller's line.
520
+ assert len(record) == 1
521
+ assert record[0].filename == __file__
522
+
488
523
  def test_ignores_sse_comments_and_heartbeats(self, client, monkeypatch):
489
524
  # `:` lines are SSE comments — used as keep-alives by some servers.
490
525
  # Bare blank lines without a preceding event should also not yield.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes