dulus 3.11.2__tar.gz → 3.11.4__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.
- {dulus-3.11.2/dulus.egg-info → dulus-3.11.4}/PKG-INFO +1 -1
- {dulus-3.11.2 → dulus-3.11.4}/docs/CHANGELOG.md +28 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/news.md +2 -0
- {dulus-3.11.2 → dulus-3.11.4/dulus.egg-info}/PKG-INFO +1 -1
- {dulus-3.11.2 → dulus-3.11.4}/dulus.egg-info/SOURCES.txt +1 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus.py +48 -7
- {dulus-3.11.2 → dulus-3.11.4}/providers.py +29 -26
- {dulus-3.11.2 → dulus-3.11.4}/pyproject.toml +247 -247
- dulus-3.11.4/tests/test_dulus_account.py +183 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_provider_errors.py +0 -52
- {dulus-3.11.2 → dulus-3.11.4}/webchat_server.py +13 -0
- {dulus-3.11.2 → dulus-3.11.4}/webchat_ui/app.js +47 -8
- {dulus-3.11.2 → dulus-3.11.4}/LICENSE +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/MANIFEST.in +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/README.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/agent.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/algolia_search.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/analytics.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/agents_bridge.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/compressor.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/context.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/githook.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/marketplace.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/mempalace_bridge.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/paths.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/personas.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/plugins.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/server.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/backend/tasks.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/banners/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/banners/banner_rotator.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/banners/banners_dulus_ai.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/batch_api.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/checkpoint/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/checkpoint/hooks.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/checkpoint/store.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/checkpoint/types.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/__main__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/ansi.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/assets/ascii/dulus_logo.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/assets/ascii/eagle.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/assets/ascii/terminal_art.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/banners.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/demo.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/effects.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/effort_slider.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/progress.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/py.typed +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/spinners.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cli_animations/status.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/clipboard_utils.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/cloudsave.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/common.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/compaction.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/config.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/context.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/active_persona.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/marketplace.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/personas.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/plugins/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/plugins/composio/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/plugins/composio/composio_plugin/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/plugins/composio/plugin.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/plugins/composio/plugin_tool.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/data/tasks.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/display_blocks.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/API.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/BRAND_GUIDE.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/CONTRIBUTING.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/DEPLOYMENT.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/Dulus_AI_Whitepaper_(v2.0).pdf +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/Dulus_YC_Company_Overview_Aug_2026.pdf +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/FAQ.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/GETTING_STARTED.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_AR.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_EN.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_ES.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_FR.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_JA.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_KO.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_PT.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_RU.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/README_ZH.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/SECURITY.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/api.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/architecture.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/azure-speech-template.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/dashboard/index.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/divider.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/dulus-bird.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/generate.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/index.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/nvidia-models.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/particle-playground.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/personas/index.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/poetry-banner.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/preview.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/python-console.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/auto-adapter.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/dulus-os.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/hero.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/lookback_two_windows.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/pyc_heap.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/pyc_receipts.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/pyc_trap.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/roundtable.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/task-board.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/readme/webchat.png +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-agents.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-brainstorm.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-bridges.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-features.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-freetier.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-memory.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-models.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-perms.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-plugins.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-quickstart.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/sec-ssj.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/spinners.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/split-pane.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/terminal-boot.svg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/docs/termux-edge.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus.egg-info/dependency_links.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus.egg-info/entry_points.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus.egg-info/requires.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus.egg-info/top_level.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_bar_client.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_gui.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_mcp/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_mcp/client.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_mcp/commands.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_mcp/config.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_mcp/hub.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_mcp/tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_mcp/types.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_quick_menu.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/add_dir_manager.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/afk_mode.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/approval_runtime.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/background_tasks.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/clipboard_utils.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/diff_visualizer.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/export_import.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/hook_engine.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/notification_manager.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/session_fork.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/shell_mode.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/todo_visualizer.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/tree_ls.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/wire_events.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/dulus_tools/yolo_mode.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/file_filter.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/fs_compass.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/governance.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/agent_bridge.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/chat_widget.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/main_window.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/personas.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/sandbox_server.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/session_utils.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/settings_dialog.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/sidebar.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/tasks_view.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/themes.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/gui/tool_panel.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/input.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/license_manager.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/lookback.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/audit.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/consolidator.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/context.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/mempalace_bridge.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/offload.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/palace.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/scan.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/adaptation_guides.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/askuserquestion_after_numbered_list.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/background_jobs_no_extra_timers.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/cleverness_over_resources.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/corporate_tls_breaks_curl_cffi.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/hardened_rules.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/investigator_workflow_heuristic.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/native_code_over_sketchy_plugins.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/no_personal_info_in_code.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/searches_include_modified_date.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/tmux_send_keys_power_patterns.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/token_optimization_technique.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/tool_chaining_capability.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/insights/webbridge_evaluate_first_pattern.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/seeds/short_memory.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/sessions.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/store.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/types.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/memory/vector_search.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/model_params.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/multi_agent/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/multi_agent/subagent.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/multi_agent/tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/paste_placeholders.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/personality_config.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/plugin/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/plugin/autoadapter.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/plugin/loader.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/plugin/recommend.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/plugin/store.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/plugin/types.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/profiles.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/pyconsole.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/README.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/components.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/index.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/wallpaper-default.jpg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/wallpapers/default.jpeg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/wallpapers/light.jpeg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/wallpapers/nature.jpeg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/dist/wallpapers/tech.jpeg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/eslint.config.js +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/index.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/info.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/package-lock.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/package.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/postcss.config.js +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/tailwind.config.js +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/tsconfig.app.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/tsconfig.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/tsconfig.node.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox/vite.config.ts +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/sandbox_bootstrap.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/setup.cfg +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/builtin.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/LICENSE-obsidian-skills +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/README.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/defuddle/SKILL.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/json-canvas/SKILL.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/json-canvas/references/EXAMPLES.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/obsidian-bases/SKILL.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/obsidian-cli/SKILL.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/obsidian-markdown/SKILL.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/obsidian-markdown/references/CALLOUTS.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/obsidian-markdown/references/EMBEDS.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/obsidian-markdown/references/PROPERTIES.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/README.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/SKILL.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/addresses.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/advancedbackgroundchecks.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/beenverified.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/clustal.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/clustrmaps.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/cyberbackgroundchecks.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/familytreenow.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/fastpeoplesearch.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/intelius.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/mylife.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/nuwber.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/peekyou.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/peoplefinders.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/radaris.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/rehold.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/searchpeoplefree.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/socialcatfish.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/spokeo.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/thatsthem.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/truepeoplesearch.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/usphonebook.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/brokers/whitepages.json +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/legal/ccpa.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/legal/drop.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/legal/gdpr.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/methods.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/site-playbooks.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/references/state-machine.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/autopilot.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/badbool.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/brokers.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/cdp.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/config.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/crypto.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/dossier.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/email_modes.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/emailer.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/ledger.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/legal.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/paths.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/pdd.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/registry.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/report.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/scan.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/storage.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/tiers.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/scripts/vectors.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/templates/consent/authorization.md +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/templates/emails/ccpa-authorized-agent.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/templates/emails/ccpa-deletion.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/templates/emails/ccpa-indirect-deletion.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/templates/emails/gdpr-erasure.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/bundled/unbroker/templates/emails/generic-optout.txt +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/clawhub.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/executor.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/loader.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skill/tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/skills.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/soul.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/spinner.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/steer_input.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/subagent.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/task/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/task/store.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/task/tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/task/types.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_afk_yolo.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_approval_runtime.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_background_task_tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_background_tasks.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_chatgpt_oauth.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_checkpoint.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_cli_animations_integration.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_clipboard_utils.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_compaction.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_composio_tool_generator.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_diff_view.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_diff_visualization.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_display_blocks.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_export_import.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_grok_usage.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_hook_engine.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_injection_fix.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_license.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_lookback_cache.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_mcp.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_mcp_algolia.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_memory.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_memory_home_resolution.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_notification_manager.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_plugin.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_profile_isolation.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_session_fork.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_shell_mode.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_skills.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_skillssh_algolia.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_steer_input.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_subagent.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_task.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_telegram_buffer.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_think_tool.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_todo_tool.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_todo_visualization.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_tool_registry.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_tree_ls.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_voice.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_webbridge_tabs.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tests/test_wire_events.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tmux_tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tool_registry.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tools_background.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tools_think.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/tools_todo.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/ui/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/ui/input.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/ui/render.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/updater.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/voice/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/voice/audio_utils.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/voice/keyterms.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/voice/recorder.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/voice/stt.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/voice/tts.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/voice/wake_word.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/webbridge/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/webbridge/core.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/webbridge/tools.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/webchat.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/webchat_ui/__init__.py +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/webchat_ui/index.html +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/webchat_ui/style.css +0 -0
- {dulus-3.11.2 → dulus-3.11.4}/welcome.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.11.
|
|
3
|
+
Version: 3.11.4
|
|
4
4
|
Summary: Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS.
|
|
5
5
|
Author-email: KevRojo <dev@dulus.ai>
|
|
6
6
|
Maintainer-email: KevRojo <dev@dulus.ai>
|
|
@@ -7,6 +7,34 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.11.4] - 2026-08-19
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Web chat no longer stutters on long replies.** The streaming bubble
|
|
14
|
+
re-parsed the whole markdown document and re-highlighted every code block on
|
|
15
|
+
each token, and the cost grows with message length. Re-renders are now
|
|
16
|
+
coalesced into one per animation frame, with a final flush so no tokens are
|
|
17
|
+
dropped.
|
|
18
|
+
- **Repeated calls to the same tool now complete the right pill.** Five Bash
|
|
19
|
+
commands in a row kept marking the first pill "done" and left the rest
|
|
20
|
+
spinning "running" forever. The result now resolves to the newest still-
|
|
21
|
+
running pill and lands directly beneath it.
|
|
22
|
+
- **A late click on an expired question can no longer fake an answer.**
|
|
23
|
+
AskUserQuestion banners outlived the agent's 300s timeout, so clicking one
|
|
24
|
+
afterwards looked "answered" while nobody was listening. Stale entries are
|
|
25
|
+
now purged before that can happen.
|
|
26
|
+
- **Kimi quota exhaustion is reported honestly.** When a Kimi membership's
|
|
27
|
+
billing-cycle quota is spent, the API answers `403 access_terminated_error`
|
|
28
|
+
— which Dulus used to misread as an invalid API key, sending you to mint a
|
|
29
|
+
new key that cannot help (quota is billed per account). It now says what
|
|
30
|
+
happened and points at `/model`.
|
|
31
|
+
- **`/login kimi force` actually switches accounts now.** It skipped the
|
|
32
|
+
"already logged in" check but left the stored refresh token and device id in
|
|
33
|
+
place, so the device flow silently re-bound the same account. Both are wiped
|
|
34
|
+
first.
|
|
35
|
+
- **Removed a duplicated line in the Ollama streaming loop.** Harmless but
|
|
36
|
+
dead.
|
|
37
|
+
|
|
10
38
|
## [3.11.1] - 2026-08-18
|
|
11
39
|
|
|
12
40
|
### Fixed
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## 🔥🔥🔥 News (Pacific Time)
|
|
4
4
|
|
|
5
|
+
- August 19, 2026 (**v3.11.4**): **🩹 Web chat polish + honest Kimi errors.** Long replies no longer stutter (streaming re-renders are coalesced to one per frame), repeated calls to the same tool complete the right pill instead of leaving the rest spinning forever, and a late click on an expired question can't fake an answer anymore. On the Kimi side: a spent membership quota is now reported as quota — not as a bogus "invalid API key" — and `/login kimi force` wipes the old session and device id so switching accounts actually works. `pip install --upgrade dulus`. 🦅🇩🇴
|
|
6
|
+
|
|
5
7
|
- August 18, 2026 (**v3.11.1**): **🔧 Kimi Code connects again.** Kimi moved its coding endpoint from `api.kimi.com` to `api.kimi.ai`, and Dulus only knew the old address — so requests to the new one went out without the user-agent Kimi requires and bounced back with a 403. Dulus now recognizes both hosts, so `kimi-code` and `/login kimi` models talk to Kimi cleanly again. `pip install --upgrade dulus`. 🦅🇩🇴
|
|
6
8
|
|
|
7
9
|
- August 17, 2026 (**v3.11.0**): **🧬 Profiles are real agents now.** A profile always had its own `plugins/`, `skills/` and `memory/` — but almost nothing read them, and switching profiles only ever *added* tools, so you'd see plugins you couldn't actually use. Every one of those paths is now scoped to the active profile: a named profile is **lean** by default (its own stuff plus the bundled skills), reads only its own memory, and can't accidentally uninstall a plugin out from under your other profiles. `/profile inherit <name> on` if you want one that sees everything. Your `default` profile is untouched.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.11.
|
|
3
|
+
Version: 3.11.4
|
|
4
4
|
Summary: Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS.
|
|
5
5
|
Author-email: KevRojo <dev@dulus.ai>
|
|
6
6
|
Maintainer-email: KevRojo <dev@dulus.ai>
|
|
@@ -341,6 +341,7 @@ tests/test_composio_tool_generator.py
|
|
|
341
341
|
tests/test_diff_view.py
|
|
342
342
|
tests/test_diff_visualization.py
|
|
343
343
|
tests/test_display_blocks.py
|
|
344
|
+
tests/test_dulus_account.py
|
|
344
345
|
tests/test_export_import.py
|
|
345
346
|
tests/test_grok_usage.py
|
|
346
347
|
tests/test_hook_engine.py
|
|
@@ -380,7 +380,7 @@ try:
|
|
|
380
380
|
from importlib.metadata import version as _pkg_version
|
|
381
381
|
VERSION = _pkg_version("dulus")
|
|
382
382
|
except Exception:
|
|
383
|
-
VERSION = "3.11.
|
|
383
|
+
VERSION = "3.11.4" # dev fallback — keep in sync with pyproject.toml
|
|
384
384
|
|
|
385
385
|
# ── ANSI helpers (used even with rich for non-markdown output) ─────────────
|
|
386
386
|
from common import C, clr, info, ok, warn, err, stream_thinking, sanitize_text
|
|
@@ -3246,11 +3246,7 @@ def cmd_harvest(_args: str, _state, config) -> bool:
|
|
|
3246
3246
|
info("Login page detected. Please log in manually, then press ENTER here...")
|
|
3247
3247
|
input()
|
|
3248
3248
|
|
|
3249
|
-
|
|
3250
|
-
# (it keeps streaming/websocket connections open), so that wait
|
|
3251
|
-
# always burned the full 30s and timed out. Wait for the DOM
|
|
3252
|
-
# instead and give it a real ceiling.
|
|
3253
|
-
page.goto("https://claude.ai/new", wait_until="domcontentloaded", timeout=60000)
|
|
3249
|
+
page.goto("https://claude.ai/new", wait_until="networkidle")
|
|
3254
3250
|
time.sleep(2)
|
|
3255
3251
|
|
|
3256
3252
|
user_agent = page.evaluate("navigator.userAgent") if browser.pages else ""
|
|
@@ -9171,6 +9167,41 @@ def cmd_login(args: str, _state, config) -> bool:
|
|
|
9171
9167
|
"""
|
|
9172
9168
|
sub = (args or "").strip().lower()
|
|
9173
9169
|
|
|
9170
|
+
# ── Dulus account (OAuth 2.0 + PKCE against Dulus's own API) ──
|
|
9171
|
+
# Unlike the provider logins below, this one authenticates you to Dulus
|
|
9172
|
+
# itself, so the CLI can reach the Dulus API without an API key pasted in
|
|
9173
|
+
# by hand. `/login dulus key` mints a dulus_sk_* key for CI and servers.
|
|
9174
|
+
if sub.split(" ")[0] in ("dulus", "account"):
|
|
9175
|
+
import dulus_account
|
|
9176
|
+
|
|
9177
|
+
rest = (args or "").strip().split()
|
|
9178
|
+
force = "force" in rest
|
|
9179
|
+
if len(rest) > 1 and rest[1] in ("key", "apikey", "api-key"):
|
|
9180
|
+
name = rest[2] if len(rest) > 2 else "cli"
|
|
9181
|
+
dulus_account.create_api_key(name, notify=lambda m: print(clr(m, "cyan")))
|
|
9182
|
+
return True
|
|
9183
|
+
|
|
9184
|
+
if not force:
|
|
9185
|
+
store = dulus_account.load_store()
|
|
9186
|
+
if store.get("access_token") and not dulus_account._token_expired(store):
|
|
9187
|
+
print(clr("✅ Dulus account already signed in.", "green"))
|
|
9188
|
+
print(clr("Use `/login dulus force` to sign in again, or `/login dulus key` to mint an API key.", "green"))
|
|
9189
|
+
return True
|
|
9190
|
+
|
|
9191
|
+
if force:
|
|
9192
|
+
dulus_account.clear_store()
|
|
9193
|
+
print(clr("Starting Dulus sign-in (OAuth 2.0 + PKCE)…", "cyan"))
|
|
9194
|
+
try:
|
|
9195
|
+
token = dulus_account.login(notify=lambda m: print(clr(m, "cyan")))
|
|
9196
|
+
except Exception as e:
|
|
9197
|
+
token = None
|
|
9198
|
+
print(clr(f"Sign-in error: {e}", "red"))
|
|
9199
|
+
if token:
|
|
9200
|
+
print(clr("✅ Signed in to your Dulus account.", "green"))
|
|
9201
|
+
return True
|
|
9202
|
+
print(clr("Could not sign in. Re-run `/login dulus`.", "yellow"))
|
|
9203
|
+
return True
|
|
9204
|
+
|
|
9174
9205
|
# ── Claude / Anthropic subscription OAuth (no API key, no cookie webbridge) ──
|
|
9175
9206
|
# Mirrors the Grok flow: opens claude.ai in the browser, you approve and paste
|
|
9176
9207
|
# back the code, Dulus exchanges it for an OAuth token. claude-* models then run
|
|
@@ -9258,7 +9289,10 @@ def cmd_login(args: str, _state, config) -> bool:
|
|
|
9258
9289
|
# /login kimi — Kimi membership via the official Kimi Code CLI device OAuth.
|
|
9259
9290
|
# Reuses ~/.kimi-code credentials when present; otherwise opens auth.kimi.com.
|
|
9260
9291
|
if sub.split(" ")[0] in ("kimi", "kimi-oauth", "moonshot-oauth"):
|
|
9261
|
-
from providers import
|
|
9292
|
+
from providers import (
|
|
9293
|
+
_kimi_oauth_login, _kimi_oauth_get_token,
|
|
9294
|
+
_kimi_oauth_clear_store,
|
|
9295
|
+
)
|
|
9262
9296
|
force = "force" in (args or "").lower()
|
|
9263
9297
|
if not force:
|
|
9264
9298
|
tok = _kimi_oauth_get_token(config)
|
|
@@ -9266,6 +9300,13 @@ def cmd_login(args: str, _state, config) -> bool:
|
|
|
9266
9300
|
print(clr("✅ Kimi OAuth session already active (Kimi membership, no API key).", "green"))
|
|
9267
9301
|
print(clr("kimi-oauth/* models use your Kimi membership automatically. Use `/login kimi force` to re-login.", "green"))
|
|
9268
9302
|
return True
|
|
9303
|
+
else:
|
|
9304
|
+
# A fresh device flow is not enough to switch accounts: the stored
|
|
9305
|
+
# refresh token revives the old session and the persisted device id
|
|
9306
|
+
# keeps us bound to it. Wipe both so the login binds cleanly.
|
|
9307
|
+
removed = _kimi_oauth_clear_store()
|
|
9308
|
+
if removed:
|
|
9309
|
+
print(clr(f"Cleared previous Kimi session ({', '.join(removed)}).", "cyan"))
|
|
9269
9310
|
print(clr("Starting Kimi membership login (device OAuth via auth.kimi.com)…", "cyan"))
|
|
9270
9311
|
print(clr("A browser will open — approve the shown device code with your Kimi account.", "cyan"))
|
|
9271
9312
|
try:
|
|
@@ -91,15 +91,6 @@ class _ProviderRetry:
|
|
|
91
91
|
# Rate limit / server overload
|
|
92
92
|
if "429" in msg or "rate limit" in msg or "too many requests" in msg:
|
|
93
93
|
return True
|
|
94
|
-
# Capacity pushback. Anthropic answers 529 "overloaded_error" and other
|
|
95
|
-
# providers say "overloaded"/"capacity"/"server is busy" with assorted
|
|
96
|
-
# status codes; the next request usually succeeds, so this is exactly
|
|
97
|
-
# the case worth absorbing silently instead of surfacing to the user.
|
|
98
|
-
if ("529" in msg or "overloaded" in msg or "over capacity" in msg
|
|
99
|
-
or "at capacity" in msg or "server is busy" in msg
|
|
100
|
-
or "model is currently loading" in msg
|
|
101
|
-
or type(exc).__name__ in ("OverloadedError", "InternalServerError")):
|
|
102
|
-
return True
|
|
103
94
|
# Server errors
|
|
104
95
|
if "500" in msg or "502" in msg or "503" in msg or "504" in msg:
|
|
105
96
|
return True
|
|
@@ -5253,6 +5244,13 @@ def friendly_api_error(exc: Exception) -> str:
|
|
|
5253
5244
|
s = str(exc).lower()
|
|
5254
5245
|
etype = type(exc).__name__
|
|
5255
5246
|
|
|
5247
|
+
# Kimi Code quota. Checked before the generic auth/permission branches: the
|
|
5248
|
+
# payload carries a 403 and the word "access", which would otherwise be read
|
|
5249
|
+
# as a bad key. Quota is billed per ACCOUNT, so a new key changes nothing.
|
|
5250
|
+
if "access_terminated_error" in s:
|
|
5251
|
+
return ("Kimi membership quota is spent for this billing cycle. It is billed per "
|
|
5252
|
+
"account, so a new API key won't help — switch model with /model, or wait "
|
|
5253
|
+
"for the cycle to reset.")
|
|
5256
5254
|
# Auth / key problems
|
|
5257
5255
|
if "authentication" in s or "invalid_api_key" in s or "401" in s or etype == "AuthenticationError":
|
|
5258
5256
|
return "API key is missing or invalid. Run /config <provider>_api_key=... or set the env var."
|
|
@@ -5532,13 +5530,6 @@ def stream_anthropic(
|
|
|
5532
5530
|
yield AssistantTurn(text, tool_calls, 0, 0, thinking=thinking,
|
|
5533
5531
|
thinking_signature=thinking_signature, error=False)
|
|
5534
5532
|
return
|
|
5535
|
-
# Nothing emitted yet and the failure is transient (529 overloaded, a
|
|
5536
|
-
# blip, a rate limit): let it propagate so _ProviderRetry can quietly
|
|
5537
|
-
# try again. Turning it into text here would strand the retry wrapper,
|
|
5538
|
-
# which only ever sees a well-behaved generator. Once output has been
|
|
5539
|
-
# emitted a retry would duplicate it, so those still report.
|
|
5540
|
-
if not text and not tool_calls and _ProviderRetry.is_retryable(_e):
|
|
5541
|
-
raise
|
|
5542
5533
|
msg = friendly_api_error(_e)
|
|
5543
5534
|
yield TextChunk(msg)
|
|
5544
5535
|
yield AssistantTurn(msg, [], 0, 0, error=True)
|
|
@@ -6167,11 +6158,6 @@ def stream_openai_compat(
|
|
|
6167
6158
|
{**config, "_modelstudio_remaining": _ms_remaining[1:]},
|
|
6168
6159
|
)
|
|
6169
6160
|
return
|
|
6170
|
-
# Transient capacity pushback before the stream opened: propagate so
|
|
6171
|
-
# _ProviderRetry absorbs it silently. This is the create() call, so
|
|
6172
|
-
# nothing has been emitted yet and a retry cannot duplicate output.
|
|
6173
|
-
if _ProviderRetry.is_retryable(e):
|
|
6174
|
-
raise
|
|
6175
6161
|
msg = friendly_api_error(e)
|
|
6176
6162
|
yield TextChunk(msg)
|
|
6177
6163
|
yield AssistantTurn(msg, [], 0, 0, error=True)
|
|
@@ -6187,10 +6173,6 @@ def stream_openai_compat(
|
|
|
6187
6173
|
{**config, "_modelstudio_remaining": _ms_remaining[1:]},
|
|
6188
6174
|
)
|
|
6189
6175
|
return
|
|
6190
|
-
# Same as above: still inside the create() call, so a transient failure
|
|
6191
|
-
# can be retried without duplicating anything.
|
|
6192
|
-
if _ProviderRetry.is_retryable(e):
|
|
6193
|
-
raise
|
|
6194
6176
|
msg = friendly_api_error(e)
|
|
6195
6177
|
yield TextChunk(msg)
|
|
6196
6178
|
yield AssistantTurn(msg, [], 0, 0, error=True)
|
|
@@ -6841,7 +6823,6 @@ def stream_ollama(
|
|
|
6841
6823
|
yield ThinkingChunk(_thinking_buffer)
|
|
6842
6824
|
_thinking_buffer = ""
|
|
6843
6825
|
|
|
6844
|
-
content = msg.get("content", "") if "content" in msg else ""
|
|
6845
6826
|
content = msg.get("content", "") if "content" in msg else ""
|
|
6846
6827
|
if content:
|
|
6847
6828
|
# Flush thinking buffer before content
|
|
@@ -6985,6 +6966,28 @@ def _kimi_oauth_save_store(data: dict) -> None:
|
|
|
6985
6966
|
_oauth_save_store(_kimi_oauth_store_path(), data)
|
|
6986
6967
|
|
|
6987
6968
|
|
|
6969
|
+
def _kimi_oauth_clear_store() -> list[str]:
|
|
6970
|
+
"""Delete the Kimi OAuth session *and* the device identity.
|
|
6971
|
+
|
|
6972
|
+
A plain re-login is not enough to switch Kimi accounts: the refresh token in
|
|
6973
|
+
``kimi_oauth.json`` silently revives the previous session, and the stable
|
|
6974
|
+
``kimi_device_id`` keeps the host tied to the old device. Both files have to
|
|
6975
|
+
go before the device flow can bind a different account.
|
|
6976
|
+
|
|
6977
|
+
Returns the names of the files actually removed (for user feedback).
|
|
6978
|
+
"""
|
|
6979
|
+
removed: list[str] = []
|
|
6980
|
+
for path in (_kimi_oauth_store_path(), _oauth_store_path("kimi_device_id")):
|
|
6981
|
+
try:
|
|
6982
|
+
path.unlink()
|
|
6983
|
+
removed.append(path.name)
|
|
6984
|
+
except FileNotFoundError:
|
|
6985
|
+
pass
|
|
6986
|
+
except OSError:
|
|
6987
|
+
pass
|
|
6988
|
+
return removed
|
|
6989
|
+
|
|
6990
|
+
|
|
6988
6991
|
def _kimi_device_headers() -> dict:
|
|
6989
6992
|
"""X-Msh-* device identity headers the official CLI sends on OAuth calls.
|
|
6990
6993
|
|