feat: discover existing workflow objects
This commit is contained in:
@@ -6,6 +6,7 @@ from .app import App
|
||||
from .authoring import EditableWorkflow
|
||||
from .capabilities import CapabilityResult, CapabilitySummary, RemoteCapability
|
||||
from .deployments import Deployment, DeploymentValidation
|
||||
from .discovery import ArtifactSummary, DeploymentSummary, RunSummary
|
||||
from .errors import (
|
||||
ArtifactNotFound,
|
||||
ArtifactVersionConflict,
|
||||
@@ -33,6 +34,7 @@ __all__ = [
|
||||
"ArtifactVersionConflict",
|
||||
"App",
|
||||
"ArtifactRef",
|
||||
"ArtifactSummary",
|
||||
"CapabilityNotFound",
|
||||
"CapabilityRef",
|
||||
"CapabilityResult",
|
||||
@@ -42,11 +44,13 @@ __all__ = [
|
||||
"DeploymentRequired",
|
||||
"Deployment",
|
||||
"DeploymentValidation",
|
||||
"DeploymentSummary",
|
||||
"InvalidResponse",
|
||||
"Page",
|
||||
"ProtocolError",
|
||||
"RemoteCapability",
|
||||
"Run",
|
||||
"RunSummary",
|
||||
"RevisionConflict",
|
||||
"TransportError",
|
||||
"ValidationFailed",
|
||||
|
||||
@@ -12,8 +12,10 @@ import httpx
|
||||
from wf_api.models import (
|
||||
CapabilityCallResult,
|
||||
InspectCapabilityResult,
|
||||
ListArtifactsResult,
|
||||
ListCapabilitiesResult,
|
||||
ListDeploymentsResult,
|
||||
ListRunsResult,
|
||||
RunResult,
|
||||
RunTraceResult,
|
||||
SaveArtifactResult,
|
||||
@@ -156,6 +158,23 @@ class PublicErrorWorkflowClientPort:
|
||||
version=version,
|
||||
)
|
||||
|
||||
async def list_artifacts(
|
||||
self,
|
||||
*,
|
||||
query: str | None = None,
|
||||
kind: Literal["workflow", "wrapper"] | None = None,
|
||||
cursor: str | None = None,
|
||||
limit: int = 50,
|
||||
) -> ListArtifactsResult:
|
||||
return await self._invoke(
|
||||
"workflow.artifacts.list",
|
||||
self._rpc.list_artifacts,
|
||||
query=query,
|
||||
kind=kind,
|
||||
cursor=cursor,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
async def create_artifact_from_plan(
|
||||
self,
|
||||
*,
|
||||
@@ -256,6 +275,21 @@ class PublicErrorWorkflowClientPort:
|
||||
run_id=run_id,
|
||||
)
|
||||
|
||||
async def list_runs(
|
||||
self,
|
||||
*,
|
||||
status: str | None = None,
|
||||
cursor: str | None = None,
|
||||
limit: int = 50,
|
||||
) -> ListRunsResult:
|
||||
return await self._invoke(
|
||||
"workflow.runs.list",
|
||||
self._rpc.list_runs,
|
||||
status=status,
|
||||
cursor=cursor,
|
||||
limit=limit,
|
||||
)
|
||||
|
||||
async def resume_run(
|
||||
self,
|
||||
*,
|
||||
|
||||
+80
-1
@@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import TYPE_CHECKING, Any, Literal
|
||||
|
||||
from wf_platform import CapabilityRef, Page, SourceRef
|
||||
from wf_transport_rpc_http import RpcWorkflowApiClient
|
||||
@@ -14,10 +14,14 @@ from ._identity import require_response_identity
|
||||
from .authoring import EditableWorkflow
|
||||
from .capabilities import CapabilitySummary, RemoteCapability
|
||||
from .codec import (
|
||||
decode_artifacts_page,
|
||||
decode_capabilities_page,
|
||||
decode_capability_inspect,
|
||||
decode_deployments,
|
||||
decode_runs_page,
|
||||
decode_workflow_artifact,
|
||||
)
|
||||
from .discovery import ArtifactSummary, DeploymentSummary, RunSummary
|
||||
from .errors import InvalidResponse
|
||||
from .protocols import WorkflowClientPort
|
||||
from .workflows import WorkflowArtifact
|
||||
@@ -148,6 +152,81 @@ class App:
|
||||
total=wire["total"],
|
||||
)
|
||||
|
||||
async def artifacts(
|
||||
self,
|
||||
*,
|
||||
query: str | None = None,
|
||||
kind: Literal["workflow", "wrapper"] | None = None,
|
||||
cursor: str | None = None,
|
||||
limit: int = 50,
|
||||
) -> Page[ArtifactSummary]:
|
||||
"""List lightweight saved artifact versions without reconstructing them."""
|
||||
wire = decode_artifacts_page(
|
||||
await self._port.list_artifacts(
|
||||
query=query, kind=kind, cursor=cursor, limit=limit
|
||||
)
|
||||
)
|
||||
return Page(
|
||||
items=tuple(
|
||||
ArtifactSummary(
|
||||
artifact_id=row["artifact_id"],
|
||||
version=row["version"],
|
||||
kind=row["kind"],
|
||||
title=row["display_name"],
|
||||
description=row["description"],
|
||||
outcomes=tuple(row["outcomes"]),
|
||||
required_sources=tuple(row["required_sources"]),
|
||||
)
|
||||
for row in wire["nodes"]
|
||||
),
|
||||
next_cursor=wire["next_cursor"],
|
||||
total=wire["total"],
|
||||
)
|
||||
|
||||
async def deployments(self) -> tuple[DeploymentSummary, ...]:
|
||||
"""List lightweight saved deployment rows."""
|
||||
wire = decode_deployments(await self._port.list_deployments())
|
||||
return tuple(
|
||||
DeploymentSummary(
|
||||
deployment_id=row["id"],
|
||||
artifact_id=row["artifact_id"],
|
||||
artifact_version=row["artifact_version"],
|
||||
binding_count=row["binding_count"],
|
||||
drift_policy=row["drift_policy"],
|
||||
)
|
||||
for row in wire["deployments"]
|
||||
)
|
||||
|
||||
async def runs(
|
||||
self,
|
||||
*,
|
||||
status: str | None = None,
|
||||
cursor: str | None = None,
|
||||
limit: int = 50,
|
||||
) -> Page[RunSummary]:
|
||||
"""List lightweight durable-run rows without loading traces."""
|
||||
wire = decode_runs_page(
|
||||
await self._port.list_runs(status=status, cursor=cursor, limit=limit)
|
||||
)
|
||||
return Page(
|
||||
items=tuple(
|
||||
RunSummary(
|
||||
run_id=row["run_id"],
|
||||
deployment_id=row["deployment_id"],
|
||||
artifact_id=row["artifact_id"],
|
||||
artifact_version=row["artifact_version"],
|
||||
status=row["status"],
|
||||
resume_readiness=row["resume_readiness"],
|
||||
diagnostic_count=row["diagnostic_count"],
|
||||
created_at=row["created_at"],
|
||||
updated_at=row["updated_at"],
|
||||
)
|
||||
for row in wire["runs"]
|
||||
),
|
||||
next_cursor=wire["next_cursor"],
|
||||
total=wire["total"],
|
||||
)
|
||||
|
||||
def new_workflow(
|
||||
self,
|
||||
name: str,
|
||||
|
||||
@@ -12,8 +12,10 @@ from wf_api.models import (
|
||||
CapabilityCallResult,
|
||||
DependencyDiagnosticPayload,
|
||||
InspectCapabilityResult,
|
||||
ListArtifactsResult,
|
||||
ListCapabilitiesResult,
|
||||
ListDeploymentsResult,
|
||||
ListRunsResult,
|
||||
RawWorkflowPlan,
|
||||
RunResult,
|
||||
RunTraceResult,
|
||||
@@ -114,6 +116,16 @@ def decode_capabilities_page(payload: object) -> ListCapabilitiesResult:
|
||||
)
|
||||
|
||||
|
||||
def decode_artifacts_page(payload: object) -> ListArtifactsResult:
|
||||
"""Validate one cursor-paged artifact catalog response."""
|
||||
return _validate(payload, ListArtifactsResult, "workflow.artifacts.list")
|
||||
|
||||
|
||||
def decode_runs_page(payload: object) -> ListRunsResult:
|
||||
"""Validate one cursor-paged durable-run response."""
|
||||
return _validate(payload, ListRunsResult, "workflow.runs.list")
|
||||
|
||||
|
||||
def decode_validate_artifact_plan(payload: object) -> ValidateArtifactPlanResult:
|
||||
"""Validate a non-persisting artifact-plan response at the client boundary."""
|
||||
return _validate(
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
"""Lightweight immutable rows for discovering existing workflow objects."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ArtifactSummary:
|
||||
"""Catalog identity and display metadata for one artifact version."""
|
||||
|
||||
artifact_id: str
|
||||
version: int
|
||||
kind: str
|
||||
title: str
|
||||
description: str | None
|
||||
outcomes: tuple[str, ...]
|
||||
required_sources: tuple[str, ...]
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class DeploymentSummary:
|
||||
"""Identity and binding metadata for one saved deployment."""
|
||||
|
||||
deployment_id: str
|
||||
artifact_id: str
|
||||
artifact_version: int
|
||||
binding_count: int
|
||||
drift_policy: str
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class RunSummary:
|
||||
"""Identity and lifecycle metadata for one durable run."""
|
||||
|
||||
run_id: str
|
||||
deployment_id: str
|
||||
artifact_id: str
|
||||
artifact_version: int
|
||||
status: str
|
||||
resume_readiness: str
|
||||
diagnostic_count: int
|
||||
created_at: str
|
||||
updated_at: str
|
||||
@@ -8,8 +8,10 @@ from typing import Any, Literal, Protocol
|
||||
from wf_api.models import (
|
||||
CapabilityCallResult,
|
||||
InspectCapabilityResult,
|
||||
ListArtifactsResult,
|
||||
ListCapabilitiesResult,
|
||||
ListDeploymentsResult,
|
||||
ListRunsResult,
|
||||
RunResult,
|
||||
RunTraceResult,
|
||||
SaveArtifactResult,
|
||||
@@ -60,6 +62,15 @@ class WorkflowClientPort(Protocol):
|
||||
version: int,
|
||||
) -> WorkflowArtifactPayload: ...
|
||||
|
||||
async def list_artifacts(
|
||||
self,
|
||||
*,
|
||||
query: str | None = None,
|
||||
kind: Literal["workflow", "wrapper"] | None = None,
|
||||
cursor: str | None = None,
|
||||
limit: int = 50,
|
||||
) -> ListArtifactsResult: ...
|
||||
|
||||
async def create_artifact_from_plan(
|
||||
self,
|
||||
*,
|
||||
@@ -112,6 +123,14 @@ class WorkflowClientPort(Protocol):
|
||||
trace_range: TraceRangeLike | None = None,
|
||||
) -> RunResult: ...
|
||||
|
||||
async def list_runs(
|
||||
self,
|
||||
*,
|
||||
status: str | None = None,
|
||||
cursor: str | None = None,
|
||||
limit: int = 50,
|
||||
) -> ListRunsResult: ...
|
||||
|
||||
async def inspect_run(self, *, run_id: str) -> RunResult: ...
|
||||
|
||||
async def resume_run(
|
||||
|
||||
Reference in New Issue
Block a user