@mseep/open-computer-use 1.0.0
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.
- package/.coderabbit.yaml +25 -0
- package/.dockerignore +95 -0
- package/.env.example +137 -0
- package/.githooks/pre-commit +68 -0
- package/.github/CODEOWNERS +125 -0
- package/.github/ISSUE_TEMPLATE/adr-proposal.md +41 -0
- package/.github/ISSUE_TEMPLATE/bug-report.md +49 -0
- package/.github/ISSUE_TEMPLATE/component-proposal.md +38 -0
- package/.github/ISSUE_TEMPLATE/config.yml +15 -0
- package/.github/ISSUE_TEMPLATE/dependency-proposal.md +59 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
- package/.github/ISSUE_TEMPLATE/nfr-proposal.md +44 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- package/.github/codeql/codeql-config.yml +11 -0
- package/.github/codeql/extensions/security-models/python-sanitizers.model.yml +17 -0
- package/.github/codeql/extensions/security-models/qlpack.yml +7 -0
- package/.github/dependabot.yml +23 -0
- package/.github/security-exceptions.yml +23 -0
- package/.github/workflows/build.yml +420 -0
- package/.github/workflows/codeql.yml +33 -0
- package/.github/workflows/contracts-lint.yml +90 -0
- package/.github/workflows/docs-lint.yml +151 -0
- package/.github/workflows/helm.yml +131 -0
- package/.github/workflows/identity-lint.yml +30 -0
- package/.github/workflows/release-chart.yml +177 -0
- package/.github/workflows/release.yml +95 -0
- package/.github/workflows/security.yml +332 -0
- package/.github/workflows/stale.yml +31 -0
- package/.github/workflows/supply-chain.yml +242 -0
- package/.gitleaks.toml +53 -0
- package/.markdownlint.yaml +51 -0
- package/.semgrepignore +85 -0
- package/.vale/styles/Architecture/ap13-data-class-substrate.yml +12 -0
- package/.vale/styles/Architecture/banned-phrases.yml +23 -0
- package/.vale/styles/Architecture/banned-vocab.yml +23 -0
- package/.vale/styles/Architecture/marketing-tone.yml +19 -0
- package/.vale.ini +18 -0
- package/CHANGELOG.md +411 -0
- package/CLAUDE.md +218 -0
- package/CONTRIBUTING.md +82 -0
- package/Dockerfile +676 -0
- package/LICENSE +98 -0
- package/LICENSE-APACHE +202 -0
- package/LICENSE-MIT +21 -0
- package/NOTICE +36 -0
- package/README.md +516 -0
- package/SECURITY.md +45 -0
- package/THIRD-PARTY-LICENSES.md +14 -0
- package/apt-packages.txt +108 -0
- package/computer-use-server/.dockerignore +13 -0
- package/computer-use-server/Dockerfile +44 -0
- package/computer-use-server/README.md +84 -0
- package/computer-use-server/app.py +1544 -0
- package/computer-use-server/bin/list-subagent-models +449 -0
- package/computer-use-server/cli-defaults/README.md +31 -0
- package/computer-use-server/cli-defaults/codex.json +7 -0
- package/computer-use-server/cli-defaults/opencode.json +18 -0
- package/computer-use-server/cli_adapters/__init__.py +46 -0
- package/computer-use-server/cli_adapters/claude.py +163 -0
- package/computer-use-server/cli_adapters/codex.py +163 -0
- package/computer-use-server/cli_adapters/opencode.py +169 -0
- package/computer-use-server/cli_adapters/result.py +34 -0
- package/computer-use-server/cli_runtime.py +316 -0
- package/computer-use-server/context_vars.py +24 -0
- package/computer-use-server/docker_manager.py +1100 -0
- package/computer-use-server/docs_html.py +12 -0
- package/computer-use-server/mcp_resources.py +170 -0
- package/computer-use-server/mcp_tools.py +1430 -0
- package/computer-use-server/requirements.txt +17 -0
- package/computer-use-server/security.py +50 -0
- package/computer-use-server/skill_manager.py +664 -0
- package/computer-use-server/static/browser-viewer.js +445 -0
- package/computer-use-server/static/chart.umd.js +14 -0
- package/computer-use-server/static/docs.html +203 -0
- package/computer-use-server/static/github-dark.min.css +10 -0
- package/computer-use-server/static/github.min.css +10 -0
- package/computer-use-server/static/highlight.min.js +1213 -0
- package/computer-use-server/static/highlightjs-line-numbers.min.js +1 -0
- package/computer-use-server/static/icons.js +74 -0
- package/computer-use-server/static/jszip.min.js +13 -0
- package/computer-use-server/static/katex/auto-render.min.js +1 -0
- package/computer-use-server/static/katex/fonts/KaTeX_AMS-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_AMS-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Bold.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Bold.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Bold.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-BoldItalic.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Italic.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Italic.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Math-BoldItalic.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Math-Italic.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Math-Italic.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Bold.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Italic.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Script-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Script-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size1-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size1-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size2-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size2-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size3-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size3-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size4-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size4-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Typewriter-Regular.woff +0 -0
- package/computer-use-server/static/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- package/computer-use-server/static/katex/katex.min.css +1 -0
- package/computer-use-server/static/katex/katex.min.js +1 -0
- package/computer-use-server/static/locale.js +242 -0
- package/computer-use-server/static/mammoth.browser.min.js +21 -0
- package/computer-use-server/static/marked.min.js +6 -0
- package/computer-use-server/static/mermaid.min.js +2811 -0
- package/computer-use-server/static/pdf.min.js +22 -0
- package/computer-use-server/static/pdf.worker.min.js +22 -0
- package/computer-use-server/static/pptxviewjs.min.js +1 -0
- package/computer-use-server/static/preact-htm.min.js +1 -0
- package/computer-use-server/static/preview.css +1030 -0
- package/computer-use-server/static/preview.js +1522 -0
- package/computer-use-server/static/xlsx.full.min.js +22 -0
- package/computer-use-server/static/xterm-addon-fit.min.js +2 -0
- package/computer-use-server/static/xterm-addon-web-links.min.js +2 -0
- package/computer-use-server/static/xterm.css +218 -0
- package/computer-use-server/static/xterm.min.js +2 -0
- package/computer-use-server/system_prompt.py +761 -0
- package/computer-use-server/uploads.py +82 -0
- package/contracts/README.md +53 -0
- package/contracts/audit/audit-fanin.asyncapi.yaml +407 -0
- package/contracts/exec/exec-channel.schema.json +240 -0
- package/contracts/mcp/2025-06-18/ocu-constraints.schema.json +178 -0
- package/contracts/storage/file-artifact-api.schema.json +390 -0
- package/contracts/storage/file-ops.schema.json +217 -0
- package/contracts/storage/mount-config.schema.json +197 -0
- package/cron/Dockerfile +15 -0
- package/cron/cleanup-quick.sh +21 -0
- package/cron/cleanup.sh +127 -0
- package/data/outputs/.gitkeep +0 -0
- package/data/uploads/.gitkeep +0 -0
- package/docker-compose.test.yml +54 -0
- package/docker-compose.webui.yml +77 -0
- package/docker-compose.yml +96 -0
- package/docs/CLOUD.md +29 -0
- package/docs/COMPARISON.md +128 -0
- package/docs/DOCKER.md +469 -0
- package/docs/DYNAMIC-SKILLS.md +77 -0
- package/docs/FEATURES.md +100 -0
- package/docs/INSTALL.md +111 -0
- package/docs/KNOWN-BUGS.md +86 -0
- package/docs/MCP.md +320 -0
- package/docs/SCREENSHOTS.md +39 -0
- package/docs/SKILLS-USER-GUIDE.md +86 -0
- package/docs/SKILLS.md +483 -0
- package/docs/TERMINAL-TAB.md +56 -0
- package/docs/architecture/02-trust-boundaries.md +224 -0
- package/docs/architecture/03-c4-context.md +61 -0
- package/docs/architecture/04-bounded-contexts.md +119 -0
- package/docs/architecture/05-c4-container.md +88 -0
- package/docs/architecture/06-threat-model.md +172 -0
- package/docs/architecture/08-contracts.md +105 -0
- package/docs/architecture/MANIFESTO.md +38 -0
- package/docs/architecture/PROCESS.md +64 -0
- package/docs/architecture/README.md +37 -0
- package/docs/architecture/adr/0000-template.md +65 -0
- package/docs/architecture/adr/0001-layer-0-gate-legacy-exclusion.md +75 -0
- package/docs/architecture/adr/0002-session-view-descriptor.md +57 -0
- package/docs/architecture/adr/0003-sandbox-runtime-tier-ladder.md +63 -0
- package/docs/architecture/adr/0004-operator-authentication-substrate.md +63 -0
- package/docs/architecture/adr/0005-egress-credential-delivery-envoy-sds.md +62 -0
- package/docs/architecture/adr/0006-egress-forward-proxy-substrate.md +65 -0
- package/docs/architecture/adr/0007-egress-auth-mechanism.md +72 -0
- package/docs/architecture/adr/0008-session-egress-attribution.md +59 -0
- package/docs/architecture/adr/0009-audit-pipeline-pluggable-by-contract.md +76 -0
- package/docs/architecture/adr/0010-storage-backend-pluggable-adapter.md +60 -0
- package/docs/architecture/adr/0011-storage-egress-lane.md +67 -0
- package/docs/architecture/adr/0012-implementation-language.md +67 -0
- package/docs/architecture/adr/0020-sandbox-image-provisioning.md +82 -0
- package/docs/architecture/adr/README.md +53 -0
- package/docs/architecture/compliance/.gitkeep +0 -0
- package/docs/architecture/components/00-overview.md +42 -0
- package/docs/architecture/components/0000-template.md +50 -0
- package/docs/architecture/components/01-mcp-gateway.md +80 -0
- package/docs/architecture/components/02-control-operator-api.md +80 -0
- package/docs/architecture/components/04-storage-broker.md +104 -0
- package/docs/architecture/components/05-session-sandbox.md +93 -0
- package/docs/architecture/components/06-egress-trust-edge.md +95 -0
- package/docs/architecture/components/07-audit-pipeline.md +110 -0
- package/docs/architecture/diagrams/.gitkeep +0 -0
- package/docs/architecture/diagrams/02-trust-boundaries.mmd +111 -0
- package/docs/architecture/diagrams/06-threat-model.mmd +41 -0
- package/docs/architecture/diagrams/08-contracts.mmd +47 -0
- package/docs/architecture/diagrams/c4-container.mmd +59 -0
- package/docs/architecture/diagrams/c4-context.mmd +46 -0
- package/docs/architecture/glossary.md +172 -0
- package/docs/architecture/manifesto/.gitkeep +0 -0
- package/docs/architecture/manifesto/01-audience-and-buyer.md +57 -0
- package/docs/architecture/manifesto/02-nfrs.md +325 -0
- package/docs/architecture/manifesto/03-non-negotiables.md +35 -0
- package/docs/architecture/manifesto/04-non-goals.md +23 -0
- package/docs/architecture/manifesto/05-licensing-posture.md +61 -0
- package/docs/architecture/manifesto/06-starter-mode-policy.md +49 -0
- package/docs/architecture/manifesto/07-governance.md +60 -0
- package/docs/architecture/primitives-backlog.md +51 -0
- package/docs/architecture.svg +117 -0
- package/docs/claude-code-gateway.md +173 -0
- package/docs/cli-config-templates.md +240 -0
- package/docs/data-flow.svg +72 -0
- package/docs/demo-landing-page.gif +0 -0
- package/docs/demo-qwen-trending.gif +0 -0
- package/docs/dynamic-skills.svg +77 -0
- package/docs/file-flow.svg +126 -0
- package/docs/future-architecture/README.md +152 -0
- package/docs/future-architecture/adr/0001-control-plane-language-go.md +80 -0
- package/docs/future-architecture/adr/0002-guest-agent-language-go.md +84 -0
- package/docs/future-architecture/adr/0003-docker-poc-first-then-k8s.md +37 -0
- package/docs/future-architecture/adr/0004-pluggable-runtime-via-runtimeclass.md +34 -0
- package/docs/future-architecture/adr/0005-mcp-as-control-plane-gateway.md +34 -0
- package/docs/future-architecture/adr/0006-no-agpl-no-bsl-dependencies.md +41 -0
- package/docs/future-architecture/adr/0007-superseded-by-future-architecture.md +37 -0
- package/docs/future-architecture/adr/0008-internal-grpc-external-rest-mcp.md +106 -0
- package/docs/future-architecture/adr/0009-external-protocol-dialects.md +94 -0
- package/docs/future-architecture/adr/0010-lambda-as-inspiration-not-runtime.md +86 -0
- package/docs/future-architecture/adr/0011-kata-as-first-class-dind-runtime.md +84 -0
- package/docs/future-architecture/antipatterns.md +552 -0
- package/docs/future-architecture/architecture/01-layers.md +109 -0
- package/docs/future-architecture/architecture/02-layer4-control-plane.md +122 -0
- package/docs/future-architecture/architecture/03-layer3-providers.md +174 -0
- package/docs/future-architecture/architecture/04-layer2-runtimes.md +114 -0
- package/docs/future-architecture/architecture/04b-credential-broker.md +153 -0
- package/docs/future-architecture/architecture/05-layer1-guest-agent.md +138 -0
- package/docs/future-architecture/architecture/06-storage.md +134 -0
- package/docs/future-architecture/architecture/07-security.md +194 -0
- package/docs/future-architecture/architecture/08-networking.md +149 -0
- package/docs/future-architecture/architecture/09-templates.md +122 -0
- package/docs/future-architecture/architecture/10-observability.md +121 -0
- package/docs/future-architecture/design-notes.md +72 -0
- package/docs/future-architecture/gaps.md +281 -0
- package/docs/future-architecture/phase-template.md +123 -0
- package/docs/future-architecture/references.md +225 -0
- package/docs/future-architecture/research/01-kata-containers.md +100 -0
- package/docs/future-architecture/research/02-e2b-infra.md +133 -0
- package/docs/future-architecture/research/03-coder.md +115 -0
- package/docs/future-architecture/research/04-cloud-hypervisor.md +99 -0
- package/docs/future-architecture/research/05-firecracker.md +114 -0
- package/docs/future-architecture/research/06-agent-sandbox.md +142 -0
- package/docs/future-architecture/research/07-chromedp.md +78 -0
- package/docs/future-architecture/research/08-microsandbox.md +78 -0
- package/docs/future-architecture/research/09-agentbox.md +135 -0
- package/docs/future-architecture/research/10-sysbox.md +100 -0
- package/docs/future-architecture/research/11-firecracker-containerd.md +93 -0
- package/docs/future-architecture/research/12-docker-socket-proxy.md +59 -0
- package/docs/future-architecture/research/14-e2b-desktop-and-surf.md +107 -0
- package/docs/future-architecture/research/18-open-webui-terminals-observed.md +135 -0
- package/docs/future-architecture/research/bank-buyer.md +96 -0
- package/docs/future-architecture/research/enthusiast-audience.md +106 -0
- package/docs/future-architecture/research/proof-uipath-anthropic-2026-05.md +76 -0
- package/docs/future-architecture/research/widemoat-thesis-advisor.md +124 -0
- package/docs/future-architecture/roadmap.md +438 -0
- package/docs/kata-runtime.md +267 -0
- package/docs/kubernetes.md +86 -0
- package/docs/logo.png +0 -0
- package/docs/multi-cli.md +161 -0
- package/docs/openwebui-filter.md +134 -0
- package/docs/roadmap/implementation-roadmap.md +104 -0
- package/docs/sandbox-contents.svg +229 -0
- package/docs/screenshots/01-create-document.png +0 -0
- package/docs/screenshots/02-file-preview.png +0 -0
- package/docs/screenshots/03-browser-viewer.png +0 -0
- package/docs/screenshots/04-sub-agent-terminal.png +0 -0
- package/docs/screenshots/05-chat-overview.png +0 -0
- package/docs/screenshots/06-sub-agent-dashboard.png +0 -0
- package/docs/screenshots/07-frontend-design-skill.png +0 -0
- package/docs/screenshots/08-pptx-skill.png +0 -0
- package/docs/screenshots/09-skill-creator.png +0 -0
- package/docs/screenshots/10-data-chart.png +0 -0
- package/docs/shared-browser.svg +102 -0
- package/docs/system-prompt.md +113 -0
- package/docs/terminal-flow.svg +69 -0
- package/examples/helm/README.md +20 -0
- package/examples/helm/standalone/values.yaml +49 -0
- package/examples/helm/with-open-webui/README.md +99 -0
- package/examples/helm/with-open-webui/values-computer-use.yaml +32 -0
- package/examples/helm/with-open-webui/values-open-webui.yaml +67 -0
- package/fonts/NotoEmoji-Regular.ttf +0 -0
- package/helm/computer-use-server/.helmignore +17 -0
- package/helm/computer-use-server/Chart.yaml +32 -0
- package/helm/computer-use-server/README.md +211 -0
- package/helm/computer-use-server/templates/NOTES.txt +66 -0
- package/helm/computer-use-server/templates/_helpers.tpl +115 -0
- package/helm/computer-use-server/templates/configmap-dind-init.yaml +82 -0
- package/helm/computer-use-server/templates/configmap.yaml +18 -0
- package/helm/computer-use-server/templates/deployment.yaml +248 -0
- package/helm/computer-use-server/templates/ingress.yaml +38 -0
- package/helm/computer-use-server/templates/networkpolicy.yaml +50 -0
- package/helm/computer-use-server/templates/pdb.yaml +16 -0
- package/helm/computer-use-server/templates/pvc-data.yaml +20 -0
- package/helm/computer-use-server/templates/pvc-skills-cache.yaml +20 -0
- package/helm/computer-use-server/templates/pvc-user-data.yaml +20 -0
- package/helm/computer-use-server/templates/pvc-var-lib-docker.yaml +27 -0
- package/helm/computer-use-server/templates/secret.yaml +23 -0
- package/helm/computer-use-server/templates/service.yaml +22 -0
- package/helm/computer-use-server/templates/serviceaccount.yaml +15 -0
- package/helm/computer-use-server/templates/tests/test-health.yaml +23 -0
- package/helm/computer-use-server/values.schema.json +183 -0
- package/helm/computer-use-server/values.yaml +297 -0
- package/lychee.toml +36 -0
- package/openwebui/Dockerfile +52 -0
- package/openwebui/README.md +38 -0
- package/openwebui/functions/README.md +48 -0
- package/openwebui/functions/computer_link_filter.py +487 -0
- package/openwebui/init.sh +305 -0
- package/openwebui/patches/README.md +44 -0
- package/openwebui/patches/fix_artifacts_auto_show.py +441 -0
- package/openwebui/patches/fix_attached_files_position.py +87 -0
- package/openwebui/patches/fix_large_tool_args.py +156 -0
- package/openwebui/patches/fix_large_tool_results.py +289 -0
- package/openwebui/patches/fix_preview_url_detection.py +230 -0
- package/openwebui/patches/fix_skip_embedding_chat_files.py +229 -0
- package/openwebui/patches/fix_skip_rag_files_native_fc.py +100 -0
- package/openwebui/patches/fix_tool_loop_errors.py +510 -0
- package/package.json +39 -0
- package/requirements.txt +112 -0
- package/scripts/check-config.sh +141 -0
- package/scripts/docs-lint/ai-slop-detector.sh +202 -0
- package/scripts/docs-lint/architecture-tree-whitelist.sh +131 -0
- package/scripts/docs-lint/ascii-diagram-detector.sh +58 -0
- package/scripts/docs-lint/front-matter-validator.sh +97 -0
- package/scripts/docs-lint/gitignored-ref-detector.sh +122 -0
- package/scripts/docs-lint/identity-email-detector.sh +48 -0
- package/scripts/docs-lint/test-linters.sh +354 -0
- package/scripts/docs-lint/wc-budget.sh +61 -0
- package/scripts/githooks/pre-push +75 -0
- package/server.json +13 -0
- package/settings-wrapper/Dockerfile +9 -0
- package/settings-wrapper/README.md +119 -0
- package/settings-wrapper/app.py +113 -0
- package/settings-wrapper/requirements.txt +2 -0
- package/settings-wrapper/skills.json +25 -0
- package/skills/README.md +46 -0
- package/skills/examples/algorithmic-art/SKILL.md +405 -0
- package/skills/examples/algorithmic-art/templates/generator_template.js +223 -0
- package/skills/examples/algorithmic-art/templates/viewer.html +601 -0
- package/skills/examples/artifacts-builder/SKILL.md +74 -0
- package/skills/examples/artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/skills/examples/artifacts-builder/scripts/init-artifact.sh +322 -0
- package/skills/examples/artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/skills/examples/canvas-design/LICENSE.txt +202 -0
- package/skills/examples/canvas-design/SKILL.md +130 -0
- package/skills/examples/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
- package/skills/examples/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
- package/skills/examples/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
- package/skills/examples/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
- package/skills/examples/copy-editing/SKILL.md +447 -0
- package/skills/examples/copy-editing/evals/evals.json +89 -0
- package/skills/examples/copy-editing/references/plain-english-alternatives.md +394 -0
- package/skills/examples/internal-comms/LICENSE.txt +202 -0
- package/skills/examples/internal-comms/SKILL.md +32 -0
- package/skills/examples/internal-comms/examples/3p-updates.md +47 -0
- package/skills/examples/internal-comms/examples/company-newsletter.md +65 -0
- package/skills/examples/internal-comms/examples/faq-answers.md +30 -0
- package/skills/examples/internal-comms/examples/general-comms.md +16 -0
- package/skills/examples/mcp-builder/SKILL.md +328 -0
- package/skills/examples/mcp-builder/reference/evaluation.md +602 -0
- package/skills/examples/mcp-builder/reference/mcp_best_practices.md +915 -0
- package/skills/examples/mcp-builder/reference/node_mcp_server.md +916 -0
- package/skills/examples/mcp-builder/reference/python_mcp_server.md +752 -0
- package/skills/examples/mcp-builder/scripts/connections.py +151 -0
- package/skills/examples/mcp-builder/scripts/evaluation.py +373 -0
- package/skills/examples/mcp-builder/scripts/example_evaluation.xml +22 -0
- package/skills/examples/mcp-builder/scripts/requirements.txt +2 -0
- package/skills/examples/product-marketing-context/SKILL.md +241 -0
- package/skills/examples/product-marketing-context/evals/evals.json +85 -0
- package/skills/examples/single-cell-rna-qc/SKILL.md +175 -0
- package/skills/examples/single-cell-rna-qc/references/scverse_qc_guidelines.md +186 -0
- package/skills/examples/single-cell-rna-qc/scripts/qc_analysis.py +232 -0
- package/skills/examples/single-cell-rna-qc/scripts/qc_core.py +233 -0
- package/skills/examples/single-cell-rna-qc/scripts/qc_plotting.py +235 -0
- package/skills/examples/skill-creator/SKILL.md +355 -0
- package/skills/examples/skill-creator/references/output-patterns.md +82 -0
- package/skills/examples/skill-creator/references/workflows.md +28 -0
- package/skills/examples/skill-creator/scripts/init_skill.py +303 -0
- package/skills/examples/skill-creator/scripts/package_skill.py +110 -0
- package/skills/examples/skill-creator/scripts/quick_validate.py +95 -0
- package/skills/examples/slack-gif-creator/SKILL.md +254 -0
- package/skills/examples/slack-gif-creator/core/easing.py +234 -0
- package/skills/examples/slack-gif-creator/core/frame_composer.py +176 -0
- package/skills/examples/slack-gif-creator/core/gif_builder.py +269 -0
- package/skills/examples/slack-gif-creator/core/validators.py +136 -0
- package/skills/examples/slack-gif-creator/requirements.txt +4 -0
- package/skills/examples/social-content/SKILL.md +278 -0
- package/skills/examples/social-content/evals/evals.json +92 -0
- package/skills/examples/social-content/references/platforms.md +170 -0
- package/skills/examples/social-content/references/post-templates.md +177 -0
- package/skills/examples/social-content/references/reverse-engineering.md +195 -0
- package/skills/examples/theme-factory/SKILL.md +59 -0
- package/skills/examples/theme-factory/theme-showcase.pdf +0 -0
- package/skills/examples/theme-factory/themes/arctic-frost.md +19 -0
- package/skills/examples/theme-factory/themes/botanical-garden.md +19 -0
- package/skills/examples/theme-factory/themes/desert-rose.md +19 -0
- package/skills/examples/theme-factory/themes/forest-canopy.md +19 -0
- package/skills/examples/theme-factory/themes/golden-hour.md +19 -0
- package/skills/examples/theme-factory/themes/midnight-galaxy.md +19 -0
- package/skills/examples/theme-factory/themes/modern-minimalist.md +19 -0
- package/skills/examples/theme-factory/themes/ocean-depths.md +19 -0
- package/skills/examples/theme-factory/themes/sunset-boulevard.md +19 -0
- package/skills/examples/theme-factory/themes/tech-innovation.md +19 -0
- package/skills/examples/web-artifacts-builder/LICENSE.txt +202 -0
- package/skills/examples/web-artifacts-builder/SKILL.md +74 -0
- package/skills/examples/web-artifacts-builder/scripts/bundle-artifact.sh +54 -0
- package/skills/examples/web-artifacts-builder/scripts/init-artifact.sh +322 -0
- package/skills/examples/web-artifacts-builder/scripts/shadcn-components.tar.gz +0 -0
- package/skills/examples/writing-skills/SKILL.md +655 -0
- package/skills/examples/writing-skills/anthropic-best-practices.md +1150 -0
- package/skills/examples/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/skills/examples/writing-skills/graphviz-conventions.dot +172 -0
- package/skills/examples/writing-skills/persuasion-principles.md +187 -0
- package/skills/examples/writing-skills/render-graphs.js +168 -0
- package/skills/examples/writing-skills/testing-skills-with-subagents.md +384 -0
- package/skills/public/describe-image/SKILL.md +105 -0
- package/skills/public/describe-image/scripts/describe.py +389 -0
- package/skills/public/doc-coauthoring/SKILL.md +375 -0
- package/skills/public/docx/LICENSE.txt +30 -0
- package/skills/public/docx/SKILL.md +199 -0
- package/skills/public/docx/docx-js.md +350 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/public/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/public/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/public/docx/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/public/docx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/public/docx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/public/docx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/public/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/public/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/public/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/public/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/public/docx/ooxml/scripts/pack.py +159 -0
- package/skills/public/docx/ooxml/scripts/unpack.py +29 -0
- package/skills/public/docx/ooxml/scripts/validate.py +69 -0
- package/skills/public/docx/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/public/docx/ooxml/scripts/validation/base.py +951 -0
- package/skills/public/docx/ooxml/scripts/validation/docx.py +274 -0
- package/skills/public/docx/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/public/docx/ooxml/scripts/validation/redlining.py +279 -0
- package/skills/public/docx/ooxml.md +632 -0
- package/skills/public/docx/scripts/__init__.py +1 -0
- package/skills/public/docx/scripts/document.py +1292 -0
- package/skills/public/docx/scripts/templates/comments.xml +3 -0
- package/skills/public/docx/scripts/templates/commentsExtended.xml +3 -0
- package/skills/public/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/skills/public/docx/scripts/templates/commentsIds.xml +3 -0
- package/skills/public/docx/scripts/templates/people.xml +3 -0
- package/skills/public/docx/scripts/utilities.py +374 -0
- package/skills/public/file-reading/LICENSE.txt +30 -0
- package/skills/public/file-reading/SKILL.md +350 -0
- package/skills/public/frontend-design/LICENSE.txt +177 -0
- package/skills/public/frontend-design/SKILL.md +42 -0
- package/skills/public/gitlab-explorer/SKILL.md +174 -0
- package/skills/public/gitlab-explorer/references/git-commands.md +323 -0
- package/skills/public/gitlab-explorer/references/glab-commands.md +282 -0
- package/skills/public/gitlab-explorer/scripts/check_gitlab_auth.sh +109 -0
- package/skills/public/pdf/FORMS.md +205 -0
- package/skills/public/pdf/REFERENCE.md +612 -0
- package/skills/public/pdf/SKILL.md +364 -0
- package/skills/public/pdf/scripts/check_bounding_boxes.py +70 -0
- package/skills/public/pdf/scripts/check_bounding_boxes_test.py +226 -0
- package/skills/public/pdf/scripts/check_fillable_fields.py +12 -0
- package/skills/public/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/skills/public/pdf/scripts/create_validation_image.py +41 -0
- package/skills/public/pdf/scripts/extract_form_field_info.py +152 -0
- package/skills/public/pdf/scripts/fill_fillable_fields.py +114 -0
- package/skills/public/pdf/scripts/fill_pdf_form_with_annotations.py +108 -0
- package/skills/public/pdf-reading/LICENSE.txt +30 -0
- package/skills/public/pdf-reading/REFERENCE.md +196 -0
- package/skills/public/pdf-reading/SKILL.md +305 -0
- package/skills/public/playwright-cli/SKILL.md +278 -0
- package/skills/public/playwright-cli/references/request-mocking.md +87 -0
- package/skills/public/playwright-cli/references/running-code.md +232 -0
- package/skills/public/playwright-cli/references/session-management.md +169 -0
- package/skills/public/playwright-cli/references/storage-state.md +275 -0
- package/skills/public/playwright-cli/references/test-generation.md +88 -0
- package/skills/public/playwright-cli/references/tracing.md +139 -0
- package/skills/public/playwright-cli/references/video-recording.md +43 -0
- package/skills/public/pptx/LICENSE.txt +30 -0
- package/skills/public/pptx/SKILL.md +484 -0
- package/skills/public/pptx/css.md +335 -0
- package/skills/public/pptx/html2pptx.md +893 -0
- package/skills/public/pptx/html2pptx.tgz +0 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/public/pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/public/pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/public/pptx/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/public/pptx/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/public/pptx/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/public/pptx/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/public/pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/public/pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/public/pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/public/pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/public/pptx/ooxml/scripts/pack.py +159 -0
- package/skills/public/pptx/ooxml/scripts/unpack.py +29 -0
- package/skills/public/pptx/ooxml/scripts/validate.py +69 -0
- package/skills/public/pptx/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/public/pptx/ooxml/scripts/validation/base.py +951 -0
- package/skills/public/pptx/ooxml/scripts/validation/docx.py +274 -0
- package/skills/public/pptx/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/public/pptx/ooxml/scripts/validation/redlining.py +279 -0
- package/skills/public/pptx/ooxml.md +427 -0
- package/skills/public/pptx/scripts/inventory.py +1020 -0
- package/skills/public/pptx/scripts/rearrange.py +231 -0
- package/skills/public/pptx/scripts/replace.py +385 -0
- package/skills/public/pptx/scripts/thumbnail.py +450 -0
- package/skills/public/skill-creator/SKILL.md +356 -0
- package/skills/public/skill-creator/references/output-patterns.md +82 -0
- package/skills/public/skill-creator/references/workflows.md +28 -0
- package/skills/public/skill-creator/scripts/init_skill.py +303 -0
- package/skills/public/skill-creator/scripts/package_skill.py +110 -0
- package/skills/public/skill-creator/scripts/quick_validate.py +95 -0
- package/skills/public/sub-agent/SKILL.md +186 -0
- package/skills/public/sub-agent/references/security-review.md +153 -0
- package/skills/public/sub-agent/references/usage.md +207 -0
- package/skills/public/sub-agent/scripts/list_subagent_models.sh +22 -0
- package/skills/public/test-driven-development/SKILL.md +371 -0
- package/skills/public/test-driven-development/testing-anti-patterns.md +299 -0
- package/skills/public/webapp-testing/LICENSE.txt +202 -0
- package/skills/public/webapp-testing/SKILL.md +96 -0
- package/skills/public/webapp-testing/examples/console_logging.py +35 -0
- package/skills/public/webapp-testing/examples/element_discovery.py +40 -0
- package/skills/public/webapp-testing/examples/static_html_automation.py +33 -0
- package/skills/public/webapp-testing/scripts/with_server.py +106 -0
- package/skills/public/xlsx/LICENSE.txt +30 -0
- package/skills/public/xlsx/SKILL.md +316 -0
- package/skills/public/xlsx/preview_data.py +93 -0
- package/skills/public/xlsx/recalc.py +178 -0
- package/tests/README.md +42 -0
- package/tests/fixtures/cli/claude_v0.9.2.0_argv.json +46 -0
- package/tests/fixtures/cli/claude_v0.9.2.0_stdout.json +32 -0
- package/tests/fixtures/cli/codex_run.jsonl +4 -0
- package/tests/fixtures/cli/opencode_run.jsonl +6 -0
- package/tests/integration/README.md +56 -0
- package/tests/integration/conftest.py +280 -0
- package/tests/integration/pytest.ini +13 -0
- package/tests/integration/test_mcp_auth.py +85 -0
- package/tests/integration/test_mcp_tools.py +101 -0
- package/tests/integration/test_workspace_lifecycle.py +125 -0
- package/tests/orchestrator/mock_llm_server.py +343 -0
- package/tests/orchestrator/test_cli_adapters.py +566 -0
- package/tests/orchestrator/test_cli_adapters_live.py +527 -0
- package/tests/orchestrator/test_cli_runtime.py +451 -0
- package/tests/orchestrator/test_docker_manager.py +302 -0
- package/tests/orchestrator/test_dynamic_instructions.py +69 -0
- package/tests/orchestrator/test_mcp_resources.py +140 -0
- package/tests/orchestrator/test_mcp_tools.py +224 -0
- package/tests/orchestrator/test_passthrough_isolation.py +201 -0
- package/tests/orchestrator/test_readme_in_container.py +76 -0
- package/tests/orchestrator/test_render_cache.py +84 -0
- package/tests/orchestrator/test_runtime_cli_endpoint.py +108 -0
- package/tests/orchestrator/test_single_user_mode.py +212 -0
- package/tests/orchestrator/test_startup_warnings.py +123 -0
- package/tests/orchestrator/test_sub_agent_dispatch.py +327 -0
- package/tests/orchestrator/test_subagent_claude_compat.py +367 -0
- package/tests/orchestrator/test_system_prompt_endpoint.py +191 -0
- package/tests/orchestrator/test_tool_descriptions.py +52 -0
- package/tests/orchestrator/test_view_image.py +201 -0
- package/tests/patches/conftest.py +30 -0
- package/tests/patches/fixtures/__init__.py +10 -0
- package/tests/patches/fixtures/middleware_v0.9.1.py +5057 -0
- package/tests/patches/fixtures/middleware_v0.9.2.py +5120 -0
- package/tests/patches/fixtures/retrieval_v0.9.1.py +2684 -0
- package/tests/patches/fixtures/retrieval_v0.9.2.py +2700 -0
- package/tests/patches/test_fix_attached_files_position.py +118 -0
- package/tests/patches/test_fix_large_tool_args.py +130 -0
- package/tests/patches/test_fix_large_tool_results.py +531 -0
- package/tests/patches/test_fix_skip_embedding_chat_files.py +160 -0
- package/tests/patches/test_fix_skip_rag_files_native_fc.py +120 -0
- package/tests/patches/test_fix_tool_loop_errors.py +128 -0
- package/tests/security/test_path_traversal_app.py +132 -0
- package/tests/security/test_path_traversal_docker.py +36 -0
- package/tests/security/test_path_traversal_settings.py +87 -0
- package/tests/security/test_safe_path_util.py +166 -0
- package/tests/security/test_xss_preview.py +46 -0
- package/tests/test-default-model-resolution.py +136 -0
- package/tests/test-docker-image.sh +358 -0
- package/tests/test-list-subagent-models.sh +421 -0
- package/tests/test-mcp-endpoint-live.sh +92 -0
- package/tests/test-mcp-native-surface.sh +213 -0
- package/tests/test-no-cyrillic.sh +135 -0
- package/tests/test-opencode-error-mapping.py +130 -0
- package/tests/test-pr88-skills.sh +305 -0
- package/tests/test-project-structure.sh +202 -0
- package/tests/test-single-user-mode.sh +269 -0
- package/tests/test-skill-no-hardcoded-models.sh +65 -0
- package/tests/test-subagent-cli-surface.py +137 -0
- package/tests/test-subagent-runtime.sh +109 -0
- package/tests/test_codex_toml_converter.py +204 -0
- package/tests/test_default_resolver_no_legacy_global.py +159 -0
- package/tests/test_filter.py +648 -0
- package/tests/test_init_sh_unchanged.sh +49 -0
- package/tests/test_opencode_alias_map_drop.py +144 -0
- package/tests/test_requirements.py +91 -0
- package/tests/test_subagent_docstring.py +193 -0
- package/tests/test_tools.py +34 -0
- package/vendor/extract-text/README.md +46 -0
- package/vendor/extract-text/extract-text +0 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# SPDX-License-Identifier: FSL-1.1-Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Open Computer Use Contributors
|
|
3
|
+
"""TEST-04: end-to-end dispatch suite for mcp_tools.sub_agent.
|
|
4
|
+
|
|
5
|
+
Mocks the subprocess boundary (cli_runtime.dispatch is replaced with an
|
|
6
|
+
AsyncMock that returns a synthetic SubAgentResult) and asserts:
|
|
7
|
+
|
|
8
|
+
1. The MCP tool signature is byte-identical to the v0.9.2.0 contract:
|
|
9
|
+
sub_agent(task, description, ctx, model='', max_turns=0,
|
|
10
|
+
working_directory='/home/assistant', resume_session_id='').
|
|
11
|
+
2. dispatch routes to the correct adapter for each SUBAGENT_CLI value
|
|
12
|
+
({claude, codex, opencode}) — verified by inspecting cli_runtime.resolve_cli()
|
|
13
|
+
under the active env at dispatch time.
|
|
14
|
+
3. Cost-guardrail caveat (Phase 7 success criterion 5; PITFALLS.md Pitfall 4):
|
|
15
|
+
when SubAgentResult.cost_usd is None (codex always; opencode when usage
|
|
16
|
+
is missing), the rendered MCP result string contains the literal
|
|
17
|
+
"unavailable" and contains NO "$0.0" / "$0.00" substring.
|
|
18
|
+
When cost_usd is a float, the rendered string contains "$X.XXXX".
|
|
19
|
+
|
|
20
|
+
The cost rendering branch was inlined into mcp_tools.sub_agent by Phase 5
|
|
21
|
+
plan 05-05 (verified at mcp_tools.py:1092-1095). This suite is the
|
|
22
|
+
regression guard that prevents future drift.
|
|
23
|
+
|
|
24
|
+
Mirrors the env-scrub + module-reload pattern from
|
|
25
|
+
tests/orchestrator/test_subagent_claude_compat.py so local-dev shells
|
|
26
|
+
with model-override env vars exported do not break the assertions.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
import asyncio
|
|
30
|
+
import importlib
|
|
31
|
+
import inspect
|
|
32
|
+
import os
|
|
33
|
+
import sys
|
|
34
|
+
from unittest.mock import AsyncMock, MagicMock
|
|
35
|
+
|
|
36
|
+
import pytest
|
|
37
|
+
|
|
38
|
+
_SERVER_DIR = os.path.join(
|
|
39
|
+
os.path.dirname(__file__), "..", "..", "computer-use-server"
|
|
40
|
+
)
|
|
41
|
+
sys.path.insert(0, _SERVER_DIR)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# Env scrub — mirror test_subagent_claude_compat.py so local dev does not
|
|
46
|
+
# poison the model-resolution assertions.
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
_DEV_ENV_VARS_TO_SCRUB = (
|
|
49
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
50
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
51
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
52
|
+
"CLAUDE_SUB_AGENT_DEFAULT_MODEL",
|
|
53
|
+
"CODEX_SUB_AGENT_DEFAULT_MODEL",
|
|
54
|
+
"OPENCODE_SUB_AGENT_DEFAULT_MODEL",
|
|
55
|
+
"CODEX_MODEL",
|
|
56
|
+
"OPENCODE_MODEL",
|
|
57
|
+
"OPENCODE_MODEL_ALIASES",
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _scrub_dev_env(monkeypatch):
|
|
62
|
+
for var in _DEV_ENV_VARS_TO_SCRUB:
|
|
63
|
+
monkeypatch.delenv(var, raising=False)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _make_result(*, cost_usd, text="OK", is_error=False, turns=1, returncode=0):
|
|
67
|
+
"""Build a synthetic SubAgentResult.
|
|
68
|
+
|
|
69
|
+
Matches cli_adapters/result.py SubAgentResult fields exactly
|
|
70
|
+
(frozen dataclass: text, cost_usd, turns, is_error, session_id,
|
|
71
|
+
raw_events, returncode).
|
|
72
|
+
"""
|
|
73
|
+
from cli_adapters.result import SubAgentResult
|
|
74
|
+
return SubAgentResult(
|
|
75
|
+
text=text,
|
|
76
|
+
cost_usd=cost_usd,
|
|
77
|
+
turns=turns,
|
|
78
|
+
is_error=is_error,
|
|
79
|
+
session_id="test-session",
|
|
80
|
+
raw_events=[],
|
|
81
|
+
returncode=returncode,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _make_ctx():
|
|
86
|
+
"""Minimal FastMCP Context double — only the methods sub_agent calls."""
|
|
87
|
+
ctx = MagicMock()
|
|
88
|
+
ctx.report_progress = AsyncMock()
|
|
89
|
+
ctx.info = MagicMock()
|
|
90
|
+
ctx.warning = MagicMock()
|
|
91
|
+
ctx.error = MagicMock()
|
|
92
|
+
return ctx
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _reload_runtime():
|
|
96
|
+
"""Reload cli_runtime + mcp_tools so module-level env reads settle.
|
|
97
|
+
|
|
98
|
+
Order matters: docker_manager validates SUBAGENT_CLI at import time,
|
|
99
|
+
cli_runtime imports from docker_manager, mcp_tools imports from
|
|
100
|
+
cli_runtime.
|
|
101
|
+
"""
|
|
102
|
+
for mod_name in ("docker_manager", "cli_runtime", "mcp_tools"):
|
|
103
|
+
if mod_name in sys.modules:
|
|
104
|
+
importlib.reload(sys.modules[mod_name])
|
|
105
|
+
else:
|
|
106
|
+
importlib.import_module(mod_name)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _unwrap_tool(tool_obj):
|
|
110
|
+
"""Return the original async function behind FastMCP @mcp.tool() wrapping."""
|
|
111
|
+
return getattr(tool_obj, "fn", None) or getattr(tool_obj, "__wrapped__", None) or tool_obj
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _install_common_stubs(monkeypatch, mcp_tools, fake_dispatch):
|
|
115
|
+
"""Stub the side-effect-heavy collaborators so sub_agent can run on host.
|
|
116
|
+
|
|
117
|
+
- cli_dispatch: replaced with the per-test fake (the boundary under test)
|
|
118
|
+
- _get_or_create_container: opaque MagicMock (dispatch never touches it
|
|
119
|
+
because we stub cli_dispatch wholesale)
|
|
120
|
+
- _ensure_gitlab_token: no-op AsyncMock
|
|
121
|
+
- _execute_bash: returns an empty result so the marker-file write +
|
|
122
|
+
_stream_session_logs body bail immediately
|
|
123
|
+
- _validate_chat_id: returns a deterministic ('test', None) tuple so we
|
|
124
|
+
do not depend on contextvar state
|
|
125
|
+
- skill_manager: no real skills lookup
|
|
126
|
+
"""
|
|
127
|
+
monkeypatch.setattr(mcp_tools, "cli_dispatch", fake_dispatch)
|
|
128
|
+
monkeypatch.setattr(
|
|
129
|
+
mcp_tools, "_get_or_create_container", lambda *a, **kw: MagicMock()
|
|
130
|
+
)
|
|
131
|
+
monkeypatch.setattr(
|
|
132
|
+
mcp_tools, "_ensure_gitlab_token", AsyncMock(return_value=None)
|
|
133
|
+
)
|
|
134
|
+
monkeypatch.setattr(
|
|
135
|
+
mcp_tools, "_execute_bash", lambda *a, **kw: {"output": "", "exit_code": 0}
|
|
136
|
+
)
|
|
137
|
+
monkeypatch.setattr(
|
|
138
|
+
mcp_tools, "_validate_chat_id", lambda: ("test", None)
|
|
139
|
+
)
|
|
140
|
+
monkeypatch.setattr(
|
|
141
|
+
mcp_tools.skill_manager, "get_user_skills_sync", lambda *a, **kw: []
|
|
142
|
+
)
|
|
143
|
+
monkeypatch.setattr(
|
|
144
|
+
mcp_tools.skill_manager, "build_sub_agent_skills_text", lambda *a, **kw: ""
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# ===========================================================================
|
|
149
|
+
# Test 1 — MCP signature regression guard.
|
|
150
|
+
# ===========================================================================
|
|
151
|
+
|
|
152
|
+
def test_signature_is_byte_identical(monkeypatch):
|
|
153
|
+
"""v0.9.2.0 contract: sub_agent(task, description, ctx, model='',
|
|
154
|
+
max_turns=0, working_directory='/home/assistant', resume_session_id='').
|
|
155
|
+
|
|
156
|
+
Any drift breaks every existing skill caller.
|
|
157
|
+
"""
|
|
158
|
+
_scrub_dev_env(monkeypatch)
|
|
159
|
+
monkeypatch.setenv("SUBAGENT_CLI", "claude")
|
|
160
|
+
_reload_runtime()
|
|
161
|
+
import mcp_tools
|
|
162
|
+
|
|
163
|
+
fn = _unwrap_tool(mcp_tools.sub_agent)
|
|
164
|
+
sig = inspect.signature(fn)
|
|
165
|
+
params = list(sig.parameters.items())
|
|
166
|
+
names = [n for n, _ in params]
|
|
167
|
+
|
|
168
|
+
assert names == [
|
|
169
|
+
"task", "description", "ctx",
|
|
170
|
+
"model", "max_turns", "working_directory", "resume_session_id",
|
|
171
|
+
], f"sub_agent parameters drifted from v0.9.2.0 contract: {names}"
|
|
172
|
+
|
|
173
|
+
defaults = {n: p.default for n, p in params if p.default is not inspect.Parameter.empty}
|
|
174
|
+
assert defaults["model"] == ""
|
|
175
|
+
assert defaults["max_turns"] == 0
|
|
176
|
+
assert defaults["working_directory"] == "/home/assistant"
|
|
177
|
+
assert defaults["resume_session_id"] == ""
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
# ===========================================================================
|
|
181
|
+
# Test 2 — dispatch routes to the correct adapter per SUBAGENT_CLI value.
|
|
182
|
+
# ===========================================================================
|
|
183
|
+
|
|
184
|
+
@pytest.mark.parametrize("cli_value,expected_cli_str", [
|
|
185
|
+
("claude", "claude"),
|
|
186
|
+
("codex", "codex"),
|
|
187
|
+
("opencode", "opencode"),
|
|
188
|
+
])
|
|
189
|
+
def test_dispatch_routes_to_correct_adapter(
|
|
190
|
+
monkeypatch, cli_value, expected_cli_str,
|
|
191
|
+
):
|
|
192
|
+
"""resolve_cli() inside the dispatch boundary must reflect SUBAGENT_CLI."""
|
|
193
|
+
_scrub_dev_env(monkeypatch)
|
|
194
|
+
monkeypatch.setenv("SUBAGENT_CLI", cli_value)
|
|
195
|
+
# Phase 2: opencode/codex no longer have hardcoded defaults — set the
|
|
196
|
+
# per-CLI default env so resolve_subagent_model("", ...) doesn't raise
|
|
197
|
+
# before fake_dispatch is reached. The actual id is irrelevant; the test
|
|
198
|
+
# only checks that dispatch was invoked with the right CLI.
|
|
199
|
+
if cli_value == "opencode":
|
|
200
|
+
monkeypatch.setenv("OPENCODE_SUB_AGENT_DEFAULT_MODEL", "anthropic/claude-sonnet-4-6")
|
|
201
|
+
elif cli_value == "codex":
|
|
202
|
+
monkeypatch.setenv("CODEX_SUB_AGENT_DEFAULT_MODEL", "gpt-5-codex")
|
|
203
|
+
_reload_runtime()
|
|
204
|
+
import cli_runtime
|
|
205
|
+
import mcp_tools
|
|
206
|
+
|
|
207
|
+
captured = {}
|
|
208
|
+
|
|
209
|
+
async def fake_dispatch(**kwargs):
|
|
210
|
+
captured.update(kwargs)
|
|
211
|
+
captured["_cli_seen"] = cli_runtime.resolve_cli()
|
|
212
|
+
# Codex never has cost; claude does; opencode optional.
|
|
213
|
+
cost = 0.0042 if cli_value == "claude" else None
|
|
214
|
+
return (
|
|
215
|
+
_make_result(cost_usd=cost, text="hello world"),
|
|
216
|
+
f"resolved-{cli_value}-model",
|
|
217
|
+
"sonnet",
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
_install_common_stubs(monkeypatch, mcp_tools, fake_dispatch)
|
|
221
|
+
|
|
222
|
+
fn = _unwrap_tool(mcp_tools.sub_agent)
|
|
223
|
+
# claude is the only CLI where 'sonnet' is a valid model alias for the
|
|
224
|
+
# default model resolution path that runs inside sub_agent BEFORE
|
|
225
|
+
# dispatch. For codex/opencode we pass an empty model so the per-CLI
|
|
226
|
+
# default kicks in inside resolve_subagent_model (called by the real
|
|
227
|
+
# dispatch — but we replace dispatch wholesale, so the model value is
|
|
228
|
+
# captured verbatim). Either way the model arg flows through to
|
|
229
|
+
# captured kwargs and we only assert the routing.
|
|
230
|
+
result = asyncio.run(fn(
|
|
231
|
+
task="hello", description="d", ctx=_make_ctx(),
|
|
232
|
+
))
|
|
233
|
+
|
|
234
|
+
seen_cli = captured.get("_cli_seen")
|
|
235
|
+
assert seen_cli is not None, "fake_dispatch was not invoked"
|
|
236
|
+
assert seen_cli.value == expected_cli_str, (
|
|
237
|
+
f"resolve_cli() returned {seen_cli!r}; expected {expected_cli_str!r}"
|
|
238
|
+
)
|
|
239
|
+
# Sanity: dispatch was awaited once (captured kwargs are present).
|
|
240
|
+
assert "task" in captured
|
|
241
|
+
assert "system_prompt" in captured
|
|
242
|
+
# Result string carries the completion banner + the synthetic text.
|
|
243
|
+
assert "Sub-Agent Completed" in result, (
|
|
244
|
+
f"missing completion banner; first 300 chars: {result[:300]}"
|
|
245
|
+
)
|
|
246
|
+
assert "hello world" in result
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# ===========================================================================
|
|
250
|
+
# Test 3 — cost rendering: cost_usd=None must render "unavailable".
|
|
251
|
+
# ===========================================================================
|
|
252
|
+
|
|
253
|
+
@pytest.mark.parametrize("cli_value", ["codex", "opencode"])
|
|
254
|
+
def test_cost_rendering_unavailable_for_none(monkeypatch, cli_value):
|
|
255
|
+
"""Pitfall 4 + Phase 7 success criterion 5.
|
|
256
|
+
|
|
257
|
+
cost_usd=None (codex always; opencode when usage is missing) must
|
|
258
|
+
render as the literal "unavailable" — NEVER as "$0.00" / "$0.0000",
|
|
259
|
+
which would mislead the operator into thinking the run was free.
|
|
260
|
+
"""
|
|
261
|
+
_scrub_dev_env(monkeypatch)
|
|
262
|
+
monkeypatch.setenv("SUBAGENT_CLI", cli_value)
|
|
263
|
+
# Phase 2: per-CLI default env required for opencode/codex.
|
|
264
|
+
if cli_value == "opencode":
|
|
265
|
+
monkeypatch.setenv("OPENCODE_SUB_AGENT_DEFAULT_MODEL", "anthropic/claude-sonnet-4-6")
|
|
266
|
+
elif cli_value == "codex":
|
|
267
|
+
monkeypatch.setenv("CODEX_SUB_AGENT_DEFAULT_MODEL", "gpt-5-codex")
|
|
268
|
+
_reload_runtime()
|
|
269
|
+
import mcp_tools
|
|
270
|
+
|
|
271
|
+
async def fake_dispatch(**kwargs):
|
|
272
|
+
return (
|
|
273
|
+
_make_result(cost_usd=None, text="ok"),
|
|
274
|
+
"model-id",
|
|
275
|
+
"model-display",
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
_install_common_stubs(monkeypatch, mcp_tools, fake_dispatch)
|
|
279
|
+
|
|
280
|
+
fn = _unwrap_tool(mcp_tools.sub_agent)
|
|
281
|
+
result = asyncio.run(fn(
|
|
282
|
+
task="t", description="d", ctx=_make_ctx(),
|
|
283
|
+
))
|
|
284
|
+
|
|
285
|
+
assert "unavailable" in result, (
|
|
286
|
+
f"expected literal 'unavailable' in result for cost_usd=None; "
|
|
287
|
+
f"first 400 chars: {result[:400]}"
|
|
288
|
+
)
|
|
289
|
+
# Negative assertions: never let a None cost render as a dollar amount.
|
|
290
|
+
assert "$0.0" not in result, (
|
|
291
|
+
f"cost_usd=None must NOT render as $0.0X; first 400 chars: {result[:400]}"
|
|
292
|
+
)
|
|
293
|
+
assert "$0.00" not in result
|
|
294
|
+
assert "$0.0000" not in result
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def test_cost_rendering_dollar_for_float(monkeypatch):
|
|
298
|
+
"""Positive case: a float cost renders as $X.XXXX (4-decimal USD)."""
|
|
299
|
+
_scrub_dev_env(monkeypatch)
|
|
300
|
+
monkeypatch.setenv("SUBAGENT_CLI", "claude")
|
|
301
|
+
_reload_runtime()
|
|
302
|
+
import mcp_tools
|
|
303
|
+
|
|
304
|
+
async def fake_dispatch(**kwargs):
|
|
305
|
+
return (
|
|
306
|
+
_make_result(cost_usd=0.0042, text="ok"),
|
|
307
|
+
"claude-sonnet-4-6",
|
|
308
|
+
"sonnet",
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
_install_common_stubs(monkeypatch, mcp_tools, fake_dispatch)
|
|
312
|
+
|
|
313
|
+
fn = _unwrap_tool(mcp_tools.sub_agent)
|
|
314
|
+
result = asyncio.run(fn(
|
|
315
|
+
task="t", description="d", ctx=_make_ctx(),
|
|
316
|
+
))
|
|
317
|
+
|
|
318
|
+
assert "$0.0042" in result, (
|
|
319
|
+
f"expected '$0.0042' for cost_usd=0.0042; first 400 chars: {result[:400]}"
|
|
320
|
+
)
|
|
321
|
+
assert "unavailable" not in result, (
|
|
322
|
+
"float cost must NOT render as 'unavailable'"
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
if __name__ == "__main__":
|
|
327
|
+
sys.exit(pytest.main([__file__, "-v"]))
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# SPDX-License-Identifier: FSL-1.1-Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Open Computer Use Contributors
|
|
3
|
+
"""ADAPT-02 byte-compat: ClaudeAdapter.build_argv must produce argv
|
|
4
|
+
byte-identical to the v0.9.2.0 production claude_command (argv layer).
|
|
5
|
+
|
|
6
|
+
The lifted code in cli_adapters/claude.py is DORMANT in Phase 4 (production
|
|
7
|
+
path stays in mcp_tools.sub_agent through Phase 6). This snapshot test is
|
|
8
|
+
the forcing function that prevents drift between the two copies, so when
|
|
9
|
+
Phase 7 flips dispatch through cli_runtime, the change is provably zero
|
|
10
|
+
regression for SUBAGENT_CLI=claude.
|
|
11
|
+
|
|
12
|
+
The shell-execution wrapper (`cd <wd> && <headers_env> ...`) lives in
|
|
13
|
+
mcp_tools.sub_agent and is NOT part of build_argv's contract — only the
|
|
14
|
+
argv list itself is asserted byte-identical.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
import pytest
|
|
22
|
+
|
|
23
|
+
_SERVER_DIR = os.path.join(
|
|
24
|
+
os.path.dirname(__file__), "..", "..", "computer-use-server"
|
|
25
|
+
)
|
|
26
|
+
sys.path.insert(0, _SERVER_DIR)
|
|
27
|
+
|
|
28
|
+
_FIXTURE_PATH = os.path.join(
|
|
29
|
+
os.path.dirname(__file__), "..", "fixtures", "cli", "claude_v0.9.2.0_argv.json"
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@pytest.fixture(scope="module")
|
|
34
|
+
def fixture():
|
|
35
|
+
with open(_FIXTURE_PATH) as f:
|
|
36
|
+
return json.load(f)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_new_session_argv_byte_compat(fixture):
|
|
40
|
+
"""NEW SESSION branch (resume_session_id == ""): 15-element argv with
|
|
41
|
+
--model + --append-system-prompt before the common flags."""
|
|
42
|
+
from cli_adapters.claude import ClaudeAdapter
|
|
43
|
+
adapter = ClaudeAdapter()
|
|
44
|
+
case = fixture["new_session"]
|
|
45
|
+
actual = adapter.build_argv(**case["inputs"])
|
|
46
|
+
assert actual == case["expected_argv"], (
|
|
47
|
+
f"build_argv NEW SESSION drifted from v0.9.2.0 baseline.\n"
|
|
48
|
+
f" expected: {case['expected_argv']}\n"
|
|
49
|
+
f" actual: {actual}\n"
|
|
50
|
+
)
|
|
51
|
+
assert len(actual) == 15, f"expected 15-element argv, got {len(actual)}"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_resume_argv_byte_compat(fixture):
|
|
55
|
+
"""RESUME branch (resume_session_id non-empty): 13-element argv with
|
|
56
|
+
--resume <session_id> in place of --model + --append-system-prompt."""
|
|
57
|
+
from cli_adapters.claude import ClaudeAdapter
|
|
58
|
+
adapter = ClaudeAdapter()
|
|
59
|
+
case = fixture["resume"]
|
|
60
|
+
actual = adapter.build_argv(**case["inputs"])
|
|
61
|
+
assert actual == case["expected_argv"], (
|
|
62
|
+
f"build_argv RESUME drifted from v0.9.2.0 baseline.\n"
|
|
63
|
+
f" expected: {case['expected_argv']}\n"
|
|
64
|
+
f" actual: {actual}\n"
|
|
65
|
+
)
|
|
66
|
+
assert len(actual) == 13, f"expected 13-element argv, got {len(actual)}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_disallowed_tools_value_is_unquoted(fixture):
|
|
70
|
+
"""The original mcp_tools.py:957 emits `--disallowedTools 'AskUserQuestion,ExitPlanMode'`
|
|
71
|
+
inside a SHELL command string — the single quotes are shell quoting, not part
|
|
72
|
+
of the argv value. In argv form the value is the literal string
|
|
73
|
+
`AskUserQuestion,ExitPlanMode` with no quotes (RESEARCH.md line 215, plan
|
|
74
|
+
04-02 SUMMARY line 97)."""
|
|
75
|
+
for case_key in ("new_session", "resume"):
|
|
76
|
+
argv = fixture[case_key]["expected_argv"]
|
|
77
|
+
idx = argv.index("--disallowedTools")
|
|
78
|
+
assert argv[idx + 1] == "AskUserQuestion,ExitPlanMode", (
|
|
79
|
+
f"{case_key}: --disallowedTools value must be unquoted, got {argv[idx + 1]!r}"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def test_parse_result_minimal_roundtrip():
|
|
84
|
+
"""parse_result consumes Claude's --output-format json line and populates
|
|
85
|
+
SubAgentResult correctly. Smoke test (the format hasn't changed and won't
|
|
86
|
+
change in Phase 4) plus the Pitfall 4 zero-cost-becomes-None invariant."""
|
|
87
|
+
from cli_adapters.claude import ClaudeAdapter
|
|
88
|
+
adapter = ClaudeAdapter()
|
|
89
|
+
line = json.dumps({
|
|
90
|
+
"type": "result",
|
|
91
|
+
"result": "task complete",
|
|
92
|
+
"total_cost_usd": 0.123,
|
|
93
|
+
"num_turns": 5,
|
|
94
|
+
"is_error": False,
|
|
95
|
+
"session_id": "sess-xyz",
|
|
96
|
+
})
|
|
97
|
+
res = adapter.parse_result(stdout=line, stderr="", returncode=0)
|
|
98
|
+
assert res.text == "task complete"
|
|
99
|
+
assert res.cost_usd == 0.123
|
|
100
|
+
assert res.turns == 5
|
|
101
|
+
assert res.is_error is False
|
|
102
|
+
assert res.session_id == "sess-xyz"
|
|
103
|
+
|
|
104
|
+
# Pitfall 4: cost_usd -> None when 0.0 (render "unavailable", not "$0.00").
|
|
105
|
+
zero_cost_line = json.dumps({
|
|
106
|
+
"type": "result", "result": "x", "total_cost_usd": 0.0,
|
|
107
|
+
"num_turns": 0, "is_error": False, "session_id": "",
|
|
108
|
+
})
|
|
109
|
+
res2 = adapter.parse_result(stdout=zero_cost_line, stderr="", returncode=0)
|
|
110
|
+
assert res2.cost_usd is None
|
|
111
|
+
assert res2.turns is None
|
|
112
|
+
assert res2.session_id is None
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# === Phase 5 / plan 05-06: end-to-end dispatch byte-compat ===
|
|
116
|
+
# Plan 05-05 flipped mcp_tools.sub_agent from inline claude_command to
|
|
117
|
+
# cli_runtime.dispatch -> ClaudeAdapter -> _execute_bash_capture. These
|
|
118
|
+
# tests assert the assembled shell command and the parsed SubAgentResult
|
|
119
|
+
# are byte-identical to what v0.9.2.0 would have produced for the same
|
|
120
|
+
# inputs.
|
|
121
|
+
|
|
122
|
+
import asyncio
|
|
123
|
+
import shlex as _shlex_mod
|
|
124
|
+
from types import SimpleNamespace
|
|
125
|
+
from unittest.mock import patch
|
|
126
|
+
|
|
127
|
+
# WARNING 2 fix: scrub model-override env vars so local-dev shells (where
|
|
128
|
+
# a developer might have e.g. ANTHROPIC_DEFAULT_SONNET_MODEL=my-deployment
|
|
129
|
+
# exported) don't break the byte-compat assertions. CI is clean; local
|
|
130
|
+
# dev gets the same guarantees.
|
|
131
|
+
_DEV_ENV_VARS_TO_SCRUB = (
|
|
132
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL",
|
|
133
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL",
|
|
134
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL",
|
|
135
|
+
"CLAUDE_SUB_AGENT_DEFAULT_MODEL",
|
|
136
|
+
"CODEX_SUB_AGENT_DEFAULT_MODEL",
|
|
137
|
+
"OPENCODE_SUB_AGENT_DEFAULT_MODEL",
|
|
138
|
+
"CODEX_MODEL",
|
|
139
|
+
"OPENCODE_MODEL",
|
|
140
|
+
"OPENCODE_MODEL_ALIASES",
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _scrub_dev_env(monkeypatch):
|
|
145
|
+
for var in _DEV_ENV_VARS_TO_SCRUB:
|
|
146
|
+
monkeypatch.delenv(var, raising=False)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def test_claude_dispatch_byte_compat(fixture, monkeypatch):
|
|
150
|
+
"""SUBAGENT_CLI=claude (default): cli_runtime.dispatch builds the same
|
|
151
|
+
shell command as v0.9.2.0's mcp_tools.sub_agent inline claude_command,
|
|
152
|
+
and parse_result returns the same SubAgentResult.
|
|
153
|
+
|
|
154
|
+
We mock _execute_bash_capture to capture the shell command without
|
|
155
|
+
needing a Docker container, then return a known stdout that the
|
|
156
|
+
ClaudeAdapter.parse_result is expected to digest into a known
|
|
157
|
+
SubAgentResult.
|
|
158
|
+
"""
|
|
159
|
+
_scrub_dev_env(monkeypatch)
|
|
160
|
+
|
|
161
|
+
# Drop modules so cli_runtime re-imports cleanly under the test env.
|
|
162
|
+
for mod in ("cli_runtime", "docker_manager"):
|
|
163
|
+
sys.modules.pop(mod, None)
|
|
164
|
+
|
|
165
|
+
# Import the freshly-loaded dispatch + Cli.
|
|
166
|
+
from cli_runtime import dispatch as cli_dispatch, Cli
|
|
167
|
+
# Sanity: default SUBAGENT_CLI resolves to claude.
|
|
168
|
+
from cli_runtime import resolve_cli
|
|
169
|
+
assert resolve_cli() == Cli.CLAUDE
|
|
170
|
+
|
|
171
|
+
# Inputs mirror the v0.9.2.0 NEW SESSION fixture. mcp_tools.sub_agent
|
|
172
|
+
# passes these via cli_dispatch(...).
|
|
173
|
+
case = fixture["new_session"]
|
|
174
|
+
inputs = case["inputs"]
|
|
175
|
+
expected_argv = case["expected_argv"]
|
|
176
|
+
|
|
177
|
+
# The captured shell command we expect dispatch to construct:
|
|
178
|
+
# cd <wd> && [headers_env]<shlex.quote(argv) joined>
|
|
179
|
+
working_directory = "/home/assistant"
|
|
180
|
+
headers_env = "" # No user_email path -> no ANTHROPIC_CUSTOM_HEADERS.
|
|
181
|
+
expected_quoted = " ".join(_shlex_mod.quote(a) for a in expected_argv)
|
|
182
|
+
expected_shell_cmd = (
|
|
183
|
+
f"cd {_shlex_mod.quote(working_directory)} && "
|
|
184
|
+
f"{headers_env}{expected_quoted}"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Stub stdout fed to ClaudeAdapter.parse_result.
|
|
188
|
+
with open(_FIXTURE_PATH.replace("argv.json", "stdout.json")) as f:
|
|
189
|
+
stdout_fixture = json.load(f)
|
|
190
|
+
happy = stdout_fixture["happy_path"]
|
|
191
|
+
|
|
192
|
+
captured_cmd = {}
|
|
193
|
+
|
|
194
|
+
def _fake_capture(container, command, timeout=None):
|
|
195
|
+
captured_cmd["cmd"] = command
|
|
196
|
+
captured_cmd["timeout"] = timeout
|
|
197
|
+
return SimpleNamespace(
|
|
198
|
+
stdout=happy["stdout"],
|
|
199
|
+
stderr=happy["stderr"],
|
|
200
|
+
returncode=happy["returncode"],
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
with patch("cli_runtime._execute_bash_capture", side_effect=_fake_capture):
|
|
204
|
+
sub_result, model_id, model_display = asyncio.run(
|
|
205
|
+
cli_dispatch(
|
|
206
|
+
container=object(), # opaque - _fake_capture ignores it
|
|
207
|
+
task=inputs["task"],
|
|
208
|
+
system_prompt=inputs["system_prompt"],
|
|
209
|
+
model="sonnet", # alias resolves to inputs["model"] via resolve_subagent_model
|
|
210
|
+
max_turns=inputs["max_turns"],
|
|
211
|
+
timeout_s=inputs["timeout_s"],
|
|
212
|
+
working_directory=working_directory,
|
|
213
|
+
resume_session_id="",
|
|
214
|
+
plan_file="",
|
|
215
|
+
headers_env=headers_env,
|
|
216
|
+
)
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# === Assert 1: shell command is byte-identical to v0.9.2.0 ===
|
|
220
|
+
assert captured_cmd["cmd"] == expected_shell_cmd, (
|
|
221
|
+
"Dispatch produced a shell command different from v0.9.2.0:\n"
|
|
222
|
+
f" expected: {expected_shell_cmd}\n"
|
|
223
|
+
f" actual: {captured_cmd['cmd']}\n"
|
|
224
|
+
)
|
|
225
|
+
# Timeout passed through to the executor.
|
|
226
|
+
assert captured_cmd["timeout"] == inputs["timeout_s"]
|
|
227
|
+
|
|
228
|
+
# === Assert 2: parsed SubAgentResult matches the parse-side fixture ===
|
|
229
|
+
exp = happy["expected"]
|
|
230
|
+
assert sub_result.text == exp["text"]
|
|
231
|
+
assert sub_result.cost_usd == exp["cost_usd"]
|
|
232
|
+
assert sub_result.turns == exp["turns"]
|
|
233
|
+
assert sub_result.session_id == exp["session_id"]
|
|
234
|
+
assert sub_result.is_error is exp["is_error"]
|
|
235
|
+
|
|
236
|
+
# === Assert 3: model resolution preserved v0.9.2.0 alias semantics ===
|
|
237
|
+
# "sonnet" -> "claude-sonnet-4-6" (default), display "sonnet".
|
|
238
|
+
assert model_id == "claude-sonnet-4-6"
|
|
239
|
+
assert model_display == "sonnet"
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def test_claude_dispatch_resume_byte_compat(fixture, monkeypatch):
|
|
243
|
+
"""RESUME branch byte-compat: same as above but with resume_session_id set.
|
|
244
|
+
Verifies the resume argv (no --model, no --append-system-prompt) is
|
|
245
|
+
assembled identically to v0.9.2.0."""
|
|
246
|
+
_scrub_dev_env(monkeypatch)
|
|
247
|
+
|
|
248
|
+
for mod in ("cli_runtime", "docker_manager"):
|
|
249
|
+
sys.modules.pop(mod, None)
|
|
250
|
+
|
|
251
|
+
from cli_runtime import dispatch as cli_dispatch
|
|
252
|
+
case = fixture["resume"]
|
|
253
|
+
inputs = case["inputs"]
|
|
254
|
+
expected_argv = case["expected_argv"]
|
|
255
|
+
|
|
256
|
+
working_directory = "/home/assistant"
|
|
257
|
+
headers_env = ""
|
|
258
|
+
expected_quoted = " ".join(_shlex_mod.quote(a) for a in expected_argv)
|
|
259
|
+
expected_shell_cmd = (
|
|
260
|
+
f"cd {_shlex_mod.quote(working_directory)} && "
|
|
261
|
+
f"{headers_env}{expected_quoted}"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
captured_cmd = {}
|
|
265
|
+
|
|
266
|
+
def _fake_capture(container, command, timeout=None):
|
|
267
|
+
captured_cmd["cmd"] = command
|
|
268
|
+
return SimpleNamespace(
|
|
269
|
+
stdout='{"type": "result", "result": "resumed ok", '
|
|
270
|
+
'"total_cost_usd": 0.05, "num_turns": 3, '
|
|
271
|
+
'"is_error": false, "session_id": "abc-123-session"}',
|
|
272
|
+
stderr="",
|
|
273
|
+
returncode=0,
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
with patch("cli_runtime._execute_bash_capture", side_effect=_fake_capture):
|
|
277
|
+
sub_result, _, _ = asyncio.run(
|
|
278
|
+
cli_dispatch(
|
|
279
|
+
container=object(),
|
|
280
|
+
task=inputs["task"],
|
|
281
|
+
system_prompt=inputs["system_prompt"],
|
|
282
|
+
model="sonnet",
|
|
283
|
+
max_turns=inputs["max_turns"],
|
|
284
|
+
timeout_s=inputs["timeout_s"],
|
|
285
|
+
working_directory=working_directory,
|
|
286
|
+
resume_session_id=inputs["resume_session_id"],
|
|
287
|
+
plan_file="",
|
|
288
|
+
headers_env=headers_env,
|
|
289
|
+
)
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
assert captured_cmd["cmd"] == expected_shell_cmd, (
|
|
293
|
+
f"Resume dispatch shell command drifted from v0.9.2.0:\n"
|
|
294
|
+
f" expected: {expected_shell_cmd}\n"
|
|
295
|
+
f" actual: {captured_cmd['cmd']}\n"
|
|
296
|
+
)
|
|
297
|
+
assert sub_result.text == "resumed ok"
|
|
298
|
+
assert sub_result.session_id == "abc-123-session"
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def test_claude_dispatch_with_headers_env_byte_compat(fixture, monkeypatch):
|
|
302
|
+
"""Headers env (ANTHROPIC_CUSTOM_HEADERS path): when mcp_tools passes a
|
|
303
|
+
non-empty headers_env (because user_email is set), dispatch concatenates
|
|
304
|
+
it BEFORE the argv - exactly the v0.9.2.0 shape."""
|
|
305
|
+
_scrub_dev_env(monkeypatch)
|
|
306
|
+
|
|
307
|
+
for mod in ("cli_runtime", "docker_manager"):
|
|
308
|
+
sys.modules.pop(mod, None)
|
|
309
|
+
from cli_runtime import dispatch as cli_dispatch
|
|
310
|
+
|
|
311
|
+
case = fixture["new_session"]
|
|
312
|
+
inputs = case["inputs"]
|
|
313
|
+
expected_argv = case["expected_argv"]
|
|
314
|
+
|
|
315
|
+
working_directory = "/home/assistant"
|
|
316
|
+
# Mirrors mcp_tools.sub_agent's headers_env construction (already shlex.quote'd).
|
|
317
|
+
headers_env = (
|
|
318
|
+
f"ANTHROPIC_CUSTOM_HEADERS="
|
|
319
|
+
f"{_shlex_mod.quote('x-openwebui-user-email: alice@example.com')} "
|
|
320
|
+
)
|
|
321
|
+
expected_quoted = " ".join(_shlex_mod.quote(a) for a in expected_argv)
|
|
322
|
+
expected_shell_cmd = (
|
|
323
|
+
f"cd {_shlex_mod.quote(working_directory)} && "
|
|
324
|
+
f"{headers_env}{expected_quoted}"
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
captured_cmd = {}
|
|
328
|
+
|
|
329
|
+
def _fake_capture(container, command, timeout=None):
|
|
330
|
+
captured_cmd["cmd"] = command
|
|
331
|
+
return SimpleNamespace(
|
|
332
|
+
stdout='{"type": "result", "result": "ok", "total_cost_usd": 0.1, '
|
|
333
|
+
'"num_turns": 1, "is_error": false, "session_id": "s1"}',
|
|
334
|
+
stderr="",
|
|
335
|
+
returncode=0,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
with patch("cli_runtime._execute_bash_capture", side_effect=_fake_capture):
|
|
339
|
+
asyncio.run(
|
|
340
|
+
cli_dispatch(
|
|
341
|
+
container=object(),
|
|
342
|
+
task=inputs["task"],
|
|
343
|
+
system_prompt=inputs["system_prompt"],
|
|
344
|
+
model="sonnet",
|
|
345
|
+
max_turns=inputs["max_turns"],
|
|
346
|
+
timeout_s=inputs["timeout_s"],
|
|
347
|
+
working_directory=working_directory,
|
|
348
|
+
resume_session_id="",
|
|
349
|
+
plan_file="",
|
|
350
|
+
headers_env=headers_env,
|
|
351
|
+
)
|
|
352
|
+
)
|
|
353
|
+
|
|
354
|
+
assert captured_cmd["cmd"] == expected_shell_cmd, (
|
|
355
|
+
f"Dispatch with headers_env drifted from v0.9.2.0 contract:\n"
|
|
356
|
+
f" expected: {expected_shell_cmd}\n"
|
|
357
|
+
f" actual: {captured_cmd['cmd']}\n"
|
|
358
|
+
)
|
|
359
|
+
# The ANTHROPIC_CUSTOM_HEADERS prefix appears verbatim (with the shell
|
|
360
|
+
# quoting that mcp_tools.sub_agent applied) - preserves GATEWAY-07
|
|
361
|
+
# contract from v0.8.12.9.
|
|
362
|
+
assert "ANTHROPIC_CUSTOM_HEADERS=" in captured_cmd["cmd"]
|
|
363
|
+
assert "x-openwebui-user-email: alice@example.com" in captured_cmd["cmd"]
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
if __name__ == "__main__":
|
|
367
|
+
sys.exit(pytest.main([__file__, "-v"]))
|