Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Add an executable bundled model directory with provider-specific dispatch, compatibility flags, request transforms, cost tiers, response observation, and nine native wire APIs.
- Add optional bounded browser/device authentication flows, explicit client registration, stored credential refresh, and cancellation-safe login settlement.
- Add lazy external tool-server search/describe/call by default with explicit direct exposure for small trusted catalogs.
- Add optional Agent Plugins 1.0.0 package loading with portable Skill and MCP discovery, client namespaces, path containment, placeholder expansion, and component-level failure isolation.
- Add native Anthropic, Bedrock, Google Gemini/Vertex, Mistral, OpenAI Responses/Azure, OpenAI-compatible, remote-proxy, and message-gateway providers with cross-provider transcript handoff.
- Add a provider-neutral image/audio/video registry, strict generic HTTP media jobs, dedicated image generation with progressive previews, and typed partial tool output.
- Add bounded request/response parsing, rotating credentials, safe response metadata observation, protocol-aware retries, and retry/fallback composition that stops before replaying meaningful streamed output.
Expand Down
14 changes: 14 additions & 0 deletions OpenGameAgent.sln
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenGameAgent.Providers.Mes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenGameAgent.Providers.MessageGateway.Tests", "tests\OpenGameAgent.Providers.MessageGateway.Tests\OpenGameAgent.Providers.MessageGateway.Tests.csproj", "{9CFA2749-BE81-45DE-A07B-CC005F87C5BD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenGameAgent.Plugins", "src\OpenGameAgent.Plugins\OpenGameAgent.Plugins.csproj", "{01A9B761-5567-4C17-B6ED-574B4089D413}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenGameAgent.Plugins.Tests", "tests\OpenGameAgent.Plugins.Tests\OpenGameAgent.Plugins.Tests.csproj", "{5697E98C-2249-4D4C-894B-CB0A8732238E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -276,6 +280,14 @@ Global
{9CFA2749-BE81-45DE-A07B-CC005F87C5BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9CFA2749-BE81-45DE-A07B-CC005F87C5BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9CFA2749-BE81-45DE-A07B-CC005F87C5BD}.Release|Any CPU.Build.0 = Release|Any CPU
{01A9B761-5567-4C17-B6ED-574B4089D413}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01A9B761-5567-4C17-B6ED-574B4089D413}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01A9B761-5567-4C17-B6ED-574B4089D413}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01A9B761-5567-4C17-B6ED-574B4089D413}.Release|Any CPU.Build.0 = Release|Any CPU
{5697E98C-2249-4D4C-894B-CB0A8732238E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5697E98C-2249-4D4C-894B-CB0A8732238E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5697E98C-2249-4D4C-894B-CB0A8732238E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5697E98C-2249-4D4C-894B-CB0A8732238E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{01759D73-7B80-47A2-9D7D-154CC64C6851} = {EA3AF59A-9A1C-4197-B2A3-F93894D131B8}
Expand Down Expand Up @@ -306,5 +318,7 @@ Global
{11929951-6AC8-445D-9539-F859E583EEC2} = {86AE6217-BFEE-4349-945A-70ECEC211437}
{31B59D2C-2431-47CB-B3A1-6A2BE4C20055} = {EA3AF59A-9A1C-4197-B2A3-F93894D131B8}
{9CFA2749-BE81-45DE-A07B-CC005F87C5BD} = {86AE6217-BFEE-4349-945A-70ECEC211437}
{01A9B761-5567-4C17-B6ED-574B4089D413} = {EA3AF59A-9A1C-4197-B2A3-F93894D131B8}
{5697E98C-2249-4D4C-894B-CB0A8732238E} = {86AE6217-BFEE-4349-945A-70ECEC211437}
EndGlobalSection
EndGlobal
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ OpenGameAgent keeps the reusable agent machinery independent from the game while
- a typed extension API for tools, skills, routes, workflows, hooks, events, and services;
- capability-aware model catalogs and developer-hosted short-lived credentials;
- lazy external-tool discovery and large-result artifact spill;
- Agent Plugins 1.0.0 packages containing portable skills and MCP servers;
- image, audio, and video generation through replaceable APIs.

The runtime does **not** decide combat legality, inventory rules, economy changes, NPC permissions, or other business rules. The game exposes narrow tools, validates every requested mutation, performs it on the correct thread or server, and returns the authoritative receipt.
Expand Down Expand Up @@ -77,13 +78,14 @@ Read [Architecture](docs/architecture.md) for the ownership and failure boundari
| Area | Capability |
| --- | --- |
| Agent kernel | Streaming typed messages, tool loop, typed partial tool results, steering, follow-up, hooks, cancellation, strict transcript validation, provider failures as results |
| Tool execution | Bounded JSON Schema subset, guaranteed result for every accepted call, safe parallel reads, conflict-key serialization, policy blocking/termination, timeouts, uncertain write outcomes |
| Tool execution | Provider-request schema preflight plus execution-time validation over a bounded JSON Schema subset, guaranteed result for every accepted call, safe parallel reads, conflict-key serialization, policy blocking/termination, timeouts, uncertain write outcomes |
| Game runtime | Arbitrary JSON input, game clocks/timelines, fast/full/workflow routing, optimistic sessions, duplicate-input protection, actor concurrency, active-run steering/abort |
| Extension API | Immutable builder; prompt/context/tool/skill/route/workflow/hook/provider/service registration; typed lifecycle events and channels; namespaced persistent state |
| Official extensions | Tool policy and search, structured player questions/recommended replies, goals, memory, artifacts, knowledge, delegation, tracing, and durable parallel workflow graphs |
| World primitives | Durable actions, resumable workflows, memories, skills, signals, game-time schedules, actor mailboxes |
| Models and auth | Bundled capability/context/reasoning/cost directory, dynamic refresh, API-key/environment/stored/OAuth/local auth, developer-hosted short-lived credential gateway |
| External tools | Lazy on-demand search/describe/call by default; explicit direct exposure for small trusted catalogs |
| Portable plugins | [Agent Plugins 1.0.0](docs/agent-plugins.md) `plugin.json`, immediate-child `SKILL.md` discovery, MCP stdio/Streamable HTTP, client namespaces, containment, and component-level failure isolation |
| Providers | Native Anthropic, Amazon Bedrock, Google Gemini/Vertex, Mistral, OpenAI Responses/Azure, OpenAI-compatible, remote gateway, and message-gateway transports; retry/fallback decorators |
| Generated media | Provider-neutral image/audio/video registry, generic async HTTP jobs, and a dedicated OpenRouter image adapter with progressive previews |
| Persistence | Crash-tolerant local snapshots plus optional append-only session history, cross-process coordination, action journals, workflow checkpoints, memories, mailboxes, artifacts, delegations, skills, and prompt templates |
Expand All @@ -94,7 +96,7 @@ Run inputs, model content, tool catalogs, loops, queues, progress, and concurren

### Model access without hand-wiring every provider

`OpenGameAgent.Models.BuiltIn` turns the bundled model directory into an executable runtime. It currently dispatches nine wire APIs across 27 provider definitions and hundreds of text/tool-capable models, applying provider-specific request formats, reasoning settings, compatibility flags, cost metadata, authentication, cancellation, and bounded response handling. The lower provider packages remain independently usable when a game wants an explicit model and endpoint instead of a directory.
`OpenGameAgent.Models.BuiltIn` turns the bundled model directory into an executable runtime. It currently dispatches nine wire APIs across 27 provider definitions and hundreds of text/tool-capable models, applying provider-specific request formats, reasoning settings, compatibility flags, cost metadata, authentication, cancellation, and bounded response handling. Provider usage is priced from the resolved directory when the provider does not report cost, while unavailable pricing remains explicitly unknown rather than appearing free. The lower provider packages remain independently usable when a game wants an explicit model and endpoint instead of a directory.

`OpenGameAgent.Models.Auth.BuiltIn` adds opt-in browser or device authorization flows for supported subscription providers. Public client registrations are never embedded in the framework: flows that require a client ID remain disabled until the game developer supplies one. `OpenGameAgent.ProviderTransport` exposes only allowlisted, bounded response metadata to observers and never passes credentials or arbitrary response headers to tracing code.

Expand Down
6 changes: 5 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ OpenGameAgent 不替游戏规定玩法,而是提供可复用的游戏坐标与
- 可扩展工具、Skills、路由、Workflow、Hooks、事件与服务的类型化接口;
- 能力感知模型目录与开发者托管的短期凭证;
- 外部工具按需发现与大型结果产物化;
- 包含可移植 Skills 与 MCP Server 的 Agent Plugins 1.0.0 插件包;
- 通过可替换 API 生成图片、语音和视频。

Runtime **不会**判断攻击是否合法、物品能否使用、资源够不够或 NPC 有没有权限。游戏只暴露窄而明确的工具,校验每次变更请求,在正确线程或服务端执行,并返回权威回执。
Expand Down Expand Up @@ -75,13 +76,14 @@ GameAgentRuntime
| 模块 | 能力 |
| --- | --- |
| Agent 内核 | 流式类型化消息、工具循环、类型化工具中间结果、steering、follow-up、hooks、取消、严格会话校验、提供方错误结果化 |
| 工具执行 | 有界 JSON Schema 子集校验、每个已接受调用都有结果、安全并行读、冲突键串行、策略拦截/终止、超时与写入结果未知语义 |
| 工具执行 | provider 请求前 schema 预检及执行期有界 JSON Schema 子集校验、每个已接受调用都有结果、安全并行读、冲突键串行、策略拦截/终止、超时与写入结果未知语义 |
| 游戏 Runtime | 任意 JSON 输入、游戏时钟/时间线、快速/完整/Workflow 路由、乐观并发会话、输入去重、角色并发、运行中 steering/abort |
| 扩展 API | 不可变构建器;提示词/上下文/工具/Skills/路由/Workflow/Hooks/提供方/服务注册;类型化生命周期事件与通道;命名空间持久状态 |
| 官方扩展 | 工具策略与搜索、玩家结构化提问/推荐回复、目标、记忆、产物、外部知识、委派、追踪和可持久并行工作流图 |
| 世界原语 | 可恢复动作、可续跑 Workflow、记忆、Skills、信号、游戏时间调度、角色邮箱 |
| 模型与认证 | 内置模型能力/上下文/推理级别/成本目录、动态刷新、API Key/环境/存储/OAuth/本地认证、开发者托管短期凭证网关 |
| 外部工具 | 默认按需搜索/描述/调用;小型可信目录可显式选择原生直连暴露 |
| 可移植插件 | [Agent Plugins 1.0.0](docs/agent-plugins.md) `plugin.json`、直接子目录 `SKILL.md` 发现、MCP stdio/Streamable HTTP、客户端命名空间、路径限制与组件级故障隔离 |
| 提供方 | Anthropic、Amazon Bedrock、Google Gemini/Vertex、Mistral、OpenAI Responses/Azure、OpenAI-compatible、远程网关和消息网关;重试与回退包装器 |
| 生成式媒体 | 图片/语音/视频中立注册表、通用异步 HTTP 任务,以及带渐进预览的专用图片适配器 |
| 持久化 | 崩溃安全本地快照、可选追加式会话历史、跨进程协调、动作日志、Workflow 检查点、记忆、邮箱、产物、委派、Skills 与提示词模板 |
Expand Down Expand Up @@ -153,6 +155,8 @@ var run = await runtime.RunAsync(input);
- **游戏服务端内:** 游戏本来就有权威服务端时最自然,让同一套 C# Runtime 靠近规则与存档。
- **独立 Agent 服务:** 适合官方承担推理费用、集中保管密钥、扩缩容或独立升级。引擎适配层通过 JSON/SSE 调用 `OpenGameAgent.Server`,并可经受认证的控制端点 steering 或 abort 活跃角色。

独立服务还提供受同一会话/Actor 所有者授权保护的持久 usage 查询,完整返回推理、缓存与分项费用。模型目录可为没有上报费用的 Provider 估算费用;没有价格数据时明确返回“未知”,不会伪装成零费用。

若客户端使用开发者付费的模型服务,应由开发者网关签发短期、有限作用域的凭证。永久上游 Key 留在开发者基础设施;框架提供客户端凭证流程,游戏负责登录、配额、吊销和滥用防护。

部署位置不会改变权威边界:只有游戏业务代码能够确认动作成功。
Expand Down
78 changes: 78 additions & 0 deletions docs/agent-plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Agent Plugins 1.0.0

`OpenGameAgent.Plugins` loads the portable portion of an Agent Plugins 1.0.0 package without changing the agent kernel. A loaded package is an ordinary `IGameAgentExtension`: skills register through the existing skill-provider API and MCP servers register through `McpToolConnectorExtension`.

## Supported package layout

```text
my-plugin/
├── plugin.json
├── skills/
│ └── build/
│ └── SKILL.md
├── mcp.json
└── org.example.client/
```

The loader supports:

- the closed `plugin.json` 1.0.0 manifest and its required canonical `$schema`;
- the specification's non-fatal handling for unknown manifest fields and a non-object `extensions` field;
- immediate-child `skills/*/SKILL.md` discovery using the Agent Skills-compatible loader;
- MCP `stdio` and `streamable-http` transports;
- client-owned HTTP headers that override package headers case-insensitively;
- `${PLUGIN_ROOT}` and `${PLUGIN_DATA}` in stdio arguments, environment values, and working directories;
- bounded diagnostics and component-level failure isolation;
- opaque manifest extension objects and safe top-level client extension directories.

Legacy HTTP+SSE is optional in Agent Plugins 1.0.0 and is not implemented. Its entries are diagnosed and skipped without disabling skills or other MCP servers.

## Load and compose

Install the optional adapter package alongside the core runtime:

```powershell
dotnet add package OpenGameAgent.Plugins --version 0.3.0-alpha.1
```

```csharp
using OpenGameAgent.Plugins;

var package = AgentPluginLoader.Load(
@"C:\plugins\world-tools",
new AgentPluginLoadOptions
{
PluginDataDirectory = @"C:\game-data\plugins\world-tools",
McpServerHeaders = new Dictionary<string, IReadOnlyDictionary<string, string>>
{
["remote-world-api"] = new Dictionary<string, string>
{
["Authorization"] = "Bearer " + shortLivedToken,
},
},
});

await using var runtime = new GameAgentBuilder(provider, model)
.UseExtension(package)
.Build();
```

The runtime owns the package after `UseExtension`. Disposing the runtime closes MCP clients and any default HTTP transport created by the loader.

`PluginDataDirectory` is required for stdio servers because Agent Plugins reserves `PLUGIN_DATA` as client-managed writable storage. When it is absent, only affected stdio entries are skipped; skills and remote MCP entries still load.

## Security and ownership

- Plugin content is untrusted. Loading a skill grants instructions, not tool permission.
- The loader rejects package reparse points and paths that escape the package root. This is stricter than accepting an internal symbolic link and keeps behavior deterministic across Godot, Unity, and server hosts.
- Plugin-relative commands must begin with `./`; bare commands use the platform executable search behavior and are launched as one executable token, never as a shell command.
- Non-loopback HTTP MCP endpoints require HTTPS. The default HTTP client rejects redirects and does not keep cookies.
- Package headers are visible configuration, not a secret store. Supply credentials through `McpServerHeaders` or a client-owned `HttpClient`; client values take precedence.
- If a client-owned `HttpClient` is supplied, the game owns its redirect, authentication, timeout, and disposal policy.
- OpenGameAgent does not dynamically load assemblies declared by a plugin. Game-specific executable extensions remain explicit, compiled `IGameAgentExtension` registrations.

## Portable and client-specific boundaries

Agent Plugins 1.0.0 standardizes skills and MCP server configuration. It does not standardize plugin installation, marketplaces, permissions, sandboxing, OAuth, signatures, dependencies, hooks, or game runtime APIs. Unknown manifest extension objects are retained as bounded JSON but receive no behavior automatically. Top-level client extension directories are exposed through `ClientExtensionDirectories` and `GetClientExtensionDirectory`; the game decides whether it implements a namespace.

The authoritative external specification and schemas are at [agent-plugins.org](https://agent-plugins.org/specification). The loader selects its locally implemented 1.0.0 rules and never downloads a schema while loading a package.
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,4 +151,4 @@ The framework cannot make arbitrary game code transactional. The game must make

Workflow checkpoints and game-state commits are also separate transactions unless the host supplies a shared transactional implementation. Every workflow node that can cause a side effect should use a stable operation ID and the durable action dispatcher. When several save forks remain accessible in one store, assign a new session/save namespace as well as a new timeline ID; transcript identity is `(session, actor)`.

The built-in schema validator intentionally implements a common bounded subset: type, enum/const, object properties and required fields, additional properties, arrays, strings, and numeric bounds. Unsupported assertion keywords fail closed rather than being silently ignored. For advanced validation, give the tool a permissive `{}` schema and supply its custom validation delegate; mutation handlers must still revalidate business rules.
The built-in schema validator intentionally implements a common bounded subset: type, enum/const, object properties and required fields, additional properties, arrays, strings, and numeric bounds. The final tool definitions produced by request hooks are preflighted before a provider stream is opened, and returned arguments are validated again before execution. Unsupported assertion keywords fail closed even when nested in an unselected schema branch. For advanced validation, give the tool a permissive `{}` schema and supply its custom validation delegate; mutation handlers must still revalidate business rules.
Loading
Loading