taskuary 0.3.6.2__tar.gz → 0.3.6.3__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.
- {taskuary-0.3.6.2/taskuary.egg-info → taskuary-0.3.6.3}/PKG-INFO +5 -5
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/README.md +4 -4
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/pyproject.toml +5 -4
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/assistant.py +24 -12
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/channels.py +9 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/cli.py +28 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/coder.py +61 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/concierge.py +25 -17
- taskuary-0.3.6.3/taskuary/connectorcatalog.json +2397 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/funnel.py +13 -5
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/funnel_selection.py +3 -9
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/general.py +6 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/ingest.py +50 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_all.py +1 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_unread.py +23 -4
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/remote_assistant.py +196 -60
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/reports.py +45 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/routing.py +5 -4
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/scopes.py +3 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/selfclose.py +19 -2
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/server.py +24 -4
- taskuary-0.3.6.3/taskuary/settings_schema.json +483 -0
- taskuary-0.3.6.3/taskuary/social.py +241 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/store.py +79 -26
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/agent.md +2 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/coder.md +4 -3
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/triage.md +5 -5
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/triage.py +37 -13
- taskuary-0.3.6.3/taskuary/triage_kind_rules.json +18 -0
- taskuary-0.3.6.2/taskuary/web/assets/HubView-BjL1r12I.js → taskuary-0.3.6.3/taskuary/web/assets/HubView-BiQkrYWk.js +1 -1
- taskuary-0.3.6.2/taskuary/web/assets/StudioScene-DXPO8NCz.js → taskuary-0.3.6.3/taskuary/web/assets/StudioScene-GfvlCIY_.js +1 -1
- taskuary-0.3.6.2/taskuary/web/assets/index-D5A7qNvG.js → taskuary-0.3.6.3/taskuary/web/assets/index-58W9N7HI.js +148 -148
- taskuary-0.3.6.2/taskuary/web/assets/index-Bsld__8Y.css → taskuary-0.3.6.3/taskuary/web/assets/index-Cpzoo5vC.css +1 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/index.html +2 -2
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/workerstate.py +5 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3/taskuary.egg-info}/PKG-INFO +5 -5
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary.egg-info/SOURCES.txt +15 -4
- taskuary-0.3.6.3/tests/test_agent_reply.py +101 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_api.py +2 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant.py +21 -3
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_blocks.py +17 -10
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_reactions.py +5 -4
- taskuary-0.3.6.3/tests/test_banner_is_one_rule.py +32 -0
- taskuary-0.3.6.3/tests/test_chat_echo_mail.py +73 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chatformat.py +2 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_core.py +3 -3
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_digest_brief.py +4 -4
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_docs_and_llm.py +9 -6
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_every_card_is_reachable.py +22 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_funnel.py +46 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_kind_dispatch.py +29 -3
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_lane_vocabulary.py +8 -2
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_morning_line.py +3 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_not_coding.py +8 -8
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_onboarding_walk.py +1 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_phone_walk_ux.py +58 -4
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_pypi_downloads.py +31 -2
- taskuary-0.3.6.3/tests/test_read_text.py +36 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_remote_assistant.py +7 -9
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reply_always_drafts.py +5 -5
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_order_and_research.py +1 -1
- taskuary-0.3.6.3/tests/test_same_failure_is_quiet.py +30 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_seeded_reports.py +41 -9
- taskuary-0.3.6.3/tests/test_social.py +263 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_the_exe_ships_what_the_wheel_ships.py +11 -5
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_urgent_and_handoff.py +1 -1
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_verdict_shape.py +14 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_walk_order.py +13 -7
- taskuary-0.3.6.3/tests/test_workerstate_said.py +19 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/LICENSE +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/setup.cfg +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/__init__.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/acp.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/agents.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/aidefaults.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/aisetup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/alchemy.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/appfacts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/artifacts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/assistantblocks.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/aws.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/azure.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/blackboard.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/brief.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/browserview.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/calendar.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/categories.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/chains.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/chatformat.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/chatservers.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/ci.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/cli_connections.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/cli_install_terminal.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/cliinstall.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/climodels.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/clis.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/clisetup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/compose.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/config.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/connectorcatalog.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/context.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/continuity.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/counsel.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/databases.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/db.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/demo.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/deps.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/desktop.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/devtools.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/digest.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/docsync.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/evalset.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/evening.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/files.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/funnel_presentation.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/github.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/guard.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/handbook.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/handraise.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/histgen.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/hooks.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/hub.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/images.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/imapmail.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/imessage.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/intacct.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/interview.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/invoice_workflow.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/jev.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/knowledge.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/lanes.json +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/learn.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/learnedgraph.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/linkedin.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/live.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/llm.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/logs.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/markets.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/mcp.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/messengers.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/msauth.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/mssql.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/operations.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/outbound.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/outbox.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/ownwork.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/phone.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/playbooks.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/pm.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/policy.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/problems.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_inventory.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_membership.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_navigation.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_order.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_projection.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_rail.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_reads.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/processing_startup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/projects.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/promptmap.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/proof.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/proposals.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/quickbooks.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/rank.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/redact.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/research.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/reshape.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/responder.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/retention.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/robinhood.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/routingmemory.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/semantic.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/senders.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/session_artifacts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/sessionfiles.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/settings_schema.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/setup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/sharepoint.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/sheets.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/simplefin.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/skillimport.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/skills/soul-interview/SKILL.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/skills/taskuary-setup/SKILL.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/spawn.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/teller.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/analyst.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/coordinator.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/counsel.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/digest.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/history/counsel-0.3.3.5.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/how-it-works.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/learned.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/marketer.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/playbook.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/profile.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/researcher.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/soul.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/style.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/templates/trader.md +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/terminal.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/testing.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/toil.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/toolcatalog.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/treg.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/update.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/verdicts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/voice.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/wabridge.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/waitroom.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/walk.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/favicon.ico +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/favicon.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/assistant.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/board.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/connections.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/docs.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/hub.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/reports.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/settings.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/web/walk/tasks.png +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/webguard.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/whatsapp/bridge.mjs +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/whatsapp/package.json +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/whatsapp/policy.mjs +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/whatsapp/policy.test.mjs +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/whatsapp/roster.mjs +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/whatsapp/roster.test.mjs +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/whoami.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/witness.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/workflows.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary/zoho.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary.egg-info/dependency_links.txt +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary.egg-info/entry_points.txt +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary.egg-info/requires.txt +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/taskuary.egg-info/top_level.txt +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_acp.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_agent_answer_route.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_agent_environment.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_agent_identity.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_agent_profiles.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_agent_sentence.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_agent_source.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_agent_wall.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_ai_defaults.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_aisetup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_alchemy.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_an_inbox_is_not_a_destination.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_answered_yourself.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_answers.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_api_worker_signals.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_app_uptime.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_appfacts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_approval_interrupt.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_acts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_can_look_things_up.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_doorways.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_ideas.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_notifications.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_opens.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_presentation.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_assistant_verdicts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_async_triage.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_audit_chain.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_audit_fixes.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_auto_start.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_aws_region.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_blackboard.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_brain_layer.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_brain_reaches_the_session.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_browser_session.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_browser_workflow.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_browserview.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_calendar.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_calendar_today.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_categories.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cc.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cc_triage.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_doors.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_freshness.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_is_not_one_task.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_proposals.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_queue.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_relationship.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_retention.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chat_setup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chatservers.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_chinese_clis.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_clean_context.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cli_connections.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cli_failure.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cli_install.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cli_install_terminal.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cli_on_fresh_path.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cli_setup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cli_update.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_climodels.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_clis.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cloud.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cloud_sources.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_coder_session_continuity.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_completion_freshness.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_compose.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_compose_sources.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_compose_workflows.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_concierge.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_concierge_counsel.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_config.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_context.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_context_refresh_freshness.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_coordination.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_correction_doors.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_counsel.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_counsel_consumers.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_counsel_migration.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_counsel_sections.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_current_restore.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_cwlogs_paging.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_databases.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_demo.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_deps.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_desktop.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_devin.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_devtools.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_diff_review.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_dispatch_retries.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_docs_flow.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_duplicate_connectors.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_email_chains.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_email_identity_routing.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_ending_a_run_writes_the_answer.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_evening_brief.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_every_cli_startable.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_explicit_completion.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_factory.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_feed_working.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_files.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_final_answer_capture.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_finished_chat_stays_finished.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_floating_assistant.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_follow_up_verdict.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_fresh_evaluation.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_freshness.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_freshness_walk.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_general.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_github_auto.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_github_images.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_guard.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_handbook.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_handbook_topics.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_handoff_channels.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_handraise.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_harvest.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_histgen.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_home_is_never_yours.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_hooks_events.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_hooks_version.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_ideas_triage.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_ignore_sender.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_ignore_sender_quiets_its_work.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_images.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_imap_catchup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_imap_history.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_imapmail.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_imessage.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_intacct.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_interrupted_work.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_invite_is_not_work.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_invoice_workflow.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_jev.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_judge_reads_the_conclusion.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_knowledge.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_learnedgraph.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_lifecycle.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_lifespan_loops_are_guarded.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_linkedin.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_linkedin_signin.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_live.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_local_file.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_mail_catchup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_mail_fetch_cost.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_mail_folders.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_mark_read.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_markets.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_mcp.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_meeting_prep.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_message_thread.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_messengers.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_msauth.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_mssql.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_muse.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_noop_ending.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_note_retrieval.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_one_app_one_reason.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_one_pty_one_geometry.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_only_your_own_thread.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_openai_compatible_brains.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_operations.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_outbound_reports.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_outbox.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_own_rows_no_reply.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_playbook_setup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_playbooks.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_pm.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_poll_lanes.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_poll_overlap.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_poll_parallel.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_poll_sources.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_pr_comments.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_problems.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_problems_dismiss.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_procedure_selection.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_processing_demo_replay.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_processing_ledger.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_profile_is_a_role.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_projects.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_prompt_sources.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_promptmap_and_catalog.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_proof_ci_proposals.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_quickbooks.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_qwen.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_rank.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_rate_limit.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_recent_closures.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reclassify.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_redact.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_redact_doors.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reply_attachments.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reply_channels.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reply_envelope.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reply_needs_a_correspondent.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reply_sources.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reply_voice.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_repo_choice_triage.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_alerts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_deliver.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_headline.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_prompt_isolation.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_reach.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_refusal.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_routing.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_report_triage.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_research.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_research_more.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_review_task.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_reviews.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_robinhood.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_routing_memory.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_s3_poll_paging.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_scopes.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_seed_fits_a_tty.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_selector_vocabulary.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_semantic.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_send_outcomes.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_send_targets.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_sender_trust.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_sender_words.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_session_artifacts.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_session_continuity.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_session_files.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_settings_schema.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_setup.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_setup_skill.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_setup_walk.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_sheets_sharepoint.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_simplefin.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_skillimport.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_someone_else_replied.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_soul_interview.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_startup_contract.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_stay_open.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_stay_open_doors.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_store_app_cli.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_store_hotpaths.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_store_pokes.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_sync_clock.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_task_ask.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_task_checklist.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_task_controls_operations.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_task_identity.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_teller.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_terminal.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_the_split_holds.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_toil.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_tracker_revisions.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_treg.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_triage_dataset.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_triage_errors.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_triage_images.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_triage_pr_rule.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_triage_retry_sweep.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_update.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_update_refused.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_verdict_paths.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_verdict_sticks.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_vision.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_voice.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_wabridge.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_wabridge_log_trim.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_waitroom.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_watermark.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_web_entrypoint.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_webguard.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_whatsapp_documents.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_whatsapp_images.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_whoami.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_why_not_started.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_withdrawn.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_witness.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_worker_brief.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_worker_events.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_worker_resumes.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_worker_scenarios.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_worker_surfaces.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_workflows.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_zz_chipverbs.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_zz_lastword.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_zz_setupchat.py +0 -0
- {taskuary-0.3.6.2 → taskuary-0.3.6.3}/tests/test_zz_toolcatalog.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: taskuary
|
|
3
|
-
Version: 0.3.6.
|
|
3
|
+
Version: 0.3.6.3
|
|
4
4
|
Summary: Automate your job - the local-first operating system for your work: AI triage in, coding agents out.
|
|
5
5
|
License: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/ldbumble/taskuary
|
|
@@ -69,7 +69,7 @@ Dynamic: license-file
|
|
|
69
69
|
|
|
70
70
|
[](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml)
|
|
71
71
|
[](https://scorecard.dev/viewer/?uri=github.com/ldbumble/taskuary)
|
|
72
|
-
[](https://pypi.org/project/taskuary/)
|
|
73
73
|
[](https://github.com/ldbumble/taskuary)
|
|
74
74
|
[](LICENSE)
|
|
75
75
|
[](https://github.com/ldbumble/taskuary/stargazers)
|
|
@@ -83,7 +83,7 @@ your agents, and brings decisions back to you. Nothing sends or ships without yo
|
|
|
83
83
|
|
|
84
84
|

|
|
85
85
|
|
|
86
|
-
Taskuary is early—currently **v0.3.6.
|
|
86
|
+
Taskuary is early—currently **v0.3.6.3**—so breaking changes are still possible before 1.0.
|
|
87
87
|
|
|
88
88
|
<p align="center">
|
|
89
89
|
<a href="https://taskuary.com/demo/"><img
|
|
@@ -270,10 +270,10 @@ outside systems, send messages, run tools, or start agents. Its changes reset wh
|
|
|
270
270
|
|
|
271
271
|
## Installs
|
|
272
272
|
|
|
273
|
-

|
|
274
274
|
|
|
275
275
|
Updated daily from PyPI with mirror traffic excluded. The raw series is
|
|
276
|
-
[
|
|
276
|
+
[downloads.csv on the `stats` branch](https://github.com/ldbumble/taskuary/blob/stats/downloads.csv).
|
|
277
277
|
|
|
278
278
|
## Documentation
|
|
279
279
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
[](https://github.com/ldbumble/taskuary/actions/workflows/ci.yml)
|
|
6
6
|
[](https://scorecard.dev/viewer/?uri=github.com/ldbumble/taskuary)
|
|
7
|
-
[](https://pypi.org/project/taskuary/)
|
|
8
8
|
[](https://github.com/ldbumble/taskuary)
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
[](https://github.com/ldbumble/taskuary/stargazers)
|
|
@@ -18,7 +18,7 @@ your agents, and brings decisions back to you. Nothing sends or ships without yo
|
|
|
18
18
|
|
|
19
19
|

|
|
20
20
|
|
|
21
|
-
Taskuary is early—currently **v0.3.6.
|
|
21
|
+
Taskuary is early—currently **v0.3.6.3**—so breaking changes are still possible before 1.0.
|
|
22
22
|
|
|
23
23
|
<p align="center">
|
|
24
24
|
<a href="https://taskuary.com/demo/"><img
|
|
@@ -205,10 +205,10 @@ outside systems, send messages, run tools, or start agents. Its changes reset wh
|
|
|
205
205
|
|
|
206
206
|
## Installs
|
|
207
207
|
|
|
208
|
-

|
|
209
209
|
|
|
210
210
|
Updated daily from PyPI with mirror traffic excluded. The raw series is
|
|
211
|
-
[
|
|
211
|
+
[downloads.csv on the `stats` branch](https://github.com/ldbumble/taskuary/blob/stats/downloads.csv).
|
|
212
212
|
|
|
213
213
|
## Documentation
|
|
214
214
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "taskuary"
|
|
7
|
-
version = "0.3.6.
|
|
7
|
+
version = "0.3.6.3"
|
|
8
8
|
description = "Automate your job - the local-first operating system for your work: AI triage in, coding agents out."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -71,10 +71,11 @@ include = ["taskuary*"]
|
|
|
71
71
|
[tool.setuptools.package-data]
|
|
72
72
|
# whatsapp/ too: the bridge error tells you to run `node bridge.mjs` out of the package, and
|
|
73
73
|
# a pip install without it is an instruction pointing at a directory that does not exist.
|
|
74
|
-
#
|
|
75
|
-
#
|
|
74
|
+
# *.json: every data file at the package root is read at runtime - lanes.json is the ONE lane
|
|
75
|
+
# vocabulary, and triage_kind_rules.json, settings_schema.json and connectorcatalog.json were all
|
|
76
|
+
# missing from the wheel once (the container died on the first; 2026-09-23). Name them by glob.
|
|
76
77
|
# A GLOB HERE DOES NOT CROSS A DIRECTORY SEPARATOR: `web/*` matches nothing inside `web/assets/`,
|
|
77
78
|
# which is why that line exists - and `web/walk/*` had to be added after the setup walk's nine
|
|
78
79
|
# screenshots shipped broken. Every new subdirectory under web/ needs its own line, or its files
|
|
79
80
|
# are simply absent from the wheel while the repo tree looks right.
|
|
80
|
-
taskuary = ["
|
|
81
|
+
taskuary = ["*.json", "web/*", "web/assets/*", "web/walk/*", "templates/*.md", "templates/history/*.md", "skills/*/*.md", "whatsapp/*"]
|
|
@@ -25,7 +25,7 @@ it brings in until it says something useful and surprising"). Handed only subjec
|
|
|
25
25
|
wrote 'no content given' in its own notes; so the check now reads WHAT PEOPLE SAID (the words of every
|
|
26
26
|
human thread of the last two days, the owner's lines marked), who is OUT OF OFFICE (from auto-replies -
|
|
27
27
|
a chase to someone away is worse than silence), the CALENDAR, and the actual words in every rolled-up
|
|
28
|
-
arrival (including machine mail), with each report's schedule and each failure's cause beside the count. That is where "Yittie said exporting freezes the
|
|
28
|
+
arrival (including machine mail), with each report's schedule, when it last ran and what that run did, and each failure's cause beside the count. That is where "Yittie said exporting freezes the
|
|
29
29
|
app - and she is in Monday's meeting" comes from.
|
|
30
30
|
|
|
31
31
|
It also leaves itself a NOTE: each check ends with what it looked at and found nothing in, when
|
|
@@ -503,7 +503,7 @@ def blk_label(bid: str) -> str:
|
|
|
503
503
|
# ── the model's pass: its own read, given what it already said ───────────────────────────────
|
|
504
504
|
CONTRACT = ('\n\nYou are writing your POST on the owner\'s Timeline - the short list of things worth saying right now. You get '
|
|
505
505
|
'CANDIDATES the hub found itself (each with a key), WHAT PEOPLE SAID (the words, by thread), who is OUT OF OFFICE, the '
|
|
506
|
-
'CALENDAR, what arrived (with each report\'s schedule and each failure\'s cause), what got done, what is open, and WHAT '
|
|
506
|
+
'CALENDAR, what arrived (with each report\'s schedule, when it last ran and what that run did, and each failure\'s cause), what got done, what is open, and WHAT '
|
|
507
507
|
'YOU ALREADY SAID. Answer JSON only: {"say": [{"key": "<a candidate key, or idea:<short-slug> for a thought of your own>", '
|
|
508
508
|
'"text": "<one line, under 30 words, first person: the fact and what I would do - quote the phrase or name the cause when there is one>", '
|
|
509
509
|
'"section": "<people|loose|ideas|systems - which part of the post this belongs under: people = what somebody said '
|
|
@@ -536,14 +536,26 @@ def _schedules(store) -> dict:
|
|
|
536
536
|
nothing without its clock: 25 digests in two days on an on_startup report is 25 launches, not a
|
|
537
537
|
scheduler bug, and two seeded reports at one timestamp is one launch, not a restart to explain."""
|
|
538
538
|
from . import reports
|
|
539
|
-
out = {}
|
|
539
|
+
out, st = {}, store.get_settings()
|
|
540
540
|
for src in store.list_sources(active_only=False):
|
|
541
541
|
if src.get('Channel') != 'report': continue
|
|
542
542
|
try: c = json.loads(src.get('ConfigJson') or '{}')
|
|
543
543
|
except ValueError: continue
|
|
544
|
-
out[c.get('title') or src.get('Address')] = reports.schedule_words(c)
|
|
544
|
+
out[c.get('title') or src.get('Address')] = reports.schedule_words(c) + _last_run(st, src)
|
|
545
545
|
return out
|
|
546
546
|
|
|
547
|
+
def _last_run(settings: dict, src: dict) -> str:
|
|
548
|
+
"""'; last ran Tue 22 Sep 20:37, nothing to report so nothing was filed' - or ''. The clock alone
|
|
549
|
+
misled: a routed report whose judge holds a run back files NO message, so the newest mid read as
|
|
550
|
+
the last firing and a 140-minute timer looked stalled two runs after it fired on time (TQ-0685).
|
|
551
|
+
The run record on the source (reports.LAST_RUN) is the receipt the arrivals cannot carry."""
|
|
552
|
+
from .reports import LAST_RUN
|
|
553
|
+
try: rec = json.loads(settings.get(f"{LAST_RUN}{src['SourceId']}") or '{}')
|
|
554
|
+
except (ValueError, TypeError): rec = {}
|
|
555
|
+
if not rec.get('at'): return ''
|
|
556
|
+
what = 'failed' if rec.get('failed') else f"posted mid {rec['message_id']}" if rec.get('message_id') else 'nothing to report so nothing was filed'
|
|
557
|
+
return f"; last ran {_when(rec['at'])}, {what}"
|
|
558
|
+
|
|
547
559
|
_FAILS = re.compile(r'fail|error|denied|timeout|could not|unable', re.I)
|
|
548
560
|
_GH_FAILED = re.compile(r'^(.+?) Failed in ', re.M) # the job lines of GitHub's "Run failed" mail
|
|
549
561
|
def _cause(r: dict) -> str:
|
|
@@ -852,7 +864,7 @@ def system_checks(store, source_ids=None, inline=None) -> str:
|
|
|
852
864
|
ids = saved if source_ids is None else _ids(source_ids)
|
|
853
865
|
subs = own if inline is None else _inline(inline)
|
|
854
866
|
if not ids and not subs:
|
|
855
|
-
return '(none selected - add a data source, or choose saved data views, on Reports ->
|
|
867
|
+
return '(none selected - add a data source, or choose saved data views, on Reports -> Advisor)'
|
|
856
868
|
from . import reports
|
|
857
869
|
found = {s['SourceId']: s for s in store.list_sources(active_only=False) if s.get('Channel') == 'report'}
|
|
858
870
|
jobs = [] # (title, cfg to render, or a note to print instead)
|
|
@@ -862,7 +874,7 @@ def system_checks(store, source_ids=None, inline=None) -> str:
|
|
|
862
874
|
try: cfg_ = json.loads(src.get('ConfigJson') or '{}')
|
|
863
875
|
except ValueError: cfg_ = {}
|
|
864
876
|
title = str(cfg_.get('title') or src.get('Address') or f'report {sid}')
|
|
865
|
-
if cfg_.get('type') == 'assistant': jobs.append((title, None, 'Skipped: an
|
|
877
|
+
if cfg_.get('type') == 'assistant': jobs.append((title, None, 'Skipped: an Advisor cannot watch itself.'))
|
|
866
878
|
else: jobs.append((title, cfg_, None))
|
|
867
879
|
for i, sub in enumerate(subs, 1):
|
|
868
880
|
jobs.append((str(sub.get('label') or sub.get('title') or '').strip() or f"{sub.get('type')} #{i}", sub, None))
|
|
@@ -1166,10 +1178,10 @@ def _idea_message(store, i: dict, a: dict, report_title=None) -> tuple:
|
|
|
1166
1178
|
active = bool(task and task.get('Status') in ('open', 'in_progress', 'waiting'))
|
|
1167
1179
|
working = bool(active and any(r.get('Status') == 'running' for r in store.list_runs(tid)))
|
|
1168
1180
|
stamp = i.get('LastSaid') or i.get('FirstSeen') or datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
1169
|
-
who = report_title or '
|
|
1181
|
+
who = report_title or 'Advisor'
|
|
1170
1182
|
# one arrival per idea: the stamp in the id made every re-say a fresh message, and a fresh task once the first closed
|
|
1171
1183
|
msg = {'external_id': f"idea:{i['IdeaId']}", 'channel': CHANNEL, 'from_name': who, 'source_name': who,
|
|
1172
|
-
'conversation_id': str(i.get('Key') or f"idea:{i['IdeaId']}"), 'subject': f"
|
|
1184
|
+
'conversation_id': str(i.get('Key') or f"idea:{i['IdeaId']}"), 'subject': f"Advisor idea: {_cut(i.get('Text'), 100)}",
|
|
1173
1185
|
'sent_at': stamp, 'body': str(i.get('Text') or '') + (f"\n\nwhy: {a.get('why')}" if a.get('why') else ''),
|
|
1174
1186
|
'idea_context': {'report': report_title, 'kind': i.get('Kind'),
|
|
1175
1187
|
'linked_task': f"{task_ref(tid)} [{task.get('Status')}] {_short(task.get('Title'), 80)}" if task else None,
|
|
@@ -1448,7 +1460,7 @@ def _run(store, llm, instruction, watch_source_ids, watch_sources, systems_only=
|
|
|
1448
1460
|
if systems_only and not (_ids(watch_source_ids) or _inline(watch_sources)):
|
|
1449
1461
|
why = ('this report reads nothing: no Taskuary block is ticked and no data source is chosen '
|
|
1450
1462
|
'- tick a block, or choose a source, on the report')
|
|
1451
|
-
logger.warning(f"assistant: {report_title or '
|
|
1463
|
+
logger.warning(f"assistant: {report_title or 'Advisor'} ran and read nothing - {why}")
|
|
1452
1464
|
return {'ran': True, 'said': 0, 'reads_nothing': True, 'summary': why, 'inputs': '',
|
|
1453
1465
|
'reviewed': {'notes': '', 'scope': 'nothing', 'systems': 0, 'why': why}}
|
|
1454
1466
|
state = {i['Key']: i for i in store.list_ideas()}
|
|
@@ -1522,7 +1534,7 @@ def _run(store, llm, instruction, watch_source_ids, watch_sources, systems_only=
|
|
|
1522
1534
|
# chose "every run", in which case the check still says it ran, in one line, with what it
|
|
1523
1535
|
# read behind it. A setting that promises every run and then shows nothing is a lie.
|
|
1524
1536
|
if not always_post: return {'ran': True, 'said': 0, 'reviewed': rv, 'inputs': read}
|
|
1525
|
-
who = (report_title or '
|
|
1537
|
+
who = (report_title or 'Advisor') if own_post else 'Advisor'
|
|
1526
1538
|
me = f'assistant:{report_id}' if own_post else 'assistant'
|
|
1527
1539
|
mid = store.add_message({'TaskId': None, 'ExternalId': f'{me}:{stamp}', 'ConversationId': me, 'Channel': CHANNEL,
|
|
1528
1540
|
'SourceName': who, 'Subject': f'{who} - nothing to report', 'FromName': who,
|
|
@@ -1551,7 +1563,7 @@ def _run(store, llm, instruction, watch_source_ids, watch_sources, systems_only=
|
|
|
1551
1563
|
head = rows[0]['Text'] if len(rows[0]['Text']) <= 90 else rows[0]['Text'][:90].rsplit(' ', 1)[0] + '…'
|
|
1552
1564
|
subj = head + (f' (+{len(rows) - 1} more)' if len(rows) > 1 else '')
|
|
1553
1565
|
identity = f'assistant:{report_id}' if own_post else 'assistant'
|
|
1554
|
-
name = (report_title or '
|
|
1566
|
+
name = (report_title or 'Advisor') if own_post else 'Advisor'
|
|
1555
1567
|
mid = store.add_message({'TaskId': None, 'ExternalId': f'{identity}:{stamp}', 'ConversationId': identity, 'Channel': CHANNEL,
|
|
1556
1568
|
'SourceName': name, 'Subject': subj, 'FromName': name, 'SentAt': stamp,
|
|
1557
1569
|
'BodyText': body, 'Status': 'feed'})
|
|
@@ -1623,7 +1635,7 @@ def act(store, idea_id: int, verb: str, actor: str = 'owner', llm=None, days: in
|
|
|
1623
1635
|
# This is NEW work noticed after an earlier task was completed. A message can point
|
|
1624
1636
|
# at only one task, so do not steal it from history or rename/reopen the completed
|
|
1625
1637
|
# task. Carry the evidence into a fresh assistant-owned task instead.
|
|
1626
|
-
title = str(a.get('title') or i.get('Text') or '
|
|
1638
|
+
title = str(a.get('title') or i.get('Text') or 'Advisor follow-up').strip()[:200]
|
|
1627
1639
|
source_text = str(message.get('BodyText') or '').strip()
|
|
1628
1640
|
summary = str(i.get('Text') or '').strip()
|
|
1629
1641
|
if source_text and source_text not in summary: summary += f'\n\nSource message: {source_text}'
|
|
@@ -336,6 +336,15 @@ def test_connector(store, cid: int) -> dict:
|
|
|
336
336
|
elif c['Type'] == 'robinhood':
|
|
337
337
|
from . import robinhood
|
|
338
338
|
detail = robinhood.test(store, c)
|
|
339
|
+
elif c['Type'] in ('bluesky', 'mastodon'):
|
|
340
|
+
# whoami, like LinkedIn: the one call that proves the credential AND comes back
|
|
341
|
+
# with something the owner recognises. Posting would be a strange thing for Test.
|
|
342
|
+
from .reports import REGISTRY, resolve_cfg
|
|
343
|
+
rtype = f"{c['Type']}_me"
|
|
344
|
+
out = REGISTRY[rtype](resolve_cfg(store, {'type': rtype}))
|
|
345
|
+
row = (out.get('rows') or [{}])[0]
|
|
346
|
+
detail = (f"signed in as {row.get('handle') or '?'}"
|
|
347
|
+
f" - {row.get('followers')} followers, {row.get('posts')} posts")
|
|
339
348
|
elif c['Type'] == 'linkedin':
|
|
340
349
|
# whoami, which is the one call that proves the token AND returns something the
|
|
341
350
|
# owner recognises - a post would be a strange thing for a Test button to do
|
|
@@ -122,6 +122,11 @@ def main():
|
|
|
122
122
|
'this transcript, and draft the reply the sender gets (you are not '
|
|
123
123
|
'sending it - the owner approves it). Give one sentence on what you did '
|
|
124
124
|
'or found. Do not run this while waiting on the owner.')
|
|
125
|
+
ap.add_argument('--reply', metavar='TEXT',
|
|
126
|
+
help="write the reply the person who asked will get, in your own words - it becomes this "
|
|
127
|
+
"task's pending reply for the owner to approve (you are not sending it), and "
|
|
128
|
+
"finishing keeps it instead of redrafting. Use - to read it from stdin.")
|
|
129
|
+
ap.add_argument('--reply-file', metavar='PATH', help='--reply, read from a file (for a long or multi-line reply)')
|
|
125
130
|
args = ap.parse_args()
|
|
126
131
|
if args.demo:
|
|
127
132
|
import os, tempfile
|
|
@@ -133,6 +138,29 @@ def main():
|
|
|
133
138
|
# --done goes over HTTP, unlike --note. A note is a database row and any process can write
|
|
134
139
|
# one; ENDING a task needs the live session's scrollback, which exists only inside the
|
|
135
140
|
# running server - this process would find no transcript and wrap an empty one.
|
|
141
|
+
if args.reply is not None or args.reply_file:
|
|
142
|
+
import os, sys, requests
|
|
143
|
+
try: sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
144
|
+
except (AttributeError, OSError): pass
|
|
145
|
+
tid = os.environ.get('TASKUARY_TASK')
|
|
146
|
+
if not str(tid).isdigit():
|
|
147
|
+
print('not in a Taskuary session - TASKUARY_TASK is not set, so there is no task to reply on')
|
|
148
|
+
return
|
|
149
|
+
if args.reply_file: text = open(args.reply_file, encoding='utf-8').read()
|
|
150
|
+
else: text = sys.stdin.read() if args.reply == '-' else args.reply
|
|
151
|
+
srv = config.load()['server']
|
|
152
|
+
host = '127.0.0.1' if srv.get('host') in ('0.0.0.0', '::', '', None) else srv['host']
|
|
153
|
+
base = f"http://{host}:{srv.get('port') or 7787}"
|
|
154
|
+
hdr = {'X-Taskuary-Token': srv['token']} if srv.get('token') else {}
|
|
155
|
+
try:
|
|
156
|
+
r = requests.post(f'{base}/api/agent/reply', timeout=60, headers=hdr,
|
|
157
|
+
json={'task_id': int(tid), 'text': text, 'agent': os.environ.get('TASKUARY_AGENT') or 'agent'})
|
|
158
|
+
out = r.json() if r.headers.get('content-type', '').startswith('application/json') else {}
|
|
159
|
+
except Exception as e:
|
|
160
|
+
print(f'could not reach Taskuary at {base}: {e}'); return
|
|
161
|
+
print('reply saved on the task, waiting on the owner to approve and send it.' if out.get('ok')
|
|
162
|
+
else f"not saved: {out.get('why') or out.get('detail') or r.text[:200]}")
|
|
163
|
+
return
|
|
136
164
|
if args.done is not None:
|
|
137
165
|
import os, sys, requests
|
|
138
166
|
try: sys.stdout.reconfigure(encoding='utf-8', errors='replace')
|
|
@@ -105,6 +105,50 @@ def reply_target(store, task_id: int):
|
|
|
105
105
|
return next((m['MessageId'] for m in reversed(store.list_messages(task_id)) if m.get('Status') != 'context'), None)
|
|
106
106
|
|
|
107
107
|
|
|
108
|
+
# ── the agent's own words ───────────────────────────────────────────────────────────────
|
|
109
|
+
# The agent that did the work often writes the better answer: it knows what it found, and a second
|
|
110
|
+
# model redrafting from its transcript loses the nuance (the owner, 2026-09-23: "sometimes the agent
|
|
111
|
+
# that did the work is better for response than another ai generating it based off of transcript").
|
|
112
|
+
# It used to have no way to hand that answer over - it asked "should I draft the reply?", wrote it
|
|
113
|
+
# on its own screen, and the task's reply stayed empty until the responder wrote a different one.
|
|
114
|
+
# Now it says so: `taskuary --reply` (a shell) or a [[TASKUARY-REPLY]] block (the general chat), the
|
|
115
|
+
# text becomes the task's pending reply as written, and the end of the run keeps it.
|
|
116
|
+
AGENT_DRAFT = 'agent:'
|
|
117
|
+
|
|
118
|
+
def agent_drafted(rv) -> bool:
|
|
119
|
+
return bool(rv) and str(rv.get('DraftBy') or '').startswith(AGENT_DRAFT) and bool(str(rv.get('DraftText') or '').strip())
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def own_draft(store, task_id: int):
|
|
123
|
+
"""The pending reply the agent wrote itself, if there is one."""
|
|
124
|
+
return next((r for r in (store.pending_review(task_id, 'draft_reply', live_only=False),
|
|
125
|
+
store.pending_review(task_id, 'draft', live_only=False)) if agent_drafted(r)), None)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def agent_reply(store, task_id: int, text: str, agent: str = 'agent', run_id: int = None) -> dict:
|
|
129
|
+
"""Put the agent's reply on the task as the pending draft - the same review the responder would
|
|
130
|
+
write into (held, live or new; one per answer, PW-236), marked as the agent's. Nothing is sent:
|
|
131
|
+
the owner approves it like every other reply."""
|
|
132
|
+
text = str(text or '').strip()
|
|
133
|
+
if not text: return {'ok': False, 'why': 'no reply text'}
|
|
134
|
+
held = store.held_review(task_id) or {}
|
|
135
|
+
mid = reply_target(store, task_id) or held.get('MessageId')
|
|
136
|
+
if not mid: return {'ok': False, 'why': 'nobody is waiting on a reply on this task - there is no one to draft it to'}
|
|
137
|
+
live = None if held else (store.pending_review(task_id, 'draft_reply', live_only=False) or store.pending_review(task_id, 'draft', live_only=False))
|
|
138
|
+
why = f'{agent} wrote this reply in its session - approve to send'
|
|
139
|
+
if held:
|
|
140
|
+
rid = held['ReviewId']; store.unhold_review(rid, why)
|
|
141
|
+
elif live:
|
|
142
|
+
rid = live['ReviewId']; store.update_review_reason(rid, why, run_id)
|
|
143
|
+
else:
|
|
144
|
+
rid = store.add_review({'TaskId': task_id, 'MessageId': mid, 'RunId': run_id, 'Kind': 'draft_reply', 'Status': 'pending', 'Reason': why})
|
|
145
|
+
rv = store.get_review(rid) or {}
|
|
146
|
+
if rv.get('MessageId') != mid: store.update_review_message(rid, mid)
|
|
147
|
+
store.update_review_draft(rid, text, run_id or rv.get('RunId'), by=AGENT_DRAFT + agent)
|
|
148
|
+
store.add_comment(task_id, agent, 'agent', f'{agent} drafted the reply itself - it is on the task, waiting on your approval.')
|
|
149
|
+
return {'ok': True, 'review_id': rid, 'message_id': mid}
|
|
150
|
+
|
|
151
|
+
|
|
108
152
|
# ── the cheap ending ────────────────────────────────────────────────────────────────────
|
|
109
153
|
# Almost everything a keyboard can do goes to the coding agent (the owner's rule), and the
|
|
110
154
|
# whole bargain is that an agent with nothing to do says "nothing to do here" and stops CHEAPLY.
|
|
@@ -213,7 +257,7 @@ def finish(store, task_id: int, rep: dict, run_id: int = None, actor: str = 'cod
|
|
|
213
257
|
# nobody can send does not hold a task the owner just closed
|
|
214
258
|
if owner_done and mid and not can_send: mid = None
|
|
215
259
|
# a held draft is proof somebody IS waiting on an answer, so it is never quietly dropped here
|
|
216
|
-
if mid and not held and nobody_waiting(store, mid, rep):
|
|
260
|
+
if mid and not held and not own_draft(store, task_id) and nobody_waiting(store, mid, rep):
|
|
217
261
|
store.add_comment(task_id, actor, 'agent', 'Nothing needed doing here and the sender is not waiting on an '
|
|
218
262
|
'answer - filed with the report, no reply drafted.')
|
|
219
263
|
mid = None
|
|
@@ -432,6 +476,16 @@ def raise_reply(store, task_id: int, mid: int, run_id: int, rep: dict,
|
|
|
432
476
|
rid = store.add_review({'TaskId': task_id, 'MessageId': mid, 'RunId': run_id, 'Kind': 'draft_reply', 'Status': 'pending',
|
|
433
477
|
'Reason': why if fresh.get('state') in ('changed', 'unresolved') else 'coder finished the work - reply awaiting approval'})
|
|
434
478
|
if (held or live) and (held or live).get('MessageId') != mid: store.update_review_message(rid, mid)
|
|
479
|
+
rv = store.get_review(rid) or {}
|
|
480
|
+
if agent_drafted(rv):
|
|
481
|
+
# the agent that did the work wrote this reply itself (agent_reply): its words stand and no second
|
|
482
|
+
# model rewrites them - only a thread that moved on (or could not be checked) is flagged for a reread
|
|
483
|
+
who = str(rv.get('DraftBy'))[len(AGENT_DRAFT):] or 'the agent'
|
|
484
|
+
store.update_review_reason(rid, f"{who}'s own reply from the session - approve to send"
|
|
485
|
+
+ (' (the thread moved on after it was written - reread it)' if fresh.get('state') == 'changed' else ''), run_id)
|
|
486
|
+
if fresh.get('state') in ('changed', 'unresolved'): store.mark_review_stale(rid)
|
|
487
|
+
_notify_done(store, task_id, rid)
|
|
488
|
+
return
|
|
435
489
|
src = complete_result or resolution_text(rep)
|
|
436
490
|
if fresh.get('state') == 'changed' and fresh.get('latest'):
|
|
437
491
|
l = fresh['latest']
|
|
@@ -450,6 +504,10 @@ def raise_reply(store, task_id: int, mid: int, run_id: int, rep: dict,
|
|
|
450
504
|
except Exception as e: logger.warning(f'reply draft failed for task {task_id}: {e}')
|
|
451
505
|
# a refresh that failed is an unresolved freshness state the owner sees: the draft waits, stale, for one that succeeds
|
|
452
506
|
if fresh.get('state') == 'unresolved': store.mark_review_stale(rid)
|
|
507
|
+
_notify_done(store, task_id, rid)
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
def _notify_done(store, task_id: int, rid: int) -> None:
|
|
453
511
|
# the ping that matters most: work FINISHED and its reply is sitting on the task on you
|
|
454
512
|
if (store.get_settings().get('notify_level') or 'needs_me') != 'off':
|
|
455
513
|
from .outbound import notify
|
|
@@ -463,3 +521,5 @@ def raise_reply(store, task_id: int, mid: int, run_id: int, rep: dict,
|
|
|
463
521
|
try: notify(store, f'{task_ref(task_id)} is done - the reply is drafted and waiting on '
|
|
464
522
|
f'your approval on the task.\n{head}{tail}')
|
|
465
523
|
except Exception as e: logger.warning(f'notify failed for task {task_id}: {e}')
|
|
524
|
+
|
|
525
|
+
|
|
@@ -67,7 +67,7 @@ CHIP_WORDS = {'approve': 'Send the reply', 'redraft': 'Redraft it', 'reply': 'Re
|
|
|
67
67
|
'not_ours_sender': 'Ignore this sender', 'block_sender': 'Block them in Settings',
|
|
68
68
|
'archive': 'Archive it', 'close': 'Close the task',
|
|
69
69
|
'done': 'Handled', 'later': 'Later', 'skip': 'Tomorrow', 'next': 'Next', 'answer_agent': 'Answer it',
|
|
70
|
-
'stop_agent': '
|
|
70
|
+
'stop_agent': 'Save and end session', 'rerun': 'Run it again', 'split': 'Split it in two',
|
|
71
71
|
'prep': 'Prep me', 'followup': 'Draft a follow-up'}
|
|
72
72
|
# What the word will actually DO, on hover - written where the difference matters. "Ignore this
|
|
73
73
|
# sender" and "Block them in Settings" are one line apart and not remotely the same act.
|
|
@@ -78,10 +78,12 @@ CHIP_HINTS = {'not_ours_sender': 'Their mail keeps arriving and stays readable -
|
|
|
78
78
|
'mine': "Your own list - no agent starts", 'next': 'Read it and move on'}
|
|
79
79
|
# per kind, in the order they are offered. `next` is last on every one of them: moving on is always available,
|
|
80
80
|
# and it is the one word that is never a decision about the thing itself.
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
# `skip` (Tomorrow) on the kinds that come back after the hour: passing one with Next returns it in an
|
|
82
|
+
# hour, and Tomorrow is how to silence it until the morning instead (2026-09-23)
|
|
83
|
+
CHIPS = {'review': ('approve', 'close', 'redraft', 'not_ours', 'skip', 'next'), 'action': ('approve', 'not_ours', 'skip', 'next'),
|
|
84
|
+
'agent': ('answer_agent', 'stop_agent', 'skip', 'next'), 'meeting': ('prep', 'regular_agent', 'next'),
|
|
83
85
|
'report': ('rerun', 'regular_agent', 'next'), 'agentdone': ('close', 'reply', 'next'),
|
|
84
|
-
'wrapup': ('close', 'next'), 'idea': ('followup', 'mine', 'done', 'next'), 'task': ('close', 'next'),
|
|
86
|
+
'wrapup': ('close', 'next'), 'idea': ('followup', 'mine', 'done', 'next'), 'task': ('close', 'skip', 'next'),
|
|
85
87
|
'asked': ('reply', 'regular_agent', 'coder', 'mine', 'not_ours', 'not_ours_sender', 'next'),
|
|
86
88
|
'todo': ('reply', 'regular_agent', 'coder', 'mine', 'not_ours', 'not_ours_sender', 'next'),
|
|
87
89
|
'fyi': ('not_ours', 'not_ours_sender', 'block_sender', 'mine', 'next'),
|
|
@@ -1894,11 +1896,14 @@ PROPOSALS = {
|
|
|
1894
1896
|
'close': ('task.complete', 'Close the task', True), 'done': ('item.settle', 'Mark it handled', True),
|
|
1895
1897
|
'later': ('item.settle', 'Push it back', True), 'skip': ('item.settle', 'Skip until tomorrow', True),
|
|
1896
1898
|
'approve': ('review.approve', 'Send the reply', True), 'answer_agent': ('agent.answer', 'Send the answer to the agent', True),
|
|
1897
|
-
'stop_agent': ('agent.stop', '
|
|
1899
|
+
'stop_agent': ('agent.stop', 'Save and end session', False), 'rerun': ('report.rerun', 'Run the report again', True),
|
|
1898
1900
|
'remember': ('memory.remember', 'Remember it', False), 'split': ('task.split', 'Split it in two', False),
|
|
1899
1901
|
'clear': ('pipe.clear', 'Clear them from the pipe', False), 'setup': ('task.setup', 'Open the walk-through', False),
|
|
1900
1902
|
}
|
|
1901
|
-
|
|
1903
|
+
# ...and ending the agent's session, which the task page's own button does on the click: it writes the
|
|
1904
|
+
# session up and drafts the reply for your yes - nothing leaves (the owner, 2026-09-23: "it should be save
|
|
1905
|
+
# end session as well same as in task", having been asked to confirm a card that read "wrap: false")
|
|
1906
|
+
AUTO = ('done', 'skip', 'later', 'close', 'stop_agent') # settles what is on the table; nothing leaves, nothing is handed off
|
|
1902
1907
|
# the operations that take the item off the table, so the walk moves on after them (the page reads
|
|
1903
1908
|
# `settles` off the proposal it is holding; a chat comes back a turn later and has only the kind)
|
|
1904
1909
|
SETTLING_KINDS = frozenset(kind for kind, _label, settles in PROPOSALS.values() if settles)
|
|
@@ -2031,12 +2036,15 @@ def propose_for(store, dock_tid: int, decision: dict, item: dict | None, text: s
|
|
|
2031
2036
|
elif verb == 'stop_agent':
|
|
2032
2037
|
end = _agent_task(store, item, text)
|
|
2033
2038
|
if not end: raise ValueError('no agent is running right now - nothing to stop')
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2039
|
+
# THE TASK PAGE'S "Save and end session", whatever the words: the session is written up whenever
|
|
2040
|
+
# there is a transcript to write it from (a wrap writes the report FROM it), and simply ended when
|
|
2041
|
+
# there is none. It used to write up only on the word "wrap" - so the button stopped an agent and
|
|
2042
|
+
# threw its work away, where the page's button of the same meaning kept it.
|
|
2043
|
+
asked_wrap = bool(re.search(r"\b(wrap|finished|it'?s done)\b", text, re.I))
|
|
2044
|
+
from . import terminal as term
|
|
2045
|
+
try: wrap = bool((term.transcript_for(store, end) or ('',))[0].strip())
|
|
2046
|
+
except Exception: wrap = False
|
|
2047
|
+
target, params = end, {'wrap': wrap}
|
|
2040
2048
|
if asked_wrap and not wrap: note = ' There is no transcript to write a report from yet, so there is nothing to wrap - this stops the agent and the task stays open.'
|
|
2041
2049
|
elif verb == 'rerun': target = it.get('source_id')
|
|
2042
2050
|
elif verb == 'remember':
|
|
@@ -2063,7 +2071,7 @@ def propose_for(store, dock_tid: int, decision: dict, item: dict | None, text: s
|
|
|
2063
2071
|
head = f"Changed to: {label} - {summary}" if op['version'] > 1 else f"{label}: {summary}"
|
|
2064
2072
|
say_ = lead + f"{head}.{note} Nothing has been started - confirm below, or tell me what to change."
|
|
2065
2073
|
return {**op, 'verb': verb, 'label': label, 'summary': summary, 'settles': bool(settles and not elsewhere),
|
|
2066
|
-
'key': it.get('key'), 'ref': it.get('ref'), 'tid': it.get('tid'), 'say': say_}
|
|
2074
|
+
'key': it.get('key'), 'ref': it.get('ref'), 'tid': it.get('tid'), 'say': say_, 'note': note.strip()}
|
|
2067
2075
|
|
|
2068
2076
|
|
|
2069
2077
|
def propose_direct(store, verb: str, key: str, text: str = '', actor: str = 'owner', table: bool = False) -> dict:
|
|
@@ -2082,7 +2090,7 @@ def propose_direct(store, verb: str, key: str, text: str = '', actor: str = 'own
|
|
|
2082
2090
|
record_related(store, tid, item, 'user', f"{PROPOSALS[verb][1]}: {item.get('title') or item.get('ref') or key}")
|
|
2083
2091
|
prop = propose_for(store, tid, {'verb': verb, 'text': text or ''}, item, text or '', actor, table=item if table else None)
|
|
2084
2092
|
prop['settles'] = bool(table and PROPOSALS[verb][2])
|
|
2085
|
-
if table and verb in AUTO: prop.update(auto=True, say=f"{prop['label']} - {_where(item)}.")
|
|
2093
|
+
if table and verb in AUTO: prop.update(auto=True, say=f"{prop['label']} - {_where(item)}." + (f" {prop['note']}" if prop.get('note') else ''))
|
|
2086
2094
|
record_related(store, tid, item, 'assistant', prop['say'], {'kind': 'proposal', 'key': prop.get('key'), 'title': prop['label'], 'op': prop['id'],
|
|
2087
2095
|
'tid': prop.get('tid'), 'ref': prop.get('ref'), 'lane': item.get('lane')})
|
|
2088
2096
|
return prop
|
|
@@ -2264,7 +2272,6 @@ def describe_op(store, op: dict) -> tuple:
|
|
|
2264
2272
|
if kind == 'preference.exclude_sender': label = 'Silence this sender' if p.get('scope') == 'sender' else 'File it and remember this kind'
|
|
2265
2273
|
if kind == 'item.settle': label = {'later': 'Push it back', 'skip': 'Skip until tomorrow'}.get(str(p.get('verb')), 'Mark it handled')
|
|
2266
2274
|
if kind == 'task.complete' and p.get('agent'): label = 'Close the task and stop its agent'
|
|
2267
|
-
if kind == 'agent.stop' and p.get('wrap'): label = 'Wrap it up'
|
|
2268
2275
|
if kind == 'report.create': label = 'Create the report'
|
|
2269
2276
|
if kind == 'connection.create': label = 'Create the connection'
|
|
2270
2277
|
if kind in toolcatalog.INSTANT or kind == 'report.delete':
|
|
@@ -2324,7 +2331,7 @@ def _outcome_line(kind: str, p: dict, o: dict | None) -> str:
|
|
|
2324
2331
|
if o.get('existing'): return f" {o.get('agent') or 'An agent'} was already on it."
|
|
2325
2332
|
if o.get('started') or o.get('chat'): return f" {o.get('agent') or 'The agent'} is on it - moving on."
|
|
2326
2333
|
if kind == 'item.settle' and o.get('closed'): return f" {task_ref(int(o['closed']))} closed."
|
|
2327
|
-
if kind == 'agent.stop'
|
|
2334
|
+
if kind == 'agent.stop': return ' The task stays open - say close it when you want it closed.'
|
|
2328
2335
|
if kind == 'memory.remember': return ' A memory settles nothing: the walk is where it was.'
|
|
2329
2336
|
if kind == 'report.create' and o.get('sourceId'):
|
|
2330
2337
|
return f" \"{o.get('title')}\" is on the Reports tab{' and runs on its schedule' if o.get('enabled') else ', switched off'}."
|
|
@@ -2536,7 +2543,8 @@ def say(store, text: str, key: str = None, llm=None, actor: str = 'owner', trace
|
|
|
2536
2543
|
# 2026-09-07: "I did already - it should close it; only confirm when you are not sure"). A hand-off, a
|
|
2537
2544
|
# send, a rule or a verb aimed elsewhere still waits for the button.
|
|
2538
2545
|
if verb in AUTO and not elsewhere:
|
|
2539
|
-
|
|
2546
|
+
# ...and a run at once still says what it could not do ("nothing to wrap")
|
|
2547
|
+
prop.update(auto=True, say=f"{prop['label']} - {_where(target_item or {})}." + (f" {prop['note']}" if prop.get('note') else ''))
|
|
2540
2548
|
rec('assistant', prop['say'], {'kind': 'proposal', 'key': prop.get('key'), 'title': prop['label'], 'op': prop['id'],
|
|
2541
2549
|
'tid': prop.get('tid'), 'ref': prop.get('ref'), 'lane': (target_item or {}).get('lane')})
|
|
2542
2550
|
return {'say': prop['say'], 'options': [], 'decision': None, 'proposal': prop}
|