chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,714 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import functools
|
||||
import typing as t
|
||||
|
||||
import typing_extensions as te
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
from .tools import Tool, ToolExecutionResponse, tool_execute_params
|
||||
|
||||
|
||||
# TODO: Maybe use `te.Unpack` in tools.execute?
|
||||
class ToolExecuteParams(te.TypedDict):
|
||||
allow_tracing: te.NotRequired[t.Optional[bool]]
|
||||
arguments: t.Dict[str, t.Optional[t.Any]]
|
||||
connected_account_id: te.NotRequired[str]
|
||||
custom_auth_params: te.NotRequired["tool_execute_params.CustomAuthParams"]
|
||||
custom_connection_data: te.NotRequired["tool_execute_params.CustomConnectionData"]
|
||||
entity_id: te.NotRequired[str]
|
||||
text: te.NotRequired[str]
|
||||
user_id: te.NotRequired[str]
|
||||
version: te.NotRequired[str]
|
||||
dangerously_skip_version_check: te.NotRequired[t.Optional[bool]]
|
||||
|
||||
|
||||
ModifierInOut = t.Union["ToolExecuteParams", "ToolExecutionResponse", "Tool"]
|
||||
|
||||
|
||||
class BeforeExecute(t.Protocol):
|
||||
"""
|
||||
A modifier that is called before the tool is executed.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
tool: str,
|
||||
toolkit: str,
|
||||
params: ToolExecuteParams,
|
||||
) -> ToolExecuteParams: ...
|
||||
|
||||
|
||||
class AfterExecute(t.Protocol):
|
||||
"""
|
||||
A modifier that is called after the tool is executed.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
tool: str,
|
||||
toolkit: str,
|
||||
response: ToolExecutionResponse,
|
||||
) -> ToolExecutionResponse: ...
|
||||
|
||||
|
||||
class SchemaModifier(t.Protocol):
|
||||
"""
|
||||
A modifier that is called to modify the schema of the tool.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
tool: str,
|
||||
toolkit: str,
|
||||
schema: "Tool",
|
||||
) -> "Tool": ...
|
||||
|
||||
|
||||
class BeforeFileUploadCallable(t.Protocol):
|
||||
"""Legacy positional form of the ``before_file_upload`` hook.
|
||||
|
||||
``(path, tool, toolkit) -> str | bool``. Still supported for back-compat,
|
||||
but new code should use :class:`BeforeFileUploadContextCallable` so it can
|
||||
discriminate local paths from URLs via ``context["source"]``.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
path: str,
|
||||
tool: str,
|
||||
toolkit: str,
|
||||
) -> t.Union[str, bool]: ...
|
||||
|
||||
|
||||
class BeforeFileUploadContext(te.TypedDict):
|
||||
"""Context passed to the new-form ``before_file_upload`` hook.
|
||||
|
||||
- ``path``: the local filesystem path for ``source="path"``, or the URL
|
||||
string for ``source="url"``.
|
||||
- ``source``: discriminator — ``"path"`` for local paths, ``"url"`` for
|
||||
``http(s)://...`` inputs. Mirrors the TypeScript SDK's ``source`` field
|
||||
(TS additionally emits ``"file"`` for ``File`` objects; Python has no
|
||||
equivalent runtime type).
|
||||
- ``tool`` / ``toolkit``: slugs of the tool being executed.
|
||||
"""
|
||||
|
||||
path: str
|
||||
source: te.Literal["path", "url"]
|
||||
tool: str
|
||||
toolkit: str
|
||||
|
||||
|
||||
class BeforeFileUploadContextCallable(t.Protocol):
|
||||
"""Preferred form of the ``before_file_upload`` hook.
|
||||
|
||||
Takes a single :class:`BeforeFileUploadContext` argument and returns either
|
||||
a new path/URL string, or ``False`` to abort the upload.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
context: BeforeFileUploadContext,
|
||||
) -> t.Union[str, bool]: ...
|
||||
|
||||
|
||||
BeforeFileUploadLike = t.Union[
|
||||
BeforeFileUploadCallable,
|
||||
BeforeFileUploadContextCallable,
|
||||
]
|
||||
"""Either form of ``before_file_upload``. Adapted internally."""
|
||||
|
||||
|
||||
def _count_positional_params(fn: t.Callable) -> int:
|
||||
"""Return the number of positional (or positional-or-keyword) params, or
|
||||
-1 if the signature can't be introspected (e.g. builtins)."""
|
||||
import inspect
|
||||
|
||||
try:
|
||||
sig = inspect.signature(fn)
|
||||
except (TypeError, ValueError):
|
||||
return -1
|
||||
return sum(
|
||||
1
|
||||
for p in sig.parameters.values()
|
||||
if p.kind
|
||||
in (
|
||||
inspect.Parameter.POSITIONAL_ONLY,
|
||||
inspect.Parameter.POSITIONAL_OR_KEYWORD,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _adapt_before_file_upload(
|
||||
hook: BeforeFileUploadLike,
|
||||
) -> BeforeFileUploadContextCallable:
|
||||
"""Normalise a user-supplied hook to the context-object form.
|
||||
|
||||
A hook declared with exactly 3 positional parameters is treated as the
|
||||
legacy ``(path, tool, toolkit)`` form; anything else (typically a single
|
||||
positional ``context`` parameter) is treated as the new form.
|
||||
"""
|
||||
if _count_positional_params(hook) == 3:
|
||||
legacy = t.cast(BeforeFileUploadCallable, hook)
|
||||
|
||||
def wrap(context: BeforeFileUploadContext) -> t.Union[str, bool]:
|
||||
return legacy(context["path"], context["tool"], context["toolkit"])
|
||||
|
||||
return wrap
|
||||
return t.cast(BeforeFileUploadContextCallable, hook)
|
||||
|
||||
|
||||
ModifierSlug: t.TypeAlias = str
|
||||
AfterExecuteModifierL: t.TypeAlias = t.Literal["after_execute"]
|
||||
BeforeExecuteModifierL: t.TypeAlias = t.Literal["before_execute"]
|
||||
SchemaModifierL: t.TypeAlias = t.Literal["schema"]
|
||||
BeforeFileUploadModifierL: t.TypeAlias = t.Literal["before_file_upload"]
|
||||
|
||||
|
||||
class Modifier:
|
||||
def __init__(
|
||||
self,
|
||||
modifier: t.Optional[
|
||||
AfterExecute
|
||||
| BeforeExecute
|
||||
| SchemaModifier
|
||||
| BeforeExecuteMeta
|
||||
| AfterExecuteMeta
|
||||
| BeforeFileUploadCallable
|
||||
| BeforeFileUploadContextCallable
|
||||
],
|
||||
type_: (
|
||||
AfterExecuteModifierL
|
||||
| BeforeExecuteModifierL
|
||||
| SchemaModifierL
|
||||
| AfterExecuteMetaModifierL
|
||||
| BeforeExecuteMetaModifierL
|
||||
| BeforeFileUploadModifierL
|
||||
),
|
||||
tools: t.List[str],
|
||||
toolkits: t.List[str],
|
||||
) -> None:
|
||||
self.modifier = modifier
|
||||
self.tools = tools
|
||||
self.type = type_
|
||||
self.toolkits = toolkits
|
||||
|
||||
def apply(
|
||||
self,
|
||||
toolkit: str,
|
||||
tool: str,
|
||||
data: ModifierInOut,
|
||||
modifer_type: str,
|
||||
) -> ModifierInOut:
|
||||
if self.modifier is None:
|
||||
raise ValueError("Modifier is not provided")
|
||||
|
||||
# If no tools or toolkits are provided, apply the modifier to all tools
|
||||
if (
|
||||
self.type == modifer_type
|
||||
and len(self.tools) == 0
|
||||
and len(self.toolkits) == 0
|
||||
):
|
||||
return self.modifier(tool, toolkit, data) # type: ignore
|
||||
|
||||
# If the modifier is not the same type, or the slug is not in the tools or
|
||||
# toolkits, return the data as is
|
||||
if (
|
||||
self.type != modifer_type
|
||||
or tool not in self.tools
|
||||
and toolkit not in self.toolkits
|
||||
):
|
||||
return data
|
||||
|
||||
# Apply the modifier to the data
|
||||
return self.modifier(tool, toolkit, data) # type: ignore
|
||||
|
||||
|
||||
@t.overload
|
||||
def after_execute(
|
||||
modifier: t.Optional[AfterExecute],
|
||||
) -> Modifier: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def after_execute(
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> t.Callable[[AfterExecute], Modifier]: ...
|
||||
|
||||
|
||||
def after_execute(
|
||||
modifier: t.Optional[AfterExecute] = None,
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> Modifier | t.Callable[[AfterExecute], Modifier]:
|
||||
if modifier is not None:
|
||||
return Modifier(
|
||||
modifier=modifier,
|
||||
type_="after_execute",
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
)
|
||||
|
||||
if tools is not None or toolkits is not None:
|
||||
return t.cast(
|
||||
t.Callable[[AfterExecute], Modifier],
|
||||
functools.partial(
|
||||
after_execute,
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
),
|
||||
)
|
||||
|
||||
raise ValueError("Either tools or toolkits must be provided")
|
||||
|
||||
|
||||
@t.overload
|
||||
def before_execute(modifier: t.Optional[BeforeExecute]) -> Modifier: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def before_execute(
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> t.Callable[[BeforeExecute], Modifier]: ...
|
||||
|
||||
|
||||
def before_execute(
|
||||
modifier: t.Optional[BeforeExecute] = None,
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> Modifier | t.Callable[[BeforeExecute], Modifier]:
|
||||
if modifier is not None:
|
||||
return Modifier(
|
||||
modifier=modifier,
|
||||
type_="before_execute",
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
)
|
||||
|
||||
if tools is not None or toolkits is not None:
|
||||
return t.cast(
|
||||
t.Callable[[BeforeExecute], Modifier],
|
||||
functools.partial(
|
||||
before_execute,
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
),
|
||||
)
|
||||
|
||||
raise ValueError("Either tools or toolkits must be provided")
|
||||
|
||||
|
||||
@t.overload
|
||||
def before_file_upload(modifier: t.Optional[BeforeFileUploadLike]) -> Modifier: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def before_file_upload(
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> t.Callable[[BeforeFileUploadLike], Modifier]: ...
|
||||
|
||||
|
||||
def before_file_upload(
|
||||
modifier: t.Optional[BeforeFileUploadLike] = None,
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> Modifier | t.Callable[[BeforeFileUploadLike], Modifier]:
|
||||
"""
|
||||
Build a ``Modifier`` for the file-upload hook (same scoping pattern as
|
||||
:func:`before_execute`).
|
||||
|
||||
Your callable may take **either**:
|
||||
|
||||
- a single ``context`` argument (:class:`BeforeFileUploadContext`) — the
|
||||
preferred form, exposes ``context["source"]`` (``"path"`` or ``"url"``),
|
||||
or
|
||||
- three positional arguments ``(path, tool, toolkit)`` — legacy form, kept
|
||||
for back-compat.
|
||||
|
||||
Return a new path/URL string to substitute, or ``False`` to abort the
|
||||
upload (raises :class:`~composio.exceptions.FileUploadAbortedError`).
|
||||
|
||||
Pass the returned ``Modifier`` in ``modifiers=[...]`` on
|
||||
:meth:`composio.core.models.tools.Tools.execute` or ``tools.get``. Multiple
|
||||
such modifiers are composed in list order.
|
||||
"""
|
||||
if modifier is not None:
|
||||
return Modifier(
|
||||
modifier=modifier,
|
||||
type_="before_file_upload",
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
)
|
||||
|
||||
if tools is not None or toolkits is not None:
|
||||
return t.cast(
|
||||
t.Callable[[BeforeFileUploadLike], Modifier],
|
||||
functools.partial(
|
||||
before_file_upload,
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
),
|
||||
)
|
||||
|
||||
raise ValueError("Either tools or toolkits must be provided")
|
||||
|
||||
|
||||
@t.overload
|
||||
def schema_modifier(modifier: t.Optional[SchemaModifier]) -> Modifier: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def schema_modifier(
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> t.Callable[[SchemaModifier], Modifier]: ...
|
||||
|
||||
|
||||
def schema_modifier(
|
||||
modifier: t.Optional[SchemaModifier] = None,
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> Modifier | t.Callable[[SchemaModifier], Modifier]:
|
||||
if modifier is not None:
|
||||
return Modifier(
|
||||
modifier=modifier,
|
||||
type_="schema",
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
)
|
||||
|
||||
if tools is not None or toolkits is not None:
|
||||
return t.cast(
|
||||
t.Callable[[SchemaModifier], Modifier],
|
||||
functools.partial(
|
||||
schema_modifier,
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
),
|
||||
)
|
||||
|
||||
raise ValueError("Either tools or toolkits must be provided")
|
||||
|
||||
|
||||
@t.overload
|
||||
def before_execute_meta(modifier: t.Optional[BeforeExecuteMeta]) -> Modifier: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def before_execute_meta(
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> t.Callable[[BeforeExecuteMeta], Modifier]: ...
|
||||
|
||||
|
||||
def before_execute_meta(
|
||||
modifier: t.Optional[BeforeExecuteMeta] = None,
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> Modifier | t.Callable[[BeforeExecuteMeta], Modifier]:
|
||||
if modifier is not None:
|
||||
return Modifier(
|
||||
modifier=modifier,
|
||||
type_="before_execute_meta",
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
)
|
||||
|
||||
if tools is not None or toolkits is not None:
|
||||
return t.cast(
|
||||
t.Callable[[BeforeExecuteMeta], Modifier],
|
||||
functools.partial(
|
||||
before_execute_meta,
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
),
|
||||
)
|
||||
|
||||
raise ValueError("Either tools or toolkits must be provided")
|
||||
|
||||
|
||||
@t.overload
|
||||
def after_execute_meta(modifier: t.Optional[AfterExecuteMeta]) -> Modifier: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def after_execute_meta(
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> t.Callable[[AfterExecuteMeta], Modifier]: ...
|
||||
|
||||
|
||||
def after_execute_meta(
|
||||
modifier: t.Optional[AfterExecuteMeta] = None,
|
||||
*,
|
||||
tools: t.Optional[t.List[str]] = None,
|
||||
toolkits: t.Optional[t.List[str]] = None,
|
||||
) -> Modifier | t.Callable[[AfterExecuteMeta], Modifier]:
|
||||
if modifier is not None:
|
||||
return Modifier(
|
||||
modifier=modifier,
|
||||
type_="after_execute_meta",
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
)
|
||||
|
||||
if tools is not None or toolkits is not None:
|
||||
return t.cast(
|
||||
t.Callable[[AfterExecuteMeta], Modifier],
|
||||
functools.partial(
|
||||
after_execute_meta,
|
||||
tools=tools or [],
|
||||
toolkits=toolkits or [],
|
||||
),
|
||||
)
|
||||
|
||||
raise ValueError("Either tools or toolkits must be provided")
|
||||
|
||||
|
||||
Modifiers = t.List[Modifier]
|
||||
|
||||
|
||||
def merge_before_file_upload(
|
||||
modifiers: t.Optional[Modifiers],
|
||||
tool: str,
|
||||
toolkit: str,
|
||||
) -> t.Optional[BeforeFileUploadContextCallable]:
|
||||
"""Compose ``before_file_upload``-type :class:`Modifier`\\ s for this *tool* / *toolkit*.
|
||||
|
||||
Scoping matches :class:`Modifier` (empty ``tools`` and ``toolkits`` = all tools).
|
||||
|
||||
Each user-supplied hook is adapted to the context form by
|
||||
:func:`_adapt_before_file_upload`, so legacy 3-arg callables keep working
|
||||
while new-form callables receive the full :class:`BeforeFileUploadContext`
|
||||
(including ``source``).
|
||||
"""
|
||||
to_chain = [
|
||||
m
|
||||
for m in (modifiers or [])
|
||||
if m.type == "before_file_upload" and m.modifier is not None
|
||||
]
|
||||
if not to_chain:
|
||||
return None
|
||||
|
||||
def _applies(m: Modifier) -> bool:
|
||||
if len(m.tools) == 0 and len(m.toolkits) == 0:
|
||||
return True
|
||||
return tool in m.tools or toolkit in m.toolkits
|
||||
|
||||
adapted_chain = [
|
||||
(m, _adapt_before_file_upload(t.cast(BeforeFileUploadLike, m.modifier)))
|
||||
for m in to_chain
|
||||
]
|
||||
|
||||
def combined(context: BeforeFileUploadContext) -> t.Union[str, bool]:
|
||||
p: str = context["path"]
|
||||
for m, hook in adapted_chain:
|
||||
if not _applies(m):
|
||||
continue
|
||||
# Preserve source/tool/toolkit while forwarding the (possibly
|
||||
# rewritten) path to the next hook.
|
||||
next_ctx: BeforeFileUploadContext = {
|
||||
"path": p,
|
||||
"source": context["source"],
|
||||
"tool": context["tool"],
|
||||
"toolkit": context["toolkit"],
|
||||
}
|
||||
out = hook(next_ctx)
|
||||
if out is False:
|
||||
return False
|
||||
if isinstance(out, str):
|
||||
p = out
|
||||
return p
|
||||
|
||||
return combined
|
||||
|
||||
|
||||
@t.overload
|
||||
def apply_modifier_by_type(
|
||||
modifiers: Modifiers,
|
||||
toolkit: str,
|
||||
tool: str,
|
||||
*,
|
||||
type: BeforeExecuteModifierL,
|
||||
request: ToolExecuteParams,
|
||||
) -> ToolExecuteParams: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def apply_modifier_by_type(
|
||||
modifiers: Modifiers,
|
||||
toolkit: str,
|
||||
tool: str,
|
||||
*,
|
||||
type: AfterExecuteModifierL,
|
||||
response: "ToolExecutionResponse",
|
||||
) -> "ToolExecutionResponse": ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def apply_modifier_by_type(
|
||||
modifiers: Modifiers,
|
||||
toolkit: str,
|
||||
tool: str,
|
||||
*,
|
||||
type: t.Literal["schema"],
|
||||
schema: "Tool",
|
||||
) -> "Tool": ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def apply_modifier_by_type(
|
||||
modifiers: Modifiers,
|
||||
toolkit: str,
|
||||
tool: str,
|
||||
*,
|
||||
type: BeforeExecuteMetaModifierL,
|
||||
session_id: str,
|
||||
params: t.Dict[str, t.Any],
|
||||
) -> t.Dict[str, t.Any]: ...
|
||||
|
||||
|
||||
@t.overload
|
||||
def apply_modifier_by_type(
|
||||
modifiers: Modifiers,
|
||||
toolkit: str,
|
||||
tool: str,
|
||||
*,
|
||||
type: AfterExecuteMetaModifierL,
|
||||
session_id: str,
|
||||
response: "ToolExecutionResponse",
|
||||
) -> "ToolExecutionResponse": ...
|
||||
|
||||
|
||||
def apply_modifier_by_type(
|
||||
modifiers: Modifiers,
|
||||
toolkit: str,
|
||||
tool: str,
|
||||
*,
|
||||
type: t.Literal[
|
||||
"before_execute",
|
||||
"after_execute",
|
||||
"schema",
|
||||
"before_execute_meta",
|
||||
"after_execute_meta",
|
||||
],
|
||||
schema: t.Optional["Tool"] = None,
|
||||
request: t.Optional["ToolExecuteParams"] = None,
|
||||
response: t.Optional["ToolExecutionResponse"] = None,
|
||||
session_id: t.Optional[str] = None,
|
||||
params: t.Optional[t.Dict[str, t.Any]] = None,
|
||||
) -> t.Union[ModifierInOut, t.Dict[str, t.Any]]:
|
||||
"""Apply a modifier to a tool."""
|
||||
# For meta modifiers, we handle them differently
|
||||
if type in ("before_execute_meta", "after_execute_meta"):
|
||||
if session_id is None:
|
||||
raise ValueError("session_id is required for meta modifiers")
|
||||
|
||||
if type == "before_execute_meta":
|
||||
if params is None:
|
||||
raise ValueError("params is required for before_execute_meta")
|
||||
result_params: t.Dict[str, t.Any] = params
|
||||
for modifier in modifiers:
|
||||
if modifier.type == type:
|
||||
# Check if modifier should be applied
|
||||
should_apply = (
|
||||
(len(modifier.tools) == 0 and len(modifier.toolkits) == 0)
|
||||
or tool in modifier.tools
|
||||
or toolkit in modifier.toolkits
|
||||
)
|
||||
|
||||
if should_apply and modifier.modifier is not None:
|
||||
result_params = t.cast(BeforeExecuteMeta, modifier.modifier)(
|
||||
tool, toolkit, session_id, result_params
|
||||
)
|
||||
return result_params
|
||||
else: # after_execute_meta
|
||||
if response is None:
|
||||
raise ValueError("response is required for after_execute_meta")
|
||||
result_response: "ToolExecutionResponse" = response
|
||||
for modifier in modifiers:
|
||||
if modifier.type == type:
|
||||
# Check if modifier should be applied
|
||||
should_apply = (
|
||||
(len(modifier.tools) == 0 and len(modifier.toolkits) == 0)
|
||||
or tool in modifier.tools
|
||||
or toolkit in modifier.toolkits
|
||||
)
|
||||
|
||||
if should_apply and modifier.modifier is not None:
|
||||
result_response = t.cast(AfterExecuteMeta, modifier.modifier)(
|
||||
tool, toolkit, session_id, result_response
|
||||
)
|
||||
return result_response
|
||||
|
||||
# For regular modifiers
|
||||
result: ModifierInOut
|
||||
if schema is not None:
|
||||
result = schema
|
||||
elif request is not None:
|
||||
result = request
|
||||
elif response is not None:
|
||||
result = response
|
||||
else:
|
||||
raise ValueError("No data provided")
|
||||
|
||||
for modifier in modifiers:
|
||||
result = modifier.apply(
|
||||
toolkit=toolkit,
|
||||
tool=tool,
|
||||
data=result,
|
||||
modifer_type=type,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
class BeforeExecuteMeta(t.Protocol):
|
||||
"""
|
||||
A modifier that is called before the meta tool is executed in a session context.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
tool: str,
|
||||
toolkit: str,
|
||||
session_id: str,
|
||||
params: t.Dict[str, t.Any],
|
||||
) -> t.Dict[str, t.Any]: ...
|
||||
|
||||
|
||||
class AfterExecuteMeta(t.Protocol):
|
||||
"""
|
||||
A modifier that is called after the meta tool is executed in a session context.
|
||||
"""
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
tool: str,
|
||||
toolkit: str,
|
||||
session_id: str,
|
||||
response: ToolExecutionResponse,
|
||||
) -> ToolExecutionResponse: ...
|
||||
|
||||
|
||||
AfterExecuteMetaModifierL: t.TypeAlias = t.Literal["after_execute_meta"]
|
||||
BeforeExecuteMetaModifierL: t.TypeAlias = t.Literal["before_execute_meta"]
|
||||
|
||||
|
||||
class ToolOptions(te.TypedDict):
|
||||
modify_schema: te.NotRequired[
|
||||
t.Dict[ModifierSlug, AfterExecute | BeforeExecute | SchemaModifier]
|
||||
]
|
||||
Reference in New Issue
Block a user