agentkernel 0.2.7__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {agentkernel-0.2.7 → agentkernel-0.2.8}/PKG-INFO +5 -1
- {agentkernel-0.2.7 → agentkernel-0.2.8}/pyproject.toml +7 -1
- agentkernel-0.2.8/src/agentkernel/api/handler.py +304 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/cli/cli.py +5 -2
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/base.py +44 -13
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/config.py +22 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/service.py +10 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/adk/adk.py +76 -29
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/openai/openai.py +79 -22
- agentkernel-0.2.8/src/agentkernel/instagram.py +8 -0
- agentkernel-0.2.8/src/agentkernel/integration/instagram/README.md +153 -0
- agentkernel-0.2.8/src/agentkernel/integration/instagram/__init__.py +14 -0
- agentkernel-0.2.8/src/agentkernel/integration/instagram/instagram_chat.py +324 -0
- agentkernel-0.2.8/src/agentkernel/integration/telegram/README.md +174 -0
- agentkernel-0.2.8/src/agentkernel/integration/telegram/__init__.py +10 -0
- agentkernel-0.2.8/src/agentkernel/integration/telegram/telegram_chat.py +299 -0
- agentkernel-0.2.8/src/agentkernel/telegram.py +8 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/langfuse/adk.py +2 -3
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/langfuse/crewai.py +2 -3
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/langfuse/langgraph.py +2 -3
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/langfuse/openai.py +2 -3
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/openllmetry/adk.py +6 -5
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/openllmetry/crewai.py +6 -5
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/openllmetry/langgraph.py +6 -5
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/openllmetry/openai.py +6 -5
- agentkernel-0.2.7/src/agentkernel/api/handler.py +0 -131
- {agentkernel-0.2.7 → agentkernel-0.2.8}/README.md +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/adk.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/api/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/api/a2a/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/api/a2a/a2a.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/api/a2a/handler.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/api/http.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/api/mcp/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/api/mcp/akmcp.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/aws.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/cli/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/builder.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/hooks.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/model.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/module.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/runtime.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/session/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/session/base.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/session/dynamodb.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/session/in_memory.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/session/redis.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/session/serde.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/util/config_yaml_util.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/core/util/key_value_cache.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/crewai.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/deployment/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/deployment/aws/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/deployment/aws/aklambda.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/adk/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/crewai/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/crewai/crewai.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/langgraph/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/langgraph/langgraph.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/framework/openai/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/messenger/README.md +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/messenger/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/messenger/messenger_chat.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/slack/README.md +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/slack/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/slack/slack_chat.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/whatsapp/README.md +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/whatsapp/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/integration/whatsapp/whatsapp_chat.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/langgraph.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/mcp.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/messenger.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/openai.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/slack.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/test/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/test/test.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/base.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/langfuse/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/langfuse/langfuse.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/openllmetry/__init__.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/openllmetry/openllmetry.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/trace/trace.py +0 -0
- {agentkernel-0.2.7 → agentkernel-0.2.8}/src/agentkernel/whatsapp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: agentkernel
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
4
4
|
Summary: Agent Kernel - Unified AI Agents Runtime
|
|
5
5
|
Author: Yaala Labs
|
|
6
6
|
Author-email: Yaala Labs <agentkernel@yaalalabs.com>
|
|
@@ -21,6 +21,7 @@ Requires-Dist: boto3>=1.41.4 ; extra == 'aws'
|
|
|
21
21
|
Requires-Dist: crewai>=0.150.0 ; extra == 'crewai'
|
|
22
22
|
Requires-Dist: openinference-instrumentation-crewai>=0.1.16 ; extra == 'crewai'
|
|
23
23
|
Requires-Dist: openinference-instrumentation-litellm>=0.1.28 ; extra == 'crewai'
|
|
24
|
+
Requires-Dist: httpx>=0.27.0 ; extra == 'instagram'
|
|
24
25
|
Requires-Dist: langfuse>=3.9.2 ; extra == 'langfuse'
|
|
25
26
|
Requires-Dist: nest-asyncio>=1.6.0 ; extra == 'langfuse'
|
|
26
27
|
Requires-Dist: langgraph~=0.6.2 ; extra == 'langgraph'
|
|
@@ -34,6 +35,7 @@ Requires-Dist: openinference-instrumentation-openai-agents>=1.3.0 ; extra == 'op
|
|
|
34
35
|
Requires-Dist: traceloop-sdk>=0.48.0 ; extra == 'openllmetry'
|
|
35
36
|
Requires-Dist: redis>=7.1.0 ; extra == 'redis'
|
|
36
37
|
Requires-Dist: slack-bolt==1.22.0 ; extra == 'slack'
|
|
38
|
+
Requires-Dist: httpx>=0.27.0 ; extra == 'telegram'
|
|
37
39
|
Requires-Dist: pytest>=8.4.1 ; extra == 'test'
|
|
38
40
|
Requires-Dist: pytest-asyncio>=1.2.0 ; extra == 'test'
|
|
39
41
|
Requires-Dist: pytest-cov>=6.2.1 ; extra == 'test'
|
|
@@ -48,6 +50,7 @@ Provides-Extra: api
|
|
|
48
50
|
Provides-Extra: aws
|
|
49
51
|
Provides-Extra: cli
|
|
50
52
|
Provides-Extra: crewai
|
|
53
|
+
Provides-Extra: instagram
|
|
51
54
|
Provides-Extra: langfuse
|
|
52
55
|
Provides-Extra: langgraph
|
|
53
56
|
Provides-Extra: mcp
|
|
@@ -56,6 +59,7 @@ Provides-Extra: openai
|
|
|
56
59
|
Provides-Extra: openllmetry
|
|
57
60
|
Provides-Extra: redis
|
|
58
61
|
Provides-Extra: slack
|
|
62
|
+
Provides-Extra: telegram
|
|
59
63
|
Provides-Extra: test
|
|
60
64
|
Provides-Extra: whatsapp
|
|
61
65
|
Description-Content-Type: text/markdown
|
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agentkernel"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.8"
|
|
8
8
|
description = "Agent Kernel - Unified AI Agents Runtime"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -71,6 +71,12 @@ whatsapp = [
|
|
|
71
71
|
messenger = [
|
|
72
72
|
"httpx>=0.27.0"
|
|
73
73
|
]
|
|
74
|
+
instagram = [
|
|
75
|
+
"httpx>=0.27.0"
|
|
76
|
+
]
|
|
77
|
+
telegram = [
|
|
78
|
+
"httpx>=0.27.0"
|
|
79
|
+
]
|
|
74
80
|
test = [
|
|
75
81
|
"pytest>=8.4.1",
|
|
76
82
|
"pytest-asyncio>=1.2.0",
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import logging
|
|
3
|
+
import traceback
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
from http import HTTPStatus
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
|
|
8
|
+
from fastapi import APIRouter, File, Form, HTTPException, UploadFile
|
|
9
|
+
from pydantic import BaseModel, ConfigDict
|
|
10
|
+
|
|
11
|
+
from agentkernel.core.model import (
|
|
12
|
+
AgentReplyImage,
|
|
13
|
+
AgentReplyText,
|
|
14
|
+
AgentRequestAny,
|
|
15
|
+
AgentRequestFile,
|
|
16
|
+
AgentRequestImage,
|
|
17
|
+
AgentRequestText,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from ..core import AgentService, GlobalRuntime
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class RESTRequestHandler(ABC):
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def get_router(self) -> APIRouter:
|
|
26
|
+
"""
|
|
27
|
+
Returns the APIRouter instance which has configured routes
|
|
28
|
+
E.g.:
|
|
29
|
+
- GET /health: Health check
|
|
30
|
+
- GET /agents: List available agents
|
|
31
|
+
|
|
32
|
+
router = APIRouter()
|
|
33
|
+
|
|
34
|
+
@router.get("/health")
|
|
35
|
+
def health():
|
|
36
|
+
return {"status": "ok"}
|
|
37
|
+
|
|
38
|
+
@router.get("/agents")
|
|
39
|
+
def list_agents():
|
|
40
|
+
return {"agents": list(GlobalRuntime.instance().agents().keys())}
|
|
41
|
+
|
|
42
|
+
"""
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class AgentRESTRequestHandler(RESTRequestHandler):
|
|
47
|
+
"""
|
|
48
|
+
API routers that expose endpoints to interact with Agent Kernel.
|
|
49
|
+
Endpoints:
|
|
50
|
+
- GET /health: Health check
|
|
51
|
+
- GET /agents: List available agents
|
|
52
|
+
- POST /run: Run an agent with a prompt
|
|
53
|
+
Payload JSON: { "prompt": str, "agent": str | null, "session_id": str | null }
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(self):
|
|
57
|
+
self._log = logging.getLogger("ak.api.agent")
|
|
58
|
+
|
|
59
|
+
class FileData(BaseModel):
|
|
60
|
+
"""Represents a file attachment"""
|
|
61
|
+
|
|
62
|
+
file_data: str # base64 encoded string or URL
|
|
63
|
+
name: str
|
|
64
|
+
mime_type: Optional[str] = None
|
|
65
|
+
|
|
66
|
+
class ImageData(BaseModel):
|
|
67
|
+
"""Represents an image attachment"""
|
|
68
|
+
|
|
69
|
+
image_data: str # base64 encoded string
|
|
70
|
+
name: str
|
|
71
|
+
mime_type: Optional[str] = None
|
|
72
|
+
|
|
73
|
+
class RunRequest(BaseModel):
|
|
74
|
+
model_config = ConfigDict(extra="allow")
|
|
75
|
+
|
|
76
|
+
prompt: str
|
|
77
|
+
agent: Optional[str] = None
|
|
78
|
+
session_id: Optional[str] = None
|
|
79
|
+
files: Optional[List["AgentRESTRequestHandler.FileData"]] = None
|
|
80
|
+
images: Optional[List["AgentRESTRequestHandler.ImageData"]] = None
|
|
81
|
+
|
|
82
|
+
def get_router(self) -> APIRouter:
|
|
83
|
+
"""
|
|
84
|
+
Returns the APIRouter instance.
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
router = APIRouter()
|
|
88
|
+
|
|
89
|
+
@router.get("/health")
|
|
90
|
+
def health():
|
|
91
|
+
return {"status": "ok"}
|
|
92
|
+
|
|
93
|
+
@router.get("/agents")
|
|
94
|
+
def list_agents():
|
|
95
|
+
return {"agents": list(GlobalRuntime.instance().agents().keys())}
|
|
96
|
+
|
|
97
|
+
@router.post("/run")
|
|
98
|
+
async def run(body: AgentRESTRequestHandler.RunRequest):
|
|
99
|
+
return await self.run(body)
|
|
100
|
+
|
|
101
|
+
@router.post("/run-multipart")
|
|
102
|
+
async def run_multipart(
|
|
103
|
+
prompt: str = Form(...),
|
|
104
|
+
agent: Optional[str] = Form(None),
|
|
105
|
+
session_id: Optional[str] = Form(None),
|
|
106
|
+
files: Optional[List[UploadFile]] = File(None),
|
|
107
|
+
images: Optional[List[UploadFile]] = File(None),
|
|
108
|
+
):
|
|
109
|
+
return await self.run_multipart(prompt, agent, session_id, files, images)
|
|
110
|
+
|
|
111
|
+
return router
|
|
112
|
+
|
|
113
|
+
async def run(self, req: RunRequest):
|
|
114
|
+
"""
|
|
115
|
+
Async method to run the agent.
|
|
116
|
+
:param req: Request object containing the prompt, optional agent name, attachments, images, and additional properties.
|
|
117
|
+
"""
|
|
118
|
+
requests = []
|
|
119
|
+
requests.append(AgentRequestText(text=req.prompt))
|
|
120
|
+
service = None
|
|
121
|
+
try:
|
|
122
|
+
# Process attachments (documents, PDFs, CSVs, etc.)
|
|
123
|
+
if req.files:
|
|
124
|
+
for file in req.files:
|
|
125
|
+
self._log.debug(f"Adding file attachment: {file.name}")
|
|
126
|
+
if not file.file_data.startswith(("http://", "https://", "data:", "s3://")) and not file.mime_type:
|
|
127
|
+
raise ValueError("mime_type is missing for file input, either in the base64 or explicitly")
|
|
128
|
+
requests.append(
|
|
129
|
+
AgentRequestFile(
|
|
130
|
+
file_data=file.file_data,
|
|
131
|
+
name=file.name,
|
|
132
|
+
mime_type=file.mime_type if file.mime_type else None,
|
|
133
|
+
)
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
# Process images (JPEG, PNG, etc.)
|
|
137
|
+
if req.images:
|
|
138
|
+
for image in req.images:
|
|
139
|
+
self._log.debug(f"Adding image: {image.name}")
|
|
140
|
+
if (
|
|
141
|
+
not image.image_data.startswith(("http://", "https://", "data:", "s3://"))
|
|
142
|
+
and not image.mime_type
|
|
143
|
+
):
|
|
144
|
+
raise ValueError("mime_type is missing for image input, either in the base64 or explicitly")
|
|
145
|
+
requests.append(
|
|
146
|
+
AgentRequestImage(
|
|
147
|
+
image_data=image.image_data,
|
|
148
|
+
name=image.name,
|
|
149
|
+
mime_type=image.mime_type if image.mime_type else None,
|
|
150
|
+
)
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Pack additional properties into AgentRequestAny
|
|
154
|
+
known_fields = {"prompt", "agent", "session_id", "files", "images"}
|
|
155
|
+
for key, value in req.model_dump().items():
|
|
156
|
+
if key not in known_fields:
|
|
157
|
+
self._log.debug(f"Adding additional context: {key}={value}")
|
|
158
|
+
requests.append(AgentRequestAny(name=key, content=value))
|
|
159
|
+
service = AgentService()
|
|
160
|
+
|
|
161
|
+
service.select(req.session_id, req.agent)
|
|
162
|
+
if not service.agent:
|
|
163
|
+
raise ValueError("No agent available")
|
|
164
|
+
|
|
165
|
+
result = await service.run_multi(requests=requests)
|
|
166
|
+
self._log.debug(f"Result: {result}")
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
"result": (
|
|
170
|
+
str(result)
|
|
171
|
+
if isinstance(result, (AgentReplyText, AgentReplyImage))
|
|
172
|
+
else "Non textual result received"
|
|
173
|
+
), # sending image is not supported at the moment
|
|
174
|
+
"session_id": service.get_response_session_id(req.session_id),
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
except HTTPException:
|
|
178
|
+
raise
|
|
179
|
+
except ValueError as e:
|
|
180
|
+
self._log.error(f"POST /run error: {e}\n{traceback.format_exc()}")
|
|
181
|
+
raise HTTPException(
|
|
182
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
183
|
+
detail={
|
|
184
|
+
"error": str(e),
|
|
185
|
+
"session_id": (
|
|
186
|
+
service.get_response_session_id(req.session_id) if service is not None else req.session_id
|
|
187
|
+
),
|
|
188
|
+
},
|
|
189
|
+
)
|
|
190
|
+
except Exception as e:
|
|
191
|
+
self._log.error(f"POST /run error: {e}\n{traceback.format_exc()}")
|
|
192
|
+
raise HTTPException(
|
|
193
|
+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
194
|
+
detail={
|
|
195
|
+
"error": str(e),
|
|
196
|
+
"session_id": service.get_response_session_id(None) if service is not None else req.session_id,
|
|
197
|
+
},
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
async def run_multipart(
|
|
201
|
+
self,
|
|
202
|
+
prompt: str,
|
|
203
|
+
agent: Optional[str] = None,
|
|
204
|
+
session_id: Optional[str] = None,
|
|
205
|
+
files: Optional[List[UploadFile]] = None,
|
|
206
|
+
images: Optional[List[UploadFile]] = None,
|
|
207
|
+
):
|
|
208
|
+
"""
|
|
209
|
+
Async method to run the agent with multipart file uploads.
|
|
210
|
+
:param prompt: The text prompt for the agent.
|
|
211
|
+
:param agent: Optional agent name.
|
|
212
|
+
:param session_id: Optional session ID.
|
|
213
|
+
:param files: Optional list of uploaded files (documents, PDFs, CSVs, etc.).
|
|
214
|
+
:param images: Optional list of uploaded images (JPEG, PNG, etc.).
|
|
215
|
+
"""
|
|
216
|
+
requests = []
|
|
217
|
+
requests.append(AgentRequestText(text=prompt))
|
|
218
|
+
service = None
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
# Process file uploads
|
|
222
|
+
if files:
|
|
223
|
+
for file in files:
|
|
224
|
+
self._log.debug(f"Processing uploaded file: {file.filename}")
|
|
225
|
+
# Read file content
|
|
226
|
+
content = await file.read()
|
|
227
|
+
# Encode to base64
|
|
228
|
+
file_data_base64 = base64.b64encode(content).decode("utf-8")
|
|
229
|
+
|
|
230
|
+
# Get mime type from the upload
|
|
231
|
+
mime_type = file.content_type
|
|
232
|
+
|
|
233
|
+
self._log.debug(f"Adding file attachment: {file.filename} (type: {mime_type})")
|
|
234
|
+
requests.append(
|
|
235
|
+
AgentRequestFile(
|
|
236
|
+
file_data=file_data_base64,
|
|
237
|
+
name=file.filename or "unknown",
|
|
238
|
+
mime_type=mime_type,
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
# Process image uploads
|
|
243
|
+
if images:
|
|
244
|
+
for image in images:
|
|
245
|
+
self._log.debug(f"Processing uploaded image: {image.filename}")
|
|
246
|
+
# Read image content
|
|
247
|
+
content = await image.read()
|
|
248
|
+
# Encode to base64
|
|
249
|
+
image_data_base64 = base64.b64encode(content).decode("utf-8")
|
|
250
|
+
|
|
251
|
+
# Get mime type from the upload
|
|
252
|
+
mime_type = image.content_type
|
|
253
|
+
|
|
254
|
+
# Validate it's an image mime type
|
|
255
|
+
if mime_type and not mime_type.startswith("image/"):
|
|
256
|
+
raise ValueError(f"Invalid image type: {mime_type} for file {image.filename}")
|
|
257
|
+
|
|
258
|
+
self._log.debug(f"Adding image: {image.filename} (type: {mime_type})")
|
|
259
|
+
requests.append(
|
|
260
|
+
AgentRequestImage(
|
|
261
|
+
image_data=image_data_base64,
|
|
262
|
+
name=image.filename or "unknown",
|
|
263
|
+
mime_type=mime_type,
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
service = AgentService()
|
|
268
|
+
service.select(session_id, agent)
|
|
269
|
+
|
|
270
|
+
if not service.agent:
|
|
271
|
+
raise ValueError("No agent available")
|
|
272
|
+
|
|
273
|
+
result = await service.run_multi(requests=requests)
|
|
274
|
+
self._log.debug(f"Result: {result}")
|
|
275
|
+
|
|
276
|
+
return {
|
|
277
|
+
"result": (
|
|
278
|
+
str(result)
|
|
279
|
+
if isinstance(result, (AgentReplyText, AgentReplyImage))
|
|
280
|
+
else "Non textual result received"
|
|
281
|
+
),
|
|
282
|
+
"session_id": service.get_response_session_id(session_id),
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
except HTTPException:
|
|
286
|
+
raise
|
|
287
|
+
except ValueError as e:
|
|
288
|
+
self._log.error(f"POST /run-multipart error: {e}\n{traceback.format_exc()}")
|
|
289
|
+
raise HTTPException(
|
|
290
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
291
|
+
detail={
|
|
292
|
+
"error": str(e),
|
|
293
|
+
"session_id": service.get_response_session_id(session_id) if service is not None else session_id,
|
|
294
|
+
},
|
|
295
|
+
)
|
|
296
|
+
except Exception as e:
|
|
297
|
+
self._log.error(f"POST /run-multipart error: {e}\n{traceback.format_exc()}")
|
|
298
|
+
raise HTTPException(
|
|
299
|
+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
300
|
+
detail={
|
|
301
|
+
"error": str(e),
|
|
302
|
+
"session_id": service.get_response_session_id(None) if service is not None else session_id,
|
|
303
|
+
},
|
|
304
|
+
)
|
|
@@ -35,6 +35,7 @@ class CLI:
|
|
|
35
35
|
self._print("!ld, !load <module_name> - Load agent module")
|
|
36
36
|
self._print("!ls, !list - List available agents")
|
|
37
37
|
self._print("!n, !new - Start a new session")
|
|
38
|
+
self._print("!c, !clear - Clear the current session memory")
|
|
38
39
|
self._print("!s, !select <agent_name> - Select an agent to run the prompt")
|
|
39
40
|
self._print("!q, !quit - Exit the program")
|
|
40
41
|
self._print()
|
|
@@ -67,14 +68,16 @@ class CLI:
|
|
|
67
68
|
command = tokens[0]
|
|
68
69
|
if command in ["!h", "!help"]:
|
|
69
70
|
self.help()
|
|
70
|
-
elif command in ["!
|
|
71
|
-
self.
|
|
71
|
+
elif command in ["!c", "!clear"]:
|
|
72
|
+
self._service.clear()
|
|
72
73
|
elif command in ["!ld", "!load"]:
|
|
73
74
|
if len(tokens) != 2:
|
|
74
75
|
self._print("Usage: !load <module_name>")
|
|
75
76
|
continue
|
|
76
77
|
session_id = self._service.session.id if self._service.session else None
|
|
77
78
|
self._service.load(name=tokens[1], session_id=session_id)
|
|
79
|
+
elif command in ["!ls", "!list"]:
|
|
80
|
+
self.list()
|
|
78
81
|
elif command in ["!n", "!new"]:
|
|
79
82
|
self._service.new()
|
|
80
83
|
elif command in ["!q", "!quit"]:
|
|
@@ -12,7 +12,7 @@ current_session = contextvars.ContextVar("session_id", default="")
|
|
|
12
12
|
|
|
13
13
|
class Session:
|
|
14
14
|
"""
|
|
15
|
-
Session is the base class for a
|
|
15
|
+
Session is the base class for a tracking state across related interactions with agents.
|
|
16
16
|
|
|
17
17
|
Agent Kernel provides an implementation of the Session class for each supported agent framework,
|
|
18
18
|
allowing the runtime to track and share state across multiple related agent logic invocations.
|
|
@@ -20,6 +20,15 @@ class Session:
|
|
|
20
20
|
Sessions may be volatile (meaning that they are not persisted) or durable (meaning that they
|
|
21
21
|
are persisted and are available across multiple invocations of the runtime). This is governed by
|
|
22
22
|
the runtime configuration.
|
|
23
|
+
|
|
24
|
+
Session class stores framework-specific session data objects in a key-value store, allowing
|
|
25
|
+
different agent frameworks to store and retrieve their own session data without interfering with
|
|
26
|
+
each other.
|
|
27
|
+
|
|
28
|
+
In addition, there are two pre-defined key-value caches for storing data that is either volatile
|
|
29
|
+
(i.e., not persisted across runtime invocations) or non-volatile (i.e., persisted across runtime
|
|
30
|
+
invocations). These caches can be used by application code to store data that is not part of the
|
|
31
|
+
agent context but needs to be retained across multiple interactions within the same session.
|
|
23
32
|
"""
|
|
24
33
|
|
|
25
34
|
VOLATILE_CACHE_KEY = "v_cache"
|
|
@@ -28,8 +37,8 @@ class Session:
|
|
|
28
37
|
@classmethod
|
|
29
38
|
def get_current_session_id(cls) -> str:
|
|
30
39
|
"""
|
|
31
|
-
Returns the current session
|
|
32
|
-
:return: The current session
|
|
40
|
+
Returns the current session identifier from the context variable.
|
|
41
|
+
:return: The current session identifier.
|
|
33
42
|
"""
|
|
34
43
|
return current_session.get()
|
|
35
44
|
|
|
@@ -56,7 +65,8 @@ class Session:
|
|
|
56
65
|
self._id = id
|
|
57
66
|
self._data = {}
|
|
58
67
|
|
|
59
|
-
# Pre-initialize key-value caches to be used by application code
|
|
68
|
+
# Pre-initialize key-value caches to be used by application code
|
|
69
|
+
# which will not be part of the agent context.
|
|
60
70
|
self.set(self.VOLATILE_CACHE_KEY, KeyValueCache())
|
|
61
71
|
self.set(self.NON_VOLATILE_CACHE_KEY, KeyValueCache())
|
|
62
72
|
|
|
@@ -72,13 +82,13 @@ class Session:
|
|
|
72
82
|
|
|
73
83
|
def get(self, key: str) -> Any:
|
|
74
84
|
"""
|
|
75
|
-
Retrieves
|
|
76
|
-
:param key: The key
|
|
77
|
-
:return: The
|
|
78
|
-
|
|
85
|
+
Retrieves the specified session data object.
|
|
86
|
+
:param key: The key of the session data object.
|
|
87
|
+
:return: The matching session object associated with the key, or None
|
|
88
|
+
if there is no data object with the specified key.
|
|
79
89
|
"""
|
|
80
90
|
result = self._data.get(key)
|
|
81
|
-
self._log.debug(f"Retrieved session object for key {key}: {result}")
|
|
91
|
+
self._log.debug(f"Retrieved session {self._id} data object for key {key}: {result}")
|
|
82
92
|
return result
|
|
83
93
|
|
|
84
94
|
def get_all_keys(self):
|
|
@@ -90,14 +100,35 @@ class Session:
|
|
|
90
100
|
|
|
91
101
|
def set(self, key: str, value: Any) -> Any:
|
|
92
102
|
"""
|
|
93
|
-
Sets a
|
|
94
|
-
:param key: The key
|
|
95
|
-
:param value: The
|
|
103
|
+
Sets a session data object for the specified key.
|
|
104
|
+
:param key: The key of the session data object.
|
|
105
|
+
:param value: The session data object.
|
|
96
106
|
"""
|
|
97
|
-
self._log.debug(f"Setting session object for key {key}: {value}")
|
|
107
|
+
self._log.debug(f"Setting session {self._id} data object for key {key}: {value}")
|
|
98
108
|
self._data[key] = value
|
|
99
109
|
return value
|
|
100
110
|
|
|
111
|
+
def delete(self, key: str) -> None:
|
|
112
|
+
"""
|
|
113
|
+
Deletes the session data object for the specified key.
|
|
114
|
+
:param key: The key of the session data object to be deleted.
|
|
115
|
+
"""
|
|
116
|
+
if key in self._data:
|
|
117
|
+
self._log.debug(f"Deleting session {self._id} data object for key {key}")
|
|
118
|
+
del self._data[key]
|
|
119
|
+
|
|
120
|
+
def clear(self) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Clears all session data objects.
|
|
123
|
+
"""
|
|
124
|
+
self._log.debug(f"Clearing session {self._id} data objects")
|
|
125
|
+
self._data = {
|
|
126
|
+
self.VOLATILE_CACHE_KEY: self.get_volatile_cache(),
|
|
127
|
+
self.NON_VOLATILE_CACHE_KEY: self.get_non_volatile_cache(),
|
|
128
|
+
}
|
|
129
|
+
self.get_volatile_cache().clear()
|
|
130
|
+
self.get_non_volatile_cache().clear()
|
|
131
|
+
|
|
101
132
|
def set_context(self):
|
|
102
133
|
"""
|
|
103
134
|
Sets the current session context variable to this session's ID.
|
|
@@ -92,6 +92,22 @@ class _MessengerConfig(BaseModel):
|
|
|
92
92
|
api_version: str = Field(default="v24.0", description="Facebook Graph API version")
|
|
93
93
|
|
|
94
94
|
|
|
95
|
+
class _InstagramConfig(BaseModel):
|
|
96
|
+
agent: str = Field(default="", description="Default agent to use for Instagram interactions")
|
|
97
|
+
verify_token: str = Field(default="", description="Instagram webhook verify token")
|
|
98
|
+
access_token: str = Field(default="", description="Instagram Business access token")
|
|
99
|
+
app_secret: str = Field(default="", description="Instagram app secret for signature verification")
|
|
100
|
+
instagram_account_id: str = Field(default="", description="Instagram Business Account ID (IGSID)")
|
|
101
|
+
api_version: str = Field(default="v21.0", description="Instagram Graph API version")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class _TelegramConfig(BaseModel):
|
|
105
|
+
agent: str = Field(default="", description="Default agent to use for Telegram")
|
|
106
|
+
bot_token: str = Field(default="", description="Telegram bot token from BotFather")
|
|
107
|
+
webhook_secret: str = Field(default="", description="Optional secret token for webhook security")
|
|
108
|
+
api_version: str = Field(default="bot", description="Telegram Bot API version prefix")
|
|
109
|
+
|
|
110
|
+
|
|
95
111
|
class _TraceConfig(BaseModel):
|
|
96
112
|
enabled: bool = Field(default=False, description="Enable tracing")
|
|
97
113
|
type: str = Field(default="langfuse", pattern="^(langfuse|openllmetry)$")
|
|
@@ -114,6 +130,12 @@ class AKConfig(YamlBaseSettingsModified):
|
|
|
114
130
|
messenger: _MessengerConfig = Field(
|
|
115
131
|
description="Facebook Messenger related configurations", default_factory=_MessengerConfig
|
|
116
132
|
)
|
|
133
|
+
instagram: _InstagramConfig = Field(
|
|
134
|
+
description="Instagram Business API related configurations", default_factory=_InstagramConfig
|
|
135
|
+
)
|
|
136
|
+
telegram: _TelegramConfig = Field(
|
|
137
|
+
description="Telegram Bot related configurations", default_factory=_TelegramConfig
|
|
138
|
+
)
|
|
117
139
|
trace: _TraceConfig = Field(description="Tracing related configurations", default_factory=_TraceConfig)
|
|
118
140
|
library_version: str = Field(default=_get_ak_version(), description="Library version")
|
|
119
141
|
|
|
@@ -94,6 +94,16 @@ class AgentService:
|
|
|
94
94
|
self._log.info(f"Starting new session: {session_id}")
|
|
95
95
|
self._session = self._runtime.sessions().new(session_id)
|
|
96
96
|
|
|
97
|
+
def clear(self):
|
|
98
|
+
"""
|
|
99
|
+
Clears the current session data.
|
|
100
|
+
"""
|
|
101
|
+
if self._session:
|
|
102
|
+
self._log.info(f"Clearing session: {self._session.id}")
|
|
103
|
+
self._session.clear()
|
|
104
|
+
else:
|
|
105
|
+
self._log.warning("No session available to clear.")
|
|
106
|
+
|
|
97
107
|
def load(self, session_id: str, name: str):
|
|
98
108
|
"""
|
|
99
109
|
Loads an agent module by name.
|