Skip to main content

WorkWeek Switch SDK — implement the switch contract for external agent teams

Project description

workweek-switch

Implement the WorkWeek switch contract for external agent teams.

The switch SDK lets your app expose capabilities that the WorkWeek platform can discover and invoke. Register handlers with decorators, self-register on startup, and the platform router handles the rest.

Install

pip install workweek-switch

Quick Start

Provider App (exposes capabilities)

from workweek_switch import WorkWeekSwitch

switch = WorkWeekSwitch(
    team_id="your-team-uuid",
    team_name="Best Apples Daily",
    gateway_url="https://gw.askvai.com",
    api_key="wk_rpt_your_key_here",
)

@switch.capability(
    "apple_recommendations",
    description="Daily recommendations for the best apples to buy",
    agent_name="Produce Analyst",
    agent_role="Apple Quality Specialist",
)
async def recommend_apples(message: str, context: dict) -> str:
    return "Honeycrisp from Washington state — peak season, $2.49/lb."

@switch.capability(
    "seasonal_analysis",
    description="Seasonal apple availability and pricing trends",
    agent_name="Market Analyst",
    agent_role="Seasonal Pricing Specialist",
)
async def seasonal(message: str, context: dict) -> str:
    return "Fuji apples peak Oct-Dec, prices drop 15% from summer highs."

app = switch.as_fastapi_app()

Consumer App (no capabilities, uses platform agents)

from workweek_switch import WorkWeekSwitch

switch = WorkWeekSwitch(
    team_id="your-team-uuid",
    team_name="My Consumer App",
    gateway_url="https://gw.askvai.com",
    api_key="wk_rpt_your_key_here",
)

# No @switch.capability() decorators — pure consumer
# Mount in your existing FastAPI app:
app.include_router(switch.as_fastapi_router())

Self-Registration (v0.2.0+)

Register your app with the platform on startup. Idempotent — safe to call every time your app starts.

from contextlib import asynccontextmanager
from fastapi import FastAPI
from workweek_switch import WorkWeekSwitch

switch = WorkWeekSwitch(
    team_id="",  # assigned by platform on first registration
    team_name="My App",
    gateway_url="https://gw.askvai.com",
    api_key="wk_rpt_your_key_here",
)

@switch.capability("my_feature", description="Does something useful")
async def my_feature(message: str, context: dict) -> str:
    return "result"

@asynccontextmanager
async def lifespan(app: FastAPI):
    # Register on startup (non-fatal if platform unreachable)
    try:
        result = await switch.register(switch_url="https://myapp.com")
        print(f"Registered: app_id={result.app_id} team_id={result.team_id}")
        if result.api_key:
            print(f"API Key (save this): {result.api_key}")
    except Exception as e:
        print(f"Registration failed (non-fatal): {e}")
    yield

app = FastAPI(lifespan=lifespan)
app.include_router(switch.as_fastapi_router())

How It Works

Switch Contract

The SDK exposes three endpoints that the WorkWeek platform expects:

Endpoint Method Purpose
/switch/manifest GET Returns registered capabilities, version hash, health status
/dispatch POST Routes a request to the matching capability handler
/health GET Liveness check

Platform Integration

Your App (SDK)                    WorkWeek Platform
    |                                    |
    |-- startup: register() ----------->| Creates App + Team + capabilities
    |                                    |
    |<--- hourly poll: GET /manifest ---|  Router syncs routing tables
    |                                    |
    |<--- invoke: POST /dispatch -------|  User invokes your capability
    |--- response --------------------- >|
  1. Register: On startup, your app calls register() to create its App + Team in the platform
  2. Manifest polling: The platform router polls /switch/manifest hourly to detect capability changes
  3. Dispatch: When a user invokes one of your capabilities, the platform sends a POST to /dispatch

Capability Lifecycle

  • Add a capability: Add a @switch.capability() decorator, deploy. Router picks it up within 1 hour (or immediately on register()).
  • Remove a capability: Remove the decorator, deploy. Router drains the capability on next poll — existing requests complete, new ones route elsewhere.
  • Update a capability: Change the handler function. No SDK/platform changes needed — dispatch always calls the current handler.

Version-Based Polling

The manifest includes a SHA-256 hash of registered capability names. The router skips processing when the version hasn't changed, keeping sync lightweight even at hundreds of tenants.

API Reference

WorkWeekSwitch

WorkWeekSwitch(
    team_id: str,              # Team UUID (assigned by platform on first register)
    team_name: str,            # Human-readable name shown in marketplace
    webhook_secret: str = None,# HMAC secret for dispatch signature verification
    gateway_url: str = None,   # Platform gateway URL (required for register())
    api_key: str = None,       # API key (required for register())
)

@switch.capability()

@switch.capability(
    name: str,                 # Capability name (must be unique within team)
    description: str = "",     # Shown in marketplace and manifest
    is_primary: bool = True,   # Primary handler for this capability
    agent_name: str = None,    # Display name (defaults to function name)
    agent_role: str = None,    # Role description (e.g., "Weather Analyst")
)
async def handler(message: str, context: dict) -> str:
    ...

Handlers can be async or sync. Sync handlers run in a thread pool automatically.

switch.register()

result = await switch.register(
    switch_url: str,           # Externally-reachable URL where manifest/dispatch live
) -> RegisterResult

Returns:

  • app_id: int — Platform app ID
  • team_id: str — Platform team UUID
  • team_name: str — Team display name
  • api_key: str | None — Full API key (first registration only, save it)
  • api_key_prefix: str | None — Key prefix for identification
  • capabilities_registered: list[str] — Capabilities the platform registered
  • already_existed: bool — True if app was already registered

switch.build_manifest()

Returns the manifest dict that /switch/manifest serves. Useful for testing.

switch.as_fastapi_app()

Returns a standalone FastAPI application with the switch contract endpoints.

switch.as_fastapi_router()

Returns a FastAPI APIRouter for embedding switch endpoints in an existing app.

HMAC Signature Verification

For production deployments, enable webhook signature verification:

switch = WorkWeekSwitch(
    team_id="...",
    team_name="...",
    webhook_secret="wk_secret_your_secret_here",
)

The platform signs dispatch request bodies with HMAC-SHA256. The SDK verifies the X-Webhook-Signature header automatically and returns 401 if invalid.

Changelog

v0.2.0

  • Added gateway_url and api_key constructor parameters
  • Added register(switch_url) method for platform self-registration
  • Added RegisterResult model
  • Added httpx as a dependency (used for registration HTTP calls)

v0.1.0

  • Initial release
  • Capability registration via @switch.capability() decorator
  • Manifest serving, dispatch routing, health check
  • HMAC signature verification
  • FastAPI app and router builders

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

workweek_switch-0.2.0.tar.gz (10.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

workweek_switch-0.2.0-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file workweek_switch-0.2.0.tar.gz.

File metadata

  • Download URL: workweek_switch-0.2.0.tar.gz
  • Upload date:
  • Size: 10.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.11

File hashes

Hashes for workweek_switch-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9ac94e3d780160b4702eab3dd7e89fd1b6783a969b473474e2d92256fa8135f8
MD5 378f538b07ffafc012c9727848fff18f
BLAKE2b-256 9d2de28ef77783ecc177449b95f7967cd7f3bf836832ddd1ce0f96a944f9f350

See more details on using hashes here.

File details

Details for the file workweek_switch-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for workweek_switch-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c6d208132a329469b17073e434e5d04957dec395be683c7d3fef9325e5186fdc
MD5 588d2dd8f6a71ddfd5704f5299d6319b
BLAKE2b-256 19855b8d488c029d04673747c5d648b2c17215415204f28106766f5ea721133d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page