Skip to content

Commit 00294c4

Browse files
Merge upstream/main (auto-sync feat/copilot)
- 8e39db2 feat(plugin, api): introduce host model callback support with Go example and API handlers - 538e341 feat(plugin, api): prevent plugin recursion on host model callbacks, enable targeted interceptor skipping - ed52c61 test(websocket, api): add unit tests for response ID injection and handling of pending tool calls
2 parents 996f7bb + ed52c61 commit 00294c4

44 files changed

Lines changed: 3746 additions & 155 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

examples/plugin/README.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ This directory contains standard dynamic library plugin examples for the CLIProx
1313
- `protocol-format/`: minimal executor focused on input/output format declarations.
1414
- `request-translator/`: request translation capability only.
1515
- `request-normalizer/`: request normalization capability only.
16-
- `codex-service-tier/`: Go-only request normalizer that sets Codex `gpt-5.4` requests to the priority service tier when enabled.
16+
- `codex-service-tier/`: Go-only request normalizer that sets Codex `gpt-5.5` requests to the priority service tier when enabled.
1717
- `scheduler/`: Go-only scheduler that can select a configured auth ID, delegate to a built-in scheduler, or deny picks.
1818
- `response-translator/`: response translation capability only.
1919
- `response-normalizer/`: response normalization capability only.
@@ -22,12 +22,13 @@ This directory contains standard dynamic library plugin examples for the CLIProx
2222
- `cli/`: command-line capability only.
2323
- `management-api/`: Management API and resource capability only.
2424
- `host-callback/`: minimal plugin resource that demonstrates host callbacks.
25+
- `host-model-callback/`: Go-only plugin resource that calls the host model execution callbacks.
2526

2627
Most standard capability examples contain `go/`, `c/`, and `rust/` subdirectories. Specialized examples may provide only the implementation language they need.
2728

2829
## Codex Service Tier
2930

30-
`codex-service-tier` declares the request normalization capability. When `fast` is `true`, it sets `service_tier` to `priority` for requests where `req.ToFormat` is `codex` and `req.Model` is `gpt-5.4`.
31+
`codex-service-tier` declares the request normalization capability. When `fast` is `true`, it sets `service_tier` to `priority` for requests where `req.ToFormat` is `codex` and `req.Model` is `gpt-5.5`.
3132

3233
```yaml
3334
plugins:
@@ -38,6 +39,22 @@ plugins:
3839
fast: false
3940
```
4041
42+
## Host Model Callback
43+
44+
`host-model-callback` declares the Management API capability and exposes a browser resource named `Host Model Callback`. The resource calls `host.model.execute` for non-streaming requests and `host.model.execute_stream` plus `host.model.stream_read` for streaming requests. It demonstrates explicit stream close with `host.model.stream_close` and an `implicit_close=true` option for RPC-scope host cleanup.
45+
46+
When the resource forwards its `host_callback_id`, CPA identifies the plugin that initiated the host model callback and skips that same plugin's interceptors for the nested execution. This makes host model callbacks non-recursive for the caller while allowing other plugins to intercept the nested request.
47+
48+
```yaml
49+
plugins:
50+
configs:
51+
host-model-callback:
52+
enabled: true
53+
priority: 1
54+
```
55+
56+
The default example model is `gpt-5.5`, but the request succeeds only when the current CPA model and auth configuration can route that model.
57+
4158
## Scheduler
4259

4360
`scheduler` declares the scheduler capability. It can select a configured auth ID from the candidate list, delegate to the built-in `fill-first` or `round-robin` scheduler, or reject picks when `deny` is `true`.

examples/plugin/README_CN.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
- `protocol-format/`:使用最小执行器重点演示输入和输出格式声明。
1414
- `request-translator/`:只演示请求转换能力。
1515
- `request-normalizer/`:只演示请求规整能力。
16-
- `codex-service-tier/`:仅 Go 实现的请求规整插件,启用后会将 Codex `gpt-5.4` 请求设置为 priority service tier。
16+
- `codex-service-tier/`:仅 Go 实现的请求规整插件,启用后会将 Codex `gpt-5.5` 请求设置为 priority service tier。
1717
- `scheduler/`:仅 Go 实现的调度插件,可选择指定 auth ID、委托内置调度器或拒绝调度。
1818
- `response-translator/`:只演示响应转换能力。
1919
- `response-normalizer/`:只演示响应规整能力。
@@ -22,12 +22,13 @@
2222
- `cli/`:只演示命令行扩展能力。
2323
- `management-api/`:只演示 Management API 和资源扩展能力。
2424
- `host-callback/`:使用最小插件资源演示宿主回调。
25+
- `host-model-callback/`:仅 Go 实现的插件资源,演示调用宿主模型执行回调。
2526

2627
多数标准能力示例都包含 `go/``c/``rust/` 三个子目录。专用示例可能只提供所需的实现语言。
2728

2829
## Codex Service Tier
2930

30-
`codex-service-tier` 声明请求规整能力。当 `fast``true` 时,如果 `req.ToFormat``codex``req.Model``gpt-5.4`,它会将 `service_tier` 设置为 `priority`
31+
`codex-service-tier` 声明请求规整能力。当 `fast``true` 时,如果 `req.ToFormat``codex``req.Model``gpt-5.5`,它会将 `service_tier` 设置为 `priority`
3132

3233
```yaml
3334
plugins:
@@ -38,6 +39,22 @@ plugins:
3839
fast: false
3940
```
4041
42+
## Host Model Callback
43+
44+
`host-model-callback` 声明 Management API 能力,并暴露名为 `Host Model Callback` 的浏览器资源。该资源在非流式请求中调用 `host.model.execute`,在流式请求中调用 `host.model.execute_stream` 和 `host.model.stream_read`。它演示了通过 `host.model.stream_close` 显式关闭流,也提供 `implicit_close=true` 用于演示 RPC 作用域结束时的宿主隐式清理。
45+
46+
当该资源转发自身收到的 `host_callback_id` 时,CPA 会识别发起宿主模型回调的插件,并在嵌套模型执行中跳过同一个插件的拦截器。因此宿主模型回调不会递归调用发起插件自身,但其他已启用插件仍可拦截这次嵌套请求。
47+
48+
```yaml
49+
plugins:
50+
configs:
51+
host-model-callback:
52+
enabled: true
53+
priority: 1
54+
```
55+
56+
默认示例模型是 `gpt-5.5`,但请求能否成功取决于当前 CPA 模型和认证配置是否可以路由该模型。
57+
4158
## Scheduler
4259

4360
`scheduler` 声明调度能力。它可以从候选列表中选择配置的 auth ID,委托内置的 `fill-first` 或 `round-robin` 调度器,或在 `deny` 为 `true` 时拒绝调度。
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Host Model Callback Plugin
2+
3+
This Go-only plugin demonstrates how a plugin-owned browser resource can call the host model execution callbacks instead of sending any external HTTP request itself.
4+
5+
## Purpose and Scope
6+
7+
The plugin registers a Management API resource named `Host Model Callback` at `/status`. CPA exposes it under:
8+
9+
```text
10+
/v0/resource/plugins/host-model-callback/status
11+
```
12+
13+
The resource examples are query-based. The resource reads URL query parameters, builds an OpenAI-compatible chat request, and calls:
14+
15+
- `host.model.execute` for non-streaming model execution.
16+
- `host.model.execute_stream`, `host.model.stream_read`, and `host.model.stream_close` for streaming execution.
17+
18+
This example is intentionally limited to host model callbacks. It does not implement an executor, translator, normalizer, auth provider, scheduler, or any direct outbound HTTP client.
19+
20+
## Build
21+
22+
From this directory:
23+
24+
```bash
25+
cd go
26+
go build -buildmode=c-shared -o host-model-callback.dylib .
27+
rm -f host-model-callback.dylib host-model-callback.h
28+
```
29+
30+
Use the platform extension expected by your target system:
31+
32+
- `.dylib` on macOS
33+
- `.so` on Linux
34+
- `.dll` on Windows
35+
36+
## Configuration
37+
38+
Build the dynamic library and place it under the configured plugin directory with a basename that matches the plugin ID. For example, `plugins/host-model-callback.dylib` maps to `plugins.configs.host-model-callback`.
39+
40+
```yaml
41+
plugins:
42+
enabled: true
43+
dir: "plugins"
44+
configs:
45+
host-model-callback:
46+
enabled: true
47+
priority: 1
48+
```
49+
50+
This plugin does not define plugin-specific configuration fields.
51+
52+
## Resource URL Examples
53+
54+
Non-streaming request with defaults:
55+
56+
```text
57+
http://localhost:8080/v0/resource/plugins/host-model-callback/status
58+
```
59+
60+
Non-streaming request with explicit protocol and prompt:
61+
62+
```text
63+
http://localhost:8080/v0/resource/plugins/host-model-callback/status?entry_protocol=openai&exit_protocol=openai&model=gpt-5.5&prompt=Say%20hello%20in%20one%20sentence
64+
```
65+
66+
Streaming request with explicit close:
67+
68+
```text
69+
http://localhost:8080/v0/resource/plugins/host-model-callback/status?stream=true&model=gpt-5.5&prompt=Write%20three%20short%20tokens
70+
```
71+
72+
Streaming request that relies on RPC-scope implicit close:
73+
74+
```text
75+
http://localhost:8080/v0/resource/plugins/host-model-callback/status?stream=true&implicit_close=true
76+
```
77+
78+
The default model ID is `gpt-5.5` to match the current nearby Codex example documentation and code. It is only an example model identifier; the request succeeds only when your CPA configuration can route that model.
79+
80+
## Parameters
81+
82+
- `entry_protocol`: inbound client protocol passed to the host model execution path. The default is `openai`.
83+
- `exit_protocol`: target provider protocol passed to the host model execution path. The default is `openai`.
84+
- `model`: model identifier passed in the host model execution request. The default is `gpt-5.5`; availability depends on the configured model registry and auth records.
85+
- `stream`: boolean flag. The default is `false`; set `stream=true` to use `host.model.execute_stream`.
86+
- `prompt`: text used to build the default OpenAI-compatible request body.
87+
- `body`: optional JSON string in the URL query used as the raw model request body. When `body` is provided, it replaces the generated body.
88+
- `alt`: optional alternate route or mode suffix passed through the host model request.
89+
- `implicit_close`: streaming-only boolean flag. The default is `false`.
90+
91+
The generated default body is OpenAI-compatible:
92+
93+
```json
94+
{
95+
"model": "gpt-5.5",
96+
"stream": false,
97+
"messages": [
98+
{
99+
"role": "user",
100+
"content": "Summarize host model callbacks in one short sentence."
101+
}
102+
]
103+
}
104+
```
105+
106+
For example, a URL-encoded `body` query value can provide the raw OpenAI-compatible request:
107+
108+
```text
109+
http://localhost:8080/v0/resource/plugins/host-model-callback/status?body=%7B%22model%22%3A%22gpt-5.5%22%2C%22stream%22%3Afalse%2C%22messages%22%3A%5B%7B%22role%22%3A%22user%22%2C%22content%22%3A%22Say%20hello%20in%20one%20sentence%22%7D%5D%7D
110+
```
111+
112+
## Stream Close Semantics
113+
114+
By default, streaming mode explicitly closes the host-owned stream with `host.model.stream_close` through a deferred close call. This is the preferred pattern for plugins because it releases stream resources as soon as the plugin has finished reading.
115+
116+
When `implicit_close=true` is set, the plugin intentionally skips the explicit close call. CPA injects `host_callback_id` into the `management.handle` request, and this example forwards that callback ID to `host.model.execute_stream` so the host can close the stream when the `management.handle` RPC callback scope returns. This mode exists only to demonstrate host cleanup behavior; normal plugin code should explicitly close streams it opens.
117+
118+
## Recursion Guard
119+
120+
This example forwards the `host_callback_id` received from `management.handle` when it calls `host.model.execute` or `host.model.execute_stream`. CPA uses that callback scope to identify the plugin that initiated the host model callback and skips that same plugin's request, response, and stream interceptors for the nested model execution.
121+
122+
Host model callbacks are therefore not recursive for the caller. Other enabled plugins can still intercept the nested request.
123+
124+
## Billing and Usage
125+
126+
The callback uses the existing CPA model executor path. Usage collection, request accounting, and billing metadata are handled by the same executor and usage reporter path as normal proxied requests. The callback layer does not bill twice and does not create an additional usage record by itself.
127+
128+
## Error Handling and Troubleshooting
129+
130+
The page displays the model status, response headers, body, stream chunks, close mode, and any callback error returned by the host envelope.
131+
132+
Common issues:
133+
134+
- `host model executor is unavailable`: the host model executor path is not initialized for this plugin callback context.
135+
- `unsupported model` or provider-specific routing errors: the `model` value is not routable with the current CPA model/auth configuration.
136+
- `host.model.execute requires stream=false`: non-stream execution was called with a streaming request.
137+
- `host.model.execute_stream requires stream=true`: streaming execution was called without `stream=true`.
138+
- Empty or partial stream output: inspect the page error section and host logs; upstream stream errors are returned through `host.model.stream_read`.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module github.com/router-for-me/CLIProxyAPI/v7/examples/plugin/host-model-callback/go
2+
3+
go 1.26.0
4+
5+
require github.com/router-for-me/CLIProxyAPI/v7 v7.0.0
6+
7+
replace github.com/router-for-me/CLIProxyAPI/v7 => ../../../..

0 commit comments

Comments
 (0)