Skip to content

Commit 83d4841

Browse files
committed
feat(io-mapper): io mapping from manifests
1 parent 20f9320 commit 83d4841

21 files changed

+956
-512
lines changed

agntcy_iomapper/__init__.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
# SPDX-FileCopyrightText: Copyright (c) 2025 Cisco and/or its affiliates.
22
# SPDX-License-Identifier: Apache-2.0
33
# ruff: noqa: F401
4-
from .agent_iomapper import (
4+
from .base import (
55
AgentIOMapper,
66
AgentIOMapperConfig,
77
AgentIOMapperInput,
88
AgentIOMapperOutput,
9-
)
10-
from .base import (
119
BaseIOMapper,
1210
BaseIOMapperConfig,
1311
BaseIOMapperInput,

agntcy_iomapper/base/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Cisco and/or its affiliates.
2+
# SPDX-License-Identifier: Apache-2.0
3+
from .agent_iomapper import *
4+
from .base import *

agntcy_iomapper/base.py renamed to agntcy_iomapper/base/base.py

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,62 @@
99

1010

1111
class ArgumentsDescription(BaseModel):
12+
"""
13+
ArgumentsDescription a pydantic model that defines
14+
the details necessary to perfom io mapping between two agents
15+
"""
16+
1217
json_schema: Schema | None = Field(
1318
default=None, description="Data format JSON schema"
1419
)
1520
description: str | None = Field(
1621
default=None, description="Data (semantic) natural language description"
1722
)
23+
agent_manifest: dict[str, Any] | None = Field(
24+
default=None,
25+
description="Agent Manifest definition as per https://supreme-adventure-wg7nnwm.pages.github.io/docs/openapi.html#model/agentmanifest",
26+
)
1827

1928
@model_validator(mode="after")
2029
def _validate_obj(self) -> Self:
21-
if self.json_schema is None and self.description is None:
30+
if (
31+
self.json_schema is None
32+
and self.description is None
33+
and self.agent_manifest
34+
):
2235
raise ValueError(
23-
'Either the "schema" field and/or the "description" field must be specified.'
36+
'Either the "schema" field and/or the "description" or agent_manifest field must be specified.'
2437
)
2538
return self
2639

2740

2841
class BaseIOMapperInput(BaseModel):
29-
input: ArgumentsDescription = Field(description="Input data descriptions")
30-
output: ArgumentsDescription = Field(description="Output data descriptions")
42+
input: ArgumentsDescription = Field(
43+
description="Input data descriptions",
44+
)
45+
output: ArgumentsDescription = Field(
46+
description="Output data descriptions",
47+
)
3148
data: Any = Field(description="Data to translate")
3249

50+
@model_validator(mode="after")
51+
def _validate_obj(self) -> Self:
52+
if self.input.agent_manifest is not None:
53+
# given an input agents manifest map its ouput definition
54+
# because the data to be mapped is the result of calling the input agent
55+
self.input.json_schema = Schema.model_validate(
56+
self.input.agent_manifest["specs"]["output"]
57+
)
58+
59+
if self.output.agent_manifest:
60+
# given an output agents manifest map its input definition
61+
# because the data to be mapped would be mapped to it's input
62+
self.output.json_schema = Schema.model_validate(
63+
self.output.agent_manifest["specs"]["input"]
64+
)
65+
66+
return self
67+
3368

3469
class BaseIOMapperOutput(BaseModel):
3570
data: Any = Field(default=None, description="Data after translation")
@@ -73,3 +108,13 @@ async def ainvoke(self, input: BaseIOMapperInput) -> BaseIOMapperOutput:
73108
Args:
74109
input: the data to be mapped
75110
"""
111+
112+
113+
class _ArgumentsDescription:
114+
@staticmethod
115+
def input_args_description(data):
116+
return ArgumentsDescription(is_source_agent=True, **data)
117+
118+
@staticmethod
119+
def output_args_description(data):
120+
return ArgumentsDescription(is_source_agent=False, **data)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Cisco and/or its affiliates.
2+
# SPDX-License-Identifier: Apache-2.0"
3+
4+
from .imperative import (
5+
ImperativeIOMapper,
6+
ImperativeIOMapperInput,
7+
ImperativeIOMapperOutput,
8+
)

agntcy_iomapper/imperative.py renamed to agntcy_iomapper/imperative/imperative.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
import jsonschema
2323
from jsonpath_ng.ext import parse
2424

25-
from .base import (
25+
from agntcy_iomapper.base import (
2626
BaseIOMapper,
2727
BaseIOMapperConfig,
2828
BaseIOMapperInput,

agntcy_iomapper/langgraph/__init__.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Cisco and/or its affiliates.
2+
# SPDX-License-Identifier: Apache-2.0"
3+
4+
from .langgraph import (
5+
LangGraphIOMapper,
6+
LangGraphIOMapperConfig,
7+
LangGraphIOMapperInput,
8+
LangGraphIOMapperOutput,
9+
)
10+
11+
from .create_langraph_iomapper import create_langraph_iomapper
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 Cisco and/or its affiliates.
2+
# SPDX-License-Identifier: Apache-2.0"
3+
from langchain_core.runnables import Runnable
4+
5+
from .langgraph import (
6+
LangGraphIOMapper,
7+
LangGraphIOMapperConfig,
8+
LangGraphIOMapperInput,
9+
LangGraphIOMapperOutput,
10+
)
11+
12+
13+
def create_langraph_iomapper(
14+
config: LangGraphIOMapperConfig,
15+
) -> Runnable[LangGraphIOMapperInput, LangGraphIOMapperOutput]:
16+
"""Creates a langgraph agent
17+
Args:
18+
config: The configuration of the llm that would be used during the mapping
19+
Returns:
20+
A runnable representing an agent. It returns as output the mapping result
21+
"""
22+
return LangGraphIOMapper(config).as_runnable()

agntcy_iomapper/langgraph.py renamed to agntcy_iomapper/langgraph/langgraph.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
from langchain.chat_models import init_chat_model
77
from langchain_core.language_models import BaseChatModel
8-
from langchain_core.runnables import Runnable, RunnableConfig
8+
from langchain_core.runnables import RunnableConfig
99
from langgraph.utils.runnable import RunnableCallable
1010
from pydantic import Field
1111

12-
from .agent_iomapper import (
12+
from agntcy_iomapper.base import (
1313
AgentIOMapper,
1414
AgentIOMapperConfig,
1515
AgentIOMapperInput,
@@ -86,9 +86,3 @@ def invoke(self, state: dict[str, Any], config: RunnableConfig) -> dict:
8686

8787
def as_runnable(self):
8888
return RunnableCallable(self.invoke, self.ainvoke, name="extract", trace=False)
89-
90-
91-
def create_iomapper(
92-
config: LangGraphIOMapperConfig,
93-
) -> Runnable[LangGraphIOMapperInput, LangGraphIOMapperOutput]:
94-
return LangGraphIOMapper(config).as_runnable()

agntcy_iomapper/pydantic_ai.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
from pydantic_ai.models.openai import OpenAIModel
1919
from typing_extensions import Self
2020

21-
from .agent_iomapper import (
21+
from agntcy_iomapper.base import (
2222
AgentIOMapper,
2323
AgentIOMapperConfig,
2424
AgentIOMapperInput,

0 commit comments

Comments
 (0)