docs: record workflow config target slice
This commit is contained in:
@@ -93,6 +93,9 @@ implementation state.
|
|||||||
- Completed: the first JSON-RPC-over-HTTP transport can expose the local/static
|
- Completed: the first JSON-RPC-over-HTTP transport can expose the local/static
|
||||||
`WorkflowServer` through fixed dotted methods. Remote CLI targeting remains
|
`WorkflowServer` through fixed dotted methods. Remote CLI targeting remains
|
||||||
the next transport-facing slice.
|
the next transport-facing slice.
|
||||||
|
- Completed: workflow config now distinguishes client targets from server
|
||||||
|
hosting config, and selected `wf` commands can target JSON-RPC HTTP with
|
||||||
|
explicit CLI overrides.
|
||||||
|
|
||||||
5. **CLI/API alignment**
|
5. **CLI/API alignment**
|
||||||
- Let the CLI target either local process-backed stores/runtime or the future
|
- Let the CLI target either local process-backed stores/runtime or the future
|
||||||
|
|||||||
@@ -452,6 +452,26 @@ Relative paths should resolve relative to the config file directory.
|
|||||||
- Do not derive identity by splitting dotted source ids.
|
- Do not derive identity by splitting dotted source ids.
|
||||||
- Do not use MCP as the first-class `wf` CLI target.
|
- Do not use MCP as the first-class `wf` CLI target.
|
||||||
|
|
||||||
|
## Implementation Status
|
||||||
|
|
||||||
|
First slice implemented:
|
||||||
|
|
||||||
|
- neutral `wf_config` models and loader
|
||||||
|
- filesystem server store config
|
||||||
|
- stdlib source bootstrap config
|
||||||
|
- local and JSON-RPC client targets
|
||||||
|
- `wf` root overrides for `--local`, `--url`, and `--timeout`
|
||||||
|
- remote JSON-RPC client support for capability and run CLI commands
|
||||||
|
- `wf-rpc-server --config` support for server store and RPC HTTP transport
|
||||||
|
|
||||||
|
Still future:
|
||||||
|
|
||||||
|
- store-backed mutable source registry
|
||||||
|
- MCP/OpenAPI source config
|
||||||
|
- `/mcp` hosting from neutral server config
|
||||||
|
- remote draft/artifact/deployment CLI commands
|
||||||
|
- auth and SQL stores
|
||||||
|
|
||||||
## Next Implementation Slice
|
## Next Implementation Slice
|
||||||
|
|
||||||
First config implementation should be small:
|
First config implementation should be small:
|
||||||
|
|||||||
@@ -9,7 +9,12 @@ from wf_api import WorkflowApi
|
|||||||
from wf_mcp.broker import build_service_from_config, load_broker_config
|
from wf_mcp.broker import build_service_from_config, load_broker_config
|
||||||
from wf_mcp.broker.service import WfMcpService
|
from wf_mcp.broker.service import WfMcpService
|
||||||
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
from wf_mcp.broker.service.workflow_operation_context import context_from_service
|
||||||
from wf_config import FilesystemStoreConfig, LocalTargetConfig, RpcHttpTargetConfig, load_workflow_config
|
from wf_config import (
|
||||||
|
FilesystemStoreConfig,
|
||||||
|
LocalTargetConfig,
|
||||||
|
RpcHttpTargetConfig,
|
||||||
|
load_workflow_config,
|
||||||
|
)
|
||||||
from wf_server import build_local_static_workflow_server
|
from wf_server import build_local_static_workflow_server
|
||||||
from wf_transport_rpc_http import RpcWorkflowApiClient
|
from wf_transport_rpc_http import RpcWorkflowApiClient
|
||||||
|
|
||||||
@@ -20,7 +25,7 @@ class CliContext:
|
|||||||
|
|
||||||
config_path: Path
|
config_path: Path
|
||||||
service: WfMcpService | None
|
service: WfMcpService | None
|
||||||
handlers: WorkflowApi | RpcWorkflowApiClient
|
handlers: "WorkflowApi | RpcWorkflowApiClient"
|
||||||
|
|
||||||
|
|
||||||
def config_path_from_context(ctx: typer.Context) -> str:
|
def config_path_from_context(ctx: typer.Context) -> str:
|
||||||
|
|||||||
@@ -2,10 +2,14 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from pathlib import Path
|
|
||||||
import typer
|
import typer
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from wf_config import FilesystemStoreConfig, RpcHttpTransportConfig, load_workflow_config
|
|
||||||
|
from wf_config import (
|
||||||
|
FilesystemStoreConfig,
|
||||||
|
RpcHttpTransportConfig,
|
||||||
|
load_workflow_config,
|
||||||
|
)
|
||||||
|
|
||||||
from wf_server import build_local_static_workflow_server
|
from wf_server import build_local_static_workflow_server
|
||||||
|
|
||||||
@@ -37,7 +41,9 @@ def serve(
|
|||||||
workflow_config = load_workflow_config(config)
|
workflow_config = load_workflow_config(config)
|
||||||
store = workflow_config.server.store
|
store = workflow_config.server.store
|
||||||
if not isinstance(store, FilesystemStoreConfig):
|
if not isinstance(store, FilesystemStoreConfig):
|
||||||
raise typer.BadParameter("wf-rpc-server currently requires filesystem store")
|
raise typer.BadParameter(
|
||||||
|
"wf-rpc-server currently requires filesystem store"
|
||||||
|
)
|
||||||
resolved_store_root = resolved_store_root or store.root
|
resolved_store_root = resolved_store_root or store.root
|
||||||
rpc_transport = next(
|
rpc_transport = next(
|
||||||
(
|
(
|
||||||
@@ -51,7 +57,9 @@ def serve(
|
|||||||
resolved_host = host or rpc_transport.host
|
resolved_host = host or rpc_transport.host
|
||||||
resolved_port = port or rpc_transport.port
|
resolved_port = port or rpc_transport.port
|
||||||
if resolved_store_root is None:
|
if resolved_store_root is None:
|
||||||
raise typer.BadParameter("--store-root is required when --config is not supplied")
|
raise typer.BadParameter(
|
||||||
|
"--store-root is required when --config is not supplied"
|
||||||
|
)
|
||||||
|
|
||||||
server = build_local_static_workflow_server(resolved_store_root)
|
server = build_local_static_workflow_server(resolved_store_root)
|
||||||
rpc_app = create_rpc_app(server)
|
rpc_app = create_rpc_app(server)
|
||||||
|
|||||||
@@ -55,20 +55,16 @@ def test_context_from_service_exposes_existing_store_objects(tmp_path: Path) ->
|
|||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
cli_context = load_cli_context(config_path)
|
cli_context = load_cli_context(config_path)
|
||||||
|
service = cli_context.service
|
||||||
|
assert service is not None
|
||||||
|
|
||||||
operation_context = context_from_service(cli_context.service)
|
operation_context = context_from_service(service)
|
||||||
|
|
||||||
assert isinstance(operation_context, WorkflowOperationContext)
|
assert isinstance(operation_context, WorkflowOperationContext)
|
||||||
assert operation_context.artifact_store is cli_context.service.artifact_store
|
assert operation_context.artifact_store is service.artifact_store
|
||||||
assert (
|
assert operation_context.draft_workspace_store is service.draft_workspace_store
|
||||||
operation_context.draft_workspace_store
|
assert operation_context.run_store is service.run_store
|
||||||
is cli_context.service.draft_workspace_store
|
assert operation_context.specs.capability_sources is service.capability_sources
|
||||||
)
|
|
||||||
assert operation_context.run_store is cli_context.service.run_store
|
|
||||||
assert (
|
|
||||||
operation_context.specs.capability_sources
|
|
||||||
is cli_context.service.capability_sources
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def test_context_from_service_delegates_specs_and_events(tmp_path: Path) -> None:
|
def test_context_from_service_delegates_specs_and_events(tmp_path: Path) -> None:
|
||||||
@@ -78,12 +74,14 @@ def test_context_from_service_delegates_specs_and_events(tmp_path: Path) -> None
|
|||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
cli_context = load_cli_context(config_path)
|
cli_context = load_cli_context(config_path)
|
||||||
operation_context = context_from_service(cli_context.service)
|
service = cli_context.service
|
||||||
|
assert service is not None
|
||||||
|
operation_context = context_from_service(service)
|
||||||
|
|
||||||
event = object()
|
event = object()
|
||||||
operation_context.events.record_event(event)
|
operation_context.events.record_event(event)
|
||||||
|
|
||||||
assert cli_context.service.list_events()[-1] is event
|
assert service.list_events()[-1] is event
|
||||||
|
|
||||||
|
|
||||||
def test_context_from_service_record_workflow_event(tmp_path: Path) -> None:
|
def test_context_from_service_record_workflow_event(tmp_path: Path) -> None:
|
||||||
@@ -93,7 +91,9 @@ def test_context_from_service_record_workflow_event(tmp_path: Path) -> None:
|
|||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
cli_context = load_cli_context(config_path)
|
cli_context = load_cli_context(config_path)
|
||||||
operation_context = context_from_service(cli_context.service)
|
service = cli_context.service
|
||||||
|
assert service is not None
|
||||||
|
operation_context = context_from_service(service)
|
||||||
|
|
||||||
operation_context.events.record_workflow_event(
|
operation_context.events.record_workflow_event(
|
||||||
"workflow_artifact_saved",
|
"workflow_artifact_saved",
|
||||||
@@ -101,7 +101,7 @@ def test_context_from_service_record_workflow_event(tmp_path: Path) -> None:
|
|||||||
payload={"artifact_id": "demo", "version": 1},
|
payload={"artifact_id": "demo", "version": 1},
|
||||||
)
|
)
|
||||||
|
|
||||||
recorded = cli_context.service.events.list_events()[-1]
|
recorded = service.events.list_events()[-1]
|
||||||
assert recorded.kind == "workflow_artifact_saved"
|
assert recorded.kind == "workflow_artifact_saved"
|
||||||
assert recorded.capability_id == "workflow.demo.v1"
|
assert recorded.capability_id == "workflow.demo.v1"
|
||||||
assert recorded.payload["artifact_id"] == "demo"
|
assert recorded.payload["artifact_id"] == "demo"
|
||||||
|
|||||||
@@ -27,12 +27,13 @@ def test_load_cli_context_builds_service_and_handlers(tmp_path: Path) -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
context = load_cli_context(config_path)
|
context = load_cli_context(config_path)
|
||||||
|
service = context.service
|
||||||
|
assert service is not None
|
||||||
|
|
||||||
assert context.config_path == config_path
|
assert context.config_path == config_path
|
||||||
assert context.service.connections.list_all()[0].id == "demo.personal"
|
assert service.connections.list_all()[0].id == "demo.personal"
|
||||||
assert context.handlers.context.artifact_store is context.service.artifact_store
|
assert context.handlers.context.artifact_store is service.artifact_store
|
||||||
assert (
|
assert (
|
||||||
context.handlers.context.draft_workspace_store
|
context.handlers.context.draft_workspace_store is service.draft_workspace_store
|
||||||
is context.service.draft_workspace_store
|
|
||||||
)
|
)
|
||||||
assert context.handlers.context.run_store is context.service.run_store
|
assert context.handlers.context.run_store is service.run_store
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ from typer.testing import CliRunner
|
|||||||
|
|
||||||
from wf_artifacts import FileWorkflowArtifactStore, WorkflowDeployment
|
from wf_artifacts import FileWorkflowArtifactStore, WorkflowDeployment
|
||||||
from wf_cli.app import app
|
from wf_cli.app import app
|
||||||
from wf_cli.context import CliContext, load_cli_context
|
from typer import Context as TyperContext
|
||||||
|
|
||||||
|
from wf_cli.context import CliContext, config_path_from_context, load_cli_context
|
||||||
from wf_cli.formats import ListOutputFormat, render_list_payload
|
from wf_cli.formats import ListOutputFormat, render_list_payload
|
||||||
from wf_cli.io import CliInputError, parse_bindings, parse_json_value
|
from wf_cli.io import CliInputError, parse_bindings, parse_json_value
|
||||||
|
|
||||||
@@ -17,6 +19,18 @@ from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
|||||||
from tests.wf_mcp.workflow_surface.conftest import echo_artifact
|
from tests.wf_mcp.workflow_surface.conftest import echo_artifact
|
||||||
|
|
||||||
|
|
||||||
|
def _load_cli_context_with_specs(ctx: TyperContext | str | Path) -> CliContext:
|
||||||
|
if isinstance(ctx, (str, Path)):
|
||||||
|
config_path = ctx
|
||||||
|
else:
|
||||||
|
config_path = config_path_from_context(ctx)
|
||||||
|
context = load_cli_context(config_path)
|
||||||
|
service = context.service
|
||||||
|
assert service is not None
|
||||||
|
service.register_specs("demo.personal", echo_tool)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
def test_render_list_payload_ids_uses_requested_id_field() -> None:
|
def test_render_list_payload_ids_uses_requested_id_field() -> None:
|
||||||
payload = {"capabilities": [{"name": "wf.std.truthy"}, {"name": "wf.std.add"}]}
|
payload = {"capabilities": [{"name": "wf.std.truthy"}, {"name": "wf.std.add"}]}
|
||||||
|
|
||||||
@@ -132,30 +146,14 @@ def _write_cli_config(root: Path) -> Path:
|
|||||||
return config_path
|
return config_path
|
||||||
|
|
||||||
|
|
||||||
from wf_cli.context import load_cli_context_from_typer, config_path_from_context, load_cli_context
|
|
||||||
|
|
||||||
def _load_cli_context_with_specs(ctx: typer.Context | str | Path) -> CliContext:
|
|
||||||
if isinstance(ctx, (str, Path)):
|
|
||||||
config_path = ctx
|
|
||||||
else:
|
|
||||||
config_path = config_path_from_context(ctx)
|
|
||||||
"""Seed executable demo specs for CLI tests only.
|
|
||||||
|
|
||||||
Config loading registers connections and stores; it does not register
|
|
||||||
in-memory test NodeSpecs. Production source registration remains outside
|
|
||||||
this CLI slice.
|
|
||||||
"""
|
|
||||||
context = load_cli_context(config_path)
|
|
||||||
context.service.register_specs("demo.personal", echo_tool)
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
def test_wf_cap_list_outputs_json() -> None:
|
def test_wf_cap_list_outputs_json() -> None:
|
||||||
root = local_temp_root() / "wf_cli_cap_list"
|
root = local_temp_root() / "wf_cli_cap_list"
|
||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
config_path = _write_cli_config(root)
|
config_path = _write_cli_config(root)
|
||||||
|
|
||||||
with patch("wf_cli.commands.caps.load_cli_context_from_typer", _load_cli_context_with_specs):
|
with patch(
|
||||||
|
"wf_cli.commands.caps.load_cli_context_from_typer", _load_cli_context_with_specs
|
||||||
|
):
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
app,
|
app,
|
||||||
["--config", str(config_path), "cap", "list", "--source", "demo.personal"],
|
["--config", str(config_path), "cap", "list", "--source", "demo.personal"],
|
||||||
@@ -172,7 +170,9 @@ def test_wf_cap_list_ids_format() -> None:
|
|||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
config_path = _write_cli_config(root)
|
config_path = _write_cli_config(root)
|
||||||
|
|
||||||
with patch("wf_cli.commands.caps.load_cli_context_from_typer", _load_cli_context_with_specs):
|
with patch(
|
||||||
|
"wf_cli.commands.caps.load_cli_context_from_typer", _load_cli_context_with_specs
|
||||||
|
):
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
app,
|
app,
|
||||||
[
|
[
|
||||||
@@ -196,7 +196,9 @@ def test_wf_cap_inspect_outputs_detail() -> None:
|
|||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
config_path = _write_cli_config(root)
|
config_path = _write_cli_config(root)
|
||||||
|
|
||||||
with patch("wf_cli.commands.caps.load_cli_context_from_typer", _load_cli_context_with_specs):
|
with patch(
|
||||||
|
"wf_cli.commands.caps.load_cli_context_from_typer", _load_cli_context_with_specs
|
||||||
|
):
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
app,
|
app,
|
||||||
["--config", str(config_path), "cap", "inspect", "demo.personal.echo_tool"],
|
["--config", str(config_path), "cap", "inspect", "demo.personal.echo_tool"],
|
||||||
|
|||||||
@@ -2,8 +2,15 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
|
from wf_api.models import RawWorkflowPlan
|
||||||
|
from wf_cli.app import app
|
||||||
from wf_cli.context import load_cli_context
|
from wf_cli.context import load_cli_context
|
||||||
from wf_transport_rpc_http import RpcWorkflowApiClient
|
from wf_core import END
|
||||||
|
from wf_server import build_local_static_workflow_server
|
||||||
|
from wf_transport_rpc_http import RpcWorkflowApiClient, create_rpc_app
|
||||||
|
|
||||||
|
|
||||||
def test_load_cli_context_uses_rpc_client_for_rpc_http_target(tmp_path) -> None:
|
def test_load_cli_context_uses_rpc_client_for_rpc_http_target(tmp_path) -> None:
|
||||||
@@ -57,16 +64,6 @@ def test_load_cli_context_local_override_beats_rpc_config(tmp_path) -> None:
|
|||||||
assert not isinstance(context.handlers, RpcWorkflowApiClient)
|
assert not isinstance(context.handlers, RpcWorkflowApiClient)
|
||||||
assert context.service is None
|
assert context.service is None
|
||||||
assert context.config_path == config_path
|
assert context.config_path == config_path
|
||||||
import asyncio
|
|
||||||
|
|
||||||
import httpx
|
|
||||||
from typer.testing import CliRunner
|
|
||||||
|
|
||||||
from wf_api.models import RawWorkflowPlan
|
|
||||||
from wf_cli.app import app
|
|
||||||
from wf_core import END
|
|
||||||
from wf_server import build_local_static_workflow_server
|
|
||||||
from wf_transport_rpc_http import create_rpc_app
|
|
||||||
|
|
||||||
|
|
||||||
def _constant_plan() -> RawWorkflowPlan:
|
def _constant_plan() -> RawWorkflowPlan:
|
||||||
@@ -124,7 +121,9 @@ def test_wf_cap_commands_use_rpc_url_override(monkeypatch, tmp_path) -> None:
|
|||||||
original_client = httpx.AsyncClient
|
original_client = httpx.AsyncClient
|
||||||
monkeypatch.setattr(
|
monkeypatch.setattr(
|
||||||
"wf_transport_rpc_http.client.httpx.AsyncClient",
|
"wf_transport_rpc_http.client.httpx.AsyncClient",
|
||||||
lambda *args, **kwargs: original_client(transport=transport, base_url="http://test"),
|
lambda *args, **kwargs: original_client(
|
||||||
|
transport=transport, base_url="http://test"
|
||||||
|
),
|
||||||
)
|
)
|
||||||
config_path = tmp_path / "wf.json"
|
config_path = tmp_path / "wf.json"
|
||||||
config_path.write_text('{"version": 1}', encoding="utf-8")
|
config_path.write_text('{"version": 1}', encoding="utf-8")
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ from typer.testing import CliRunner
|
|||||||
|
|
||||||
from wf_artifacts import FileWorkflowArtifactStore, WorkflowDeployment
|
from wf_artifacts import FileWorkflowArtifactStore, WorkflowDeployment
|
||||||
from wf_cli.app import app
|
from wf_cli.app import app
|
||||||
from wf_cli.context import CliContext, load_cli_context
|
from typer import Context as TyperContext
|
||||||
|
|
||||||
|
from wf_cli.context import CliContext, config_path_from_context, load_cli_context
|
||||||
|
|
||||||
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
from tests.wf_mcp.test_support import echo_tool, local_temp_root
|
||||||
from tests.wf_mcp.workflow_surface.conftest import echo_artifact
|
from tests.wf_mcp.workflow_surface.conftest import echo_artifact
|
||||||
@@ -17,6 +19,25 @@ from tests.wf_mcp.workflow_surface.conftest import echo_artifact
|
|||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
|
|
||||||
|
|
||||||
|
def _load_cli_context_with_specs(ctx: TyperContext | str | Path) -> CliContext:
|
||||||
|
"""Test-only hook: seed executable demo specs for CLI integration tests.
|
||||||
|
|
||||||
|
``build_service_from_config`` registers connections, adapters, and
|
||||||
|
file-backed stores, but not in-memory node specs. Production code does
|
||||||
|
not auto-register specs; this helper exists solely so CLI tests can
|
||||||
|
exercise the full command path with a runnable deployment.
|
||||||
|
"""
|
||||||
|
if isinstance(ctx, (str, Path)):
|
||||||
|
config_path = ctx
|
||||||
|
else:
|
||||||
|
config_path = config_path_from_context(ctx)
|
||||||
|
context = load_cli_context(config_path)
|
||||||
|
service = context.service
|
||||||
|
assert service is not None
|
||||||
|
service.register_specs("demo.personal", echo_tool)
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
def _write_config(root: Path) -> Path:
|
def _write_config(root: Path) -> Path:
|
||||||
config_path = root / "wf_mcp.config.json"
|
config_path = root / "wf_mcp.config.json"
|
||||||
config_path.write_text(
|
config_path.write_text(
|
||||||
@@ -53,25 +74,6 @@ def _seed_echo_deployment(root: Path) -> Path:
|
|||||||
return config_path
|
return config_path
|
||||||
|
|
||||||
|
|
||||||
from wf_cli.context import load_cli_context_from_typer, config_path_from_context, load_cli_context
|
|
||||||
|
|
||||||
def _load_cli_context_with_specs(ctx: typer.Context | str | Path) -> CliContext:
|
|
||||||
if isinstance(ctx, (str, Path)):
|
|
||||||
config_path = ctx
|
|
||||||
else:
|
|
||||||
config_path = config_path_from_context(ctx)
|
|
||||||
"""Test-only hook: seed executable demo specs for CLI integration tests.
|
|
||||||
|
|
||||||
``build_service_from_config`` registers connections, adapters, and
|
|
||||||
file-backed stores, but not in-memory node specs. Production code does
|
|
||||||
not auto-register specs; this helper exists solely so CLI tests can
|
|
||||||
exercise the full command path with a runnable deployment.
|
|
||||||
"""
|
|
||||||
context = load_cli_context(config_path)
|
|
||||||
context.service.register_specs("demo.personal", echo_tool)
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
def test_wf_deploy_validate_outputs_json() -> None:
|
def test_wf_deploy_validate_outputs_json() -> None:
|
||||||
root = local_temp_root() / "wf_cli_deploy_validate"
|
root = local_temp_root() / "wf_cli_deploy_validate"
|
||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -99,7 +101,9 @@ def test_wf_run_start_accepts_inline_json_input() -> None:
|
|||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
config_path = _seed_echo_deployment(root)
|
config_path = _seed_echo_deployment(root)
|
||||||
|
|
||||||
with patch("wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs):
|
with patch(
|
||||||
|
"wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs
|
||||||
|
):
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
app,
|
app,
|
||||||
[
|
[
|
||||||
@@ -128,7 +132,9 @@ def test_wf_run_start_accepts_input_file() -> None:
|
|||||||
input_path = root / "input.json"
|
input_path = root / "input.json"
|
||||||
input_path.write_text('{"text": "from file"}', encoding="utf-8")
|
input_path.write_text('{"text": "from file"}', encoding="utf-8")
|
||||||
|
|
||||||
with patch("wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs):
|
with patch(
|
||||||
|
"wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs
|
||||||
|
):
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
app,
|
app,
|
||||||
[
|
[
|
||||||
@@ -153,7 +159,9 @@ def test_wf_run_inspect_and_trace_existing_run() -> None:
|
|||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
config_path = _seed_echo_deployment(root)
|
config_path = _seed_echo_deployment(root)
|
||||||
|
|
||||||
with patch("wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs):
|
with patch(
|
||||||
|
"wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs
|
||||||
|
):
|
||||||
start = runner.invoke(
|
start = runner.invoke(
|
||||||
app,
|
app,
|
||||||
[
|
[
|
||||||
@@ -206,7 +214,9 @@ def test_wf_run_start_reports_bad_json() -> None:
|
|||||||
root.mkdir(parents=True, exist_ok=True)
|
root.mkdir(parents=True, exist_ok=True)
|
||||||
config_path = _seed_echo_deployment(root)
|
config_path = _seed_echo_deployment(root)
|
||||||
|
|
||||||
with patch("wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs):
|
with patch(
|
||||||
|
"wf_cli.commands.runs.load_cli_context_from_typer", _load_cli_context_with_specs
|
||||||
|
):
|
||||||
result = runner.invoke(
|
result = runner.invoke(
|
||||||
app,
|
app,
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
@@ -10,6 +12,7 @@ from wf_config import (
|
|||||||
RpcHttpTransportConfig,
|
RpcHttpTransportConfig,
|
||||||
StdlibSourceConfig,
|
StdlibSourceConfig,
|
||||||
WorkflowConfigFile,
|
WorkflowConfigFile,
|
||||||
|
load_workflow_config,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -87,9 +90,6 @@ def test_workflow_config_rejects_unknown_target_kind() -> None:
|
|||||||
"client": {"target": {"kind": "mcp"}},
|
"client": {"target": {"kind": "mcp"}},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
import json
|
|
||||||
|
|
||||||
from wf_config import load_workflow_config
|
|
||||||
|
|
||||||
|
|
||||||
def test_load_workflow_config_resolves_filesystem_store_relative_to_config(
|
def test_load_workflow_config_resolves_filesystem_store_relative_to_config(
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
from typer.testing import CliRunner
|
from typer.testing import CliRunner
|
||||||
|
|
||||||
from wf_transport_rpc_http.cli import app
|
from wf_transport_rpc_http.cli import app
|
||||||
@@ -12,7 +14,6 @@ def test_rpc_server_cli_help_mentions_store_root() -> None:
|
|||||||
assert "--store-root" in result.output
|
assert "--store-root" in result.output
|
||||||
assert "--host" in result.output
|
assert "--host" in result.output
|
||||||
assert "--port" in result.output
|
assert "--port" in result.output
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
def test_rpc_server_cli_accepts_config_file(tmp_path) -> None:
|
def test_rpc_server_cli_accepts_config_file(tmp_path) -> None:
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user