mirror of
https://github.com/github/spec-kit.git
synced 2026-08-03 06:26:30 +08:00
feat: add native Cline integration (#2508)
* test: strip ansi to make asserts work * feat: add native Cline integration
This commit is contained in:
@@ -330,6 +330,7 @@ class TestInitIntegrationFlag:
|
||||
def test_shared_infra_skip_warning_displayed(self, tmp_path, capsys):
|
||||
"""Console warning is displayed when files are skipped."""
|
||||
from specify_cli import _install_shared_infra
|
||||
from tests.conftest import strip_ansi
|
||||
|
||||
project = tmp_path / "warn-test"
|
||||
project.mkdir()
|
||||
|
||||
213
tests/integrations/test_integration_cline.py
Normal file
213
tests/integrations/test_integration_cline.py
Normal file
@@ -0,0 +1,213 @@
|
||||
"""Tests for ClineIntegration."""
|
||||
|
||||
import os
|
||||
import pytest
|
||||
|
||||
from specify_cli.integrations import get_integration
|
||||
from specify_cli.integrations.cline import format_cline_command_name
|
||||
from .test_integration_base_markdown import MarkdownIntegrationTests
|
||||
|
||||
|
||||
class TestClineCommandNameFormatter:
|
||||
"""Test the Cline command name formatter."""
|
||||
|
||||
def test_simple_name_without_prefix(self):
|
||||
"""Test formatting a simple name without 'speckit.' prefix."""
|
||||
assert format_cline_command_name("plan") == "speckit-plan"
|
||||
assert format_cline_command_name("tasks") == "speckit-tasks"
|
||||
assert format_cline_command_name("specify") == "speckit-specify"
|
||||
|
||||
def test_name_with_speckit_prefix(self):
|
||||
"""Test formatting a name that already has 'speckit.' prefix."""
|
||||
assert format_cline_command_name("speckit.plan") == "speckit-plan"
|
||||
assert format_cline_command_name("speckit.tasks") == "speckit-tasks"
|
||||
|
||||
def test_extension_command_name(self):
|
||||
"""Test formatting extension command names with dots."""
|
||||
assert (
|
||||
format_cline_command_name("speckit.my-extension.example")
|
||||
== "speckit-my-extension-example"
|
||||
)
|
||||
assert (
|
||||
format_cline_command_name("my-extension.example")
|
||||
== "speckit-my-extension-example"
|
||||
)
|
||||
|
||||
def test_idempotent_already_hyphenated(self):
|
||||
"""Test that already-hyphenated names are returned unchanged (idempotent)."""
|
||||
assert format_cline_command_name("speckit-plan") == "speckit-plan"
|
||||
assert (
|
||||
format_cline_command_name("speckit-my-extension-example")
|
||||
== "speckit-my-extension-example"
|
||||
)
|
||||
|
||||
|
||||
class TestClineIntegration(MarkdownIntegrationTests):
|
||||
KEY = "cline"
|
||||
FOLDER = ".clinerules/"
|
||||
COMMANDS_SUBDIR = "workflows"
|
||||
REGISTRAR_DIR = ".clinerules/workflows"
|
||||
CONTEXT_FILE = ".clinerules/specify-rules.md"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"cmd_name, expected_filename",
|
||||
[
|
||||
("plan", "speckit-plan.md"),
|
||||
("speckit.plan", "speckit-plan.md"),
|
||||
("speckit.git.commit", "speckit-git-commit.md"),
|
||||
("speckit", "speckit-speckit.md"),
|
||||
("speckitfoo", "speckit-speckitfoo.md"),
|
||||
],
|
||||
)
|
||||
def test_cline_command_filename(self, cmd_name, expected_filename):
|
||||
"""Verify Cline uses hyphenated filenames."""
|
||||
cline = get_integration("cline")
|
||||
assert cline.command_filename(cmd_name) == expected_filename
|
||||
|
||||
def test_cline_invoke_separator(self):
|
||||
"""Verify Cline uses hyphen as invoke separator."""
|
||||
cline = get_integration("cline")
|
||||
assert cline.invoke_separator == "-"
|
||||
assert cline.registrar_config["invoke_separator"] == "-"
|
||||
|
||||
def test_cline_name_injection_and_formatting(self):
|
||||
"""Verify Cline has inject_name and format_name configured."""
|
||||
cline = get_integration("cline")
|
||||
assert cline.registrar_config["inject_name"] is True
|
||||
assert cline.registrar_config["format_name"] == format_cline_command_name
|
||||
|
||||
def test_cline_handoff_rewrite(self):
|
||||
"""Verify Cline rewrites agent: speckit.foo to agent: speckit-foo."""
|
||||
cline = get_integration("cline")
|
||||
content = "---\nagent: speckit.plan\n---\n"
|
||||
rewritten = cline._rewrite_handoff_references(content)
|
||||
assert rewritten == "---\nagent: speckit-plan\n---\n"
|
||||
|
||||
def test_cline_hook_instruction_injection(self):
|
||||
"""Verify Cline injects the dot-to-hyphen note for hooks."""
|
||||
cline = get_integration("cline")
|
||||
content = "- For each executable hook, output the following:\n"
|
||||
injected = cline._inject_hook_command_note(content)
|
||||
assert "replace dots (`.`) with hyphens (`-`)" in injected
|
||||
assert "- For each executable hook, output the following:" in injected
|
||||
|
||||
# -- Overrides for MarkdownIntegrationTests ---------------------------
|
||||
|
||||
def test_setup_creates_files(self, tmp_path):
|
||||
from specify_cli.integrations.manifest import IntegrationManifest
|
||||
|
||||
i = get_integration(self.KEY)
|
||||
m = IntegrationManifest(self.KEY, tmp_path)
|
||||
created = i.setup(tmp_path, m)
|
||||
assert len(created) > 0
|
||||
cmd_files = [
|
||||
f
|
||||
for f in created
|
||||
if "scripts" not in f.parts
|
||||
and f.suffix == ".md"
|
||||
and f.name != i.context_file
|
||||
]
|
||||
for f in cmd_files:
|
||||
assert f.exists()
|
||||
assert f.name.startswith("speckit-")
|
||||
assert f.name.endswith(".md")
|
||||
|
||||
specify_file = next(
|
||||
(f for f in cmd_files if f.name == "speckit-specify.md"), None
|
||||
)
|
||||
assert specify_file is not None
|
||||
specify_contents = specify_file.read_text(encoding="utf-8")
|
||||
assert "/speckit-plan" in specify_contents
|
||||
assert "/speckit.plan" not in specify_contents
|
||||
|
||||
def test_integration_flag_creates_files(self, tmp_path):
|
||||
from typer.testing import CliRunner
|
||||
from specify_cli import app
|
||||
|
||||
project = tmp_path / f"int-{self.KEY}"
|
||||
project.mkdir()
|
||||
old_cwd = os.getcwd()
|
||||
try:
|
||||
os.chdir(project)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"init",
|
||||
"--here",
|
||||
"--integration",
|
||||
self.KEY,
|
||||
"--script",
|
||||
"sh",
|
||||
"--no-git",
|
||||
"--ignore-agent-tools",
|
||||
],
|
||||
catch_exceptions=False,
|
||||
)
|
||||
finally:
|
||||
os.chdir(old_cwd)
|
||||
assert result.exit_code == 0
|
||||
i = get_integration(self.KEY)
|
||||
cmd_dir = i.commands_dest(project)
|
||||
assert cmd_dir.is_dir()
|
||||
commands = sorted(cmd_dir.glob("speckit-*"))
|
||||
assert len(commands) > 0
|
||||
|
||||
def _expected_files(self, script_variant: str) -> list[str]:
|
||||
"""Override to expect hyphenated speckit- prefix."""
|
||||
i = get_integration(self.KEY)
|
||||
cmd_dir = i.registrar_config["dir"]
|
||||
files = []
|
||||
|
||||
# Command files
|
||||
for stem in (
|
||||
self.COMMANDS_SUBDIR_STEMS
|
||||
if hasattr(self, "COMMANDS_SUBDIR_STEMS")
|
||||
else self.COMMAND_STEMS
|
||||
):
|
||||
files.append(f"{cmd_dir}/speckit-{stem.replace('.', '-')}.md")
|
||||
|
||||
# Framework files
|
||||
files.append(".specify/integration.json")
|
||||
files.append(".specify/init-options.json")
|
||||
files.append(f".specify/integrations/{self.KEY}.manifest.json")
|
||||
files.append(".specify/integrations/speckit.manifest.json")
|
||||
|
||||
if script_variant == "sh":
|
||||
for name in [
|
||||
"check-prerequisites.sh",
|
||||
"common.sh",
|
||||
"create-new-feature.sh",
|
||||
"setup-plan.sh",
|
||||
"setup-tasks.sh",
|
||||
]:
|
||||
files.append(f".specify/scripts/bash/{name}")
|
||||
else:
|
||||
for name in [
|
||||
"check-prerequisites.ps1",
|
||||
"common.ps1",
|
||||
"create-new-feature.ps1",
|
||||
"setup-plan.ps1",
|
||||
"setup-tasks.ps1",
|
||||
]:
|
||||
files.append(f".specify/scripts/powershell/{name}")
|
||||
|
||||
for name in [
|
||||
"checklist-template.md",
|
||||
"constitution-template.md",
|
||||
"plan-template.md",
|
||||
"spec-template.md",
|
||||
"tasks-template.md",
|
||||
]:
|
||||
files.append(f".specify/templates/{name}")
|
||||
|
||||
files.append(".specify/memory/constitution.md")
|
||||
# Bundled workflow
|
||||
files.append(".specify/workflows/speckit/workflow.yml")
|
||||
files.append(".specify/workflows/workflow-registry.json")
|
||||
|
||||
# Agent context file (if set)
|
||||
if i.context_file:
|
||||
files.append(i.context_file)
|
||||
|
||||
return sorted(files)
|
||||
@@ -330,7 +330,7 @@ class TestForgeCommandRegistrar:
|
||||
assert "speckit.my-extension.example" in registered
|
||||
|
||||
# Check the generated file has hyphenated name in frontmatter
|
||||
forge_cmd = tmp_path / ".forge" / "commands" / "speckit.my-extension.example.md"
|
||||
forge_cmd = tmp_path / ".forge" / "commands" / "speckit-my-extension-example.md"
|
||||
assert forge_cmd.exists()
|
||||
|
||||
content = forge_cmd.read_text(encoding="utf-8")
|
||||
@@ -378,7 +378,7 @@ class TestForgeCommandRegistrar:
|
||||
)
|
||||
|
||||
# Check the alias file has hyphenated name in frontmatter
|
||||
alias_file = tmp_path / ".forge" / "commands" / "speckit.my-extension.ex.md"
|
||||
alias_file = tmp_path / ".forge" / "commands" / "speckit-my-extension-ex.md"
|
||||
assert alias_file.exists()
|
||||
|
||||
content = alias_file.read_text(encoding="utf-8")
|
||||
@@ -467,7 +467,7 @@ class TestForgeCommandRegistrar:
|
||||
|
||||
assert "speckit.git.feature" in registered
|
||||
|
||||
forge_cmd = tmp_path / ".forge" / "commands" / "speckit.git.feature.md"
|
||||
forge_cmd = tmp_path / ".forge" / "commands" / "speckit-git-feature.md"
|
||||
assert forge_cmd.exists(), "Expected Forge command file was not created"
|
||||
|
||||
content = forge_cmd.read_text(encoding="utf-8")
|
||||
|
||||
@@ -185,7 +185,8 @@ class TestIntegrationInstall:
|
||||
finally:
|
||||
os.chdir(old_cwd)
|
||||
assert result.exit_code == 0
|
||||
normalized = " ".join(result.output.split())
|
||||
output = strip_ansi(result.output)
|
||||
normalized = " ".join(output.split())
|
||||
assert "already installed" in normalized
|
||||
assert "specify integration use codex" in normalized
|
||||
assert "specify integration upgrade codex" in normalized
|
||||
|
||||
@@ -1315,6 +1315,42 @@ $ARGUMENTS
|
||||
assert not (skills_dir / "speckit-specify" / "SKILL.md").exists()
|
||||
assert not (skills_dir / "speckit-shortcut" / "SKILL.md").exists()
|
||||
|
||||
def test_unregister_commands_handles_legacy_dot_notated_files(self, project_dir):
|
||||
"""Unregister should clean up both legacy dot-notated and new hyphenated files."""
|
||||
# 1. Mock an agent that uses hyphenated/formatted names (e.g. Cline)
|
||||
from specify_cli.agents import CommandRegistrar as AgentCommandRegistrar
|
||||
registrar = AgentCommandRegistrar()
|
||||
|
||||
# We'll use "cline" since it has format_name
|
||||
assert "cline" in registrar.AGENT_CONFIGS
|
||||
cline_config = registrar.AGENT_CONFIGS["cline"]
|
||||
cline_dir = project_dir / cline_config["dir"]
|
||||
cline_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 2. Create both legacy and new files
|
||||
# Command name: speckit.git.commit
|
||||
# Formatted name: speckit-git-commit
|
||||
cmd_name = "speckit.git.commit"
|
||||
formatted_name = "speckit-git-commit"
|
||||
|
||||
legacy_file = cline_dir / f"{cmd_name}.md"
|
||||
formatted_file = cline_dir / f"{formatted_name}.md"
|
||||
|
||||
legacy_file.write_text("legacy body")
|
||||
formatted_file.write_text("formatted body")
|
||||
|
||||
assert legacy_file.exists()
|
||||
assert formatted_file.exists()
|
||||
|
||||
# 3. Call unregister
|
||||
registrar.unregister_commands({"cline": [cmd_name]}, project_dir)
|
||||
|
||||
# 4. Verify both are gone
|
||||
assert not legacy_file.exists(), "Legacy dot-notated file should be removed"
|
||||
assert (
|
||||
not formatted_file.exists()
|
||||
), "Formatted hyphenated file should be removed"
|
||||
|
||||
def test_register_commands_for_all_agents_distinguishes_codex_from_amp(self, extension_dir, project_dir):
|
||||
"""A Codex project under .agents/skills should not implicitly activate Amp."""
|
||||
skills_dir = project_dir / ".agents" / "skills"
|
||||
@@ -4616,6 +4652,43 @@ class TestHookInvocationRendering:
|
||||
assert execution["command"] == "speckit.tasks"
|
||||
assert execution["invocation"] == "$speckit-tasks"
|
||||
|
||||
def test_cline_hooks_render_hyphenated_invocation(self, project_dir):
|
||||
"""Cline projects should render /speckit-* invocations."""
|
||||
init_options = project_dir / ".specify" / "init-options.json"
|
||||
init_options.parent.mkdir(parents=True, exist_ok=True)
|
||||
init_options.write_text(json.dumps({"ai": "cline"}))
|
||||
|
||||
hook_executor = HookExecutor(project_dir)
|
||||
execution = hook_executor.execute_hook(
|
||||
{
|
||||
"extension": "test-ext",
|
||||
"command": "speckit.tasks",
|
||||
"optional": False,
|
||||
}
|
||||
)
|
||||
|
||||
assert execution["command"] == "speckit.tasks"
|
||||
assert execution["invocation"] == "/speckit-tasks"
|
||||
|
||||
def test_cline_hooks_render_extension_command(self, project_dir):
|
||||
"""Cline projects should render /speckit-my-ext-cmd for extension hooks."""
|
||||
init_options = project_dir / ".specify" / "init-options.json"
|
||||
init_options.parent.mkdir(parents=True, exist_ok=True)
|
||||
init_options.write_text(json.dumps({"ai": "cline"}))
|
||||
|
||||
hook_executor = HookExecutor(project_dir)
|
||||
# Test with a non-speckit. command
|
||||
execution = hook_executor.execute_hook(
|
||||
{
|
||||
"extension": "test-ext",
|
||||
"command": "my-extension.do-something",
|
||||
"optional": False,
|
||||
}
|
||||
)
|
||||
|
||||
assert execution["command"] == "my-extension.do-something"
|
||||
assert execution["invocation"] == "/speckit-my-extension-do-something"
|
||||
|
||||
def test_non_skill_command_keeps_slash_invocation(self, project_dir):
|
||||
"""Custom hook commands should keep slash invocation style."""
|
||||
init_options = project_dir / ".specify" / "init-options.json"
|
||||
@@ -4751,3 +4824,157 @@ class TestExtensionRemoveCLI:
|
||||
)
|
||||
|
||||
assert "2 commands" in result.output
|
||||
|
||||
|
||||
class TestClineExtensionHyphenation:
|
||||
"""Test that Cline integration uses hyphenated commands and frontmatter references."""
|
||||
|
||||
def _setup_mock_extension(self, tmp_path, ai_name):
|
||||
import yaml
|
||||
import json
|
||||
|
||||
# 1. Setup mock project
|
||||
project_dir = tmp_path / "project"
|
||||
project_dir.mkdir()
|
||||
(project_dir / ".specify").mkdir()
|
||||
|
||||
init_options = project_dir / ".specify" / "init-options.json"
|
||||
init_options.write_text(json.dumps({"ai": ai_name}), encoding="utf-8")
|
||||
|
||||
if ai_name == "cline":
|
||||
commands_dest_dir = project_dir / ".clinerules" / "workflows"
|
||||
else:
|
||||
commands_dest_dir = project_dir / ".agents" / "commands"
|
||||
commands_dest_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# 2. Setup mock extension directory
|
||||
ext_dir = tmp_path / "mock-ext"
|
||||
ext_dir.mkdir()
|
||||
|
||||
manifest_data = {
|
||||
"schema_version": "1.0",
|
||||
"extension": {
|
||||
"id": "mock-ext",
|
||||
"name": "Mock Extension",
|
||||
"version": "1.0.0",
|
||||
"description": f"Mock extension for {ai_name} tests",
|
||||
"author": "Tester",
|
||||
"repository": "https://github.com/test/mock-ext",
|
||||
"license": "MIT",
|
||||
},
|
||||
"requires": {
|
||||
"speckit_version": ">=0.1.0",
|
||||
},
|
||||
"provides": {
|
||||
"commands": [
|
||||
{
|
||||
"name": "speckit.mock-ext.hello",
|
||||
"file": "commands/hello.md",
|
||||
"description": "Test hello command",
|
||||
"aliases": ["speckit.mock-ext.greet"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
with open(ext_dir / "extension.yml", "w", encoding="utf-8") as f:
|
||||
yaml.dump(manifest_data, f)
|
||||
|
||||
commands_dir = ext_dir / "commands"
|
||||
commands_dir.mkdir()
|
||||
|
||||
# Command file with dotted speckit references in frontmatter and body
|
||||
cmd_content = """---
|
||||
description: "Test hello command"
|
||||
agent: speckit.tasks
|
||||
handoffs:
|
||||
- agent: speckit.iterate.start
|
||||
message: "Hand off to start"
|
||||
---
|
||||
|
||||
# Test Hello Command
|
||||
|
||||
Please refer to speckit.mock-ext.greet for instructions.
|
||||
$ARGUMENTS
|
||||
"""
|
||||
(commands_dir / "hello.md").write_text(cmd_content, encoding="utf-8")
|
||||
|
||||
return project_dir, ext_dir, commands_dest_dir
|
||||
|
||||
def test_cline_extension_hyphenation(self, tmp_path):
|
||||
from typer.testing import CliRunner
|
||||
from unittest.mock import patch
|
||||
from specify_cli import app
|
||||
from specify_cli.agents import CommandRegistrar
|
||||
|
||||
project_dir, ext_dir, cline_workflows_dir = self._setup_mock_extension(tmp_path, "cline")
|
||||
|
||||
# 3. Run specify extension add
|
||||
runner = CliRunner()
|
||||
with patch.object(Path, "cwd", return_value=project_dir):
|
||||
result = runner.invoke(
|
||||
app, ["extension", "add", str(ext_dir), "--dev"], catch_exceptions=False
|
||||
)
|
||||
|
||||
# Verify CLI printed hyphenated commands
|
||||
# Note: We assert that the primary command 'speckit-mock-ext-hello' is printed,
|
||||
# but we do not assert that the alias 'speckit-mock-ext-greet' is printed in the console
|
||||
# because manifest.commands only lists primary commands.
|
||||
assert "speckit-mock-ext-hello" in result.output
|
||||
assert "speckit.mock-ext.hello" not in result.output
|
||||
|
||||
# Verify on-disk command names are hyphenated
|
||||
hello_file = cline_workflows_dir / "speckit-mock-ext-hello.md"
|
||||
greet_file = cline_workflows_dir / "speckit-mock-ext-greet.md"
|
||||
|
||||
assert hello_file.exists()
|
||||
assert greet_file.exists()
|
||||
|
||||
# Verify frontmatter in the generated files is recursively hyphenated
|
||||
hello_text = hello_file.read_text(encoding="utf-8")
|
||||
hello_fm, hello_body = CommandRegistrar.parse_frontmatter(hello_text)
|
||||
assert hello_fm["agent"] == "speckit-tasks"
|
||||
assert hello_fm["handoffs"][0]["agent"] == "speckit-iterate-start"
|
||||
|
||||
# Verify body references are hyphenated for Cline
|
||||
assert "speckit-mock-ext-greet" in hello_body
|
||||
assert "speckit.mock-ext.greet" not in hello_body
|
||||
|
||||
def test_non_cline_extension_no_hyphenation(self, tmp_path):
|
||||
from typer.testing import CliRunner
|
||||
from unittest.mock import patch
|
||||
from specify_cli import app
|
||||
from specify_cli.agents import CommandRegistrar
|
||||
|
||||
project_dir, ext_dir, claude_commands_dir = self._setup_mock_extension(tmp_path, "claude")
|
||||
|
||||
# 3. Run specify extension add
|
||||
runner = CliRunner()
|
||||
with patch.object(Path, "cwd", return_value=project_dir):
|
||||
result = runner.invoke(
|
||||
app, ["extension", "add", str(ext_dir), "--dev"], catch_exceptions=False
|
||||
)
|
||||
|
||||
# Verify CLI printed dotted commands
|
||||
# Note: We assert that the primary command 'speckit.mock-ext.hello' is printed,
|
||||
# but we do not assert that the alias 'speckit.mock-ext.greet' is printed in the console
|
||||
# because manifest.commands only lists primary commands.
|
||||
assert "speckit.mock-ext.hello" in result.output
|
||||
assert "speckit-mock-ext-hello" not in result.output
|
||||
|
||||
# Verify on-disk command names are dotted
|
||||
hello_file = claude_commands_dir / "speckit.mock-ext.hello.md"
|
||||
greet_file = claude_commands_dir / "speckit.mock-ext.greet.md"
|
||||
|
||||
assert hello_file.exists()
|
||||
assert greet_file.exists()
|
||||
|
||||
# Verify frontmatter references are still dotted
|
||||
hello_text = hello_file.read_text(encoding="utf-8")
|
||||
hello_fm, hello_body = CommandRegistrar.parse_frontmatter(hello_text)
|
||||
assert hello_fm["agent"] == "speckit.tasks"
|
||||
assert hello_fm["handoffs"][0]["agent"] == "speckit.iterate.start"
|
||||
|
||||
# Verify body references are still dotted for non-Cline
|
||||
assert "speckit.mock-ext.greet" in hello_body
|
||||
assert "speckit-mock-ext-greet" not in hello_body
|
||||
|
||||
@@ -520,6 +520,7 @@ class TestCommandStep:
|
||||
assert result.output["integration"] == "gemini"
|
||||
|
||||
def test_step_override_model(self):
|
||||
from unittest.mock import patch
|
||||
from specify_cli.workflows.steps.command import CommandStep
|
||||
from specify_cli.workflows.base import StepContext
|
||||
|
||||
@@ -531,10 +532,12 @@ class TestCommandStep:
|
||||
"model": "opus-4",
|
||||
"input": {},
|
||||
}
|
||||
result = step.execute(config, ctx)
|
||||
with patch("specify_cli.workflows.steps.command.shutil.which", return_value=None):
|
||||
result = step.execute(config, ctx)
|
||||
assert result.output["model"] == "opus-4"
|
||||
|
||||
def test_options_merge(self):
|
||||
from unittest.mock import patch
|
||||
from specify_cli.workflows.steps.command import CommandStep
|
||||
from specify_cli.workflows.base import StepContext
|
||||
|
||||
@@ -546,7 +549,8 @@ class TestCommandStep:
|
||||
"options": {"thinking-budget": 32768},
|
||||
"input": {},
|
||||
}
|
||||
result = step.execute(config, ctx)
|
||||
with patch("specify_cli.workflows.steps.command.shutil.which", return_value=None):
|
||||
result = step.execute(config, ctx)
|
||||
assert result.output["options"]["max-tokens"] == 8000
|
||||
assert result.output["options"]["thinking-budget"] == 32768
|
||||
|
||||
|
||||
Reference in New Issue
Block a user