jentic.py•5.97 kB
from jentic.lib.cfg import AgentConfig
from jentic.lib.core_api import BackendAPI
from jentic.lib.models import (
APIIdentifier,
ExecuteResponse,
ExecutionRequest,
LoadRequest,
LoadResponse,
SearchRequest,
SearchResponse,
)
class Jentic:
"""High-level async client for the Jentic API Hub.
This class is opinionated but intentionally thin: it validates inputs,
delegates all network traffic to :class:`jentic.lib.core_api.BackendAPI`,
and returns Pydantic models so you get autocompletion and type checking
out-of-the-box.
Environment
-----------
Unless you explicitly supply an :class:`~jentic.lib.cfg.AgentConfig` the
client loads configuration from *environment variables* via
:meth:`jentic.lib.cfg.AgentConfig.from_env`.
The only **required** variable is ``JENTIC_AGENT_API_KEY`` – the Agent API
key you copy from the Jentic dashboard. Example::
export JENTIC_AGENT_API_KEY=ak_live_*******
All other values (``JENTIC_ENVIRONMENT`` etc.) default sensibly for production.
Examples
--------
Minimal search → load → execute loop ::
import asyncio
from jentic import Jentic, SearchRequest, LoadRequest, ExecutionRequest
async def main() -> None:
client = Jentic()
search = await client.search(SearchRequest(query="send an message via discord"))
op_id = search.results[0].id
# Load the operation, view inputs and outputs
response = await client.load(LoadRequest(ids=[op_id]))
tool_info = response.tool_info[op_id]
# Execute the operation
result = await client.execute(ExecutionRequest(id=op_id, inputs={"to":"bob@example.com","body":"Hi"}))
# Print the result
print (result.status_code)
print (result.output)
asyncio.run(main())
Notes for advanced users
------------------------
• If you need fully-specified LLM tools, see
:class:`jentic.lib.agent_runtime.AgentToolManager` instead.
Parameters
----------
config : AgentConfig | None, optional
Pre-validated agent configuration. If ``None`` the instance resolves
config from the current environment.
"""
def __init__(self, config: AgentConfig | None = None):
self._backend = BackendAPI(config or AgentConfig.from_env())
async def list_apis(self) -> list[APIIdentifier]:
"""Return every API the current agent is authorised to see.
Returns
-------
list[APIIdentifier]
Each identifier contains the *vendor*, *name* and *version*.
"""
return await self._backend.list_apis()
async def search(self, request: SearchRequest) -> SearchResponse:
"""Full-text search across APIs, operations and workflows.
The `query` string supports natural-language phrases – the backend uses
semantic search to find best matches. Results are automatically scoped
to the APIs your *agent key* grants access to.
Parameters
----------
request : SearchRequest
Pass an instance for maximum control (limit, keywords, filter list
of APIs). For convenience you can also call
``await client.search(SearchRequest(query="..."))``.
Returns
-------
SearchResponse
• ``results`` – ranked list of operations & workflows
• ``total_count`` – total hits before pagination
• ``query`` – the original query string
Examples
--------
>>> sr = SearchRequest(query="create a Trello card", limit=10)
>>> hits = await client.search(sr)
>>> hits.results[0].summary
'Create a new card in a Trello list'
"""
return await self._backend.search(request)
async def execute(self, request: ExecutionRequest) -> ExecuteResponse:
"""Execute a previously-loaded operation or workflow.
``ExecutionRequest.id`` must be the *exact* UUID you obtained from the
search results – the SDK figures out whether it is an operation or a
workflow.
Parameters
----------
request : ExecutionRequest
• ``id`` – UUID prefixed with ``op_`` or ``wf_``
• ``inputs`` – dict that satisfies the JSON schema returned by
:meth:`load`
Returns
-------
ExecuteResponse
• ``success`` is *True* the ``output`` field contains the tool’s
returned data (often JSON). On failure the ``error`` field is
populated and ``success`` is *False*.
• ``status_code`` – HTTP status code of the response
Example
-------
>>> req = ExecutionRequest(id="op_123", inputs={"text":"hello"})
>>> resp = await client.execute(req)
>>> resp.success
True
"""
return await self._backend.execute(request)
async def load(self, request: LoadRequest) -> LoadResponse:
"""Fetch JSON schemas & auth metadata for given IDs.
Call this *after* a successful search and *before* execute so you can
validate user input and inform the LLM of required environment
variables.
Parameters
----------
request : LoadRequest
``ids`` should contain one or many UUIDs returned by search.
Returns
-------
LoadResponse
• ``tool_info`` - mapping id -> tool info
Tip
---
The returned object is compatible with
:class:`jentic.lib.agent_runtime.AgentToolManager` so you can write the
JSON to *jentic.json* and immediately generate tool definitions.
"""
get_files_response = await self._backend.load(request)
return LoadResponse.from_get_files_response(get_files_response)