mirror of
https://github.com/NCBM/plyngent.git
synced 2026-07-25 08:04:57 +08:00
docs: tool plugins guide and config cross-links
This commit is contained in:
@@ -143,10 +143,15 @@ access_key_or_token = "sk-..."
|
||||
# tool_directives = '''### Workspace ...'''
|
||||
confirm_destructive = true
|
||||
max_context_tokens = 200000
|
||||
# Optional third-party tools (entry points plyngent.tools); default load none.
|
||||
# tool_plugins = ["acme"]
|
||||
# See doc/plugins.md.
|
||||
```
|
||||
|
||||
Per-provider **`timeout`** is passed to the HTTP session for chat/completions, Responses, and `GET /models`. A single number sets one timeout; `{ connect, read }` splits TCP/TLS setup vs idle wait between response bytes (SSE can run longer than `read` while chunks keep arriving). Tool/process timeouts (`run_command`, PTY, policy confirm) are separate.
|
||||
|
||||
Third-party **tool plugins**: install a package that declares `project.entry-points."plyngent.tools"`, then allowlist it with `[agent].tool_plugins`. Details: [doc/plugins.md](doc/plugins.md).
|
||||
|
||||
Supported provider presets today: `openai` (default if `preset` is omitted; default models `gpt-5.4` / `gpt-5.4-mini` / `gpt-5.4-nano` when `models` is omitted), `openai-compatible`, `deepseek` (OpenAI convention; default models `deepseek-v4-flash` and `deepseek-v4-pro` if `models` is omitted). Anthropic presets are modeled in config but not wired in the runtime client yet.
|
||||
|
||||
If `[database]` is omitted (or SQLite `url` is unset/empty), chat uses a durable file under the user data dir (e.g. `~/.local/share/plyngent/chat.db` on Linux). Set `url = ":memory:"` for a true in-memory SQLite (CLI warns; no file; useful for tests).
|
||||
|
||||
+5
-2
@@ -20,9 +20,12 @@
|
||||
- memory: Storage controlling for sessions and messages.
|
||||
- router: Multi-source capability routing (Phase H; not implemented).
|
||||
- config: Plyngent configuration center (TOML).
|
||||
- agent: Tool loop, streaming, usage, compact.
|
||||
- tools: Workspace file/process/VCS/chat tools.
|
||||
- agent: Tool loop, streaming, usage, compact; `@tool` / tags / registry.
|
||||
- tools: Workspace file/process/VCS/chat/todo tools; catalog; plugins;
|
||||
instance/session context and views.
|
||||
- prompting: Shared ask/choose/form for CLI and tools.
|
||||
- cli: Click entry, slash registry, REPL, one-shot chat.
|
||||
- web: Web service (Phase H; not implemented).
|
||||
|
||||
Tool plugins (third-party entry points): [plugins.md](./plugins.md).
|
||||
|
||||
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
# Tool plugins
|
||||
|
||||
Third-party tools install as Python packages and register through the
|
||||
**`plyngent.tools`** entry-point group. The host **allowlists** which plugins
|
||||
load; default is **load none**.
|
||||
|
||||
Importing a plugin only **registers** tools into the process catalog. The CLI
|
||||
still **selects** which names become model-visible (`surface=local` today).
|
||||
|
||||
## Layers (short)
|
||||
|
||||
```text
|
||||
DEFINE+REGISTER @tool → ToolDefinition + catalog entry (source=plugin:…)
|
||||
SELECT catalog.select(surface=…, …) → list[ToolDefinition]
|
||||
EXECUTE ToolRegistry (confirm, instance/session bind, invoke)
|
||||
```
|
||||
|
||||
| Layer | Question |
|
||||
|--------|----------|
|
||||
| Register | What tools exist in this process? |
|
||||
| Select | Which may the model see this session? |
|
||||
| Execute | How are they confirmed and run? |
|
||||
|
||||
Builtins use the same path with `source=builtin`. Plugins must not reuse a
|
||||
builtin (or another plugin) **tool name** — registration fails with a
|
||||
collision error.
|
||||
|
||||
## Author a plugin package
|
||||
|
||||
### 1. Define tools with `@tool`
|
||||
|
||||
```python
|
||||
# acme_plyngent/tools.py
|
||||
from plyngent.agent import ToolTag, tool
|
||||
|
||||
|
||||
@tool(name="acme_ping", tags=ToolTag.LOCAL)
|
||||
async def acme_ping() -> str:
|
||||
"""Return a fixed pong (example plugin tool)."""
|
||||
return "pong"
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- Prefer **`async def`** handlers (builtins are async-first).
|
||||
- Default **`tags=ToolTag.LOCAL`**. Set at least one of `LOCAL` or `PUBLIC`.
|
||||
- Workspace/exec tools should stay **`LOCAL`** unless reviewed for a shared host.
|
||||
- Session-only helpers may add **`PUBLIC`** and **`SESSION_STATE`** when they
|
||||
only touch session data and host-approved APIs (see plans under `doc/plans/`).
|
||||
- Optional soft-confirm bits: **`YOLO`** (eligible for YOLO auto-approve),
|
||||
**`TRUSTABLE`** (grant once per session after approve). Hard denylists are
|
||||
never YOLO-skipped.
|
||||
- Docstring becomes the model-facing description; parameter schemas come from
|
||||
type hints.
|
||||
- Use `register=False` only for unit tests that build a private registry.
|
||||
|
||||
### 2. Entry point
|
||||
|
||||
Call a zero-arg loader (or import a module) so `@tool` runs under the plugin
|
||||
registration source:
|
||||
|
||||
```python
|
||||
# acme_plyngent/__init__.py
|
||||
def load() -> None:
|
||||
"""Import tool modules so @tool registers into the process catalog."""
|
||||
from acme_plyngent import tools as _tools
|
||||
|
||||
_ = _tools # registration side effects
|
||||
```
|
||||
|
||||
Declare the entry point (PEP 621 / setuptools / hatch style):
|
||||
|
||||
```toml
|
||||
# pyproject.toml of the plugin package
|
||||
[project]
|
||||
name = "acme-plyngent"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"plyngent", # or pin a compatible range
|
||||
]
|
||||
|
||||
[project.entry-points."plyngent.tools"]
|
||||
acme = "acme_plyngent:load"
|
||||
```
|
||||
|
||||
- Entry-point **name** (`acme`) is the **plugin id** used in config allowlists
|
||||
and in catalog metadata (`plugin:acme`).
|
||||
- Value is `module:attr`. If `attr` is callable, plyngent calls it after load;
|
||||
if it is a module, import alone is enough when tools registered at import time.
|
||||
|
||||
Install the plugin into the **same environment** as `plyngent` (editable fine):
|
||||
|
||||
```bash
|
||||
pdm add acme-plyngent
|
||||
# or: pip install -e ./path/to/acme-plyngent
|
||||
```
|
||||
|
||||
## Enable plugins in config
|
||||
|
||||
In the user config (`plyngent config path`), under **`[agent]`**:
|
||||
|
||||
```toml
|
||||
[agent]
|
||||
# Allowlist of entry-point names. Default empty = load no plugins.
|
||||
tool_plugins = ["acme"]
|
||||
# tool_plugins = ["*"] # every discovered plyngent.tools entry point
|
||||
# Never load these names even if listed or matched by *:
|
||||
# tool_plugins_disable = ["legacy"]
|
||||
```
|
||||
|
||||
| Setting | Meaning |
|
||||
|---------|---------|
|
||||
| `tool_plugins = []` / omitted | Load **no** plugins (safe default). |
|
||||
| `tool_plugins = ["acme", "other"]` | Load only those entry-point names. |
|
||||
| `tool_plugins = ["*"]` | Load all discovered plugins. |
|
||||
| `tool_plugins_disable = ["x"]` | Skip `x` even when allowlisted or `*`. |
|
||||
|
||||
Restart the chat REPL after changing config so the tool registry rebuilds.
|
||||
|
||||
CLI load order (simplified):
|
||||
|
||||
1. `register_builtin_tools()`
|
||||
2. `load_plugin_tools(tool_plugins, disable=tool_plugins_disable)`
|
||||
3. `catalog.select(surface="local")` → `ToolRegistry`
|
||||
|
||||
Inspect the model surface in the REPL:
|
||||
|
||||
```text
|
||||
/tools --list
|
||||
```
|
||||
|
||||
Listed tools show **tags** and **catalog source** (`builtin` vs `plugin:…`).
|
||||
|
||||
## Policy checklist for authors
|
||||
|
||||
1. Prefer **LOCAL** for host FS, shell, PTY, or arbitrary network side effects.
|
||||
2. Do not shadow builtin names (`read_file`, `run_command`, todo tools, …).
|
||||
3. Do not rely on process-global workspace/todo alone when a host binds
|
||||
instance/session context — prefer the same patterns as builtins
|
||||
(`get_workspace_root` already prefers instance policy; session state via
|
||||
context when you need it).
|
||||
4. Soft danger: annotate with `YOLO` / `TRUSTABLE` only when the product
|
||||
confirm story matches; hard denylists stay in workspace/command policy.
|
||||
5. Keep tools **async**; raise ordinary exceptions or return `error: …` strings
|
||||
consistently with builtins.
|
||||
|
||||
## Surfaces (local vs public)
|
||||
|
||||
| Catalog select | Included tools |
|
||||
|----------------|----------------|
|
||||
| `surface="local"` (CLI) | `LOCAL` and/or `PUBLIC` |
|
||||
| `surface="public"` | `PUBLIC` only |
|
||||
|
||||
There is **no** multi-tenant public host in-tree yet; `surface=public` is
|
||||
available for hosts that want a PUBLIC-only select (builtins: mainly the
|
||||
todo series). Plugins should not set `PUBLIC` on workspace/exec tools by
|
||||
default.
|
||||
|
||||
## API reference (code)
|
||||
|
||||
| Piece | Module |
|
||||
|-------|--------|
|
||||
| `@tool`, `ToolTag`, `ToolRegistry` | `plyngent.agent` / `plyngent.agent.tools` |
|
||||
| Catalog, `ToolSource`, `select` | `plyngent.tools.catalog` |
|
||||
| `load_plugin_tools` | `plyngent.tools.plugins` |
|
||||
| Config fields | `AgentConfig.tool_plugins`, `tool_plugins_disable` |
|
||||
|
||||
## Related docs
|
||||
|
||||
- [architecture.md](./architecture.md) — package layout
|
||||
- [plyngent.example.toml](./plyngent.example.toml) — config sample
|
||||
- Design notes (may lag code): [plans/](./plans/) — registration, tags, PUBLIC surface
|
||||
@@ -38,6 +38,12 @@ max_context_tokens = 200000
|
||||
# compact_user_prefix = "Summarize the following conversation:\n\n{transcript}"
|
||||
# compact_seed_text = "Compacted from {src}:\n\n{summary}\n\nCarry on."
|
||||
|
||||
# Third-party tools (entry-point group plyngent.tools). Default: load none.
|
||||
# See doc/plugins.md.
|
||||
# tool_plugins = ["acme"]
|
||||
# tool_plugins = ["*"]
|
||||
# tool_plugins_disable = ["legacy"]
|
||||
|
||||
# --- OpenAI-compatible (vLLM, LiteLLM, OpenAI, …) ---
|
||||
[providers.openai_compat]
|
||||
preset = "openai-compatible"
|
||||
|
||||
Reference in New Issue
Block a user