Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,9 @@ tasks:
'{{.UV_BIN}}' run pytest

# Run SDK example to verify it works
# cd {{ .ROOT_DIR }}/sdk/examples/example-py
# '{{.UV_BIN}}' sync
# '{{.UV_BIN}}' run python example.py
cd {{ .ROOT_DIR }}/examples
'{{ .UV_BIN }}' sync
'{{ .UV_BIN }}' run python example.py

sdk:deps:python:
desc: Install deps for python SDK package
Expand Down
10 changes: 10 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Python
dist/
__pycache__/
*.egg-info/
*.pyc
*.pyo
*.pyd

# Virtual Environments
.venv/
1 change: 1 addition & 0 deletions examples/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.14
129 changes: 129 additions & 0 deletions examples/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Copyright AGNTCY Contributors (https://github.com/agntcy)
# SPDX-License-Identifier: Apache-2.0

from google.protobuf.json_format import MessageToJson

from agntcy.dir_sdk.client import Client
from agntcy.dir_sdk.models import core_v1, search_v1, routing_v1


def generate_record(name):
return core_v1.Record(
data={
"name": name,
"version": "v1.0.0",
"schema_version": "0.8.0",
"description": "My example agent",
"authors": ["AGNTCY"],
"created_at": "2025-03-19T17:06:37Z",
"skills": [
{
"name": "natural_language_processing/natural_language_generation/text_completion",
"id": 10201
},
{
"name": "natural_language_processing/analytical_reasoning/problem_solving",
"id": 10702
}
],
"locators": [
{
"type": "docker_image",
"url": "https://ghcr.io/agntcy/marketing-strategy"
}
],
"domains": [
{
"name": "technology/networking",
"id": 103
}
],
"modules": [
{
"name": "integration/a2a",
"id": 203,
"data": {
"protocol_version": "lightweight orchestra moral",
"card_data": "centres",
"capabilities": [
"state_transition_history",
"push_notifications"
],
"transports": [
"grpc",
"http"
],
"output_modes": [
"text/html"
]
}
}
]
},
)


def main() -> None:
client = Client()

records = [generate_record(x) for x in ["example-record", "example-record2"]]

# Push objects to the store
refs = client.push(records)

for ref in refs:
print("Pushed object ref:", ref.cid)

# Pull objects from the store
pulled_records = client.pull(refs)

for pulled_record in pulled_records:
print("Pulled object data:", MessageToJson(pulled_record))

# Lookup the object
metadatas = client.lookup(refs)

for metadata in metadatas:
print("Lookup object metadata:", MessageToJson(metadata))

# Publish the object
record_refs = routing_v1.RecordRefs(refs=[refs[0]])
publish_request = routing_v1.PublishRequest(record_refs=record_refs)
client.publish(publish_request)
print("Object published.")

# List objects in the store
query = routing_v1.RecordQuery(
type=routing_v1.RECORD_QUERY_TYPE_SKILL,
value="/skills/Natural Language Processing/Text Completion",
)

list_request = routing_v1.ListRequest(queries=[query])
objects = list(client.list(list_request))

for o in objects:
print("Listed object:", MessageToJson(o))

# Search objects
search_query = search_v1.RecordQuery(
type=search_v1.RECORD_QUERY_TYPE_VERSION, value="v1.*",
)

search_request = search_v1.SearchCIDsRequest(queries=[search_query], limit=3)
objects = list(client.search_cids(search_request))

print("Searched objects:",objects)

# Unpublish the object
record_refs = routing_v1.RecordRefs(refs=[refs[0]])
unpublish_request = routing_v1.UnpublishRequest(record_refs=record_refs)
client.unpublish(unpublish_request)
print("Object unpublished.")

# Delete the object
client.delete(refs)
print("Objects are deleted.")


if __name__ == "__main__":
main()
104 changes: 104 additions & 0 deletions examples/example_interactive_oidc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright AGNTCY Contributors (https://github.com/agntcy)
# SPDX-License-Identifier: Apache-2.0

from __future__ import annotations

import argparse
import os

from agntcy.dir_sdk.client import Client, Config, OAuthPkceError
from agntcy.dir_sdk.models import search_v1

DEFAULT_OIDC_ISSUER = "https://dev.idp.ads.outshift.io"
DEFAULT_SERVER_ADDRESS = "dev.gateway.ads.outshift.io:443"
DEFAULT_TLS_SERVER_NAME = "dev.gateway.ads.outshift.io"
DEFAULT_REDIRECT_URI = "http://localhost:8484/callback"


def require_env(name: str) -> str:
value = os.environ.get(name, "").strip()
if not value:
msg = f"{name} is required for the interactive OIDC example"
raise RuntimeError(msg)
return value


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Interactive OIDC example that calls SearchCIDs only.",
)
parser.add_argument(
"--version",
default="v1*",
help="Version query used for SearchCIDs (default: v1*)",
)
parser.add_argument(
"--limit",
type=int,
default=3,
help="Maximum number of CIDs to return (default: 3)",
)
return parser.parse_args()


def build_client() -> Client:
config = Config(
server_address=os.environ.get(
"DIRECTORY_CLIENT_SERVER_ADDRESS",
DEFAULT_SERVER_ADDRESS,
),
auth_mode="oidc",
oidc_issuer=DEFAULT_OIDC_ISSUER,
oidc_client_id=require_env("DIRECTORY_CLIENT_OIDC_CLIENT_ID"),
oidc_client_secret=os.environ.get("DIRECTORY_CLIENT_OIDC_CLIENT_SECRET", ""),
tls_server_name=os.environ.get(
"DIRECTORY_CLIENT_TLS_SERVER_NAME",
DEFAULT_TLS_SERVER_NAME,
),
oidc_redirect_uri=os.environ.get(
"DIRECTORY_CLIENT_OIDC_REDIRECT_URI",
DEFAULT_REDIRECT_URI,
),
oidc_callback_port=int(
os.environ.get("DIRECTORY_CLIENT_OIDC_CALLBACK_PORT", "8484"),
),
)
client = Client(config)
holder = getattr(client, "_oauth_holder", None)
if holder is not None:
try:
holder.get_access_token()
print("Using cached OIDC token.")
return client
except RuntimeError:
pass

print("No cached OIDC token found. Starting interactive login.")
client.authenticate_oauth_pkce()
return client


def main() -> None:
args = parse_args()
client = build_client()

search_query = search_v1.RecordQuery(
type=search_v1.RECORD_QUERY_TYPE_VERSION,
value=args.version,
)
search_request = search_v1.SearchCIDsRequest(
queries=[search_query],
limit=args.limit,
)
objects = list(client.search_cids(search_request))
print(f"SearchCIDs results for version {args.version!r}:")
for obj in objects:
print(obj)


if __name__ == "__main__":
try:
main()
except OAuthPkceError as e:
print(f"Interactive OIDC login failed: {e}")
raise
14 changes: 14 additions & 0 deletions examples/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[project]
name = "dir-example"
version = "0.0.0"
requires-python = ">=3.10"
dependencies = [
"agntcy-dir",
"httpx>=0.28.1",
]

[[tool.uv.index]]
url = "https://buf.build/gen/python"

[tool.uv.sources]
agntcy-dir = { path = "..", editable = true }
Loading
Loading