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.