fruxon 2.0.0__tar.gz → 2.0.2__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.
- {fruxon-2.0.0 → fruxon-2.0.2}/HISTORY.md +158 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/PKG-INFO +16 -12
- {fruxon-2.0.0 → fruxon-2.0.2}/README.md +15 -11
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/_version.py +2 -2
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/checks/__init__.py +8 -1
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/checks/agent.py +101 -88
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/checks/ledger.py +51 -7
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/__init__.py +10 -1
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/_stream.py +11 -5
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents.py +5 -5
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_approvals.py +26 -8
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_draft.py +18 -19
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_executions.py +17 -10
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_revisions.py +6 -6
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/assets.py +6 -6
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/auth.py +134 -29
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/examples.py +14 -2
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/integrations.py +299 -2
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/llm_providers.py +365 -9
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/messages.py +46 -7
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/metrics.py +4 -4
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/participants.py +4 -4
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/secrets.py +5 -5
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/storage.py +3 -3
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/tools.py +1 -1
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/triggers.py +1 -1
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/triggers_ledger.py +42 -3
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/triggers_shape.py +15 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/credentials.py +4 -2
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/device_auth.py +10 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/flow_validation.py +11 -1
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/fruxon.py +196 -11
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/models.py +22 -8
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/skills/fruxon-agent-mode/SKILL.md +9 -5
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/skills/fruxon-build-agent/SKILL.md +42 -25
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/skills/fruxon-create-integration/SKILL.md +22 -11
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/skills/fruxon-debug-trace/SKILL.md +5 -5
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/skills/fruxon-meet/SKILL.md +6 -3
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/app.py +24 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/demo.py +56 -35
- fruxon-2.0.2/src/fruxon/tui/links.py +163 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/screens/agent.py +26 -21
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/screens/base.py +52 -1
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/screens/home.py +38 -7
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/screens/ledger.py +25 -12
- fruxon-2.0.2/src/fruxon/tui/screens/loader.py +257 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/screens/pickers.py +2 -1
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/screens/trace.py +5 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/source.py +39 -22
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/views.py +7 -5
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/widgets.py +30 -54
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_approvals.py +37 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_checks_agent.py +15 -14
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_cli.py +261 -27
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_dash_app.py +196 -1
- fruxon-2.0.2/tests/test_dash_links.py +218 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_dash_source.py +26 -13
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_device_auth.py +35 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_flow_validation.py +8 -0
- fruxon-2.0.2/tests/test_integrations_connect_cli.py +338 -0
- fruxon-2.0.2/tests/test_llm_providers_connect_cli.py +314 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_messages.py +20 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers_ledger.py +41 -2
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers_shape.py +114 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/.gitignore +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/LICENSE +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/pyproject.toml +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/__init__.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/__main__.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/_ssl.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/checks/references.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/_crash.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/_schema.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/_shared.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_budget.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_channels.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_evaluations.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_improvements.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_lifecycle.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_memory.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_reply_style.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_sandbox.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_sandbox_test.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_slots.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_system_blocks.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_tests.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/agents_topics.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/applications.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/applications_entry_points.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/capabilities.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/completion.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/config.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/consult_pins.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/conversation_imports.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/dash.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/describe.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/doctor.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/environments.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/escalations.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/guides.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/keys.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/knowledge_bases.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/knowledge_documents.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/knowledge_notices.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/knowledge_sources.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/pipelines.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/skills.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/triggers_budget.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/triggers_check.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/triggers_ledger_stage_tests.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/triggers_questions.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/cli/workspaces.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/doctor.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/exceptions.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/output.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/params.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/sandbox_scenario.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/skills/__init__.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/skills/fruxon-use-integrations/SKILL.md +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/telemetry.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/__init__.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/screens/__init__.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/tui/theme.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/ui.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/update_check.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/src/fruxon/validation.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/.test_durations.json +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/__init__.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/conftest.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_actor.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_agent_lifecycle.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_agent_revisions_list.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_agent_slots.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_agents_check_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_agents_revisions_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_agents_sandbox.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_applications.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_assets.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_budgets.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_capabilities.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_channels.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_checks_ledger.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_cli_base_url_routing.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_cli_crash.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_cli_root_flags.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_client.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_connect_nudge.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_consult.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_conversation_imports.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_credentials.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_dash_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_dash_client.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_describe.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_docs_commands_exist.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_doctor.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_draft_bootstrap.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_draft_evaluate_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_draft_pull_shape.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_draft_run_replay.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_draft_validate_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_drafts.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_entry_points.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_environments.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_escalations.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_evaluations.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_execution_records.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_fruxon.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_guides.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_improvements.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_integration_configs_write_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_integration_triggers_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_integrations_authorize_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_kb_trial_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_knowledge_bases.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_knowledge_documents.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_knowledge_notices.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_knowledge_sources.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_llm_provider_configs_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_managed_by.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_memory.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_metrics.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_online_llm_config_refs.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_online_prefetch_refs.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_online_secret_refs.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_output.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_params.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_participants.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_participants_write.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_pipelines.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_reply_style.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_sandbox_scenario.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_schema.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_schema_fetch.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_secrets.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_skills.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_ssl.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_storage.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_system_blocks.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_system_blocks_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_telemetry.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_test_chats.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_topics.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_trigger_budgets.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers_check_cli.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers_ledger_batch_views.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers_ledger_stage_tests.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers_questions.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_triggers_write.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_tui_boundary.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_ui.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_update_check.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_validation.py +0 -0
- {fruxon-2.0.0 → fruxon-2.0.2}/tests/test_workspaces_cli.py +0 -0
|
@@ -1,5 +1,155 @@
|
|
|
1
1
|
# History
|
|
2
2
|
|
|
3
|
+
## Unreleased — `fruxon messages list --reason EMAIL_THREAD_UNAVAILABLE`
|
|
4
|
+
|
|
5
|
+
- `--reason` takes the server's new `EMAIL_THREAD_UNAVAILABLE` (fruxon-backend
|
|
6
|
+
#1494): an email thread's pinned conversation could not take the message (its
|
|
7
|
+
topic is missing, abandoned or mismatched, or its session belongs to another
|
|
8
|
+
thread), so it was withheld, the Gmail thread labelled `Fruxon/Needs human`,
|
|
9
|
+
and it is never replayed. It was refused as a typo before reaching the server.
|
|
10
|
+
A server without it answers 400 for it.
|
|
11
|
+
|
|
12
|
+
## Unreleased — a link to fill in an LLM provider's API key
|
|
13
|
+
|
|
14
|
+
- **`fruxon llm-providers connect <provider>`** creates a config for an LLM
|
|
15
|
+
provider and prints a credential link. A human opens it, signs in to Fruxon
|
|
16
|
+
and types the API key (Bedrock's access key pair, Vertex's service account
|
|
17
|
+
key); the page tests it with the provider and publishes the config, which an
|
|
18
|
+
agent pins as `provider.tenantConfigId`. So an agent building an agent through
|
|
19
|
+
the CLI hands the user a link instead of asking for the key, and never sees
|
|
20
|
+
it. `--config <id>` fills an existing config instead; `--name` and
|
|
21
|
+
`--param name=value` (a non-secret setting such as `region`; required ones
|
|
22
|
+
are checked, and a secret is refused, before anything is created) shape the
|
|
23
|
+
new one. A key the provider turns down saves nothing and five lock the link;
|
|
24
|
+
one it could not check is saved with a warning. The link opens only for a
|
|
25
|
+
workspace member whose role may set up model providers (`llm_providers:write`,
|
|
26
|
+
which the Developer preset carries); `--no-sign-in` mints one whoever holds it
|
|
27
|
+
can fill (Admin or Owner). `--for`, `--note` and `--expires-in-hours` go on
|
|
28
|
+
the link. A config the command created is deleted again when no link could be
|
|
29
|
+
minted for it. A provider sharing another's credential is pointed at its
|
|
30
|
+
owner.
|
|
31
|
+
- **`fruxon llm-providers link-status <provider> <config> <request>`** says
|
|
32
|
+
where that link stands — `OPEN`, `FILLED`, `REFUSED`, `EXPIRED`, `LOCKED` or
|
|
33
|
+
`WITHDRAWN` — and `--wait` waits until it is filled or stops working. Exits 0
|
|
34
|
+
for open or filled, 13 once it stopped working, 14 when `--wait` runs out.
|
|
35
|
+
- Client methods `create_llm_provider_config`, `delete_llm_provider_config`,
|
|
36
|
+
`create_llm_credential_link` and `get_llm_credential_link`.
|
|
37
|
+
|
|
38
|
+
## Unreleased — a link to fill in an integration's credentials
|
|
39
|
+
|
|
40
|
+
- **`fruxon integrations connect <integration>`** creates a config for an
|
|
41
|
+
integration that takes an API key, a bearer token or a username and password,
|
|
42
|
+
and prints a credential link. A human opens it, signs in to Fruxon and types
|
|
43
|
+
the credential; the page tests it against the service and publishes the
|
|
44
|
+
config. So an agent building an agent through the CLI hands the user a link
|
|
45
|
+
instead of asking for the secret, and never sees it. `--config <id>` fills an
|
|
46
|
+
existing config instead; `--name`, `--auth-method` (when the integration
|
|
47
|
+
declares several methods a link can fill) and `--param name=value` (a
|
|
48
|
+
connection setting such as a subdomain; required ones are checked before
|
|
49
|
+
anything is created) shape the new one. The link opens only for a workspace
|
|
50
|
+
member whose role may set up integrations; `--no-sign-in` mints one whoever
|
|
51
|
+
holds it can fill. `--for`, `--note` and `--expires-in-hours` (1–720, default
|
|
52
|
+
168) go on the link. A config the command created is deleted again when no
|
|
53
|
+
link could be minted for it. OAuth integrations are pointed at
|
|
54
|
+
`integrations authorize`. Needs `integrations:write`, which the default
|
|
55
|
+
login preset carries (fruxon-backend #1487); a `--no-sign-in` link also needs
|
|
56
|
+
`workspace:write` (Admin or Owner).
|
|
57
|
+
- Client methods `create_integration_config`, `delete_integration_config` and
|
|
58
|
+
`create_credential_link`.
|
|
59
|
+
|
|
60
|
+
## Unreleased — `fruxon messages list --reason` takes every withhold reason
|
|
61
|
+
|
|
62
|
+
- `--reason` accepted only `HUMAN_OWNED_CONVERSATION` and `ADMISSION_REFUSED`, so
|
|
63
|
+
`--reason OVER_BUDGET` and the other email-channel reasons were refused as typos
|
|
64
|
+
before reaching the server. It now takes every server `InboundWithholdReason`:
|
|
65
|
+
`NOT_ADDRESSED`, the email channel's `AUTO_REPLY`, `BULK_OR_LIST`, `BOUNCE`,
|
|
66
|
+
`OWN_ADDRESS`, `NOT_FOR_RECIPIENT`, `UNVERIFIED_SENDER`, `OVER_BUDGET`,
|
|
67
|
+
`THREAD_HAS_ANOTHER_SENDER`, `DELIVERY_DEFERRED_TOO_LONG`, and the new
|
|
68
|
+
`DRAFT_EDITED` (a customer wrote while a person was editing the agent's Gmail
|
|
69
|
+
draft; fruxon-backend #1488). A server without `DRAFT_EDITED` answers 400 for it.
|
|
70
|
+
|
|
71
|
+
## Unreleased — a quality check that could not run is no failed reply
|
|
72
|
+
|
|
73
|
+
- `AgentJudgeActivity.pass_rate` is `passed / (passed + failed)`, as the server
|
|
74
|
+
now computes it (fruxon-backend #1482). A check that could not run (a model
|
|
75
|
+
error or a timeout) gave no verdict: it is counted in `errors` only, where it
|
|
76
|
+
used to count against the rate. A log-only agent whose checks errored gets
|
|
77
|
+
`None`, not 0, so the `fruxon dash` Quality check tile shows its average score.
|
|
78
|
+
The docstring said "errors included"; it now says what the field holds.
|
|
79
|
+
|
|
80
|
+
## Unreleased — `o` in `fruxon dash` opens the same page in the web app
|
|
81
|
+
|
|
82
|
+
- `o` opens the web app on the exact tab or record behind what the console
|
|
83
|
+
shows: Home → the Application's Overview over the same window, an agent → its
|
|
84
|
+
page, a run → that execution (`?tab=executions&id=`), an automation → its
|
|
85
|
+
Overview, Settings or Work tab, an item → that item (`?tab=work&item=`), the
|
|
86
|
+
Items filter → `&status=`. On Configuration it opens where the selected
|
|
87
|
+
finding is put right (the agent editor, an integration's configs, an LLM
|
|
88
|
+
provider, the automation's settings or edit page, its work filtered to a
|
|
89
|
+
stage). The selected row wins; `O` opens the screen's own page.
|
|
90
|
+
- Every link carries `?workspace=<slug>`, so the browser switches to the
|
|
91
|
+
console's workspace before it opens the page.
|
|
92
|
+
- The automation link was broken (`/applications/{id}/…`); it is
|
|
93
|
+
`/app/{slug}/automations/triggers/{id}` now.
|
|
94
|
+
- The URL stays up as a notification after it opens — over SSH, that is the
|
|
95
|
+
link. `--demo` shows the URL it would open and opens nothing.
|
|
96
|
+
- `CheckResult.fix` names where a finding is put right (`editor`,
|
|
97
|
+
`integration:<id>`, `llm-provider:<id>`, `trigger-settings`,
|
|
98
|
+
`work:<status>:<stage>`, …); `to_dict()` and `-o json` are unchanged. The
|
|
99
|
+
link map is one pure function, `fruxon.tui.links.web_link`.
|
|
100
|
+
|
|
101
|
+
## Unreleased — an agent reads as one agent, not a flow
|
|
102
|
+
|
|
103
|
+
An agent runs as one definition. These surfaces still drew it as steps.
|
|
104
|
+
|
|
105
|
+
- **`fruxon dash`**: an agent's Configuration tab shows an **Agent · rev N**
|
|
106
|
+
panel: one box with the agent's model, its tools, and each tool behind a
|
|
107
|
+
human-approval gate (`⧗ issue_refund · approval by …`). A gate with no
|
|
108
|
+
approver is named in red. It was a **Flow** panel drawing boxes joined by
|
|
109
|
+
arrows. The `--demo` agents no longer appear as a five-step pipeline. The
|
|
110
|
+
`consults this agent` line under the panel is gone; the Consult roster row
|
|
111
|
+
covers consults.
|
|
112
|
+
- **`fruxon agents executions trace`**: the text tree's first line for an
|
|
113
|
+
agent run reads `1 Agent` instead of `1 FLOW_STEP · Agent`. Paths and
|
|
114
|
+
`-o json` are unchanged: the JSON is still the server's payload.
|
|
115
|
+
- **`fruxon agents draft run`**: the NDJSON stream no longer relays the
|
|
116
|
+
server's `step_trace` for the `FLOW_STEP` frame around a run. The steps
|
|
117
|
+
inside it still come through.
|
|
118
|
+
- **`fruxon agents approvals get` / `list`** no longer print a `step` for an
|
|
119
|
+
agent's gate. It was always `agent`, because the gate sits on a tool the
|
|
120
|
+
agent called. A workflow's tool step (`TOOL_FLOW_STEP`) still names its
|
|
121
|
+
step. `-o json` keeps `stepIdentifier` either way.
|
|
122
|
+
- **`fruxon agents check`** and the dash's check rows say `consult is off
|
|
123
|
+
(network.enabled)`, `consult is on (network.enabled) but the roster is
|
|
124
|
+
empty`, and `no tool needs human approval`. They used to say "no step
|
|
125
|
+
enables consult", list step names, or say "on any step".
|
|
126
|
+
- **Help text, guides and docs** talk about an agent and its definition,
|
|
127
|
+
not a flow or a step. This covers `draft validate` (its list of checks now
|
|
128
|
+
matches what it checks), `draft evaluate` (and its confirmation prompt),
|
|
129
|
+
`secrets`, `assets`, `metrics`, `participants`, `llm-providers configs`,
|
|
130
|
+
`storage`, `agents approvals`, and the Python client's docstrings. The
|
|
131
|
+
README and `docs/python-client.md` "Test a draft" examples now use the real
|
|
132
|
+
`put_draft` → `test(agent, base_revision, request)` calls; the old ones
|
|
133
|
+
posted a `flow` body to a signature that doesn't exist.
|
|
134
|
+
|
|
135
|
+
## Unreleased — a form stage's own wording, checked before saving
|
|
136
|
+
|
|
137
|
+
Follows the backend's operator-worded form messages (BE #1415) and a form
|
|
138
|
+
batch's drafted rows (BE #1335).
|
|
139
|
+
|
|
140
|
+
- **`fruxon triggers preview-shape`** shows a FORM stage's `join notice` under
|
|
141
|
+
its question: the line sent when more items join an open form, with its
|
|
142
|
+
counts filled in. A stage whose `formJoinNotice` is blank says a join sends
|
|
143
|
+
nothing. `-o json` carries it as `formJoinNotice`
|
|
144
|
+
(`WorkShapeStagePreview.form_join_notice`), null on every other stage.
|
|
145
|
+
- **`fruxon triggers set-stages --help`** documents `formClosing` (the line
|
|
146
|
+
under the header in the form message) and `formJoinNotice`, the
|
|
147
|
+
`{{item_count}}` / `{{added_count}}` they fill in, unset vs blank, and that
|
|
148
|
+
the server refuses both on a stage that is not a form.
|
|
149
|
+
- **`fruxon triggers ledger batches`** prints `N waiting, M drafted` for an open
|
|
150
|
+
FORM batch: rows saved on the page and not yet submitted, which no item
|
|
151
|
+
shows. `-o json` carries `draftCount` (`LedgerBatch.draft_count`).
|
|
152
|
+
|
|
3
153
|
## Unreleased — `fruxon triggers check`, and an automation's Configuration tab in `fruxon dash`
|
|
4
154
|
|
|
5
155
|
- **`fruxon triggers check <trigger> [-o json]`** audits a work-shape
|
|
@@ -14,6 +164,14 @@
|
|
|
14
164
|
`p` previews what a stage sends its agent (saves nothing), and lists the
|
|
15
165
|
shape.
|
|
16
166
|
|
|
167
|
+
## Unreleased — `fruxon dash` opens on the Fruxon wordmark
|
|
168
|
+
|
|
169
|
+
While Home makes its first reads, `fruxon dash` shows "FRUXON" spelled out
|
|
170
|
+
one letter at a time in outlined letters (the F in the brand's red) with a
|
|
171
|
+
spinner and what is being read. It leaves once Home has its numbers, after
|
|
172
|
+
at least 1.6 s; a failed read ends it at once, and enter, space or esc skip
|
|
173
|
+
it.
|
|
174
|
+
|
|
17
175
|
## Unreleased — `fruxon dash`, a read-only console for an Application
|
|
18
176
|
|
|
19
177
|
Everything else in the CLI prints and exits. `fruxon dash` stays open and
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: fruxon
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.2
|
|
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
|
|
@@ -82,7 +82,7 @@ Auth:
|
|
|
82
82
|
|
|
83
83
|
| Command | What it does |
|
|
84
84
|
| --- | --- |
|
|
85
|
-
| `fruxon login` | Browser-based sign-in. token goes to your OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows). `--token $KEY` for headless. `--preset observer\|operator\|developer\|maintainer\|admin` declares the access level the key is minted with (default: developer); the approval page shows it for the user to approve or deny. |
|
|
85
|
+
| `fruxon login` | Browser-based sign-in. token goes to your OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows). `--token $KEY` for headless. `--preset observer\|operator\|developer\|maintainer\|admin` declares the access level the key is minted with (default: developer); the approval page shows it for the user to approve or deny. Adds a workspace without moving the default (the first sign-in sets it); `--set-default` moves it. |
|
|
86
86
|
| `fruxon whoami` | Show the active key/workspace and where each value came from (flag, env, keychain, file). |
|
|
87
87
|
| `fruxon logout` | Forget stored credentials. `--workspace <id>` signs out of one and leaves the rest; `--all` clears every one. |
|
|
88
88
|
| `fruxon workspaces list` | Which workspaces this machine is signed in to, each with its host and cell, and which one is the default. Offline, no auth. |
|
|
@@ -98,7 +98,7 @@ Execution:
|
|
|
98
98
|
| `fruxon agents executions get <agent> <record-id>` | Record summary for one execution — status, duration, cost, tokens. |
|
|
99
99
|
| `fruxon agents executions trace <agent> <record-id>` | Step-by-step trace of one execution — LLM/tool calls, durations, and for a tool that records it, where the call's time went (service stages vs. unaccounted). Flags a result the model got offloaded or projected. Prints a quality check's verdict (score, criteria, rationale) under its `JUDGE` step, and marks a reply the check refused. `--show-io` also prints each tool step's parameters and result (the payload lives at `steps[].result`, a sibling of `toolTrace` — whose `resultDelivery` carries sizes only). `--show-system` labels each LLM step's system prompt block by block — your prompt vs. the platform's `<tag>` blocks, sizes, and the cache breakpoint. |
|
|
100
100
|
| `fruxon agents executions result <agent> <record-id>` | The final output one execution produced. |
|
|
101
|
-
| `fruxon agents approvals list/get/respond/cancel <agent>` | Operate
|
|
101
|
+
| `fruxon agents approvals list/get/respond/cancel <agent>` | Operate human-in-the-loop approval gates — see what a run is blocked on and answer it. `respond`/`cancel` confirm first and refuse without `--yes` in agent mode (an LLM must not silently auto-approve). |
|
|
102
102
|
| `fruxon agents memory list/subjects/get/forget-subject <agent>` | Inspect and prune what an agent remembers. `list` filters server-side by `--subject`/`--query`/`--scope`; `forget-subject` is a GDPR-style delete (confirms; refuses without `--yes` in agent mode). |
|
|
103
103
|
| `fruxon agents topics list/search/get/messages/sessions <agent>` + `fruxon agents inbox <agent>` | Read the conversation spine — the agent's topics (threads), one topic's transcript, its episodes, and its inbox (what it's focused on). `list`/`search` filter server-side by `--state`/`--participant`/`--query`. Read-only. Each message carries `author` — a human colleague's turn is stored as `ASSISTANT` on purpose, so `role` alone cannot tell their reply from the agent's; `HUMAN_OPERATOR` can. A message the runtime *withheld* is in no transcript at all — see `fruxon messages list`. `sessions` explains a fresh, blind session: a topic outlives its sessions, and `endCause` on the previous one (`CONSOLE_ALREADY_RESOLVED` — a human closed it in the provider's console) is why the next started with no history. |
|
|
104
104
|
| `fruxon escalations list/history/unhandled/policy/ack` | What happened when an agent handed a conversation to a person. `list` is the queue (live takeovers + degraded escalations nobody was reachable for); `unhandled` is the append-only ledger under it. **`history` is the record of closed console-routed takeovers** — those leave the queue, so `list --status ALL` answers `[]` about a conversation a human worked for half an hour. Read `humanObservedAt` before believing a `RESOLVED`: null means nobody was ever seen picking it up. `policy <agent>` resolves who the *next* escalation would reach — an empty ladder under `NATIVE_HANDOFF` is correct, the console supplies the human. |
|
|
@@ -143,13 +143,15 @@ Integrations + tools:
|
|
|
143
143
|
| `fruxon integrations list/get/create/update/verify/open` | Manage external integrations — the connections agents draw tools from. `create`/`update`/`verify` take a `--file` JSON body; `open` opens the dashboard. |
|
|
144
144
|
| `fruxon integrations configs list/get/update/publish` | The per-integration auth/config records. `update --file` patches a config's draft (only the fields sent; `{"egressCountry": ""}` clears an egress pin) and prints it with secrets masked; `publish` makes the draft the revision tool calls resolve, asks first (`--yes` in agent mode), and prints the new revision's `id` and `version`, never the credentials. |
|
|
145
145
|
| `fruxon integrations authorize <integration>` | Mint an application-level OAuth authorization URL to **connect** an integration — auto-detects its OAuth2 method (`--auth-method` to pick, `--scope`/`--config-param` to tune). OAuth needs a browser consent step, so the CLI hands you the link; a human clicks it, and the connection is saved as a tenant config a slot can pin. |
|
|
146
|
+
| `fruxon integrations connect <integration>` | Create a config for an API-key, token or password integration (Stripe, most REST APIs) and print a **credential link**: a human opens it, signs in to Fruxon, types the credential, and the page tests it and publishes the config. The secret never passes through the terminal or an agent driving the CLI. `--config <id>` fills an existing config, `--param name=value` sets a connection setting, `--no-sign-in` mints a link anyone holding it can fill (for a client without a Fruxon login), `--expires-in-hours` 1–720. Needs `integrations:write` (the default login preset); `--no-sign-in` also needs `workspace:write` (Admin or Owner). |
|
|
146
147
|
| `fruxon integrations triggers <integration>` | List the event types an integration can fire an agent on — each descriptor's `id` is the `eventType` a trigger listens for, plus the `payloadFields` (dotted paths) a binding's `parameterMappings` can read. Discovery for wiring an inbound-event trigger without guessing. |
|
|
147
148
|
| `fruxon integrations mcp …` | Inspect and enable the MCP server for an integration. |
|
|
148
149
|
| `fruxon tools list/get/create/update/delete/run` | Manage the tools inside an integration. Integration-scoped. `get` and `run` select the tool with `--tool`; `run` executes it outside any agent — real credentials, real result — with `-p key=value`, and `-c` naming the config that supplies credentials. The tenant list API hides internal `knowledge_base` / `assets` tools; `tools list` recovers them by ID and lists them like any other (`--no-include-internal` for the raw server answer). |
|
|
149
150
|
| `fruxon keys list/mint/revoke/delete/history/scopes` | Audit and revoke scoped tokens. Minting opens the dashboard so the secret never enters the CLI process. |
|
|
150
151
|
| `fruxon llm-providers list/get/models` | Browse LLM providers and models supported at the tenant level. |
|
|
151
|
-
| `fruxon llm-providers
|
|
152
|
-
| `fruxon
|
|
152
|
+
| `fruxon llm-providers connect <provider>` / `link-status` | Create a config for an LLM provider and print a **credential link**: a human opens it, signs in to Fruxon, types the API key (or access keys, or service account key), and the page tests it with the provider and publishes the config an agent pins as `provider.tenantConfigId`. The key never passes through the terminal or an agent driving the CLI. `--config <id>` fills an existing config, `--param name=value` sets a non-secret setting such as Bedrock's `region`, `--no-sign-in` mints a link anyone holding it can fill (Admin or Owner). `link-status <provider> <config> <request> [--wait]` says when it was filled. |
|
|
153
|
+
| `fruxon llm-providers configs list/get/test/publish` | The workspace's saved LLM credentials — the `provider.tenantConfigId` an agent pins. `get` shows the draft (secrets masked), the published revision and last known health. `test` probes the draft on every provider surface that shares the credential (or just one, given that surface's provider id), one line per failing surface, exit 12 on failure (`llm_providers:test`). `publish` ships the draft as a new revision that every agent on the config switches to — it confirms, needs `--yes` in agent mode, and does not wait on a passing test (`llm_providers:write`). |
|
|
154
|
+
| `fruxon assets create/list/get/wait/operations/delete` | Manage knowledge-base (RAG) assets an agent can query — upload local files, wait for async ingestion, inspect operations, and use the ids for `assetConfig.assetIds`. `delete` confirms + refuses without `--yes` in agent mode. |
|
|
153
155
|
| `fruxon knowledge-bases list/get/create/update/publish/archive/delete` | The authored, reviewable corpus behind a `manual_knowledge` asset — **not** the asset itself, which is what gets searched (`get` prints the asset id as `backingAssetId`). **`publish` is the step that makes any of it findable**: only `PUBLISHED` documents travel in a snapshot, and only publishing the *base* moves one, so a base full of finished articles answers nothing until it runs. It returns on *acceptance*, not searchability — RAG ingests afterwards, so a pending publish state is normal. `list` hides archived bases, which keep answering for agents already attached to them; `delete` is refused while an agent revision still attaches one, and `archive` is the reversible path. |
|
|
154
156
|
| `fruxon knowledge-bases usage <kb>` | Whether agents actually use the base: searches per hour, day or week (`--interval`), the passage tokens each search handed the agent, how many found nothing (split from searches that **could not fully search** it — index missing or still building, a phrasing failed), and which agents searched (up to 20 you can open, the rest counted together). `--origin test` counts test runs instead of production. Retrieved tokens are counted by the search index, so what the model read can be less when a large result is trimmed or offloaded. Searches are recorded from 15 October 2026 and kept 90 days at most, so a window reaching further back says where counting began rather than showing empty days. A 404 is a wrong id or a backend that predates the read. |
|
|
155
157
|
| `fruxon knowledge-bases notices/notice/post-notice/edit-notice/extend-notice/withdraw-notice` | Time-boxed notices on a base — an outage being fixed, a known bug, a closure. **Not documents**: never indexed or published, so every agent attaching the base is given each active notice whole from its next turn. `post-notice --valid-for 4h` (or `--until`) — every notice ends, at most 30 days after it was posted, and a base holds ten active ones (409 `notice_limit` / `notice_too_long`, each with its remedy). The body is Markdown, at most 1,200 characters, best as four headings: *What is happening*, *Applies when*, *Tell the customer*, *Do not*. A time without an offset is read in the notice's zone (`--time-zone`, else this machine's), which is also the zone agents tell customers the end in. `withdraw-notice` tells each conversation that was given it, on its next turn, that it ended; it confirms, and needs `--yes` in agent mode. An ended notice is not extended: `post-notice --from <id>` posts it again as a new one. |
|
|
@@ -158,10 +160,10 @@ Integrations + tools:
|
|
|
158
160
|
| `fruxon knowledge-bases consolidate` → `apply` / `calibrate` | Two steps on purpose. `consolidate` queues a **report** of near-duplicate clusters and writes nothing — a standalone pass can no longer merge as it goes, and the old `--apply` is refused. `apply <kb> <run> --cluster <id>` (or `--all`) merges the clusters you accepted: the report's version rides along as a compare-and-set read off the run itself, and each member is revalidated against the content hash the report recorded, so a cluster whose documents moved comes back STALE and is left **entirely** alone rather than partly merged. It re-runs the base's consolidator agent per cluster, so a base without a deployed one is refused. `calibrate` records what a person reviewed a report under — it applies and publishes nothing, and is what reopens automatic source approval. |
|
|
159
161
|
| `fruxon knowledge-bases source list/get/add/update/plan-update/preview/activity/passes/sync/pause/resume/archive/unarchive/fork/delete` | The pipelines that read a customer's history and write articles. `managementMode` decides **who owns the implementation**, which is what the verbs key on: a LINKED source's resources are yours and survive a `delete`, a MANAGED one's agents, automation and ledger go with it — and `fork` flips managed to linked, keeping the history, one-way. **Stopped is the default**: a built source lands paused and `unarchive` returns one paused, so `resume` and `sync` confirm (they start reading someone's history, and dispatched items cost a run each) while `pause` and `archive` do not. `preview` admits nothing and is deliberately not narrowed by the watermark — a caught-up source would otherwise look broken — and reports **floors, not totals**, once a ceiling stopped the scan. `activity` speaks the ledger's vocabulary, so `ready` is backlog rather than motion, and a missing work ledger is reduced health rather than an error. |
|
|
160
162
|
| `fruxon assets search/documents/chunks` | Reproduce and inspect a retrieval. `search` runs the same query an agent's `search_assets` does (`--mode HYBRID/VECTOR/FULL_TEXT`, `--top-k`, fusion weights) — note `score` is on a different scale per mode, and in hybrid the top hit is always 1.0. `documents` lists what the index contains (a `chunkCount` of 0 means that file yielded no indexable text); `chunks` reads one document's chunks in order. The `documentId` these print is the **index's** id, which is what `chunks` takes — on a knowledge base's backing asset it is not the editable document's id, and it changes whenever a document's body is re-indexed. The `fileName` (`<knowledge document id>.md`) is the document a `knowledge_base` tool would edit. |
|
|
161
|
-
| `fruxon metrics list` | Browse the evaluation-metric catalog — the ids
|
|
163
|
+
| `fruxon metrics list` | Browse the evaluation-metric catalog — the ids an agent's quality check (`judge.metrics[]`) binds, with a default weight each. |
|
|
162
164
|
| `fruxon triggers list/get/create/update/delete/fire/bind/unbind` | Manage triggers — the schedule/event sources that fire agents. `create`/`update` take `--file` (+`--schema`); `create` also takes `--application`, the Application that will own the trigger and must own everything it fires. `bind`/`unbind` wire which agents fire; `fire` runs it now (`--close-gathering` also runs every group a batch stage is gathering). `fire`/`delete`/`unbind` confirm + refuse without `--yes` in agent mode. The control plane for autonomy. `get` returns the full stored `workShape` and every `scheduleTimes` slot, so `get -o json | jq .workShape` produces a body `update --file` can post straight back — a PATCH replaces the whole shape, so edit what you read. Each binding carries its `outputDestination` (where a fired run's reply is delivered, e.g. a Telegram group) verbatim, and text output names it as `delivers to telegram -5129894975 (Daria Group)`; a `bindings` list posted back without it unpins the delivery. |
|
|
163
165
|
| `fruxon triggers doors` | The pre-configured source doors a work shape can be built on — the **first** question of authoring an automation, and the one `--schema` cannot answer: it tells you a `workShape.door` carries a `doorId`, not which ids exist. Each row is the integration a chosen `integrationConfigId` must belong to, plus the one query field that is genuinely yours (label + example), and `supportsStartFrom` — whether that door's source accepts a lower bound, and so whether a `door.startFrom` horizon does anything there. `door.skipWhen` is the other field that is yours rather than the integration's: a `{match, conditions[]}` filter, same shape as a trigger's event filter, whose matching records are **never admitted** — no item, no stage, no model call. It has to live on the `door` because saving re-expands `source` from it, so the same filter written onto `source` is discarded by the next save. `door.projection` is the third: a list of dotted record paths naming the fields an admitted item **keeps**, with the door's own `defaultProjection` as the suggestion to seed it from — without one an item carries the whole record, into the Work grid and into every stage's prompt on every pass. Read that against the door's `labelPaths` (or, for the sheet and table doors, `labelFieldName` naming the field whose answer picks the label column): those are where an item's title comes from, and a projection that drops one is refused at save time rather than quietly repaired. Read-only and static: a door is a claim that one combination of list tool, identity path and watermark actually works, made in platform code by someone who verified it. An integration with no door is still fully usable — configure `workShape.source` by hand. |
|
|
164
|
-
| `fruxon triggers preview-shape/test-source` | Dry-run a work shape before saving or activating it; both write nothing. `preview-shape` renders, per stage, the resolved instruction, the whole `user_query` the agent is handed (item payload included), and the JSON schema the stage's declared `produces` keys become — against a real backlog item when you name a trigger. `--file` takes a draft shape, or just the stages — the same file `set-stages` takes — which it merges into the named trigger's saved shape the way `set-stages` would, so the preview is of what that save would write. `test-source` runs the door's list tool once and says, per record, whether admission would take it, plus the exact arguments the tool was called with (for Gmail, your query with the day-granular `after:` folded in). Records a `door.skipWhen` filter would drop read `FILTERED`, with a footer count — which is where to see what a rule costs before it goes onto a live automation. `--count` pages the whole door instead and answers how much is waiting: the total, how many the filter drops, how many the ledger already holds, how many clear the watermark, and which server ceiling stopped the scan — so `total − filtered − already held` is the work that would actually arrive. Each record prints **as the item will carry it** — narrowed to the shape's `door.projection`, with an `item keeps` line naming the paths that survived, so a field your projection drops and a field the source never sent are not the same silence. `--file` tests a shape being edited — and a draft whose `door.startFrom` (Unix ms) sets a first-run horizon gets a `first run sends` line with the `after:` term that horizon produces, which is the only place to see it: `startFrom` seeds the ledger cursor once, when the ledger is created. |
|
|
166
|
+
| `fruxon triggers preview-shape/test-source` | Dry-run a work shape before saving or activating it; both write nothing. `preview-shape` renders, per stage, the resolved instruction, the whole `user_query` the agent is handed (item payload included), and the JSON schema the stage's declared `produces` keys become — against a real backlog item when you name a trigger. A FORM stage shows its form message and, under it, the `join notice` sent when more items join the open form, both in the stage's own `formClosing` / `formJoinNotice` wording. `--file` takes a draft shape, or just the stages — the same file `set-stages` takes — which it merges into the named trigger's saved shape the way `set-stages` would, so the preview is of what that save would write. `test-source` runs the door's list tool once and says, per record, whether admission would take it, plus the exact arguments the tool was called with (for Gmail, your query with the day-granular `after:` folded in). Records a `door.skipWhen` filter would drop read `FILTERED`, with a footer count — which is where to see what a rule costs before it goes onto a live automation. `--count` pages the whole door instead and answers how much is waiting: the total, how many the filter drops, how many the ledger already holds, how many clear the watermark, and which server ceiling stopped the scan — so `total − filtered − already held` is the work that would actually arrive. Each record prints **as the item will carry it** — narrowed to the shape's `door.projection`, with an `item keeps` line naming the paths that survived, so a field your projection drops and a field the source never sent are not the same silence. `--file` tests a shape being edited — and a draft whose `door.startFrom` (Unix ms) sets a first-run horizon gets a `first run sends` line with the `after:` term that horizon produces, which is the only place to see it: `startFrom` seeds the ledger cursor once, when the ledger is created. |
|
|
165
167
|
| `fruxon triggers ledger funnel/items/cursor/transitions/effects/batches` | The work items a schedule trigger's work shape admitted. `funnel` counts per stage and status (every item is in exactly one cell). `items` is the grid — `--stage`, `--status`, `--ignore-reason`, `--item-key` (client-side; the endpoint has no such filter), each item's `label` (what the Work grid calls the row, as against the provider's opaque `itemKey`), and its accumulated `data`, which is where a stage's declared `produces` keys land. A listing is **one page of 20** that reports how many matched in total — a ledger's healthy state is thousands of rows served ten per request, so an unbounded walk is rate-limited long before the end; `-n` sizes the page and `--all` walks the lot. `--ignore-reason` narrows to the items one exclusion reason set aside — the same filter `redrive-many` selects by, matched whole and case-sensitively, so it is how you read a batch before putting it back. `--where field=value` (or `!=`, repeatable, dotted for a nested field) selects by what a stage wrote into `data` — `--where destination=SKIP` — matched whole and case-sensitively, as text and as the number, boolean or null it spells; the server filters and the CLI re-applies it, so an older server is slower, never wrong. `cursor` is the watermark and its freshness. `transitions` is one item's attempt history; `effects` is what it did to the outside world — an `UNKNOWN` row parks the item until someone settles it. `batches` is what an ASK stage is waiting on a human for — read its `delivery` first, because `UNDELIVERABLE` / `FAILED` mean nobody was asked and nobody will answer while the batch, the count and the stage all look healthy (`QUEUE_ONLY` is not a fault); a WAITING item's `batchId` is the join to it, and the pairing is total, so one `--open-only` listing resolves every waiting row. `batches --answers <batch>` is one question's answers item by item — what the person gave (`given`), what was handed back (`answer`), what the item holds now (`current`), with `mismatch` where the first two differ (a prose reply is every item's `given` at once, `givenIsReply`, and is never compared); a `given` the server did not record is read from the resolving run's sheet read (`givenFrom: "trace"`, `--no-trace` to skip). `batches --transcript <batch>` prints the conversation it was asked in, read under the agent that owns it — the stage's asking agent, not the desk that talks to the person. `funnel` and `items` also carry `cost` (all-in USD) and `runs` — so the funnel says *which stage* the money goes to, not merely how much. An item's `runs` spans every stage it passed through and so is not `stageAttempts`, which resets per stage; a `Cost` of `—` means nothing there has ever been claimed, as against `$0.0000`, which means it ran and was free. Cost is not sortable: the endpoint's `--order-by` allow-list does not carry it. |
|
|
166
168
|
| `fruxon triggers ledger passes` | Every time the automation fired, newest first — `admitted` (what the door took), `dispatched` (what the pass claimed and sent to work, questions parked on a human included), `completed` (how many of *this pass's* dispatches reached the terminal stage), `runs`, and the pass's all-in USD. `runs` sits **below** `dispatched` while runs are in flight or when a dispatch went to a person rather than a model — that gap is normal, not a lost item. And a pass's `cost` **rises after** it fired, as those runs finish, so a pass read seconds later reports a floor rather than its bill. An `outcome` other than `FIRED` means no sweep happened: `FILTERED` / `COALESCED` are healthy (nothing to do, or folded into a pass already running), `FAILED` / `FILTER_ERROR` are not. `-n/--limit` bounds the walk. |
|
|
167
169
|
| `fruxon triggers ledger spend/spend-series/item-series` | What the automation spent and what happened to its items, over time. `spend` is the **current UTC calendar** day, week (from Monday) or month (`--period`), so a weekly read on a Monday is hours of spend, not seven days — the figure the automation's spend chip shows: item runs, the conversations its questions are held in, and its report, one row per agent and part (`ITEM_RUNS` / `CONVERSATIONS` / `REPORTS` / `OTHER`). It is **not** the funnel's `cost`, which files item runs under the cell each item sits in *now*; the two overlap, so never add them. `spend-series` is the same figure per `day` or `week` over `--since`/`--until` (default the last 30 days), `--by-stage` adding a column per agent and part; it reads live run records, so a window older than the workspace's run history is counted from `countedFromMs` and the CLI says so. `--interval hour` is refused (tokens are priced per day), and a `week` bucket starts on a Thursday, so it does not line up with `spend --period weekly`. `item-series` counts admitted, finished, set aside and dead per `hour`, `day` or `week` — **events, not items**: a re-driven item that finishes again counts twice and an operator's ignore counts as set aside. Both series omit empty buckets; the footer says how many had anything. A server that predates the series reads 404s (exit 11). |
|
|
@@ -177,9 +179,9 @@ Integrations + tools:
|
|
|
177
179
|
| `fruxon triggers ledger walk/walk-steps` | `walk --item <id> --yes` chains stage tests: the item's stage (or `--from`), then each stage it advances into, on the data it advanced with, until a real pass would stop too. Each ASK stage it reaches takes `--reply <stage>=<text>` or `--answer <stage>=<value>`; `--agent-revision <agent>=<N>` runs every stage of that agent on an undeployed revision. `stopped.code` is `COMPLETED`, `REACHED_UNTIL` (`--until`), `NOT_ADVANCED` (a `WAIT`, too, and an ADVANCE a pass would undo: a duplicate, or fields the next stage requires), `REPLY_NEEDED` (an ASK stage nobody answered), `STAGE_NOT_TESTABLE`, `MAX_STEPS` (default 10), `TIMEOUT` or `CANCELLED`. Every step is a paid run, so it confirms first and needs `--yes` in agent mode; it exits 0 whenever it ran. `walk-steps <trigger> <walk>` reads a walk back in step order. |
|
|
178
180
|
| `fruxon triggers ledger reset-cursor/purge` | `reset-cursor` moves where the next scan starts, as a compare-and-swap on the version it just read (`--value` omitted = the door's own horizon); it never re-runs admitted work. It is the *after* to `workShape.door.startFrom`'s *before* — a horizon set at creation seeds the cursor before anything sweeps, and is ignored once a pass has read the source. `purge` starts the ledger over — cancels open questions, deletes items and effects, bumps the cursor version — and confirms the exact item count first. The items' transitions stay, as the ledger's history. Destructive; the effects' external targets are not touched. |
|
|
179
181
|
| `fruxon triggers questions list/answer` | The human half of an ASK stage, tenant-wide. `ledger batches <trigger>` answers *what is this automation waiting on*; this answers *what is waiting on anyone* — soonest deadline first, which is how an undelivered question gets found at all. Read **`delivery`** first: `UNDELIVERABLE` (nobody reachable in the slot) and `FAILED` (a target resolved, the send did not land) both mean nobody was asked and nobody will answer unless you do — `QUEUE_ONLY` is healthy. `--undelivered-only` narrows to that pair; `--trigger` filters client-side (the endpoint has no such filter). `answer` settles one on the assignee's behalf and is `--yes`-gated: the reply interpreter **fails closed**, so an answer it cannot place advances nothing and the question stays open, and each item advances only once the stage's `answeredWhenPath` is filled — answering two of three advances two. |
|
|
180
|
-
| `fruxon triggers set-stages <id> --file` | Replace an automation's stages without rewriting the rest of its work shape (a PATCH replaces the whole shape, so this reads it, splices, and posts). Takes a bare stages array or any document carrying one. Pre-flights the two refusals the server only reports after the write: live items at a stage your list drops, and a `door` that will re-expand `source` on save. `--dry-run` prints the merged shape and the warnings; `preview-shape <id> --file` takes the same file and renders what each stage would hand its agent. |
|
|
182
|
+
| `fruxon triggers set-stages <id> --file` | Replace an automation's stages without rewriting the rest of its work shape (a PATCH replaces the whole shape, so this reads it, splices, and posts). Takes a bare stages array or any document carrying one. Pre-flights the two refusals the server only reports after the write: live items at a stage your list drops, and a `door` that will re-expand `source` on save. `--dry-run` prints the merged shape and the warnings; `preview-shape <id> --file` takes the same file and renders what each stage would hand its agent. `--help` documents every stage field the server reads but the CLI passes through untouched — `routes`, `ignoreReasons`, a FORM stage's `answerField`, `formClosing` and `formJoinNotice`. |
|
|
181
183
|
| `fruxon triggers revisions list/get/restore` | A trigger's audit history — every mutation writes a snapshot, and `changeReason` separates a config edit from a binding reconcile. `get -o json | jq .workShape` is the shape as it stood, which is how you undo an edit by hand. `restore` replays one and is **not** a universal undo: it runs the same validation a save does, so a snapshot that drops a stage still holding live items is refused. |
|
|
182
|
-
| `fruxon secrets list/get/grants` | Discover tenant secrets
|
|
184
|
+
| `fruxon secrets list/get/grants` | Discover tenant secrets an agent can reference — the ids for `allowedSecretIds` and the `{{secret.KEY}}` names, with publish-state and per-agent grants. Metadata only; values are never returned. |
|
|
183
185
|
| `fruxon participants list/get/create/update/delete/enable/disable` | Manage agent-network participants (people / groups / agents the network routes to). `list` takes `--query` (matches names **and channel addresses and account ids**, so a phone number or handle resolves to an id, and searches both directory tiers by default), `--kind`, `--tier`, `--agent`, `--environment-id`, and pages up to `--limit` / `--all`. `create`/`update` take `--file` (+`--schema`); `enable`/`disable` toggle routing; `delete` confirms + refuses without `--yes` in agent mode. |
|
|
184
186
|
| `fruxon applications roles <id>` | The Application's roster roles — who holds each, who defers to it, and how many holders are `consultable`. The answer to what a `--role` contact binding leaves open: the server takes any role string, so a role with references and no holders refuses at delivery time. `--unheld-only` lists just those. Trust the consultable count — every role path, delivery and consult alike, resolves through the consult-allowed member edges, so a holder without one is tagged but unreachable. |
|
|
185
187
|
| `fruxon applications list/get` | Inspect Applications — the container that owns agents, workflows and people. Every agent belongs to exactly one, and `agents create` needs its id, so this is where you find it. Creating and re-homing an Application itself stays in the dashboard. |
|
|
@@ -299,9 +301,11 @@ schema = client.get_agent_parameter_metadata("support-agent", revision=1)
|
|
|
299
301
|
for p in schema["metadata"]:
|
|
300
302
|
print(p["name"], p["type"], "required" if p.get("required") else "optional")
|
|
301
303
|
|
|
302
|
-
# Test a draft
|
|
303
|
-
|
|
304
|
-
|
|
304
|
+
# Test a draft without publishing it (same result shape as execute):
|
|
305
|
+
# save the draft on top of revision 3, then run it
|
|
306
|
+
client.put_draft("support-agent", 3, {"definition": {...}, "parametersMetadata": [...]})
|
|
307
|
+
result = client.test("support-agent", 3, {"parameters": {"question": "Hi"}})
|
|
308
|
+
for event in client.stream_test("support-agent", 3, {"parameters": {"question": "Hi"}}):
|
|
305
309
|
...
|
|
306
310
|
|
|
307
311
|
# Integrations & tools — the connections + capabilities agents are built from
|
|
@@ -47,7 +47,7 @@ Auth:
|
|
|
47
47
|
|
|
48
48
|
| Command | What it does |
|
|
49
49
|
| --- | --- |
|
|
50
|
-
| `fruxon login` | Browser-based sign-in. token goes to your OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows). `--token $KEY` for headless. `--preset observer\|operator\|developer\|maintainer\|admin` declares the access level the key is minted with (default: developer); the approval page shows it for the user to approve or deny. |
|
|
50
|
+
| `fruxon login` | Browser-based sign-in. token goes to your OS keychain (Keychain on macOS, Secret Service on Linux, Credential Manager on Windows). `--token $KEY` for headless. `--preset observer\|operator\|developer\|maintainer\|admin` declares the access level the key is minted with (default: developer); the approval page shows it for the user to approve or deny. Adds a workspace without moving the default (the first sign-in sets it); `--set-default` moves it. |
|
|
51
51
|
| `fruxon whoami` | Show the active key/workspace and where each value came from (flag, env, keychain, file). |
|
|
52
52
|
| `fruxon logout` | Forget stored credentials. `--workspace <id>` signs out of one and leaves the rest; `--all` clears every one. |
|
|
53
53
|
| `fruxon workspaces list` | Which workspaces this machine is signed in to, each with its host and cell, and which one is the default. Offline, no auth. |
|
|
@@ -63,7 +63,7 @@ Execution:
|
|
|
63
63
|
| `fruxon agents executions get <agent> <record-id>` | Record summary for one execution — status, duration, cost, tokens. |
|
|
64
64
|
| `fruxon agents executions trace <agent> <record-id>` | Step-by-step trace of one execution — LLM/tool calls, durations, and for a tool that records it, where the call's time went (service stages vs. unaccounted). Flags a result the model got offloaded or projected. Prints a quality check's verdict (score, criteria, rationale) under its `JUDGE` step, and marks a reply the check refused. `--show-io` also prints each tool step's parameters and result (the payload lives at `steps[].result`, a sibling of `toolTrace` — whose `resultDelivery` carries sizes only). `--show-system` labels each LLM step's system prompt block by block — your prompt vs. the platform's `<tag>` blocks, sizes, and the cache breakpoint. |
|
|
65
65
|
| `fruxon agents executions result <agent> <record-id>` | The final output one execution produced. |
|
|
66
|
-
| `fruxon agents approvals list/get/respond/cancel <agent>` | Operate
|
|
66
|
+
| `fruxon agents approvals list/get/respond/cancel <agent>` | Operate human-in-the-loop approval gates — see what a run is blocked on and answer it. `respond`/`cancel` confirm first and refuse without `--yes` in agent mode (an LLM must not silently auto-approve). |
|
|
67
67
|
| `fruxon agents memory list/subjects/get/forget-subject <agent>` | Inspect and prune what an agent remembers. `list` filters server-side by `--subject`/`--query`/`--scope`; `forget-subject` is a GDPR-style delete (confirms; refuses without `--yes` in agent mode). |
|
|
68
68
|
| `fruxon agents topics list/search/get/messages/sessions <agent>` + `fruxon agents inbox <agent>` | Read the conversation spine — the agent's topics (threads), one topic's transcript, its episodes, and its inbox (what it's focused on). `list`/`search` filter server-side by `--state`/`--participant`/`--query`. Read-only. Each message carries `author` — a human colleague's turn is stored as `ASSISTANT` on purpose, so `role` alone cannot tell their reply from the agent's; `HUMAN_OPERATOR` can. A message the runtime *withheld* is in no transcript at all — see `fruxon messages list`. `sessions` explains a fresh, blind session: a topic outlives its sessions, and `endCause` on the previous one (`CONSOLE_ALREADY_RESOLVED` — a human closed it in the provider's console) is why the next started with no history. |
|
|
69
69
|
| `fruxon escalations list/history/unhandled/policy/ack` | What happened when an agent handed a conversation to a person. `list` is the queue (live takeovers + degraded escalations nobody was reachable for); `unhandled` is the append-only ledger under it. **`history` is the record of closed console-routed takeovers** — those leave the queue, so `list --status ALL` answers `[]` about a conversation a human worked for half an hour. Read `humanObservedAt` before believing a `RESOLVED`: null means nobody was ever seen picking it up. `policy <agent>` resolves who the *next* escalation would reach — an empty ladder under `NATIVE_HANDOFF` is correct, the console supplies the human. |
|
|
@@ -108,13 +108,15 @@ Integrations + tools:
|
|
|
108
108
|
| `fruxon integrations list/get/create/update/verify/open` | Manage external integrations — the connections agents draw tools from. `create`/`update`/`verify` take a `--file` JSON body; `open` opens the dashboard. |
|
|
109
109
|
| `fruxon integrations configs list/get/update/publish` | The per-integration auth/config records. `update --file` patches a config's draft (only the fields sent; `{"egressCountry": ""}` clears an egress pin) and prints it with secrets masked; `publish` makes the draft the revision tool calls resolve, asks first (`--yes` in agent mode), and prints the new revision's `id` and `version`, never the credentials. |
|
|
110
110
|
| `fruxon integrations authorize <integration>` | Mint an application-level OAuth authorization URL to **connect** an integration — auto-detects its OAuth2 method (`--auth-method` to pick, `--scope`/`--config-param` to tune). OAuth needs a browser consent step, so the CLI hands you the link; a human clicks it, and the connection is saved as a tenant config a slot can pin. |
|
|
111
|
+
| `fruxon integrations connect <integration>` | Create a config for an API-key, token or password integration (Stripe, most REST APIs) and print a **credential link**: a human opens it, signs in to Fruxon, types the credential, and the page tests it and publishes the config. The secret never passes through the terminal or an agent driving the CLI. `--config <id>` fills an existing config, `--param name=value` sets a connection setting, `--no-sign-in` mints a link anyone holding it can fill (for a client without a Fruxon login), `--expires-in-hours` 1–720. Needs `integrations:write` (the default login preset); `--no-sign-in` also needs `workspace:write` (Admin or Owner). |
|
|
111
112
|
| `fruxon integrations triggers <integration>` | List the event types an integration can fire an agent on — each descriptor's `id` is the `eventType` a trigger listens for, plus the `payloadFields` (dotted paths) a binding's `parameterMappings` can read. Discovery for wiring an inbound-event trigger without guessing. |
|
|
112
113
|
| `fruxon integrations mcp …` | Inspect and enable the MCP server for an integration. |
|
|
113
114
|
| `fruxon tools list/get/create/update/delete/run` | Manage the tools inside an integration. Integration-scoped. `get` and `run` select the tool with `--tool`; `run` executes it outside any agent — real credentials, real result — with `-p key=value`, and `-c` naming the config that supplies credentials. The tenant list API hides internal `knowledge_base` / `assets` tools; `tools list` recovers them by ID and lists them like any other (`--no-include-internal` for the raw server answer). |
|
|
114
115
|
| `fruxon keys list/mint/revoke/delete/history/scopes` | Audit and revoke scoped tokens. Minting opens the dashboard so the secret never enters the CLI process. |
|
|
115
116
|
| `fruxon llm-providers list/get/models` | Browse LLM providers and models supported at the tenant level. |
|
|
116
|
-
| `fruxon llm-providers
|
|
117
|
-
| `fruxon
|
|
117
|
+
| `fruxon llm-providers connect <provider>` / `link-status` | Create a config for an LLM provider and print a **credential link**: a human opens it, signs in to Fruxon, types the API key (or access keys, or service account key), and the page tests it with the provider and publishes the config an agent pins as `provider.tenantConfigId`. The key never passes through the terminal or an agent driving the CLI. `--config <id>` fills an existing config, `--param name=value` sets a non-secret setting such as Bedrock's `region`, `--no-sign-in` mints a link anyone holding it can fill (Admin or Owner). `link-status <provider> <config> <request> [--wait]` says when it was filled. |
|
|
118
|
+
| `fruxon llm-providers configs list/get/test/publish` | The workspace's saved LLM credentials — the `provider.tenantConfigId` an agent pins. `get` shows the draft (secrets masked), the published revision and last known health. `test` probes the draft on every provider surface that shares the credential (or just one, given that surface's provider id), one line per failing surface, exit 12 on failure (`llm_providers:test`). `publish` ships the draft as a new revision that every agent on the config switches to — it confirms, needs `--yes` in agent mode, and does not wait on a passing test (`llm_providers:write`). |
|
|
119
|
+
| `fruxon assets create/list/get/wait/operations/delete` | Manage knowledge-base (RAG) assets an agent can query — upload local files, wait for async ingestion, inspect operations, and use the ids for `assetConfig.assetIds`. `delete` confirms + refuses without `--yes` in agent mode. |
|
|
118
120
|
| `fruxon knowledge-bases list/get/create/update/publish/archive/delete` | The authored, reviewable corpus behind a `manual_knowledge` asset — **not** the asset itself, which is what gets searched (`get` prints the asset id as `backingAssetId`). **`publish` is the step that makes any of it findable**: only `PUBLISHED` documents travel in a snapshot, and only publishing the *base* moves one, so a base full of finished articles answers nothing until it runs. It returns on *acceptance*, not searchability — RAG ingests afterwards, so a pending publish state is normal. `list` hides archived bases, which keep answering for agents already attached to them; `delete` is refused while an agent revision still attaches one, and `archive` is the reversible path. |
|
|
119
121
|
| `fruxon knowledge-bases usage <kb>` | Whether agents actually use the base: searches per hour, day or week (`--interval`), the passage tokens each search handed the agent, how many found nothing (split from searches that **could not fully search** it — index missing or still building, a phrasing failed), and which agents searched (up to 20 you can open, the rest counted together). `--origin test` counts test runs instead of production. Retrieved tokens are counted by the search index, so what the model read can be less when a large result is trimmed or offloaded. Searches are recorded from 15 October 2026 and kept 90 days at most, so a window reaching further back says where counting began rather than showing empty days. A 404 is a wrong id or a backend that predates the read. |
|
|
120
122
|
| `fruxon knowledge-bases notices/notice/post-notice/edit-notice/extend-notice/withdraw-notice` | Time-boxed notices on a base — an outage being fixed, a known bug, a closure. **Not documents**: never indexed or published, so every agent attaching the base is given each active notice whole from its next turn. `post-notice --valid-for 4h` (or `--until`) — every notice ends, at most 30 days after it was posted, and a base holds ten active ones (409 `notice_limit` / `notice_too_long`, each with its remedy). The body is Markdown, at most 1,200 characters, best as four headings: *What is happening*, *Applies when*, *Tell the customer*, *Do not*. A time without an offset is read in the notice's zone (`--time-zone`, else this machine's), which is also the zone agents tell customers the end in. `withdraw-notice` tells each conversation that was given it, on its next turn, that it ended; it confirms, and needs `--yes` in agent mode. An ended notice is not extended: `post-notice --from <id>` posts it again as a new one. |
|
|
@@ -123,10 +125,10 @@ Integrations + tools:
|
|
|
123
125
|
| `fruxon knowledge-bases consolidate` → `apply` / `calibrate` | Two steps on purpose. `consolidate` queues a **report** of near-duplicate clusters and writes nothing — a standalone pass can no longer merge as it goes, and the old `--apply` is refused. `apply <kb> <run> --cluster <id>` (or `--all`) merges the clusters you accepted: the report's version rides along as a compare-and-set read off the run itself, and each member is revalidated against the content hash the report recorded, so a cluster whose documents moved comes back STALE and is left **entirely** alone rather than partly merged. It re-runs the base's consolidator agent per cluster, so a base without a deployed one is refused. `calibrate` records what a person reviewed a report under — it applies and publishes nothing, and is what reopens automatic source approval. |
|
|
124
126
|
| `fruxon knowledge-bases source list/get/add/update/plan-update/preview/activity/passes/sync/pause/resume/archive/unarchive/fork/delete` | The pipelines that read a customer's history and write articles. `managementMode` decides **who owns the implementation**, which is what the verbs key on: a LINKED source's resources are yours and survive a `delete`, a MANAGED one's agents, automation and ledger go with it — and `fork` flips managed to linked, keeping the history, one-way. **Stopped is the default**: a built source lands paused and `unarchive` returns one paused, so `resume` and `sync` confirm (they start reading someone's history, and dispatched items cost a run each) while `pause` and `archive` do not. `preview` admits nothing and is deliberately not narrowed by the watermark — a caught-up source would otherwise look broken — and reports **floors, not totals**, once a ceiling stopped the scan. `activity` speaks the ledger's vocabulary, so `ready` is backlog rather than motion, and a missing work ledger is reduced health rather than an error. |
|
|
125
127
|
| `fruxon assets search/documents/chunks` | Reproduce and inspect a retrieval. `search` runs the same query an agent's `search_assets` does (`--mode HYBRID/VECTOR/FULL_TEXT`, `--top-k`, fusion weights) — note `score` is on a different scale per mode, and in hybrid the top hit is always 1.0. `documents` lists what the index contains (a `chunkCount` of 0 means that file yielded no indexable text); `chunks` reads one document's chunks in order. The `documentId` these print is the **index's** id, which is what `chunks` takes — on a knowledge base's backing asset it is not the editable document's id, and it changes whenever a document's body is re-indexed. The `fileName` (`<knowledge document id>.md`) is the document a `knowledge_base` tool would edit. |
|
|
126
|
-
| `fruxon metrics list` | Browse the evaluation-metric catalog — the ids
|
|
128
|
+
| `fruxon metrics list` | Browse the evaluation-metric catalog — the ids an agent's quality check (`judge.metrics[]`) binds, with a default weight each. |
|
|
127
129
|
| `fruxon triggers list/get/create/update/delete/fire/bind/unbind` | Manage triggers — the schedule/event sources that fire agents. `create`/`update` take `--file` (+`--schema`); `create` also takes `--application`, the Application that will own the trigger and must own everything it fires. `bind`/`unbind` wire which agents fire; `fire` runs it now (`--close-gathering` also runs every group a batch stage is gathering). `fire`/`delete`/`unbind` confirm + refuse without `--yes` in agent mode. The control plane for autonomy. `get` returns the full stored `workShape` and every `scheduleTimes` slot, so `get -o json | jq .workShape` produces a body `update --file` can post straight back — a PATCH replaces the whole shape, so edit what you read. Each binding carries its `outputDestination` (where a fired run's reply is delivered, e.g. a Telegram group) verbatim, and text output names it as `delivers to telegram -5129894975 (Daria Group)`; a `bindings` list posted back without it unpins the delivery. |
|
|
128
130
|
| `fruxon triggers doors` | The pre-configured source doors a work shape can be built on — the **first** question of authoring an automation, and the one `--schema` cannot answer: it tells you a `workShape.door` carries a `doorId`, not which ids exist. Each row is the integration a chosen `integrationConfigId` must belong to, plus the one query field that is genuinely yours (label + example), and `supportsStartFrom` — whether that door's source accepts a lower bound, and so whether a `door.startFrom` horizon does anything there. `door.skipWhen` is the other field that is yours rather than the integration's: a `{match, conditions[]}` filter, same shape as a trigger's event filter, whose matching records are **never admitted** — no item, no stage, no model call. It has to live on the `door` because saving re-expands `source` from it, so the same filter written onto `source` is discarded by the next save. `door.projection` is the third: a list of dotted record paths naming the fields an admitted item **keeps**, with the door's own `defaultProjection` as the suggestion to seed it from — without one an item carries the whole record, into the Work grid and into every stage's prompt on every pass. Read that against the door's `labelPaths` (or, for the sheet and table doors, `labelFieldName` naming the field whose answer picks the label column): those are where an item's title comes from, and a projection that drops one is refused at save time rather than quietly repaired. Read-only and static: a door is a claim that one combination of list tool, identity path and watermark actually works, made in platform code by someone who verified it. An integration with no door is still fully usable — configure `workShape.source` by hand. |
|
|
129
|
-
| `fruxon triggers preview-shape/test-source` | Dry-run a work shape before saving or activating it; both write nothing. `preview-shape` renders, per stage, the resolved instruction, the whole `user_query` the agent is handed (item payload included), and the JSON schema the stage's declared `produces` keys become — against a real backlog item when you name a trigger. `--file` takes a draft shape, or just the stages — the same file `set-stages` takes — which it merges into the named trigger's saved shape the way `set-stages` would, so the preview is of what that save would write. `test-source` runs the door's list tool once and says, per record, whether admission would take it, plus the exact arguments the tool was called with (for Gmail, your query with the day-granular `after:` folded in). Records a `door.skipWhen` filter would drop read `FILTERED`, with a footer count — which is where to see what a rule costs before it goes onto a live automation. `--count` pages the whole door instead and answers how much is waiting: the total, how many the filter drops, how many the ledger already holds, how many clear the watermark, and which server ceiling stopped the scan — so `total − filtered − already held` is the work that would actually arrive. Each record prints **as the item will carry it** — narrowed to the shape's `door.projection`, with an `item keeps` line naming the paths that survived, so a field your projection drops and a field the source never sent are not the same silence. `--file` tests a shape being edited — and a draft whose `door.startFrom` (Unix ms) sets a first-run horizon gets a `first run sends` line with the `after:` term that horizon produces, which is the only place to see it: `startFrom` seeds the ledger cursor once, when the ledger is created. |
|
|
131
|
+
| `fruxon triggers preview-shape/test-source` | Dry-run a work shape before saving or activating it; both write nothing. `preview-shape` renders, per stage, the resolved instruction, the whole `user_query` the agent is handed (item payload included), and the JSON schema the stage's declared `produces` keys become — against a real backlog item when you name a trigger. A FORM stage shows its form message and, under it, the `join notice` sent when more items join the open form, both in the stage's own `formClosing` / `formJoinNotice` wording. `--file` takes a draft shape, or just the stages — the same file `set-stages` takes — which it merges into the named trigger's saved shape the way `set-stages` would, so the preview is of what that save would write. `test-source` runs the door's list tool once and says, per record, whether admission would take it, plus the exact arguments the tool was called with (for Gmail, your query with the day-granular `after:` folded in). Records a `door.skipWhen` filter would drop read `FILTERED`, with a footer count — which is where to see what a rule costs before it goes onto a live automation. `--count` pages the whole door instead and answers how much is waiting: the total, how many the filter drops, how many the ledger already holds, how many clear the watermark, and which server ceiling stopped the scan — so `total − filtered − already held` is the work that would actually arrive. Each record prints **as the item will carry it** — narrowed to the shape's `door.projection`, with an `item keeps` line naming the paths that survived, so a field your projection drops and a field the source never sent are not the same silence. `--file` tests a shape being edited — and a draft whose `door.startFrom` (Unix ms) sets a first-run horizon gets a `first run sends` line with the `after:` term that horizon produces, which is the only place to see it: `startFrom` seeds the ledger cursor once, when the ledger is created. |
|
|
130
132
|
| `fruxon triggers ledger funnel/items/cursor/transitions/effects/batches` | The work items a schedule trigger's work shape admitted. `funnel` counts per stage and status (every item is in exactly one cell). `items` is the grid — `--stage`, `--status`, `--ignore-reason`, `--item-key` (client-side; the endpoint has no such filter), each item's `label` (what the Work grid calls the row, as against the provider's opaque `itemKey`), and its accumulated `data`, which is where a stage's declared `produces` keys land. A listing is **one page of 20** that reports how many matched in total — a ledger's healthy state is thousands of rows served ten per request, so an unbounded walk is rate-limited long before the end; `-n` sizes the page and `--all` walks the lot. `--ignore-reason` narrows to the items one exclusion reason set aside — the same filter `redrive-many` selects by, matched whole and case-sensitively, so it is how you read a batch before putting it back. `--where field=value` (or `!=`, repeatable, dotted for a nested field) selects by what a stage wrote into `data` — `--where destination=SKIP` — matched whole and case-sensitively, as text and as the number, boolean or null it spells; the server filters and the CLI re-applies it, so an older server is slower, never wrong. `cursor` is the watermark and its freshness. `transitions` is one item's attempt history; `effects` is what it did to the outside world — an `UNKNOWN` row parks the item until someone settles it. `batches` is what an ASK stage is waiting on a human for — read its `delivery` first, because `UNDELIVERABLE` / `FAILED` mean nobody was asked and nobody will answer while the batch, the count and the stage all look healthy (`QUEUE_ONLY` is not a fault); a WAITING item's `batchId` is the join to it, and the pairing is total, so one `--open-only` listing resolves every waiting row. `batches --answers <batch>` is one question's answers item by item — what the person gave (`given`), what was handed back (`answer`), what the item holds now (`current`), with `mismatch` where the first two differ (a prose reply is every item's `given` at once, `givenIsReply`, and is never compared); a `given` the server did not record is read from the resolving run's sheet read (`givenFrom: "trace"`, `--no-trace` to skip). `batches --transcript <batch>` prints the conversation it was asked in, read under the agent that owns it — the stage's asking agent, not the desk that talks to the person. `funnel` and `items` also carry `cost` (all-in USD) and `runs` — so the funnel says *which stage* the money goes to, not merely how much. An item's `runs` spans every stage it passed through and so is not `stageAttempts`, which resets per stage; a `Cost` of `—` means nothing there has ever been claimed, as against `$0.0000`, which means it ran and was free. Cost is not sortable: the endpoint's `--order-by` allow-list does not carry it. |
|
|
131
133
|
| `fruxon triggers ledger passes` | Every time the automation fired, newest first — `admitted` (what the door took), `dispatched` (what the pass claimed and sent to work, questions parked on a human included), `completed` (how many of *this pass's* dispatches reached the terminal stage), `runs`, and the pass's all-in USD. `runs` sits **below** `dispatched` while runs are in flight or when a dispatch went to a person rather than a model — that gap is normal, not a lost item. And a pass's `cost` **rises after** it fired, as those runs finish, so a pass read seconds later reports a floor rather than its bill. An `outcome` other than `FIRED` means no sweep happened: `FILTERED` / `COALESCED` are healthy (nothing to do, or folded into a pass already running), `FAILED` / `FILTER_ERROR` are not. `-n/--limit` bounds the walk. |
|
|
132
134
|
| `fruxon triggers ledger spend/spend-series/item-series` | What the automation spent and what happened to its items, over time. `spend` is the **current UTC calendar** day, week (from Monday) or month (`--period`), so a weekly read on a Monday is hours of spend, not seven days — the figure the automation's spend chip shows: item runs, the conversations its questions are held in, and its report, one row per agent and part (`ITEM_RUNS` / `CONVERSATIONS` / `REPORTS` / `OTHER`). It is **not** the funnel's `cost`, which files item runs under the cell each item sits in *now*; the two overlap, so never add them. `spend-series` is the same figure per `day` or `week` over `--since`/`--until` (default the last 30 days), `--by-stage` adding a column per agent and part; it reads live run records, so a window older than the workspace's run history is counted from `countedFromMs` and the CLI says so. `--interval hour` is refused (tokens are priced per day), and a `week` bucket starts on a Thursday, so it does not line up with `spend --period weekly`. `item-series` counts admitted, finished, set aside and dead per `hour`, `day` or `week` — **events, not items**: a re-driven item that finishes again counts twice and an operator's ignore counts as set aside. Both series omit empty buckets; the footer says how many had anything. A server that predates the series reads 404s (exit 11). |
|
|
@@ -142,9 +144,9 @@ Integrations + tools:
|
|
|
142
144
|
| `fruxon triggers ledger walk/walk-steps` | `walk --item <id> --yes` chains stage tests: the item's stage (or `--from`), then each stage it advances into, on the data it advanced with, until a real pass would stop too. Each ASK stage it reaches takes `--reply <stage>=<text>` or `--answer <stage>=<value>`; `--agent-revision <agent>=<N>` runs every stage of that agent on an undeployed revision. `stopped.code` is `COMPLETED`, `REACHED_UNTIL` (`--until`), `NOT_ADVANCED` (a `WAIT`, too, and an ADVANCE a pass would undo: a duplicate, or fields the next stage requires), `REPLY_NEEDED` (an ASK stage nobody answered), `STAGE_NOT_TESTABLE`, `MAX_STEPS` (default 10), `TIMEOUT` or `CANCELLED`. Every step is a paid run, so it confirms first and needs `--yes` in agent mode; it exits 0 whenever it ran. `walk-steps <trigger> <walk>` reads a walk back in step order. |
|
|
143
145
|
| `fruxon triggers ledger reset-cursor/purge` | `reset-cursor` moves where the next scan starts, as a compare-and-swap on the version it just read (`--value` omitted = the door's own horizon); it never re-runs admitted work. It is the *after* to `workShape.door.startFrom`'s *before* — a horizon set at creation seeds the cursor before anything sweeps, and is ignored once a pass has read the source. `purge` starts the ledger over — cancels open questions, deletes items and effects, bumps the cursor version — and confirms the exact item count first. The items' transitions stay, as the ledger's history. Destructive; the effects' external targets are not touched. |
|
|
144
146
|
| `fruxon triggers questions list/answer` | The human half of an ASK stage, tenant-wide. `ledger batches <trigger>` answers *what is this automation waiting on*; this answers *what is waiting on anyone* — soonest deadline first, which is how an undelivered question gets found at all. Read **`delivery`** first: `UNDELIVERABLE` (nobody reachable in the slot) and `FAILED` (a target resolved, the send did not land) both mean nobody was asked and nobody will answer unless you do — `QUEUE_ONLY` is healthy. `--undelivered-only` narrows to that pair; `--trigger` filters client-side (the endpoint has no such filter). `answer` settles one on the assignee's behalf and is `--yes`-gated: the reply interpreter **fails closed**, so an answer it cannot place advances nothing and the question stays open, and each item advances only once the stage's `answeredWhenPath` is filled — answering two of three advances two. |
|
|
145
|
-
| `fruxon triggers set-stages <id> --file` | Replace an automation's stages without rewriting the rest of its work shape (a PATCH replaces the whole shape, so this reads it, splices, and posts). Takes a bare stages array or any document carrying one. Pre-flights the two refusals the server only reports after the write: live items at a stage your list drops, and a `door` that will re-expand `source` on save. `--dry-run` prints the merged shape and the warnings; `preview-shape <id> --file` takes the same file and renders what each stage would hand its agent. |
|
|
147
|
+
| `fruxon triggers set-stages <id> --file` | Replace an automation's stages without rewriting the rest of its work shape (a PATCH replaces the whole shape, so this reads it, splices, and posts). Takes a bare stages array or any document carrying one. Pre-flights the two refusals the server only reports after the write: live items at a stage your list drops, and a `door` that will re-expand `source` on save. `--dry-run` prints the merged shape and the warnings; `preview-shape <id> --file` takes the same file and renders what each stage would hand its agent. `--help` documents every stage field the server reads but the CLI passes through untouched — `routes`, `ignoreReasons`, a FORM stage's `answerField`, `formClosing` and `formJoinNotice`. |
|
|
146
148
|
| `fruxon triggers revisions list/get/restore` | A trigger's audit history — every mutation writes a snapshot, and `changeReason` separates a config edit from a binding reconcile. `get -o json | jq .workShape` is the shape as it stood, which is how you undo an edit by hand. `restore` replays one and is **not** a universal undo: it runs the same validation a save does, so a snapshot that drops a stage still holding live items is refused. |
|
|
147
|
-
| `fruxon secrets list/get/grants` | Discover tenant secrets
|
|
149
|
+
| `fruxon secrets list/get/grants` | Discover tenant secrets an agent can reference — the ids for `allowedSecretIds` and the `{{secret.KEY}}` names, with publish-state and per-agent grants. Metadata only; values are never returned. |
|
|
148
150
|
| `fruxon participants list/get/create/update/delete/enable/disable` | Manage agent-network participants (people / groups / agents the network routes to). `list` takes `--query` (matches names **and channel addresses and account ids**, so a phone number or handle resolves to an id, and searches both directory tiers by default), `--kind`, `--tier`, `--agent`, `--environment-id`, and pages up to `--limit` / `--all`. `create`/`update` take `--file` (+`--schema`); `enable`/`disable` toggle routing; `delete` confirms + refuses without `--yes` in agent mode. |
|
|
149
151
|
| `fruxon applications roles <id>` | The Application's roster roles — who holds each, who defers to it, and how many holders are `consultable`. The answer to what a `--role` contact binding leaves open: the server takes any role string, so a role with references and no holders refuses at delivery time. `--unheld-only` lists just those. Trust the consultable count — every role path, delivery and consult alike, resolves through the consult-allowed member edges, so a holder without one is tagged but unreachable. |
|
|
150
152
|
| `fruxon applications list/get` | Inspect Applications — the container that owns agents, workflows and people. Every agent belongs to exactly one, and `agents create` needs its id, so this is where you find it. Creating and re-homing an Application itself stays in the dashboard. |
|
|
@@ -264,9 +266,11 @@ schema = client.get_agent_parameter_metadata("support-agent", revision=1)
|
|
|
264
266
|
for p in schema["metadata"]:
|
|
265
267
|
print(p["name"], p["type"], "required" if p.get("required") else "optional")
|
|
266
268
|
|
|
267
|
-
# Test a draft
|
|
268
|
-
|
|
269
|
-
|
|
269
|
+
# Test a draft without publishing it (same result shape as execute):
|
|
270
|
+
# save the draft on top of revision 3, then run it
|
|
271
|
+
client.put_draft("support-agent", 3, {"definition": {...}, "parametersMetadata": [...]})
|
|
272
|
+
result = client.test("support-agent", 3, {"parameters": {"question": "Hi"}})
|
|
273
|
+
for event in client.stream_test("support-agent", 3, {"parameters": {"question": "Hi"}}):
|
|
270
274
|
...
|
|
271
275
|
|
|
272
276
|
# Integrations & tools — the connections + capabilities agents are built from
|
|
@@ -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.0.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 0,
|
|
21
|
+
__version__ = version = '2.0.2'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 0, 2)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -30,6 +30,12 @@ class CheckResult:
|
|
|
30
30
|
``explain`` says what the row checks and why it matters, for a reader who
|
|
31
31
|
has never seen it before; the CLI does not print it, the console shows it
|
|
32
32
|
beside the selected row.
|
|
33
|
+
|
|
34
|
+
``fix`` says where the finding is put right, as a short reference rather
|
|
35
|
+
than a URL — ``editor`` (the agent's definition), ``channels``,
|
|
36
|
+
``integration:<id>``, ``llm-provider:<id>``, ``work:<status>:<stage>``
|
|
37
|
+
and so on — so the console can link to the page without the checks
|
|
38
|
+
knowing the web app's routes.
|
|
33
39
|
"""
|
|
34
40
|
|
|
35
41
|
title: str
|
|
@@ -37,6 +43,7 @@ class CheckResult:
|
|
|
37
43
|
detail: str
|
|
38
44
|
hint: str | None = None
|
|
39
45
|
explain: str = ""
|
|
46
|
+
fix: str = ""
|
|
40
47
|
|
|
41
48
|
def to_dict(self) -> dict:
|
|
42
49
|
"""The row as ``agents check -o json`` has always printed it."""
|
|
@@ -49,7 +56,7 @@ class CheckReport:
|
|
|
49
56
|
|
|
50
57
|
``revision`` is the revision the audit read (``None`` when there is
|
|
51
58
|
none). ``revision_body`` is that revision as fetched, kept so a caller
|
|
52
|
-
that wants to draw the agent
|
|
59
|
+
that wants to draw the agent does not have to fetch it again.
|
|
53
60
|
"""
|
|
54
61
|
|
|
55
62
|
subject: str
|