fix: make cap unwrap text imply text output

This commit is contained in:
lda
2026-06-09 17:14:15 +07:00 Verified
parent ae4c3b2aa8
commit 1e7688bb72
4 changed files with 59 additions and 10 deletions
+3 -3
View File
@@ -182,12 +182,12 @@ MCP content-block envelopes:
wf cap call wf.std.constant --input '{"value": "hello"}' --format compact wf cap call wf.std.constant --input '{"value": "hello"}' --format compact
``` ```
Use `--format text --unwrap-text` to extract exactly one MCP text content block. Use `--unwrap-text` to extract exactly one MCP text content block. This implies
This mode refuses images, resources, blobs, multiple content blocks, and text output and refuses images, resources, blobs, multiple content blocks, and
non-MCP output: non-MCP output:
```bash ```bash
wf cap call everything.default.echo --input '{"message": "hello"}' --format text --unwrap-text wf cap call everything.default.echo --input '{"message": "hello"}' --unwrap-text
``` ```
Use `--max-output-chars N` to bound compact/text terminal output. JSON output Use `--max-output-chars N` to bound compact/text terminal output. JSON output
+29 -4
View File
@@ -12,6 +12,18 @@ from wf_cli.formats import ListOutputFormat, emit_list_payload
from wf_cli.io import CliInputError, emit_json, parse_json_input from wf_cli.io import CliInputError, emit_json, parse_json_input
from wf_cli.remote_errors import run_cli_operation from wf_cli.remote_errors import run_cli_operation
CAP_CALL_HELP = """Call one workflow capability once for authoring/runtime smoke tests.
Output modes:
- json: Full lossless payload. Default. Never truncated.
- compact: One bounded summary line.
- text: Requires --unwrap-text and prints exactly one MCP text content block.
Text unwrap refuses images, resources, blobs, multiple blocks, and non-MCP
output. Use --max-output-chars to bound compact/text terminal output.
"""
class CapCallOutputFormat(StrEnum): class CapCallOutputFormat(StrEnum):
JSON = "json" JSON = "json"
@@ -80,7 +92,7 @@ def inspect_capability(
emit_json(payload) emit_json(payload)
@app.command("call") @app.command("call", help=CAP_CALL_HELP)
def call_capability( def call_capability(
ctx: typer.Context, ctx: typer.Context,
qualified_name: Annotated[str, typer.Argument(help="Workflow capability name.")], qualified_name: Annotated[str, typer.Argument(help="Workflow capability name.")],
@@ -121,11 +133,10 @@ def call_capability(
bool, bool,
typer.Option( typer.Option(
"--unwrap-text", "--unwrap-text",
help="Only with --format text: unwrap one MCP text block.", help="Unwrap one safe MCP text block; implies --format text.",
), ),
] = False, ] = False,
) -> None: ) -> None:
"""Call one workflow capability once for authoring/runtime smoke tests."""
try: try:
payload = parse_json_input(input_json=input_json, input_file=input_file) payload = parse_json_input(input_json=input_json, input_file=input_file)
except CliInputError as exc: except CliInputError as exc:
@@ -143,7 +154,10 @@ def call_capability(
try: try:
rendered = render_cap_call_output( rendered = render_cap_call_output(
result, result,
output_format=output_format, output_format=_resolve_cap_call_output_format(
output_format=output_format,
unwrap_text=unwrap_text,
),
unwrap_text=unwrap_text, unwrap_text=unwrap_text,
max_output_chars=max_output_chars, max_output_chars=max_output_chars,
) )
@@ -173,6 +187,17 @@ def render_cap_call_output(
return _truncate_text(summary, max_output_chars=max_output_chars) return _truncate_text(summary, max_output_chars=max_output_chars)
def _resolve_cap_call_output_format(
*,
output_format: CapCallOutputFormat,
unwrap_text: bool,
) -> CapCallOutputFormat:
"""Treat --unwrap-text as the explicit request for safe text extraction."""
if unwrap_text and output_format is CapCallOutputFormat.JSON:
return CapCallOutputFormat.TEXT
return output_format
def _compact_cap_call_summary(result: dict[str, Any]) -> str: def _compact_cap_call_summary(result: dict[str, Any]) -> str:
output = result.get("output") output = result.get("output")
output_summary = _summarize_output(output) output_summary = _summarize_output(output)
+23 -2
View File
@@ -157,8 +157,6 @@ def test_cap_call_cli_unwraps_single_mcp_text_block(monkeypatch) -> None:
"everything.default.echo", "everything.default.echo",
"--input", "--input",
'{"message": "hello"}', '{"message": "hello"}',
"--format",
"text",
"--unwrap-text", "--unwrap-text",
], ],
) )
@@ -191,6 +189,29 @@ def test_cap_call_cli_refuses_to_unwrap_blob_content(monkeypatch) -> None:
assert "exactly one MCP text content block" in result.output assert "exactly one MCP text content block" in result.output
def test_cap_call_cli_format_text_requires_unwrap_text(monkeypatch) -> None:
_patch_context(
monkeypatch,
_base_result({"content": [{"type": "text", "text": "hello text"}]}),
)
result = CliRunner().invoke(
app,
[
"cap",
"call",
"everything.default.echo",
"--input",
"{}",
"--format",
"text",
],
)
assert result.exit_code != 0
assert "--format text requires --unwrap-text" in result.output
def test_cap_call_cli_refuses_to_unwrap_multiple_text_blocks(monkeypatch) -> None: def test_cap_call_cli_refuses_to_unwrap_multiple_text_blocks(monkeypatch) -> None:
_patch_context( _patch_context(
monkeypatch, monkeypatch,
+4 -1
View File
@@ -381,8 +381,11 @@ def test_wf_cap_commands_use_rpc_url_override(monkeypatch, tmp_path) -> None:
help_result = runner.invoke(app, ["cap", "call", "--help"]) help_result = runner.invoke(app, ["cap", "call", "--help"])
assert help_result.exit_code == 0 assert help_result.exit_code == 0
help_text = " ".join(help_result.output.split())
assert "--unwrap-text" in help_result.output assert "--unwrap-text" in help_result.output
assert "MCP text block" in help_result.output assert "MCP text content block" in help_text
assert "multiple blocks" in help_text
assert "non-MCP" in help_text
def test_wf_source_commands_use_rpc_url_override(monkeypatch, tmp_path) -> None: def test_wf_source_commands_use_rpc_url_override(monkeypatch, tmp_path) -> None: