Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7e5350c
model: preserve authoritative native replay through framework history
bytethm Oct 22, 2026
217ad52
model/openai/responses: add stateless adapter and local tool support
bytethm Oct 22, 2026
7565b76
model/openai/responses: harden replay integration and compatibility
bytethm Oct 23, 2026
7e91ab5
model/openai/responses: preserve native history and request identities
bytethm Oct 23, 2026
75ccb89
model/openai/responses: clarify root module compatibility requirements
bytethm Oct 23, 2026
e5d6bb5
model/openai/responses: isolate native history from callback mutations
bytethm Oct 26, 2026
51d7abf
model/openai/responses: skip redundant callback validation
bytethm Oct 26, 2026
d3a3b6f
model/openai/responses: cover retries, routing and tool recovery
bytethm Oct 26, 2026
178ef6d
session/redis: reject undecodable native replay events
bytethm Oct 26, 2026
1446c15
model/openai/responses: validate completion and merge includes
bytethm Oct 26, 2026
870823f
model/openai/responses: report fixture errors without fatal assertions
bytethm Oct 26, 2026
7172704
model/openai/responses: align guides and runnable examples
bytethm Oct 27, 2026
e61d78d
model/openai/responses: clarify setup and pin replay compatibility
bytethm Oct 27, 2026
fccd07e
examples/openairesponses: show revised completed answers
bytethm Oct 28, 2026
64274c1
examples/openairesponses: format chat test imports
bytethm Oct 28, 2026
8ca2eb9
model/openai/responses: avoid redundant history encoding
bytethm Oct 29, 2026
4d35b05
model: freeze native replay v1 fingerprint encoding
bytethm Oct 29, 2026
1b5fed4
model/openai/responses: preserve structured failure metadata
bytethm Oct 30, 2026
9ab4c67
model/openai/responses: defer native callback APIs
bytethm Oct 30, 2026
0e57523
model/openai/v3: organize SDK v3 adapters in a versioned module
bytethm Oct 30, 2026
4e8fe93
model/openai/v3/responses: isolate module and upgrade SDK
bytethm Oct 30, 2026
8f9fac1
model/openai/sdkv3: clarify SDK generation module path
bytethm Oct 30, 2026
d468cfd
llmflow: clarify native tool resume ordering
bytethm Oct 30, 2026
dd6a080
model: allow independent edits to native replay projections
bytethm Nov 2, 2026
16e6522
model: name native completion metadata provider data
bytethm Nov 2, 2026
9326297
model: trim redundant provider data tests
bytethm Nov 2, 2026
1effed0
graph: extract tool argument repair before callbacks
bytethm Nov 2, 2026
7472c95
model: unify provider data naming and initial storage format
bytethm Nov 3, 2026
a54cea2
model/openai/sdkv3/responses: simplify default store examples
bytethm Nov 3, 2026
4246b1f
model/openai/sdkv3/responses: isolate framework integration tests
bytethm Nov 3, 2026
0467368
model: synchronize edited provider data after model callbacks
bytethm Nov 6, 2026
e723e8e
model: simplify provider data serialization
bytethm Nov 6, 2026
ef9bb04
Merge branch 'main' of github.com:trpc-group/trpc-agent-go into feat/…
bytethm Nov 6, 2026
b379173
graph: honor native tool call replacements after model callbacks
bytethm Nov 6, 2026
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
25 changes: 25 additions & 0 deletions .github/workflows/prc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,31 @@ jobs:
EXAMPLES_SHARD_INDEX: ${{ matrix.shard_index }}
EXAMPLES_SHARD_TOTAL: ${{ matrix.shard_total }}
run: bash .github/scripts/check-examples-build.sh
check-openai-responses-example:
name: check OpenAI Responses example (Go 1.25)
runs-on: ubuntu-latest
env:
CGO_ENABLED: "1"
steps:
- uses: actions/checkout@v3
- uses: actions/setup-go@v5
with:
go-version: "1.25.0"
cache-dependency-path: |
go.mod
go.sum
model/openai/responses/go.mod
model/openai/responses/go.sum
examples/openairesponses/go.mod
examples/openairesponses/go.sum
- name: Test Responses adapter module
working-directory: model/openai/responses
run: go test ./...
- name: Check example module metadata and build
working-directory: examples/openairesponses
run: |
go mod tidy -diff
go build ./...
check-lfs-excluded:
name: check git lfs excluded
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions agent/llmagent/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,10 @@ func WithPreserveForeignMessages(preserve bool) Option {

// WithEventMessageProjector rewrites one event-derived message before
// it is appended to the model request.
// A projector cannot remove native replay records: editing the projection of
// such a record causes a validation error before the model is called. To
// rebase completed native history intentionally, use a session summary or
// newly authored messages instead of rewriting an active native tool turn here.
func WithEventMessageProjector(
projector EventMessageProjector,
) Option {
Expand Down
92 changes: 92 additions & 0 deletions docs/mkdocs/en/model.md
Original file line number Diff line number Diff line change
Expand Up @@ -2217,6 +2217,98 @@ If you do not need to inspect tool arguments during streaming, keep
`WithShowToolCallDelta` disabled to avoid handling partial JSON fragments and
to preserve the default clean text-streaming behavior.

## OpenAI Responses API

Use `model/openai/responses` to access the OpenAI Responses API for conversations, streaming output, and function calling. Create a model with `responses.New` and pass it to `LLMAgent`.

The adapter is a separate Go module that requires Go 1.25 or newer. For the Chat Completions API, continue using `openai.New` from `model/openai`.

### Environment and minimal integration

The OpenAI SDK reads `OPENAI_API_KEY` when `responses.WithAPIKey` is omitted, and `OPENAI_BASE_URL` when `responses.WithBaseURL` is omitted. The default base URL is `https://api.openai.com/v1`.

The example below creates a non-streaming chat agent and prints the assistant's reply. When using Runner, keep reading the event channel until it closes, or cancel the run context.

```go
package main

import (
"context"
"fmt"
"log"

"trpc.group/trpc-go/trpc-agent-go/agent/llmagent"
"trpc.group/trpc-go/trpc-agent-go/model"
"trpc.group/trpc-go/trpc-agent-go/model/openai/responses"
"trpc.group/trpc-go/trpc-agent-go/runner"
)

func main() {
ctx := context.Background()
userID := "demo-user"
sessionID := "demo-session"

llm := responses.New("gpt-5", responses.WithStore(false))
agent := llmagent.New(
"responses-chat",
llmagent.WithModel(llm),
llmagent.WithDescription("A concise chat assistant."),
llmagent.WithInstruction("Answer the user's questions clearly and concisely."),
llmagent.WithGenerationConfig(model.GenerationConfig{Stream: false}),
)
r := runner.NewRunner("responses-chat-example", agent)
defer r.Close()

events, err := r.Run(ctx, userID, sessionID, model.NewUserMessage("Hello"))
if err != nil {
log.Printf("run: %v", err)
return
}
for evt := range events {
if evt == nil || evt.Response == nil {
continue
}
if evt.Error != nil {
log.Printf("event: %s", evt.Error.Message)
continue
}
if len(evt.Response.Choices) == 0 {
continue
}
msg := evt.Response.Choices[0].Message
if msg.Role == model.RoleAssistant && msg.Content != "" {
fmt.Println(msg.Content)
}
}
}
```

Runner creates an in-memory session when none is supplied and closes that session in `Close`. The examples pass an explicit in-memory session with the same process lifetime. Local tools are wired in [`examples/openairesponses/tools/main.go`](https://github.com/trpc-group/trpc-agent-go/blob/main/examples/openairesponses/tools/main.go).

[`examples/openairesponses`](https://github.com/trpc-group/trpc-agent-go/tree/main/examples/openairesponses) is its own Go 1.25 module. `-model` defaults to `gpt-5`, and `-streaming` defaults to `true`.

```bash
cd examples/openairesponses
export OPENAI_API_KEY="your-api-key"
# Optional. The SDK reads OPENAI_BASE_URL when it is set.
# export OPENAI_BASE_URL="https://api.openai.com/v1"

go run ./chat
go run ./chat -streaming=false
go run ./tools
go run ./tools -streaming=false
```

Type `/exit` to quit. In `tools`, use two turns in the same process, such as `Calculate 123 * 456.` and then `Add 789 to that result.` The session retains the first result for the second turn and is discarded when the process exits. The example README shows an illustrative transcript.

### Notes

- Every request sends the full client-managed conversation. `store=false` is the default. `WithStore(true)` changes provider-side storage only. In ordinary `LLMAgent` and `Runner` use, application code does not read or edit `Message.Replay`. Treat that record as sensitive conversation state. Registering a Responses model that is never selected does not change a legacy session.
- Downstream modules need a root release that contains `Message.Replay` and `Info.ReplayProtocol`. Repository-relative `replace` directives are for local development and are not inherited. `model.Message` and `model.Info` gained fields, so positional composite literals for those structs must use keyed fields even in applications that never select Responses.
- Server-managed continuation through `previous_response_id` or `conversation`, hosted tools, tool search, background execution, approval interactions, and provider compaction are outside this adapter. Unknown output types, including hosted-tool calls, fail. This is not a complete Responses API client. `openai.WithShowToolCallDelta` is not a Responses option. `Stop`, presence penalty, frequency penalty, and logprobs are rejected. `MaxTokens`, `Temperature`, and `TopP` are sent when set. The examples set only `GenerationConfig.Stream`.
- Function calls run through the framework's tool executor rather than OpenAI-hosted tools. `Runner` only executes calls from a completed assistant message. A stream without a valid completed response is an error, and its partial function calls are not executed. Streaming examples display assistant text deltas. They display tool calls only from the completed `Message.ToolCalls`, and tool results only from the committed tool message.
- History, callbacks, summaries, compatibility, and recovery are specified in the [Responses adapter README](https://github.com/trpc-group/trpc-agent-go/blob/main/model/openai/responses/README.md).

## Anthropic Model

Anthropic Model is used to interface with Claude models and compatible platforms, supporting streaming output, thought modes and tool calls, and providing a rich callback mechanism, while also allowing for flexible configuration of custom HTTP headers.
Expand Down
92 changes: 92 additions & 0 deletions docs/mkdocs/zh/model.md
Original file line number Diff line number Diff line change
Expand Up @@ -2177,6 +2177,98 @@ llm := openai.New(
`WithShowToolCallDelta` 的默认关闭状态,以避免处理部分 JSON 片段,
并保留默认的“仅流式输出助手文本”的简洁行为。

## OpenAI Responses API

使用 `model/openai/responses` 接入 OpenAI Responses API,支持对话、流式输出和函数调用。通过 `responses.New` 创建模型,再传给 `LLMAgent` 即可使用。

该适配器是独立的 Go 模块,要求 Go 1.25 或更高版本。使用 Chat Completions API 时,继续使用 `model/openai` 的 `openai.New`。

### 环境变量与最小集成

省略 `responses.WithAPIKey` 时,OpenAI SDK 读取 `OPENAI_API_KEY`。省略 `responses.WithBaseURL` 时,SDK 读取 `OPENAI_BASE_URL`,默认地址为 `https://api.openai.com/v1`。

下面的示例创建一个非流式聊天 Agent,并打印助手回复。使用 Runner 时,需持续读取事件通道直到关闭,或取消本次运行的 context。

```go
package main

import (
"context"
"fmt"
"log"

"trpc.group/trpc-go/trpc-agent-go/agent/llmagent"
"trpc.group/trpc-go/trpc-agent-go/model"
"trpc.group/trpc-go/trpc-agent-go/model/openai/responses"
"trpc.group/trpc-go/trpc-agent-go/runner"
)

func main() {
ctx := context.Background()
userID := "demo-user"
sessionID := "demo-session"

llm := responses.New("gpt-5", responses.WithStore(false))
agent := llmagent.New(
"responses-chat",
llmagent.WithModel(llm),
llmagent.WithDescription("A concise chat assistant."),
llmagent.WithInstruction("Answer the user's questions clearly and concisely."),
llmagent.WithGenerationConfig(model.GenerationConfig{Stream: false}),
)
r := runner.NewRunner("responses-chat-example", agent)
defer r.Close()

events, err := r.Run(ctx, userID, sessionID, model.NewUserMessage("Hello"))
if err != nil {
log.Printf("run: %v", err)
return
}
for evt := range events {
if evt == nil || evt.Response == nil {
continue
}
if evt.Error != nil {
log.Printf("event: %s", evt.Error.Message)
continue
}
if len(evt.Response.Choices) == 0 {
continue
}
msg := evt.Response.Choices[0].Message
if msg.Role == model.RoleAssistant && msg.Content != "" {
fmt.Println(msg.Content)
}
}
}
```

未传入会话服务时,Runner 会创建内存会话,并在 `Close` 时关闭它。示例显式传入内存会话,生命周期同样限于当前进程。本地工具的接法见 [`examples/openairesponses/tools/main.go`](https://github.com/trpc-group/trpc-agent-go/blob/main/examples/openairesponses/tools/main.go)。

[`examples/openairesponses`](https://github.com/trpc-group/trpc-agent-go/tree/main/examples/openairesponses) 是独立的 Go 1.25 模块。`-model` 默认为 `gpt-5`,`-streaming` 默认为 `true`。

```bash
cd examples/openairesponses
export OPENAI_API_KEY="your-api-key"
# 可选。设置后由 SDK 读取 OPENAI_BASE_URL。
# export OPENAI_BASE_URL="https://api.openai.com/v1"

go run ./chat
go run ./chat -streaming=false
go run ./tools
go run ./tools -streaming=false
```

输入 `/exit` 结束对话。在 `tools` 中,于同一进程里分两轮提问,例如先说 `Calculate 123 * 456.`,再说 `Add 789 to that result.`。同一会话会保留第一轮结果供第二轮使用,进程退出后即丢弃。示例 README 给出了示意交互。

### 说明

- 每次请求都发送客户端维护的完整对话。默认 `store=false`。`WithStore(true)` 只改变提供方侧的存储。在普通的 `LLMAgent` 和 `Runner` 用法中,业务代码不需要读取或修改 `Message.Replay`。请把该记录视为敏感的对话状态。注册了 Responses 模型但从未选中它,不会改写已有的旧会话。
- 下游模块需要包含 `Message.Replay` 和 `Info.ReplayProtocol` 的根模块版本。仓库内的相对 `replace` 只用于本地开发,不会传递给下游。`model.Message` 和 `model.Info` 增加了字段,用位置复合字面量构造这两个结构的代码必须改为具名字段,即使应用从不选择 Responses 也是如此。
- 通过 `previous_response_id` 或 `conversation` 做服务端续接、托管工具、工具搜索、后台执行、审批交互和提供方侧历史压缩都不在此适配器内。未知输出类型(包括托管工具调用)会直接失败。此适配器不是完整的 Responses API 客户端。`openai.WithShowToolCallDelta` 不是 Responses 的选项。`Stop`、presence penalty、frequency penalty 和 logprobs 会被拒绝。请求设置了 `MaxTokens`、`Temperature` 或 `TopP` 时,这些字段会被发送。示例只设置 `GenerationConfig.Stream`。
- 函数调用由框架中的工具执行器处理,不使用 OpenAI 托管工具。`Runner` 只执行完成的 assistant 消息中的调用。没有合法完成事件的流是错误,其中的部分函数调用不会被执行。流式示例会显示 assistant 文本增量,工具调用只取完成消息里的 `Message.ToolCalls`,工具结果只取已提交的工具消息。
- 历史、回调、摘要、兼容性和恢复的完整约定见 [Responses 适配器 README](https://github.com/trpc-group/trpc-agent-go/blob/main/model/openai/responses/README.md)。

## Anthropic Model

Anthropic Model 用于对接 Claude 模型及其兼容平台,支持流式输出、思考模式与工具调用,并提供丰富的回调机制,同时可灵活设置自定义 HTTP Header.
Expand Down
5 changes: 4 additions & 1 deletion examples/model/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ Make sure you have Go installed and the project dependencies are available.

The example shows how to use the OpenAI-like model implementation with automatic environment variable reading and flexible command line configuration.

See also the focused sub-examples in this directory:
See also these focused model examples:

- `retry/` for SDK-level retry configuration.
- `requesty/` for using the OpenAI-compatible Requesty router (`https://router.requesty.ai/v1`).
- `switch/` for runtime model switching.
- `selector/` for per-LLM-call model selection with `runner.Run`.
- `failover/` for primary/backup model failover before the first non-error chunk.
- `hedge/` for delayed or failure-triggered hedge requests across multiple candidates.
- [`../openairesponses/`](../openairesponses/) for the OpenAI Responses API.
It is a sibling of this directory because that adapter is a separate Go 1.25
module.

## Key Features

Expand Down
Loading
Loading