Skip to content

Export compiled flows as weaver-spec SelectableItems for contextweaver catalog ingestion #107

@dgenio

Description

@dgenio

Context

Issue #24 (Flow-to-VirtualTool adapter) covers wrapping a compiled flow as a Tool within ChainWeaver. But it doesn't address the cross-repo contract: exporting a flow as a weaver-spec SelectableItem that contextweaver can ingest into its catalog.

This is the mechanism that directly reduces tool explosion. If an agent has 50 tools but 5 of them are always used in a 5-tool sequence, compiling that sequence into a flow and exposing it as a single SelectableItem reduces the catalog from 50 to 46 (50 - 5 + 1). At scale, this is multiplicative.

The spec contract

Per weaver-spec, a SelectableItem has:

@dataclass
class SelectableItem:
    id: str
    label: str
    description: str
    capability_id: Optional[str] = None
    metadata: Dict[str, Any] = {}

contextweaver's SelectableItem is richer:

@dataclass
class SelectableItem:
    id: str
    kind: Literal["tool", "agent", "skill", "internal"]
    name: str
    description: str
    tags: list[str] = []
    namespace: str = ""
    args_schema: dict[str, Any] = {}
    output_schema: dict[str, Any] | None = None
    ...

A compiled flow exported as a SelectableItem should use kind="flow" (or kind="skill") and derive metadata from the flow definition.

Why it matters

  • Pillar 1 — Directly reduces the number of tools the LLM sees. A 5-step sequence becomes one option in the ChoiceCard.
  • Ecosystem value — This is the primary data path from ChainWeaver to contextweaver. Without it, the two repos are independent tools rather than an integrated system.
  • Composability — Flows-as-items means contextweaver can route to chains, not just individual tools. The LLM can choose "process and email customer report" (a flow) alongside individual tools.

Acceptance Criteria

  • flow_to_selectable_item(flow: Flow, executor: FlowExecutor) -> SelectableItem function
    • id = f"flow::{flow.name}" (namespaced to avoid collisions with regular tools)
    • kind = configured (default "skill" to distinguish from individual tools)
    • name = flow name or configured display name
    • description = flow description (or auto-generated from step descriptions)
    • tags = union of constituent tool tags + "flow" tag
    • args_schema = derived from flow's first step input schema (or flow-level input_schema if set)
    • output_schema = derived from flow's last step output schema
    • metadata = {"flow_name": ..., "step_count": ..., "tool_names": [...]}
  • Returns a weaver-spec SelectableItem (from weaver_contracts package), not contextweaver's internal type
  • Also returns contextweaver-compatible SelectableItem via optional parameter or separate function
  • Batch export: export_catalog(registry: FlowRegistry, executor: FlowExecutor) -> list[SelectableItem]
  • Unit tests: single flow export, batch export, schema derivation, metadata population, empty flow
  • weaver_contracts as optional dependency
  • Example: export flows and merge into contextweaver catalog

Implementation Notes

def flow_to_selectable_item(
    flow: Flow,
    executor: FlowExecutor,
    *,
    kind: str = "skill",
    namespace: str = "chainweaver",
) -> SelectableItem:
    """Export a compiled flow as a weaver-spec SelectableItem for contextweaver ingestion."""
    first_tool = executor.get_tool(flow.steps[0].tool_name)
    last_tool = executor.get_tool(flow.steps[-1].tool_name)
    
    return SelectableItem(
        id=f"flow::{flow.name}",
        label=flow.name,
        description=flow.description or _auto_describe(flow, executor),
        capability_id=f"chainweaver.flow.{flow.name}",
        metadata={
            "flow_name": flow.name,
            "step_count": len(flow.steps),
            "tool_names": [s.tool_name for s in flow.steps],
            "kind": kind,
            "namespace": namespace,
        },
    )

Files likely touched:

  • chainweaver/export.py — new module
  • tests/test_export.py — new
  • chainweaver/__init__.py — export
  • examples/export_to_contextweaver.py — new example

Dependencies

Notes

  • The flow:: prefix in the ID prevents collisions if a regular tool has the same name as a flow.
  • Auto-description could use the LLM description optimizer (Add offline LLM-assisted tool description optimizer #100) for flow descriptions that are maximally discriminative against the other tools in the catalog.
  • Consider a CLI command: chainweaver export --format selectable-items --output catalog.json

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:flow-as-toolUsing flows as composable toolsarea:integrationsExternal system integrationscomplexity:averageModerate effort, some design neededpriority:highMust address first within the milestonetype:featureNew feature or capability

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions