Python SDK: Agent Integration

The SDK provides API calls. Your application chooses what work to record, how to price expenses and how to handle failed work. There is no built-in track_agent_work context manager or exported track decorator.

Define your own wrapper

Save this application code as keito_tracking.py. It records elapsed time only after work succeeds. Supply the work date in the workspace’s timezone. General automation uses source="api"; Keito’s agent lifecycle source has a separate validated metadata contract.

from time import perf_counter
from uuid import uuid4
from keito.core.request_options import RequestOptions


def record_completed_work(client, *, project_id, task_id, spent_date, work):
    operation_id = str(uuid4())
    started = perf_counter()
    result = work()
    seconds = max(1, round(perf_counter() - started))
    client.time_entries.create(
        project_id=project_id,
        task_id=task_id,
        spent_date=spent_date,
        hours=seconds / 3600,
        source="api",
        notes="Completed automated operation",
        metadata={"session_id": operation_id, "duration_seconds": seconds},
        request_options=RequestOptions(
            additional_headers={"Idempotency-Key": f"completed-work-{operation_id}"}
        ),
    )
    return result

Persist the operation ID if you need to recover after a process crash. Reconcile uncertain API writes before rerunning work with a new ID. Decide explicitly whether failed work should be recorded; this helper does not record it and does not delete an existing entry.

Use the wrapper

from keito import Keito
from keito_tracking import record_completed_work

with Keito() as client:
    result = record_completed_work(
        client,
        project_id="YOUR_PROJECT_ID",
        task_id="YOUR_TASK_ID",
        spent_date="2026-10-30",
        work=lambda: my_agent.run("Review the implementation"),
    )

my_agent is your application’s agent, not a Keito object. For running timers, use start_timer and stop_timer, and stop the owned timer explicitly on either success or failure. Concurrent operations should not replace one another’s running timers.

Expenses remain explicit

Record a known cost with client.expenses.create using a real expense-category ID. An amount-based category requires total_cost; a per-unit category requires units and uses the configured category rate. Token counts in metadata do not calculate a price. Expense creation does not pay a provider or send an invoice.

See Expenses and receipts, LangChain and CrewAI for examples using your own wrapper.