mirror of
https://github.com/langchain-ai/deepagents.git
synced 2026-07-21 17:25:26 -04:00
0187d14b83
`deepagents-code` now supports experimental plugin marketplaces with namespaced skills and MCP servers. Enable with `DEEPAGENTS_CODE_EXPERIMENTAL=1`. Docs: https://github.com/langchain-ai/docs/pull/4905 --- `deepagents-code` can now manage experimental plugin marketplaces and load installed plugins that contribute namespaced skills and MCP servers. The new plugin manager establishes the `tui/modals`, `tui/screens`, and `tui/widgets` UI convention, with colocated styling and focused state/content modules. - Supports local, GitHub, Git, and marketplace JSON sources. - Adds install, enable, disable, uninstall, and safe marketplace removal through `/plugins` and `dcode plugin`. - Reloads plugin skills and plugin MCP configuration with `/reload` when experimental mode is enabled. - Namespaces plugin skills as `{plugin_id}:{skill_name}` through a code-local `PluginSkillsMiddleware` adapter, so no SDK changes are required. Made by [Open SWE](https://openswe.vercel.app/agents/019f5dea-0f1f-73fe-9803-32d1b13fbd4c) --------- Signed-off-by: Johannes du Plessis <johannes@langchain.dev> Co-authored-by: Alexander Olsen <aolsenjazz@gmail.com> Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Mason Daugherty <mason@langchain.dev> Co-authored-by: open-swe[bot] <215916821+open-swe[bot]@users.noreply.github.com> Co-authored-by: Mason Daugherty <github@mdrxy.com>
108 lines
2.9 KiB
Python
108 lines
2.9 KiB
Python
"""Variable substitution for plugin-provided configuration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
from deepagents_code.plugins.models import JsonValue
|
|
|
|
|
|
def plugin_environment(
|
|
*, plugin_root: Path, plugin_data: Path, project_dir: Path | None = None
|
|
) -> dict[str, str]:
|
|
"""Build environment variables exposed to plugin subprocesses.
|
|
|
|
Args:
|
|
plugin_root: Plugin root directory.
|
|
plugin_data: Plugin data directory.
|
|
project_dir: Optional project directory.
|
|
|
|
Returns:
|
|
Environment variables for plugin subprocesses.
|
|
"""
|
|
root = str(plugin_root)
|
|
data = str(plugin_data)
|
|
env = {
|
|
"CLAUDE_PLUGIN_ROOT": root,
|
|
"CLAUDE_PLUGIN_DATA": data,
|
|
"PLUGIN_ROOT": root,
|
|
"PLUGIN_DATA": data,
|
|
}
|
|
if project_dir is not None:
|
|
env["CLAUDE_PROJECT_DIR"] = str(project_dir)
|
|
return env
|
|
|
|
|
|
def substitute_string(
|
|
value: str, *, plugin_root: Path, plugin_data: Path, project_dir: Path | None = None
|
|
) -> str:
|
|
"""Substitute plugin path variables in a string.
|
|
|
|
Args:
|
|
value: String to transform.
|
|
plugin_root: Plugin root directory.
|
|
plugin_data: Plugin data directory.
|
|
project_dir: Optional project directory.
|
|
|
|
Returns:
|
|
String with supported plugin variables substituted.
|
|
"""
|
|
env = plugin_environment(
|
|
plugin_root=plugin_root, plugin_data=plugin_data, project_dir=project_dir
|
|
)
|
|
result = value
|
|
for key, replacement in env.items():
|
|
result = result.replace(f"${{{key}}}", replacement)
|
|
return result
|
|
|
|
|
|
def substitute_json(
|
|
value: JsonValue,
|
|
*,
|
|
plugin_root: Path,
|
|
plugin_data: Path,
|
|
project_dir: Path | None = None,
|
|
) -> JsonValue:
|
|
"""Substitute plugin variables throughout a JSON-compatible value.
|
|
|
|
Args:
|
|
value: JSON-compatible value to transform.
|
|
plugin_root: Plugin root directory.
|
|
plugin_data: Plugin data directory.
|
|
project_dir: Optional project directory.
|
|
|
|
Returns:
|
|
Value with strings recursively substituted.
|
|
"""
|
|
if isinstance(value, str):
|
|
return substitute_string(
|
|
value,
|
|
plugin_root=plugin_root,
|
|
plugin_data=plugin_data,
|
|
project_dir=project_dir,
|
|
)
|
|
if isinstance(value, list):
|
|
return [
|
|
substitute_json(
|
|
item,
|
|
plugin_root=plugin_root,
|
|
plugin_data=plugin_data,
|
|
project_dir=project_dir,
|
|
)
|
|
for item in value
|
|
]
|
|
if isinstance(value, dict):
|
|
return {
|
|
key: substitute_json(
|
|
item,
|
|
plugin_root=plugin_root,
|
|
plugin_data=plugin_data,
|
|
project_dir=project_dir,
|
|
)
|
|
for key, item in value.items()
|
|
}
|
|
return value
|