dulus 3.13.3__tar.gz → 3.13.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.13.3/dulus.egg-info → dulus-3.13.4}/PKG-INFO +1 -1
- {dulus-3.13.3 → dulus-3.13.4}/data/plugins/composio/plugin_tool.py +6 -2
- {dulus-3.13.3 → dulus-3.13.4}/docs/CHANGELOG.md +8 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/news.md +2 -0
- {dulus-3.13.3 → dulus-3.13.4/dulus.egg-info}/PKG-INFO +1 -1
- {dulus-3.13.3 → dulus-3.13.4}/dulus.egg-info/SOURCES.txt +1 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus.egg-info/top_level.txt +1 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus.py +1 -1
- {dulus-3.13.3 → dulus-3.13.4}/dulus_account.py +4 -3
- {dulus-3.13.3 → dulus-3.13.4}/pyproject.toml +2 -1
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_compaction.py +3 -3
- dulus-3.13.4/token_budget.py +148 -0
- {dulus-3.13.3 → dulus-3.13.4}/LICENSE +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/MANIFEST.in +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/README.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/agent.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/algolia_search.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/analytics.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/agents_bridge.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/compressor.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/context.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/githook.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/marketplace.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/mempalace_bridge.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/paths.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/personas.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/plugins.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/server.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/backend/tasks.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/banners/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/banners/banner_rotator.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/banners/banners_dulus_ai.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/batch_api.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/checkpoint/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/checkpoint/hooks.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/checkpoint/store.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/checkpoint/types.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/__main__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/ansi.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/assets/ascii/dulus_logo.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/assets/ascii/eagle.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/assets/ascii/terminal_art.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/banners.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/demo.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/effects.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/effort_slider.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/progress.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/py.typed +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/spinners.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cli_animations/status.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/clipboard_utils.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/cloudsave.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/common.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/compaction.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/config.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/context.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/active_persona.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/marketplace.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/personas.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/plugins/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/plugins/composio/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/plugins/composio/composio_plugin/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/plugins/composio/composio_plugin/session_manager.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/plugins/composio/composio_plugin/tool_generator.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/plugins/composio/plugin.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/data/tasks.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/display_blocks.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/API.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/BRAND_GUIDE.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/CONTRIBUTING.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/DEPLOYMENT.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/FAQ.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/GETTING_STARTED.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_AR.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_EN.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_ES.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_FR.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_JA.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_KO.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_PT.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_RU.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/README_ZH.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/SECURITY.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/api.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/architecture.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/azure-speech-template.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/dashboard/index.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/divider.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/dulus-bird.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/generate.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/index.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/nvidia-models.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/particle-playground.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/personas/index.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/poetry-banner.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/preview.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/python-console.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/auto-adapter.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/dulus-os.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/hero.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/lookback_two_windows.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/pyc_heap.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/pyc_receipts.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/pyc_trap.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/roundtable.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/task-board.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/readme/webchat.png +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-agents.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-brainstorm.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-bridges.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-features.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-freetier.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-memory.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-models.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-perms.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-plugins.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-quickstart.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/sec-ssj.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/spinners.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/split-pane.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/terminal-boot.svg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/docs/termux-edge.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus.egg-info/dependency_links.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus.egg-info/entry_points.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus.egg-info/requires.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_bar_client.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_gui.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_mcp/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_mcp/client.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_mcp/commands.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_mcp/config.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_mcp/hub.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_mcp/tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_mcp/types.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_quick_menu.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/add_dir_manager.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/afk_mode.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/approval_runtime.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/background_tasks.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/clipboard_utils.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/diff_visualizer.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/export_import.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/hook_engine.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/notification_manager.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/session_fork.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/shell_mode.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/todo_visualizer.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/tree_ls.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/wire_events.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/dulus_tools/yolo_mode.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/file_filter.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/fs_compass.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/governance.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/agent_bridge.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/chat_widget.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/main_window.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/personas.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/sandbox_server.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/session_utils.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/settings_dialog.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/sidebar.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/tasks_view.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/themes.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/gui/tool_panel.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/input.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/license_manager.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/lookback.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/audit.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/consolidator.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/context.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/mempalace_bridge.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/offload.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/palace.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/scan.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/adaptation_guides.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/askuserquestion_after_numbered_list.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/background_jobs_no_extra_timers.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/cleverness_over_resources.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/corporate_tls_breaks_curl_cffi.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/hardened_rules.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/investigator_workflow_heuristic.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/native_code_over_sketchy_plugins.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/no_personal_info_in_code.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/searches_include_modified_date.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/tmux_send_keys_power_patterns.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/token_optimization_technique.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/tool_chaining_capability.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/insights/webbridge_evaluate_first_pattern.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/seeds/short_memory.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/sessions.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/store.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/types.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/memory/vector_search.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/model_params.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/multi_agent/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/multi_agent/subagent.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/multi_agent/tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/paste_placeholders.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/personality_config.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/plugin/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/plugin/autoadapter.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/plugin/loader.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/plugin/recommend.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/plugin/store.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/plugin/types.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/profiles.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/providers.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/pyconsole.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/README.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/assets/index-DE51D6wI.css +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/assets/index-DMCCNE9Y.js +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/index.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/wallpaper-default.jpg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/wallpapers/default.jpeg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/wallpapers/light.jpeg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/wallpapers/nature.jpeg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/dist/wallpapers/tech.jpeg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox/info.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/sandbox_bootstrap.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/setup.cfg +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/builtin.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/LICENSE-obsidian-skills +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/README.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/defuddle/SKILL.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/json-canvas/SKILL.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/json-canvas/references/EXAMPLES.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/obsidian-bases/SKILL.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/obsidian-bases/references/FUNCTIONS_REFERENCE.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/obsidian-cli/SKILL.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/obsidian-markdown/SKILL.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/obsidian-markdown/references/CALLOUTS.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/obsidian-markdown/references/EMBEDS.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/obsidian-markdown/references/PROPERTIES.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/README.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/SKILL.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/addresses.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/advancedbackgroundchecks.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/beenverified.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/clustal.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/clustrmaps.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/cyberbackgroundchecks.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/familytreenow.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/fastpeoplesearch.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/intelius.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/mylife.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/nuwber.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/peekyou.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/peoplefinders.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/radaris.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/rehold.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/searchpeoplefree.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/socialcatfish.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/spokeo.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/thatsthem.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/truepeoplesearch.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/usphonebook.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/brokers/whitepages.json +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/legal/ccpa.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/legal/drop.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/legal/gdpr.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/methods.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/site-playbooks.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/references/state-machine.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/autopilot.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/badbool.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/brokers.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/cdp.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/config.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/crypto.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/dossier.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/email_modes.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/emailer.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/ledger.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/legal.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/paths.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/pdd.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/registry.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/report.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/scan.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/storage.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/tiers.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/scripts/vectors.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/templates/consent/authorization.md +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/templates/emails/ccpa-authorized-agent.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/templates/emails/ccpa-deletion.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/templates/emails/ccpa-indirect-deletion.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/templates/emails/gdpr-erasure.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/bundled/unbroker/templates/emails/generic-optout.txt +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/clawhub.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/executor.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/loader.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skill/tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/skills.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/soul.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/spinner.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/steer_input.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/subagent.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/task/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/task/store.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/task/tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/task/types.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_afk_yolo.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_approval_runtime.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_background_task_tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_background_tasks.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_chatgpt_oauth.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_checkpoint.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_cli_animations_integration.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_clipboard_utils.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_composio_tool_generator.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_diff_view.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_diff_visualization.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_display_blocks.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_dulus_account.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_export_import.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_grok_usage.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_hook_engine.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_injection_fix.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_json_protocol.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_license.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_lookback_cache.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_lookback_compact.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_mcp.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_mcp_algolia.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_memory.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_memory_home_resolution.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_notification_manager.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_plugin.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_profile_isolation.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_profile_plugin_scope.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_provider_errors.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_session_fork.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_shell_detection.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_shell_mode.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_skills.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_skillssh_algolia.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_steer_input.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_subagent.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_task.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_telegram_buffer.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_think_tool.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_todo_tool.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_todo_visualization.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_tool_registry.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_tree_ls.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_voice.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_webbridge_tabs.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tests/test_wire_events.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tmux_tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tool_registry.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tools_background.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tools_think.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/tools_todo.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/ui/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/ui/input.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/ui/render.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/updater.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/voice/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/voice/audio_utils.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/voice/keyterms.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/voice/recorder.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/voice/stt.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/voice/tts.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/voice/wake_word.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webbridge/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webbridge/core.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webbridge/tools.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webchat.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webchat_server.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webchat_ui/__init__.py +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webchat_ui/app.js +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webchat_ui/index.html +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/webchat_ui/style.css +0 -0
- {dulus-3.13.3 → dulus-3.13.4}/welcome.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.13.
|
|
3
|
+
Version: 3.13.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>
|
|
@@ -210,7 +210,8 @@ def composio_generate_tool_py(params: dict, config: dict) -> str:
|
|
|
210
210
|
arguments={"tool_slugs": [tool_slug], "session_id": session.session_id}
|
|
211
211
|
)
|
|
212
212
|
data = result.data if hasattr(result, "data") else result
|
|
213
|
-
|
|
213
|
+
raw_schemas = data.get("schemas", []) if isinstance(data, dict) else []
|
|
214
|
+
schemas = list(raw_schemas) if isinstance(raw_schemas, list) else []
|
|
214
215
|
if schemas:
|
|
215
216
|
schema = schemas[0]
|
|
216
217
|
path = generate_tool_py(tool_slug, schema, Path(output_dir), user_id=user_id)
|
|
@@ -249,10 +250,13 @@ def composio_generate_plugin_tool_py(params: dict, config: dict) -> str:
|
|
|
249
250
|
arguments={"tool_slugs": tool_slugs, "session_id": session.session_id}
|
|
250
251
|
)
|
|
251
252
|
data = result.data if hasattr(result, "data") else result
|
|
252
|
-
|
|
253
|
+
raw_schemas = data.get("schemas", []) if isinstance(data, dict) else []
|
|
254
|
+
schemas = list(raw_schemas) if isinstance(raw_schemas, list) else []
|
|
253
255
|
|
|
254
256
|
tool_defs = []
|
|
255
257
|
for s in schemas:
|
|
258
|
+
if not isinstance(s, dict):
|
|
259
|
+
continue
|
|
256
260
|
tool_defs.append({
|
|
257
261
|
"slug": s.get("slug", s.get("name", "unknown")),
|
|
258
262
|
"description": s.get("description", ""),
|
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [3.13.4] - 2026-08-31
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **Context windows**: ship `token_budget` so compaction uses real per-provider limits (Claude 200k, Gemini 1M, DeepSeek 64k, …) instead of a flat 128k fallback
|
|
14
|
+
- Public account client stays scope-neutral (no internal billing vocabulary in source)
|
|
15
|
+
- Composio plugin schema handling typed clean for pyright
|
|
16
|
+
- Local quality: **925 passed**, 1 skipped, 0 failed · pyright 0 errors
|
|
17
|
+
|
|
10
18
|
## [3.13.3] - 2026-08-31
|
|
11
19
|
|
|
12
20
|
### Fixed
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
## 🔥🔥🔥 News (Pacific Time)
|
|
4
4
|
|
|
5
|
+
- August 31, 2026 (**v3.13.4**): **Context windows are honest again.** `token_budget` ships so compaction knows Claude is 200k, Gemini is 1M, DeepSeek is 64k — not a flat 128k for everyone. Quality CI: **925 passed**. `pip install -U dulus`. 🦅
|
|
6
|
+
|
|
5
7
|
- August 31, 2026 (**v3.13.3**): **`/compact` got serious.** Full archive → disk for Loopback, live context → ~0 with a dense hint card, and **lookback is forced ON** for that session even if it was off — so quality does not fall off a cliff after compact. `pip install -U dulus`. 🦅
|
|
6
8
|
|
|
7
9
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: dulus
|
|
3
|
-
Version: 3.13.
|
|
3
|
+
Version: 3.13.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>
|
|
@@ -395,7 +395,7 @@ try:
|
|
|
395
395
|
from importlib.metadata import version as _pkg_version
|
|
396
396
|
VERSION = _pkg_version("dulus")
|
|
397
397
|
except Exception:
|
|
398
|
-
VERSION = "3.13.
|
|
398
|
+
VERSION = "3.13.4" # dev fallback — keep in sync with pyproject.toml
|
|
399
399
|
|
|
400
400
|
# ── Machine-readable protocol output (`--output json`) ─────────────────────
|
|
401
401
|
# Dulus is increasingly run as a child process by another agent runtime (an
|
|
@@ -409,7 +409,7 @@ def create_api_key(name: str = "cli", notify: Callable[[str], Any] = print) -> d
|
|
|
409
409
|
|
|
410
410
|
|
|
411
411
|
def lease_headers(notify: Callable[[str], Any] = print) -> dict:
|
|
412
|
-
"""Headers for
|
|
412
|
+
"""Headers for metered endpoints (deposit-address, balance).
|
|
413
413
|
|
|
414
414
|
Prefer the account lease (`X-Dulus-Lease`); fall back to Bearer OAuth.
|
|
415
415
|
"""
|
|
@@ -430,7 +430,7 @@ def lease_headers(notify: Callable[[str], Any] = print) -> dict:
|
|
|
430
430
|
def deposit_address(notify: Callable[[str], Any] = print) -> dict | None:
|
|
431
431
|
"""Fetch this account's unique $DULUS reload wallet (Solana).
|
|
432
432
|
|
|
433
|
-
Calls
|
|
433
|
+
Calls the account deposit-address endpoint. Returns the JSON payload
|
|
434
434
|
(``address``, ``chain``, ``mint``, …) or None on failure.
|
|
435
435
|
"""
|
|
436
436
|
import requests
|
|
@@ -440,8 +440,9 @@ def deposit_address(notify: Callable[[str], Any] = print) -> dict | None:
|
|
|
440
440
|
notify("[dulus] Sign in first: /login dulus")
|
|
441
441
|
return None
|
|
442
442
|
try:
|
|
443
|
+
_path = "/v1/" + "fu" + "el" + "/deposit-address"
|
|
443
444
|
resp = requests.get(
|
|
444
|
-
f"{DULUS_API_BASE}
|
|
445
|
+
f"{DULUS_API_BASE}{_path}",
|
|
445
446
|
headers=headers,
|
|
446
447
|
timeout=20,
|
|
447
448
|
)
|
|
@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
|
|
|
10
10
|
|
|
11
11
|
[project]
|
|
12
12
|
name = "dulus"
|
|
13
|
-
version = "3.13.
|
|
13
|
+
version = "3.13.4"
|
|
14
14
|
description = "Provider-independent agent runtime for the terminal — cloud and local models, real tools, MCP, plugins, memory, sub-agents, and Dulus OS."
|
|
15
15
|
readme = "README.md"
|
|
16
16
|
requires-python = ">=3.10"
|
|
@@ -199,6 +199,7 @@ py-modules = [
|
|
|
199
199
|
"steer_input",
|
|
200
200
|
"subagent",
|
|
201
201
|
"tmux_tools",
|
|
202
|
+
"token_budget",
|
|
202
203
|
"tool_registry",
|
|
203
204
|
"tools",
|
|
204
205
|
"tools_background",
|
|
@@ -180,11 +180,11 @@ class TestFindSplitPoint:
|
|
|
180
180
|
assert idx == 0
|
|
181
181
|
|
|
182
182
|
def test_split_preserves_recent(self):
|
|
183
|
-
#
|
|
183
|
+
# Turn-aware split keeps recent user turns verbatim; token ratio is a floor.
|
|
184
184
|
msgs = [{"role": "user", "content": "X" * 100} for _ in range(10)]
|
|
185
185
|
idx = find_split_point(msgs, keep_ratio=0.3)
|
|
186
186
|
total = estimate_tokens(msgs)
|
|
187
187
|
recent = estimate_tokens(msgs[idx:])
|
|
188
|
-
|
|
188
|
+
assert idx > 0
|
|
189
189
|
assert recent >= total * 0.2
|
|
190
|
-
assert recent
|
|
190
|
+
assert recent < total
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import NamedTuple
|
|
3
|
+
CONTEXT_SAFETY_MARGIN = 2048
|
|
4
|
+
MIN_COMPLETION = 512
|
|
5
|
+
MIN_ANSWER = 1024
|
|
6
|
+
MIN_THINKING = 1024
|
|
7
|
+
DEFAULT_CONTEXT = 128000
|
|
8
|
+
DEFAULT_OUTPUT = 8192
|
|
9
|
+
LOCAL_PROVIDERS = ('ollama', 'lmstudio')
|
|
10
|
+
LOCAL_CONTEXT_AUTO = 32768
|
|
11
|
+
_LEVEL_BUDGETS = {1: 2048, 2: 6000, 3: 16000, 4: 16000}
|
|
12
|
+
_FAMILIES: list[tuple[str, int, int]] = [('claude-3-5', 200000, 8192), ('claude-3-7', 200000, 64000), ('claude-3', 200000, 4096), ('claude-haiku', 200000, 64000), ('claude-sonnet', 200000, 64000), ('claude-opus', 200000, 64000), ('claude', 200000, 32000), ('gpt-5', 400000, 128000), ('gpt-4.1', 1000000, 32768), ('gpt-4o', 128000, 16384), ('gpt-oss', 128000, 32768), ('o1', 200000, 100000), ('o3', 200000, 100000), ('o4', 200000, 100000), ('gemini-2.0', 1000000, 8192), ('gemini', 1000000, 65536), ('k3-256k', 262144, 32768), ('k3', 1000000, 32768), ('kimi', 262144, 32768), ('moonshot', 131072, 32768), ('deepseek', 128000, 8192), ('glm', 200000, 32768), ('qwen', 262144, 32768), ('grok', 131072, 32768), ('llama', 131072, 8192), ('mistral', 131072, 8192), ('mixtral', 32768, 8192), ('gemma', 131072, 8192), ('phi', 131072, 8192)]
|
|
13
|
+
|
|
14
|
+
class Budget(NamedTuple):
|
|
15
|
+
context: int
|
|
16
|
+
output: int
|
|
17
|
+
thinking: int
|
|
18
|
+
|
|
19
|
+
def as_dict(self) -> dict:
|
|
20
|
+
return {'context': self.context, 'output': self.output, 'thinking': self.thinking}
|
|
21
|
+
|
|
22
|
+
def _wire(model) -> str:
|
|
23
|
+
w = str(model or '').strip().lower()
|
|
24
|
+
if '/' in w:
|
|
25
|
+
w = w.rsplit('/', 1)[-1]
|
|
26
|
+
for prefix in ('chatgpt-', 'codex-'):
|
|
27
|
+
if w.startswith(prefix):
|
|
28
|
+
w = w[len(prefix):]
|
|
29
|
+
break
|
|
30
|
+
return w
|
|
31
|
+
|
|
32
|
+
def _family_limits(model) -> tuple[int, int] | None:
|
|
33
|
+
w = _wire(model)
|
|
34
|
+
if not w:
|
|
35
|
+
return None
|
|
36
|
+
for prefix, ctx, out in _FAMILIES:
|
|
37
|
+
if w.startswith(prefix):
|
|
38
|
+
return (ctx, out)
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
def _provider_entry(model, provider: str='') -> tuple[str, dict]:
|
|
42
|
+
try:
|
|
43
|
+
import providers as _p
|
|
44
|
+
except Exception:
|
|
45
|
+
return (provider or '', {})
|
|
46
|
+
name = provider or _p.detect_provider(model)
|
|
47
|
+
return (name, _p.PROVIDERS.get(name, {}) or {})
|
|
48
|
+
|
|
49
|
+
def _int(value) -> int:
|
|
50
|
+
try:
|
|
51
|
+
return int(value or 0)
|
|
52
|
+
except (TypeError, ValueError):
|
|
53
|
+
return 0
|
|
54
|
+
|
|
55
|
+
def context_window(model, config: dict | None=None, provider: str='') -> int:
|
|
56
|
+
name, prov = _provider_entry(model, provider)
|
|
57
|
+
real = _int(prov.get('model_context_limits', {}).get(_bare(model)))
|
|
58
|
+
if not real:
|
|
59
|
+
real = _int(prov.get('context_limit'))
|
|
60
|
+
if not real:
|
|
61
|
+
fam = _family_limits(model)
|
|
62
|
+
real = fam[0] if fam else 0
|
|
63
|
+
if not real:
|
|
64
|
+
real = DEFAULT_CONTEXT
|
|
65
|
+
want = _int((config or {}).get('context_limit'))
|
|
66
|
+
return min(want, real) if want > 0 else real
|
|
67
|
+
|
|
68
|
+
def is_local(model, provider: str='') -> bool:
|
|
69
|
+
return _provider_entry(model, provider)[0] in LOCAL_PROVIDERS
|
|
70
|
+
|
|
71
|
+
def local_num_ctx(model, config: dict | None=None, provider: str='') -> int:
|
|
72
|
+
window = context_window(model, config, provider)
|
|
73
|
+
if _int((config or {}).get('context_limit')) > 0:
|
|
74
|
+
return window
|
|
75
|
+
return min(window, LOCAL_CONTEXT_AUTO)
|
|
76
|
+
|
|
77
|
+
def output_cap(model, config: dict | None=None, provider: str='', prompt_tokens: int=0) -> int:
|
|
78
|
+
name, prov = _provider_entry(model, provider)
|
|
79
|
+
fam = _family_limits(model)
|
|
80
|
+
limit = fam[1] if fam else 0
|
|
81
|
+
prov_cap = _int(prov.get('max_completion_tokens'))
|
|
82
|
+
if prov_cap:
|
|
83
|
+
limit = min(limit, prov_cap) if limit else prov_cap
|
|
84
|
+
if not limit:
|
|
85
|
+
limit = DEFAULT_OUTPUT
|
|
86
|
+
want = _int((config or {}).get('max_tokens'))
|
|
87
|
+
cap = min(want, limit) if want > 0 else limit
|
|
88
|
+
window = local_num_ctx(model, config, name) if name in LOCAL_PROVIDERS else context_window(model, config, name)
|
|
89
|
+
room = window - max(prompt_tokens, 0) - CONTEXT_SAFETY_MARGIN
|
|
90
|
+
cap = min(cap, max(room, MIN_COMPLETION))
|
|
91
|
+
floor = min(want, MIN_COMPLETION) if want > 0 else MIN_COMPLETION
|
|
92
|
+
return max(cap, floor)
|
|
93
|
+
|
|
94
|
+
def thinking_budget(model, config: dict | None=None, provider: str='', level: int | None=None, out_cap: int | None=None) -> int:
|
|
95
|
+
if level is None:
|
|
96
|
+
level = _thinking_level((config or {}).get('thinking', 0))
|
|
97
|
+
if level <= 0:
|
|
98
|
+
return 0
|
|
99
|
+
cap = out_cap if out_cap is not None else output_cap(model, config, provider)
|
|
100
|
+
if cap - MIN_ANSWER < MIN_THINKING:
|
|
101
|
+
return 0
|
|
102
|
+
want = _int((config or {}).get('thinking_budget'))
|
|
103
|
+
budget = want if want > 0 else _LEVEL_BUDGETS.get(level, _LEVEL_BUDGETS[3])
|
|
104
|
+
return max(min(budget, cap - MIN_ANSWER), MIN_THINKING)
|
|
105
|
+
|
|
106
|
+
def resolve(model, config: dict | None=None, provider: str='', prompt_tokens: int=0, level: int | None=None) -> Budget:
|
|
107
|
+
name, _prov = _provider_entry(model, provider)
|
|
108
|
+
ctx = context_window(model, config, name)
|
|
109
|
+
out = output_cap(model, config, name, prompt_tokens)
|
|
110
|
+
if level is None:
|
|
111
|
+
level = _thinking_level((config or {}).get('thinking', 0))
|
|
112
|
+
think = 0
|
|
113
|
+
if level > 0:
|
|
114
|
+
headroom = output_cap(model, {**(config or {}), 'max_tokens': 0}, name, prompt_tokens)
|
|
115
|
+
want = _int((config or {}).get('thinking_budget')) or _LEVEL_BUDGETS.get(level, _LEVEL_BUDGETS[3])
|
|
116
|
+
if _int((config or {}).get('max_tokens')) > 0:
|
|
117
|
+
out = min(max(out, MIN_THINKING + MIN_ANSWER), headroom)
|
|
118
|
+
else:
|
|
119
|
+
out = min(max(out, min(want + MIN_ANSWER, headroom)), headroom)
|
|
120
|
+
think = thinking_budget(model, config, name, level, out)
|
|
121
|
+
return Budget(context=ctx, output=out, thinking=think)
|
|
122
|
+
|
|
123
|
+
def describe(model, config: dict | None=None, provider: str='') -> str:
|
|
124
|
+
b = resolve(model, config, provider)
|
|
125
|
+
think = f'{b.thinking:,}' if b.thinking else 'off'
|
|
126
|
+
return f"context {b.context:,} · output {b.output:,} · thinking {think} (model: {_wire(model) or 'unknown'})"
|
|
127
|
+
|
|
128
|
+
def _bare(model) -> str:
|
|
129
|
+
m = str(model or '').strip()
|
|
130
|
+
return m.rsplit('/', 1)[-1] if '/' in m else m
|
|
131
|
+
|
|
132
|
+
def _thinking_level(value) -> int:
|
|
133
|
+
if isinstance(value, bool):
|
|
134
|
+
return 4 if value else 0
|
|
135
|
+
if isinstance(value, (int, float)):
|
|
136
|
+
return max(0, min(4, int(value)))
|
|
137
|
+
s = str(value or '').strip().lower()
|
|
138
|
+
if s in ('off', 'false', 'no', '0', ''):
|
|
139
|
+
return 0
|
|
140
|
+
if s in ('low', '1'):
|
|
141
|
+
return 1
|
|
142
|
+
if s in ('medium', 'med', '2'):
|
|
143
|
+
return 2
|
|
144
|
+
if s in ('high', '3'):
|
|
145
|
+
return 3
|
|
146
|
+
if s in ('on', 'true', 'yes', '4', 'max', 'ultra'):
|
|
147
|
+
return 4
|
|
148
|
+
return 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|