Skip to content

Commit a6a44b7

Browse files
committed
Merge branch 'main' of github.com:pherzheyu/trpc-agent-go into feature/model-gemini
2 parents 8cd298d + 42a1bba commit a6a44b7

File tree

122 files changed

+6638
-1771
lines changed

Some content is hidden

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

122 files changed

+6638
-1771
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ func calculator(ctx context.Context, req calculatorReq) (calculatorRsp, error) {
246246
result = req.A * req.B
247247
case "div", "/":
248248
result = req.A / req.B
249+
default:
250+
return calculatorRsp{}, fmt.Errorf("invalid operation: %s", req.Op)
249251
}
250252
return calculatorRsp{Result: result}, nil
251253
}

README.zh_CN.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,9 @@ func calculator(ctx context.Context, req calculatorReq) (calculatorRsp, error) {
246246
result = req.A * req.B
247247
case "div", "/":
248248
result = req.A / req.B
249-
}
249+
default:
250+
return calculatorRsp{}, fmt.Errorf("invalid operation: %s", req.Op)
251+
}
250252
return calculatorRsp{Result: result}, nil
251253
}
252254

agent/callbacks.go

Lines changed: 274 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,74 +23,317 @@ const ErrorTypeAgentCallbackError = "agent_callback_error"
2323
// Returns (customResponse, error).
2424
// - customResponse: if not nil, this response will be returned to user and agent execution will be skipped.
2525
// - error: if not nil, agent execution will be stopped with this error.
26-
type BeforeAgentCallback func(ctx context.Context, invocation *Invocation) (*model.Response, error)
26+
// Deprecated: Use BeforeAgentCallbackStructured instead for better type safety and context passing.
27+
type BeforeAgentCallback = func(ctx context.Context, invocation *Invocation) (*model.Response, error)
2728

2829
// AfterAgentCallback is called after the agent runs.
2930
// Returns (customResponse, error).
3031
// - customResponse: if not nil, this response will be used instead of the actual agent response.
3132
// - error: if not nil, this error will be returned.
32-
type AfterAgentCallback func(ctx context.Context, invocation *Invocation, runErr error) (*model.Response, error)
33+
// Deprecated: Use AfterAgentCallbackStructured instead for better type safety and context passing.
34+
type AfterAgentCallback = func(ctx context.Context, invocation *Invocation, runErr error) (*model.Response, error)
35+
36+
// BeforeAgentArgs contains all parameters for before agent callback.
37+
type BeforeAgentArgs struct {
38+
// Invocation is the invocation context.
39+
Invocation *Invocation
40+
}
41+
42+
// BeforeAgentResult contains the return value for before agent callback.
43+
type BeforeAgentResult struct {
44+
// Context if not nil, will be used by the framework for subsequent operations.
45+
Context context.Context
46+
// CustomResponse if not nil, will skip agent execution and return this response.
47+
CustomResponse *model.Response
48+
}
49+
50+
// BeforeAgentCallbackStructured is called before the agent runs.
51+
// Returns (result, error).
52+
// - result: contains optional custom response and context for subsequent operations.
53+
// - CustomResponse: if not nil, this response will be returned to user and agent execution will be skipped.
54+
// - Context: if not nil, will be used by the framework for subsequent operations.
55+
//
56+
// - error: if not nil, agent execution will be stopped with this error.
57+
type BeforeAgentCallbackStructured = func(
58+
ctx context.Context,
59+
args *BeforeAgentArgs,
60+
) (*BeforeAgentResult, error)
61+
62+
// AfterAgentArgs contains all parameters for after agent callback.
63+
type AfterAgentArgs struct {
64+
// Invocation is the invocation context.
65+
Invocation *Invocation
66+
// Error is the error occurred during agent execution (may be nil).
67+
Error error
68+
}
69+
70+
// AfterAgentResult contains the return value for after agent callback.
71+
type AfterAgentResult struct {
72+
// Context if not nil, will be used by the framework for subsequent operations.
73+
Context context.Context
74+
// CustomResponse if not nil, will replace the original response.
75+
CustomResponse *model.Response
76+
}
77+
78+
// AfterAgentCallbackStructured is called after the agent runs.
79+
// Returns (result, error).
80+
// - result: contains optional custom response and context for subsequent operations.
81+
// - CustomResponse: if not nil, this response will be used instead of the actual agent response.
82+
// - Context: if not nil, will be used by the framework for subsequent operations.
83+
//
84+
// - error: if not nil, this error will be returned.
85+
type AfterAgentCallbackStructured = func(
86+
ctx context.Context,
87+
args *AfterAgentArgs,
88+
) (*AfterAgentResult, error)
3389

3490
// Callbacks holds callbacks for agent operations.
91+
// Internally stores the new structured callback types.
3592
type Callbacks struct {
36-
// BeforeAgent is a list of callbacks that are called before the agent runs.
37-
BeforeAgent []BeforeAgentCallback
38-
// AfterAgent is a list of callbacks that are called after the agent runs.
39-
AfterAgent []AfterAgentCallback
93+
// BeforeAgent is a list of callbacks called before the agent runs.
94+
BeforeAgent []BeforeAgentCallbackStructured
95+
// AfterAgent is a list of callbacks called after the agent runs.
96+
AfterAgent []AfterAgentCallbackStructured
97+
// continueOnError controls whether to continue executing callbacks when an error occurs.
98+
// Default: false (stop on first error)
99+
continueOnError bool
100+
// continueOnResponse controls whether to continue executing callbacks when a CustomResponse is returned.
101+
// Default: false (stop on first CustomResponse)
102+
continueOnResponse bool
103+
}
104+
105+
// CallbacksOption configures Callbacks behavior.
106+
type CallbacksOption func(*Callbacks)
107+
108+
// WithContinueOnError sets whether to continue executing callbacks when an error occurs.
109+
func WithContinueOnError(continueOnError bool) CallbacksOption {
110+
return func(c *Callbacks) {
111+
c.continueOnError = continueOnError
112+
}
113+
}
114+
115+
// WithContinueOnResponse sets whether to continue executing callbacks when a CustomResponse is returned.
116+
func WithContinueOnResponse(continueOnResponse bool) CallbacksOption {
117+
return func(c *Callbacks) {
118+
c.continueOnResponse = continueOnResponse
119+
}
40120
}
41121

42122
// NewCallbacks creates a new Callbacks instance for agent.
43-
func NewCallbacks() *Callbacks {
44-
return &Callbacks{}
123+
func NewCallbacks(opts ...CallbacksOption) *Callbacks {
124+
c := &Callbacks{}
125+
for _, opt := range opts {
126+
opt(c)
127+
}
128+
return c
45129
}
46130

47131
// RegisterBeforeAgent registers a before agent callback.
48-
func (c *Callbacks) RegisterBeforeAgent(cb BeforeAgentCallback) *Callbacks {
49-
c.BeforeAgent = append(c.BeforeAgent, cb)
132+
// Supports both old and new callback function signatures.
133+
// Old signatures are automatically wrapped into new signatures.
134+
func (c *Callbacks) RegisterBeforeAgent(cb any) *Callbacks {
135+
switch callback := cb.(type) {
136+
case BeforeAgentCallbackStructured:
137+
c.BeforeAgent = append(c.BeforeAgent, callback)
138+
case BeforeAgentCallback:
139+
wrapped := func(ctx context.Context, args *BeforeAgentArgs) (*BeforeAgentResult, error) {
140+
// Call old signature
141+
resp, err := callback(ctx, args.Invocation)
142+
if err != nil {
143+
return nil, err
144+
}
145+
if resp != nil {
146+
return &BeforeAgentResult{CustomResponse: resp}, nil
147+
}
148+
return &BeforeAgentResult{}, nil // Return empty result to indicate callback was executed.
149+
}
150+
c.BeforeAgent = append(c.BeforeAgent, wrapped)
151+
default:
152+
panic("unsupported callback type")
153+
}
50154
return c
51155
}
52156

53157
// RegisterAfterAgent registers an after agent callback.
54-
func (c *Callbacks) RegisterAfterAgent(cb AfterAgentCallback) *Callbacks {
55-
c.AfterAgent = append(c.AfterAgent, cb)
158+
// Supports both old and new callback function signatures.
159+
// Old signatures are automatically wrapped into new signatures.
160+
func (c *Callbacks) RegisterAfterAgent(cb any) *Callbacks {
161+
switch callback := cb.(type) {
162+
case AfterAgentCallbackStructured:
163+
c.AfterAgent = append(c.AfterAgent, callback)
164+
case AfterAgentCallback:
165+
wrapped := func(ctx context.Context, args *AfterAgentArgs) (*AfterAgentResult, error) {
166+
// Call old signature
167+
resp, err := callback(ctx, args.Invocation, args.Error)
168+
if err != nil {
169+
return nil, err
170+
}
171+
if resp != nil {
172+
return &AfterAgentResult{CustomResponse: resp}, nil
173+
}
174+
return &AfterAgentResult{}, nil // Return empty result to indicate callback was executed.
175+
}
176+
c.AfterAgent = append(c.AfterAgent, wrapped)
177+
default:
178+
panic("unsupported callback type")
179+
}
56180
return c
57181
}
58182

183+
// handleCallbackError processes callback error and returns whether to continue.
184+
func (c *Callbacks) handleCallbackError(err error, firstErr *error) (shouldStop bool) {
185+
if err == nil {
186+
return false
187+
}
188+
if !c.continueOnError {
189+
return true
190+
}
191+
if *firstErr == nil {
192+
*firstErr = err
193+
}
194+
return false
195+
}
196+
197+
// processCallbackResult processes callback result and updates context.
198+
// Returns whether to stop execution immediately.
199+
func (c *Callbacks) processCallbackResult(
200+
result *BeforeAgentResult,
201+
ctx *context.Context,
202+
lastResult **BeforeAgentResult,
203+
) (shouldStop bool) {
204+
if result == nil {
205+
return false
206+
}
207+
if result.Context != nil {
208+
*ctx = result.Context
209+
}
210+
if result.CustomResponse != nil {
211+
*lastResult = result
212+
if !c.continueOnResponse {
213+
return true
214+
}
215+
} else {
216+
*lastResult = result
217+
}
218+
return false
219+
}
220+
221+
// finalizeBeforeAgentResult determines the final return value for before agent callbacks.
222+
func (c *Callbacks) finalizeBeforeAgentResult(
223+
lastResult *BeforeAgentResult,
224+
firstErr error,
225+
) (*BeforeAgentResult, error) {
226+
if lastResult != nil && lastResult.CustomResponse != nil {
227+
if c.continueOnError && firstErr != nil {
228+
return lastResult, firstErr
229+
}
230+
return lastResult, nil
231+
}
232+
if c.continueOnError && firstErr != nil {
233+
return lastResult, firstErr
234+
}
235+
if lastResult != nil && lastResult.Context == nil && lastResult.CustomResponse == nil {
236+
return nil, nil
237+
}
238+
return lastResult, nil
239+
}
240+
59241
// RunBeforeAgent runs all before agent callbacks in order.
60-
// Returns (customResponse, error).
61-
// If any callback returns a custom response, stop and return.
242+
// This method uses the new structured callback interface.
243+
// If a callback returns a non-nil Context in the result, it will be used for subsequent callbacks.
62244
func (c *Callbacks) RunBeforeAgent(
63245
ctx context.Context,
64-
invocation *Invocation,
65-
) (*model.Response, error) {
246+
args *BeforeAgentArgs,
247+
) (*BeforeAgentResult, error) {
248+
var lastResult *BeforeAgentResult
249+
var firstErr error
250+
66251
for _, cb := range c.BeforeAgent {
67-
customResponse, err := cb(ctx, invocation)
68-
if err != nil {
252+
result, err := cb(ctx, args)
253+
254+
if c.handleCallbackError(err, &firstErr) {
69255
return nil, err
70256
}
71-
if customResponse != nil {
72-
return customResponse, nil
257+
258+
if c.processCallbackResult(result, &ctx, &lastResult) {
259+
if c.continueOnError && firstErr != nil {
260+
return result, firstErr
261+
}
262+
return result, nil
263+
}
264+
}
265+
266+
return c.finalizeBeforeAgentResult(lastResult, firstErr)
267+
}
268+
269+
// processAfterCallbackResult processes after callback result and updates context.
270+
// Returns whether to stop execution immediately.
271+
func (c *Callbacks) processAfterCallbackResult(
272+
result *AfterAgentResult,
273+
ctx *context.Context,
274+
lastResult **AfterAgentResult,
275+
) (shouldStop bool) {
276+
if result == nil {
277+
return false
278+
}
279+
if result.Context != nil {
280+
*ctx = result.Context
281+
}
282+
if result.CustomResponse != nil {
283+
*lastResult = result
284+
if !c.continueOnResponse {
285+
return true
73286
}
287+
} else {
288+
*lastResult = result
74289
}
75-
return nil, nil
290+
return false
291+
}
292+
293+
// finalizeAfterAgentResult determines the final return value for after agent callbacks.
294+
func (c *Callbacks) finalizeAfterAgentResult(
295+
lastResult *AfterAgentResult,
296+
firstErr error,
297+
) (*AfterAgentResult, error) {
298+
if lastResult != nil && lastResult.CustomResponse != nil {
299+
if c.continueOnError && firstErr != nil {
300+
return lastResult, firstErr
301+
}
302+
return lastResult, nil
303+
}
304+
if c.continueOnError && firstErr != nil {
305+
return lastResult, firstErr
306+
}
307+
if lastResult != nil && lastResult.Context == nil && lastResult.CustomResponse == nil {
308+
return nil, nil
309+
}
310+
return lastResult, nil
76311
}
77312

78313
// RunAfterAgent runs all after agent callbacks in order.
79-
// Returns (customResponse, error).
80-
// If any callback returns a custom response, stop and return.
314+
// This method uses the new structured callback interface.
315+
// If a callback returns a non-nil Context in the result, it will be used for subsequent callbacks.
81316
func (c *Callbacks) RunAfterAgent(
82317
ctx context.Context,
83-
invocation *Invocation,
84-
runErr error,
85-
) (*model.Response, error) {
318+
args *AfterAgentArgs,
319+
) (*AfterAgentResult, error) {
320+
var lastResult *AfterAgentResult
321+
var firstErr error
322+
86323
for _, cb := range c.AfterAgent {
87-
customResponse, err := cb(ctx, invocation, runErr)
88-
if err != nil {
324+
result, err := cb(ctx, args)
325+
326+
if c.handleCallbackError(err, &firstErr) {
89327
return nil, err
90328
}
91-
if customResponse != nil {
92-
return customResponse, nil
329+
330+
if c.processAfterCallbackResult(result, &ctx, &lastResult) {
331+
if c.continueOnError && firstErr != nil {
332+
return result, firstErr
333+
}
334+
return result, nil
93335
}
94336
}
95-
return nil, nil
337+
338+
return c.finalizeAfterAgentResult(lastResult, firstErr)
96339
}

0 commit comments

Comments
 (0)