Skip to content

First Tactic

Goal: wrap a typed Python class as a tactic and serve it over HTTP.

Prerequisites

python -m pip install -e ".[dev]"

Files Used

examples/echo_service/
  app.py
  tactics.py
tests/
  test_examples.py
  test_composition.py

The same tactic shape is available as an executable example at examples/echo_service/tactics.py.

Tactic

Create a tactic:

from pydantic import BaseModel
from lllm import Tactic


class EchoInput(BaseModel):
    text: str


class EchoOutput(BaseModel):
    text: str


class EchoTactic(Tactic[EchoInput, EchoOutput]):
    name = "echo"
    input_type = EchoInput
    output_type = EchoOutput

    def _run(self, input_value, *, context=None):
        return EchoOutput(text=input_value.text.upper())

Service

Serve it:

from lllm.services import create_tactic_app

app = create_tactic_app(EchoTactic())

Call

Call it:

curl -X POST http://127.0.0.1:8000/run \
  -H 'content-type: application/json' \
  -d '{"input":{"text":"hello"}}'

Expected response:

{
  "output": {
    "text": "HELLO"
  },
  "request_id": "...",
  "tactic": "echo"
}

Package Ref

Bind a package-style ref to the same local tactic:

from lllm import TacticResolver

resolver = TacticResolver()
resolver.register("psi://demo/echo/tactics/echo", EchoTactic())

assert resolver.run("psi://demo/echo/tactics/echo", {"text": "hi"}).text == "HI"

The same ref can later resolve to a service URL from .psi/config.toml without changing callers.

Verify

python -m pytest tests/test_examples.py tests/test_composition.py -q

Expected output:

... passed

Next, publish the tactic metadata through PsiHub or wrap it with a proxy or sandbox before serving it.