
context.Context in a Go agent: cancellation, deadlines, and causes
Stop a run, give each call a deadline, say why it stopped, and let the work that must finish still finish.
The whole loopAn agent run makes many slow calls: a model call that takes half a minute, a tool that runs a test suite, another model call, and so on for dozens of turns.
At any point, the person who started it may want it stopped, a call may hang, or the process may be shutting down.
In Go, all three travel the same way, through a context.Context passed into every function that waits on something.
This page goes through the ways an agent uses one, each with code from the companion repository, where it is tested. Several of the tools are recent additions to Go, so here is what each needs:
| Feature | Since |
|---|---|
signal.NotifyContext |
Go 1.16 |
context.Cause, context.WithCancelCause, exec.Cmd.WaitDelay |
Go 1.20 |
context.WithTimeoutCause, context.WithoutCancel, context.AfterFunc |
Go 1.21 |
testing.T.Context |
Go 1.24 |
testing/synctest |
Go 1.25 |
errors.AsType |
Go 1.26 |
The companion code needs Go 1.27; with an older toolchain, go downloads the right one when it reads the module’s go.mod.
Without a context
Take the context away and two things go wrong.
The first is Ctrl-C.
By default, a Go program that gets an interrupt exits on the spot, and its deferred functions never run.
For an agent, that means a model call dropped partway, which the provider may bill anyway; a tool stopped in the middle of an action, such as writing a file or filing an issue; no checkpoint saved, so the run can’t resume; and no report of what it spent or why it ended.
Stopped with a plain kill, the agent’s process gets SIGTERM alone, so a go test or a tool server it started can keep running on its own.
The second is that every kind of waiting needs its own way to stop.
You can catch the signal yourself, but then something has to reach everything that is blocked: an HTTP request, a child process to kill, a timer to stop, each of your own goroutines waiting on a channel.
Each has a different mechanism, and before Go 1.7 brought context into the standard library, each library had its own; net/http still carries one of them, the Cancel field on a request, now deprecated in favor of the request’s context.
context replaces all of those with one stop signal that reaches every layer and says why it fired.
Every blocking call agrees on it, from net/http and os/exec to the model providers’ SDKs and your own code, and it carries the reason with it.
The rest of this page is that alternative, piece by piece.
How a context works
context.Context is an interface with four methods:
Done()returns a channel that is closed when the context ends, for use in aselect(Goroutines with an owner explains channels andselect).Err()isnilwhile the context is live, thencontext.Canceledorcontext.DeadlineExceeded.Deadline()reports when the context will end on its own, if it has a deadline.Value(key)returns a value stored in the context, ornil.
A context is never changed.
Functions such as context.WithCancel and context.WithTimeout take a parent and return a new child, with a function that cancels it, so the contexts in a program form a tree with context.Background() at the root.
Cancellation travels down the tree and never up:
Two more rules complete the picture.
The first cancellation wins: once a context is done, later calls to its cancel function change nothing, including its cause.
And context.Cause (explained under “Say why it stopped” below) always has an answer: the cause given when the context was cancelled, the parent’s cause when cancellation came from above, and Err() itself when nobody gave one.
context.Background() is the root for main, for init, and for anything that starts a whole operation.
context.TODO() is the same empty context under another name, a marker for code that should be passed a context and isn’t yet; linters and readers can find it.
One context, from main down
The context starts in main, and the first thing it is good for is Ctrl-C:
func main() {
// Ctrl-C cancels ctx, and the loop stops before its next turn.
ctx, stop := signal.NotifyContext(context.Background(),
os.Interrupt)
defer stop()
if err := run(ctx, os.Stdout); err != nil {
log.Fatal(err)
}
}
signal.NotifyContext returns a context that is cancelled when the process gets an interrupt.
From here the context is passed down, as the first parameter of every function that does I/O or can block: the loop, the model client, each tool.
Nothing below main makes a fresh context.Background(), because a fresh context cuts the chain: whatever ran under it would ignore Ctrl-C.
Passing it as a parameter, never storing it in a struct, keeps each call’s context its own. A client that stored one context would cancel every later request when the first request was cancelled.
A server starts its chains elsewhere.
In an HTTP handler, r.Context() is the request’s context, and it ends when the client disconnects or the handler returns.
An agent run started from a handler derives its context from it, so a person who closes the browser tab stops the run; the browser streaming example is built that way.
A deadline for each model call
A model call that hangs should fail on its own, without waiting for a person to notice. The client gives every request its own deadline, derived from the run’s context:
// send posts a request to the API and returns the decoded response.
func (c *Client) send(ctx context.Context,
wire chatRequest) (chatResponse, error) {
ctx, cancel := context.WithTimeoutCause(ctx, c.timeout(),
ErrCallTimeout)
defer cancel()
resp, err := c.post(ctx, wire)
if err != nil {
return chatResponse{}, err
}
defer resp.Body.Close()
return readResponse(ctx, resp)
}
The derived context ends at whichever comes first: the caller’s cancellation, or the call’s own timeout.
defer cancel() releases the timer when the call returns early, which is most of the time; without it, the timer lives until it fires.
The run has limits of its own above this, a turn limit and a cost budget, so a deadline for the whole run is rarely needed.
When it is, wrap the run’s context the same way, and each call’s shorter deadline still applies inside it.
context.WithDeadline does the same with a time instead of a duration.
Code can also read the time left: deadline, ok := ctx.Deadline() reports the deadline, if there is one, and time.Until(deadline) how long remains.
An agent can use it to skip starting work that can’t finish in time, such as a model call that usually takes 40 seconds when 10 remain, and stop with a clear reason instead of a timeout partway through.
Say why it stopped
A cancelled context reports one of two errors, context.Canceled or context.DeadlineExceeded, and neither says which deadline passed.
“Deadline exceeded” from a run with a call timeout, a tool timeout, and a test timeout is a puzzle.
context.WithTimeoutCause and context.WithCancelCause attach a cause, an error of your own, and context.Cause reads it back.
Above, the call’s timeout carries ErrCallTimeout.
Go’s HTTP transports don’t all report a cancelled request the same way, so the client puts both the cause and the kind of cancellation into the error it returns, and callers can check either one with errors.Is.
The detail: when a request is cancelled, Go’s HTTP/1 transport returns the cause, and its HTTP/2 transport returns only the kind of cancellation. The client joins both into the error:
// callError makes the error from a cancelled call carry both the kind
// of cancellation and its cause. The HTTP/1 transport reports only the
// cause, and the HTTP/2 transport only the kind.
func callError(ctx context.Context, err error) error {
if ctx.Err() == nil {
return err
}
if !errors.Is(err, ctx.Err()) {
err = fmt.Errorf("%w: %w", ctx.Err(), err)
}
if cause := context.Cause(ctx); !errors.Is(err, cause) {
err = fmt.Errorf("%w: %w", err, cause)
}
return err
}
With both in the chain, the program can say in plain words why a run ended, checking the specific causes before the general kinds:
// whyStopped says in a few words why a run ended, from its error.
func whyStopped(err error) string {
switch {
case err == nil:
return "the model answered"
case errors.Is(err, agent.ErrMaxTurns):
return "the turn limit"
case errors.Is(err, agent.ErrBudgetExceeded):
return "the cost budget"
case errors.Is(err, openrouter.ErrStreamIdle): // before Canceled
return "the stream went quiet, worth retrying"
case errors.Is(err, context.Canceled):
return "cancelled"
case errors.Is(err, openrouter.ErrCallTimeout):
return "the model call timed out, worth retrying"
case errors.Is(err, context.DeadlineExceeded):
return "a deadline passed"
case errors.Is(err, agent.ErrBadReply):
return "a reply the loop can't use"
}
if e, ok := errors.AsType[*openrouter.APIError](err); ok {
if e.Retryable() {
return fmt.Sprintf("API error %d, worth retrying", e.Status)
}
return fmt.Sprintf("API error %d", e.Status)
}
return "an error"
}
The last check, errors.AsType[*openrouter.APIError](err), has a type in square brackets: it says which kind of error to look for. AsType returns it already converted to that type, with ok false if the chain has none. The errors page covers it, and the glossary explains the brackets.
“The model call timed out, worth retrying” and “cancelled” call for different responses, and only the cause tells them apart.
Between turns, and the calls that didn’t run
Every model call notices cancellation on its own, because the context reaches the HTTP request. The loop also checks between turns, so it doesn’t start a call it would cancel at once:
// beforeTurn checks what can stop a run before it spends another call:
// cancellation, and the cost budget.
func beforeTurn(ctx context.Context, res Result, lim Limits) error {
if err := stopped(ctx); err != nil {
return err
}
if lim.MaxCost > 0 && res.Usage.Cost >= lim.MaxCost {
return fmt.Errorf("%w: spent $%.6f of $%.6f",
ErrBudgetExceeded, res.Usage.Cost, lim.MaxCost)
}
return nil
}
// stopped returns the error for a run whose ctx is done, carrying the
// kind of cancellation and, when it says more, the cause. It returns
// nil while ctx isn't done.
func stopped(ctx context.Context) error {
if ctx.Err() == nil {
return nil
}
err := fmt.Errorf("stopped before turn: %w", ctx.Err())
if cause := context.Cause(ctx); !errors.Is(err, cause) {
err = fmt.Errorf("%w: %w", err, cause)
}
return err
}
When cancellation arrives partway through a reply that asked for several tools, some calls have run and some haven’t. Every tool call in a conversation needs a matching result, or the next request to the model is rejected, so the calls that didn’t run get a result that says why:
// runTools answers every call in a reply, in order, passing each tool
// message to yield as it is made. Once ctx is done, the calls that
// haven't run get a "cancelled" result instead, so every tool call in
// the conversation still has its answer. It reports false if yield did.
func runTools(ctx context.Context, byName map[string]Tool,
calls []ToolCall, yield func(Message) bool) ([]Message, bool) {
var out []Message
for _, call := range calls {
msg := Message{Role: "tool", ToolCallID: call.ID, IsError: true}
if ctx.Err() != nil {
msg.Content = "cancelled before it ran: " +
context.Cause(ctx).Error()
} else {
msg = runTool(ctx, byName, call)
}
out = append(out, msg)
if !yield(msg) {
return out, false
}
}
return out, true
}
In runTools, yield is a function the caller passes in; the loop calls it to hand over each message as it is made, and it returns false when the caller wants no more. Iterators in an agent explains the pattern.
Waiting in your own code
The standard library’s blocking calls take a context and stop on their own.
Code that waits on its own channels and timers has to watch the context itself, with a select on ctx.Done() beside whatever it is waiting for.
The agent limits how many tool calls run at once with a buffered channel of slots, and waiting for a slot gives up when the context ends:
// Slots limits how many things run at once, such as the tool calls of
// one reply, or test runs across every agent in a program. Make one with
// NewSlots; a nil Slots would wait forever.
type Slots chan struct{}
// NewSlots returns Slots that let n things run at once.
func NewSlots(n int) Slots { return make(Slots, max(n, 1)) }
// Acquire waits for a free slot, and gives up when ctx is done,
// returning why. Every successful Acquire needs a Release.
func (s Slots) Acquire(ctx context.Context) error {
select {
case s <- struct{}{}:
return nil
case <-ctx.Done():
return fmt.Errorf("wait for a slot: %w", context.Cause(ctx))
}
}
// Release frees a slot that Acquire took.
func (s Slots) Release() { <-s }
A rate limiter that waits on a timer does the same, and stops the timer when it leaves early:
// Wait returns when the caller may start a call, or when ctx is done,
// with why. A turn given up this way is still used, which errs on the
// side of sending fewer requests.
func (l *Limiter) Wait(ctx context.Context) error {
l.mu.Lock()
now := time.Now()
at := l.next
if at.Before(now) {
at = now
}
l.next = at.Add(l.Every)
l.mu.Unlock()
if !at.After(now) {
return nil
}
t := time.NewTimer(at.Sub(now))
defer t.Stop()
select {
case <-t.C:
return nil
case <-ctx.Done():
return fmt.Errorf("wait for the rate limit: %w",
context.Cause(ctx))
}
}
Both return the cause, so a caller sees why the wait ended.
Without the ctx.Done() case, a goroutine blocked on a full channel waits forever after its run is gone: a goroutine leak, which in a long-running service adds up one stopped run at a time.
Every goroutine needs an owner and a way to stop, and for most of them the way to stop is a context.
Tools that start processes
A tool that runs go test starts a process, and a cancelled context has to reach it too.
exec.CommandContext kills the process when the context is done:
ctx, cancel := context.WithTimeoutCause(ctx, timeout,
ErrTestsTimedOut)
defer cancel()
inner := fmt.Sprintf("-timeout=%s", timeout*3/4)
cmd := exec.CommandContext(ctx, "go", "test", "-json", "-count=1",
inner, "./...")
cmd.Dir = dir
cmd.Env = testEnv()
cmd.WaitDelay = 5 * time.Second
var stdout, stderr bytes.Buffer
cmd.Stdout, cmd.Stderr = &stdout, &stderr
err = cmd.Run()
if ctx.Err() != nil {
err := fmt.Errorf("go test: %w", ctx.Err())
if cause := context.Cause(ctx); !errors.Is(err, cause) {
err = fmt.Errorf("%w: %w", err, cause)
}
return "", err
}
_, exited := errors.AsType[*exec.ExitError](err)
if err != nil && !exited {
return "", fmt.Errorf("run_tests: %w", err)
}
if err != nil && stdout.Len() == 0 {
return "", fmt.Errorf("run_tests: %s",
strings.TrimSpace(stderr.String()))
}
return report(&stdout, stderr.String(), dir), nil
}
Three details here are easy to miss:
go testgets its own-timeout, three quarters of the tool’s, so the tests usually stop themselves first and report which test hung.cmd.WaitDelaybounds how longRunwaits for the output pipes after the process is killed; a test that started a child process can otherwise keep them open.- The tool checks
ctx.Err()before looking at the command’s error, because a killed process reports only “signal: killed”, and the cause says why it was killed.
A tool that is a Go function, rather than a separate process, must check its context itself, by passing it to every call that can block. A tool that ignores its context can’t be stopped: a timeout wrapper around it still has to wait until the tool returns, however late.
Some calls can’t take a context at all, such as a read from a connection or a pipe.
context.AfterFunc runs a function when the context is done, and closing the connection there unblocks the read.
The MCP client starts a server process and talks to it over pipes, and arranges exactly that while it connects:
stop := context.AfterFunc(ctx, func() { _ = c.Close() })
if err := c.connect(ctx); err != nil {
stop()
err = fmt.Errorf("connect to %s: %w", cmd.Path, err)
return nil, errors.Join(err, c.Close())
}
return c, nil
The stop function it returns cancels the arrangement, for when the work finishes first.
A timer as a cause: the idle stream
A streamed reply can stop arriving without ending: the connection stays open and nothing comes. A deadline for the whole call doesn’t fit, because a long reply legitimately takes minutes. What fits is a timer that is reset every time a piece arrives, and cancels with its own cause when it fires:
// Stream sends the conversation and yields the reply in pieces as the
// model writes it. A stream that goes quiet for IdleTimeout is
// cancelled with ErrStreamIdle as the cause.
func (c *Client) Stream(ctx context.Context,
req agent.Request) iter.Seq2[agent.Delta, error] {
return func(yield func(agent.Delta, error) bool) {
ctx, cancel := context.WithCancelCause(ctx)
defer cancel(nil)
idle := time.AfterFunc(c.idleTimeout(), func() {
cancel(ErrStreamIdle)
})
defer idle.Stop()
time.AfterFunc runs the cancellation on the timer’s own goroutine.
The timer is armed only while the program is waiting for bytes, by a wrapper around the response body:
// idleReader runs an idle timer only while it waits for the network,
// so the timer fires when the stream itself has gone quiet for the
// whole timeout, not when the program is busy with what it already
// has. If the timer has already fired, Reset runs it again, which is
// harmless: cancelling twice keeps the first cause.
type idleReader struct {
r io.Reader
timer *time.Timer
timeout time.Duration
}
func (ir *idleReader) Read(p []byte) (int, error) {
ir.timer.Reset(ir.timeout)
n, err := ir.r.Read(p)
ir.timer.Stop()
return n, err //nolint:wrapcheck // Reader errors pass as is
}
Each Read resets the timer before it waits and stops it once data arrives, so the timeout measures how long the connection has been silent, and time the program spends handling an event never counts against it.
The cause, ErrStreamIdle, is what lets the program report “the stream went quiet, worth retrying” instead of “cancelled”.
Work that must finish anyway
Some work should finish even when the run is being cancelled: saving the checkpoint that preserves what the run has done, or writing the record of a tool call that already changed something.
context.WithoutCancel returns a context that keeps the parent’s values but never ends with it:
// save writes the run as it is now. A tool message whose call still
// has a marker is left out: the call's outcome is unknown, so on
// resume it goes to the resolution ladder instead of counting as
// answered. So is one that doesn't settle its call. The save ignores
// cancellation, since the save that keeps a stopping run's work must
// finish.
func (j *journal) save(ctx context.Context, phase Phase) error {
if j.cp == nil {
return nil
}
st := j.st
st.Version, st.Phase = StateVersion, phase
st.Messages = j.settledMessages()
st.Usage, st.Turns = j.res.Usage, j.res.Turns
st.Context, st.Final = j.res.Context, j.res.Final
st.Pending = j.res.Pending
err := j.cp.Save(context.WithoutCancel(ctx), st)
if err != nil {
return fmt.Errorf("save run: %w", err)
}
return nil
}
The listing’s comment mentions the resolution ladder: the three steps a resumed run uses to settle a tool call whose result was never recorded. It runs the call again if a repeat is harmless, asks the service whether the call happened, and only then asks a person. Durable runs covers it.
Use it narrowly, for short writes that must complete, and give the operation its own timeout if it can block, since nothing else will stop it.
A graceful shutdown goes one step further: in-flight work gets a grace period before it is cancelled.
This function builds that from the same parts: a context detached with WithoutCancel, and a goroutine that cancels it with the original cause, after the grace period when the cause is a shutdown and at once for anything else:
// graced returns a context that ctx's cancellation reaches d late if
// its cause is ErrShutdown, and at once otherwise. stop ends the
// goroutine that watches ctx.
func graced(ctx context.Context, d time.Duration) (context.Context,
func()) {
inner, cancel := context.WithCancelCause(
context.WithoutCancel(ctx))
done := make(chan struct{})
go func() {
select {
case <-done:
return
case <-ctx.Done():
}
cause := context.Cause(ctx)
if errors.Is(cause, ErrShutdown) {
select {
case <-done:
return
case <-time.After(d):
}
}
cancel(cause)
}()
return inner, func() { close(done); cancel(nil) }
}
The goroutine has an owner: the returned stop function ends it, so a run that finishes early doesn’t leave it waiting.
Testing timeouts without waiting
A test for a two-minute timeout shouldn’t take two minutes.
testing/synctest gives the test its own fake clock, which moves forward only when every goroutine in the test is blocked, and then straight to the next timer:
// TestTimeoutSynctest checks the call deadline with testing/synctest,
// whose fake clock lets a two-minute timeout pass instantly.
func TestTimeoutSynctest(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
c := &Client{HTTP: &http.Client{Transport: blockingTransport{}}}
start := time.Now()
_, err := c.Generate(t.Context(), agent.Request{})
if !errors.Is(err, ErrCallTimeout) ||
!errors.Is(err, context.DeadlineExceeded) {
t.Errorf("err = %v", err)
}
if d := time.Since(start); d != 2*time.Minute {
t.Errorf("the call gave up after %v, want 2m0s", d)
}
})
}
The test checks both the cause and the kind of error, and that the call gave up after exactly two minutes of fake time.
It finishes instantly.
t.Context() is a context that is cancelled when the test ends, so anything the test starts with it stops with the test.
Values in a context
A context can also carry values, and the rule is narrow: values that describe the request, which pass through layers that don’t know about them, never optional parameters. The agent uses one, the ID of the tool call that a tool is running for, so that logging and tracing wrappers can name the call without every tool passing it along:
// callKey carries the tool call a tool is running for, so a wrapper can
// name it; Tool.Run sees only the arguments.
type callKey struct{}
// CallFrom returns the tool call the context's tool is running for.
func CallFrom(ctx context.Context) (ToolCall, bool) {
c, ok := ctx.Value(callKey{}).(ToolCall)
return c, ok
}
The key is an unexported type, callKey; since only this package can name that type, only this package can set or read the value, and CallFrom hands it out with its real type.
Mistakes to avoid
context.Background()deep inside the code. It cuts the chain, and nothing under it can be cancelled. Take actxparameter instead.- A context stored in a struct. Each call should get its own; a stored one outlives the request it belonged to.
- A forgotten
cancel.WithTimeout,WithCancel, and theirCauseforms each return one;deferit, or the timer and goroutine it holds linger.go vetreports acancelthat some path never calls. - A timeout with no cause. “Context deadline exceeded” from somewhere in a run is hard to act on; a cause names the deadline.
- A tool that ignores its context. It can’t be stopped, and a run can’t finish shutting down while it runs.
- Parameters passed as context values. A value the function needs belongs in its signature; a context value is invisible to the caller and unchecked by the compiler.
- Comparing error strings. Check
errors.Is(err, context.Canceled)and your own causes witherrors.Is; the text of a cancellation error differs between transports.
Try it
From the code directory of a clone of the companion repository:
$ go test ./ch06/openrouter -run 'TestTimeoutSynctest|TestStreamIdleSynctest' -v
$ go test ./ch06/agent -run TestCancelPartwayThroughAReply -v
- In
TestTimeoutSynctest, change the client’s timeout and watch the test check the new duration, still instantly. - In
ch06/openrouter/client.go, changeWithTimeoutCausetoWithTimeoutand drop the cause: which tests fail, and what doeswhyStoppedreport for a call timeout now? - Run a tool that sleeps without checking its context.
TestTimeoutsinch12/agent/wrappers_test.goalready has one, nameddeaf, under a one-second timeout. Change itstime.Sleep(3 * time.Second)to 5 seconds and rungo test ./ch12/agent -run TestTimeouts -v. The test fails withignores its context: "done", <nil> after 5s: the timeout fired, but the tool never looked, so the call finished only when the tool chose to (the test uses a fake clock, so it still runs instantly).
Undo your edits with git restore . in the code directory.
package signal ("os/signal")
Package signal implements access to incoming signals.
Package signal implements access to incoming signals. package signal ("os/signal"). Documented at pkg.go.dev, os/signal.
func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc)
NotifyContext returns a copy of the parent context that is marked done (its Done channel is closed) when one of the listed signals arrives, when the returned stop function is called, or when the parent context's Done channel is closed, whichever happens first.
NotifyContext returns a copy of the parent context that is marked done (its Done channel is closed) when one of the listed signals arrives, when the returned stop function is called, or when the parent context's Done channel is closed, whichever happens first. func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc). Documented at pkg.go.dev, os/signal.NotifyContext.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
func Background() Context
Background returns a non-nil, empty [Context].
Background returns a non-nil, empty [Context]. func Background() Context. Documented at pkg.go.dev, context.Background.
package os ("os")
Package os provides a platform-independent interface to operating system functionality.
Package os provides a platform-independent interface to operating system functionality. package os ("os"). Documented at pkg.go.dev, os.
var Interrupt Signal = syscall.SIGINT
var Interrupt Signal = syscall.SIGINT. Documented at pkg.go.dev, os.Interrupt.
func run(ctx context.Context, w io.Writer) error
func run(ctx context.Context, w io.Writer) error. In ch01/main.go, line 44.
var Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout")
var Stdout = NewFile(uintptr(syscall.Stdout), "/dev/stdout"). Documented at pkg.go.dev, os.Stdout.
var nil Type
nil is a predeclared identifier representing the zero value for a pointer, channel, func, interface, map, or slice type.
nil is a predeclared identifier representing the zero value for a pointer, channel, func, interface, map, or slice type. var nil Type. Documented at pkg.go.dev, builtin.nil.
package log ("log")
Package log implements a simple logging package.
Package log implements a simple logging package. package log ("log"). Documented at pkg.go.dev, log.
func Fatal(v ...any)
Fatal is equivalent to [Print] followed by a call to os.Exit(1).
Fatal is equivalent to [Print] followed by a call to os.Exit(1). func Fatal(v ...any). Documented at pkg.go.dev, log.Fatal.
type Client struct {
BaseURL string // DefaultBaseURL if empty
APIKey string // sent as a bearer token
Model string // a model ID from OpenRouter's list
HTTP *http.Client // http.DefaultClient if nil
Timeout time.Duration // per Generate call; 2 minutes if zero
// IdleTimeout is the longest a stream may go without sending a
// byte, including the wait for its headers; 30 seconds if zero
// (chapter 6). Stream doesn't use Timeout.
// ...
}
Client calls a model through OpenRouter.
Client calls a model through OpenRouter. type Client struct { BaseURL string // DefaultBaseURL if empty APIKey string // sent as a bearer token Model string // a model ID from OpenRouter's list HTTP *http.Client // http.DefaultClient if nil Timeout time.Duration // per Generate call; 2 minutes if zero // IdleTimeout is the longest a stream may go without sending a // byte, including the wait for its headers; 30 seconds if zero // (chapter 6). Stream doesn't use Timeout. // ... }. In ch06/openrouter/client.go, line 40.
func (c *Client) send(ctx context.Context,
wire chatRequest) (chatResponse, error)
send posts a request to the API and returns the decoded response.
send posts a request to the API and returns the decoded response. func (c *Client) send(ctx context.Context, wire chatRequest) (chatResponse, error). In ch06/openrouter/client.go, line 73.
var ctx context.Context
var ctx context.Context. In ch06/openrouter/client.go, line 73.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
type Context interface {
// Deadline returns the time when work done on behalf of this context
// should be canceled. Deadline returns ok==false when no deadline is
// set. Successive calls to Deadline return the same results.
Deadline() (deadline time.Time, ok bool)
// Done returns a channel that's closed when work done on behalf of this
// context should be canceled. Done may return nil if this context can
// never be canceled. Successive calls to Done return the same value.
// The close of the Done channel may happen asynchronously,
// ...
}
A Context carries a deadline, a cancellation signal, and other values across API boundaries.
A Context carries a deadline, a cancellation signal, and other values across API boundaries. type Context interface { // Deadline returns the time when work done on behalf of this context // should be canceled. Deadline returns ok==false when no deadline is // set. Successive calls to Deadline return the same results. Deadline() (deadline time.Time, ok bool) // Done returns a channel that's closed when work done on behalf of this // context should be canceled. Done may return nil if this context can // never be canceled. Successive calls to Done return the same value. // The close of the Done channel may happen asynchronously, // ... }. Documented at pkg.go.dev, context.Context.
var wire chatRequest
var wire chatRequest. In ch06/openrouter/client.go, line 74.
type chatRequest struct {
Model string `json:"model"`
Messages []chatMessage `json:"messages"`
Tools []chatTool `json:"tools,omitzero"`
MaxTokens int `json:"max_tokens,omitzero"`
// Settings for asking about token probabilities (chapter 3).
Temperature *float64 `json:"temperature,omitzero"` // 0 is a setting
Logprobs bool `json:"logprobs,omitzero"`
TopLogprobs int `json:"top_logprobs,omitzero"`
// ...
}
type chatRequest struct { Model string `json:"model"` Messages []chatMessage `json:"messages"` Tools []chatTool `json:"tools,omitzero"` MaxTokens int `json:"max_tokens,omitzero"` // Settings for asking about token probabilities (chapter 3). Temperature *float64 `json:"temperature,omitzero"` // 0 is a setting Logprobs bool `json:"logprobs,omitzero"` TopLogprobs int `json:"top_logprobs,omitzero"` // ... }. In ch06/openrouter/wire.go, line 15.
type chatResponse struct {
ID string `json:"id"`
Model string `json:"model"`
Provider string `json:"provider"`
Choices []chatChoice `json:"choices"`
Usage chatUsage `json:"usage"`
Error *apiError `json:"error"`
}
type chatResponse struct { ID string `json:"id"` Model string `json:"model"` Provider string `json:"provider"` Choices []chatChoice `json:"choices"` Usage chatUsage `json:"usage"` Error *apiError `json:"error"` }. In ch06/openrouter/wire.go, line 87.
type error interface {
Error() string
}
The error built-in interface type is the conventional interface for representing an error condition, with the nil value representing no error.
The error built-in interface type is the conventional interface for representing an error condition, with the nil value representing no error. type error interface { Error() string }. Documented at pkg.go.dev, builtin.error.
var cancel context.CancelFunc
var cancel context.CancelFunc. In ch06/openrouter/client.go, line 75.
func WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc)
WithTimeoutCause behaves like [WithTimeout] but also sets the cause of the returned Context when the timeout expires.
WithTimeoutCause behaves like [WithTimeout] but also sets the cause of the returned Context when the timeout expires. func WithTimeoutCause(parent Context, timeout time.Duration, cause error) (Context, CancelFunc). Documented at pkg.go.dev, context.WithTimeoutCause.
func (c *Client) timeout() time.Duration
func (c *Client) timeout() time.Duration. In ch06/openrouter/client.go, line 285.
var ErrCallTimeout = errors.New("openrouter: model call timed out")
ErrCallTimeout is the cause recorded when a call runs past Client.Timeout.
ErrCallTimeout is the cause recorded when a call runs past Client.Timeout. var ErrCallTimeout = errors.New("openrouter: model call timed out"). In ch06/openrouter/client.go, line 26.
var resp *http.Response
var resp *http.Response. In ch06/openrouter/client.go, line 78.
func (c *Client) post(ctx context.Context,
wire chatRequest) (*http.Response, error)
post sends a request to the chat completions endpoint and returns the response, whatever its status.
post sends a request to the chat completions endpoint and returns the response, whatever its status. func (c *Client) post(ctx context.Context, wire chatRequest) (*http.Response, error). In ch06/openrouter/client.go, line 88.
field Body io.ReadCloser
Body represents the response body.
Body represents the response body. field Body io.ReadCloser. Documented at pkg.go.dev, net/http.Response.Body.
func (Closer) Close() error
func (Closer) Close() error. Documented at pkg.go.dev, io.Closer.Close.
func readResponse(ctx context.Context,
resp *http.Response) (chatResponse, error)
readResponse reads and decodes a response, and checks it holds a reply.
readResponse reads and decodes a response, and checks it holds a reply. func readResponse(ctx context.Context, resp *http.Response) (chatResponse, error). In ch06/openrouter/client.go, line 165.
func callError(ctx context.Context, err error) error
callError makes the error from a cancelled call carry both the kind of cancellation and its cause.
callError makes the error from a cancelled call carry both the kind of cancellation and its cause. func callError(ctx context.Context, err error) error. In ch06/openrouter/client.go, line 252.
var ctx context.Context
var ctx context.Context. In ch06/openrouter/client.go, line 252.
func (Context) Err() error
If Done is not yet closed, Err returns nil.
If Done is not yet closed, Err returns nil. func (Context) Err() error. Documented at pkg.go.dev, context.Context.Err.
package errors ("errors")
Package errors implements functions to manipulate errors.
Package errors implements functions to manipulate errors. package errors ("errors"). Documented at pkg.go.dev, errors.
func Is(err, target error) bool
Is reports whether any error in err's tree matches target.
Is reports whether any error in err's tree matches target. func Is(err, target error) bool. Documented at pkg.go.dev, errors.Is.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
func Errorf(format string, a ...any) (err error)
Errorf formats according to a format specifier and returns the string as a value that satisfies error.
Errorf formats according to a format specifier and returns the string as a value that satisfies error. func Errorf(format string, a ...any) (err error). Documented at pkg.go.dev, fmt.Errorf.
var cause error
var cause error. In ch06/openrouter/client.go, line 259.
func Cause(c Context) error
Cause returns a non-nil error explaining why c was canceled.
Cause returns a non-nil error explaining why c was canceled. func Cause(c Context) error. Documented at pkg.go.dev, context.Cause.
func whyStopped(err error) string
whyStopped says in a few words why a run ended, from its error.
whyStopped says in a few words why a run ended, from its error. func whyStopped(err error) string. In ch06/main.go, line 258.
type string string
string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text.
string is the set of all strings of 8-bit bytes, conventionally but not necessarily representing UTF-8-encoded text. type string string. Documented at pkg.go.dev, builtin.string.
package errors ("errors")
Package errors implements functions to manipulate errors.
Package errors implements functions to manipulate errors. package errors ("errors"). Documented at pkg.go.dev, errors.
package agent ("github.com/blackwell-systems/go-agents-book/code/ch06/agent")
Package agent is the agent loop and the types it works with.
Package agent is the agent loop and the types it works with. package agent ("github.com/blackwell-systems/go-agents-book/code/ch06/agent"). In ch06/agent.
var ErrMaxTurns = fmt.Errorf("%w: max turns reached", ErrBudget)
var ErrMaxTurns = fmt.Errorf("%w: max turns reached", ErrBudget). In ch06/agent/errors.go, line 16.
var ErrBudgetExceeded = fmt.Errorf("%w: cost budget reached", ErrBudget)
var ErrBudgetExceeded = fmt.Errorf("%w: cost budget reached", ErrBudget). In ch06/agent/errors.go, line 17.
package openrouter ("github.com/blackwell-systems/go-agents-book/code/ch06/openrouter")
Package openrouter is a client for OpenRouter's chat completions API that satisfies agent.Model.
Package openrouter is a client for OpenRouter's chat completions API that satisfies agent.Model. package openrouter ("github.com/blackwell-systems/go-agents-book/code/ch06/openrouter"). In ch06/openrouter.
var ErrStreamIdle = errors.New("openrouter: stream went quiet")
ErrStreamIdle is the cause recorded when a stream sends nothing for longer than Client.IdleTimeout.
ErrStreamIdle is the cause recorded when a stream sends nothing for longer than Client.IdleTimeout. var ErrStreamIdle = errors.New("openrouter: stream went quiet"). In ch06/openrouter/stream.go, line 20.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
var Canceled = errors.New("context canceled")
Canceled is the error returned by [Context.Err] when the context is canceled for some reason other than its deadline passing.
Canceled is the error returned by [Context.Err] when the context is canceled for some reason other than its deadline passing. var Canceled = errors.New("context canceled"). Documented at pkg.go.dev, context.Canceled.
var DeadlineExceeded error = deadlineExceededError{}
DeadlineExceeded is the error returned by [Context.Err] when the context is canceled due to its deadline passing.
DeadlineExceeded is the error returned by [Context.Err] when the context is canceled due to its deadline passing. var DeadlineExceeded error = deadlineExceededError{}. Documented at pkg.go.dev, context.DeadlineExceeded.
var ErrBadReply = errors.New("agent: bad reply")
ErrBadReply: the model's reply can't be used as it is.
ErrBadReply: the model's reply can't be used as it is. var ErrBadReply = errors.New("agent: bad reply"). In ch06/agent/errors.go, line 20.
func AsType[E error](err error) (E, bool)
AsType finds the first error in err's tree that matches the type E, and if one is found, returns that error value and true.
AsType finds the first error in err's tree that matches the type E, and if one is found, returns that error value and true. func AsType[E error](err error) (E, bool). Documented at pkg.go.dev, errors.AsType.
type APIError struct {
Status int // HTTP status, or the code in the reply
Message string // the API's own explanation
RetryAfter time.Duration // the wait the API asked for, or 0
}
An APIError is a request the API refused, or a provider failure it reported.
An APIError is a request the API refused, or a provider failure it reported. type APIError struct { Status int // HTTP status, or the code in the reply Message string // the API's own explanation RetryAfter time.Duration // the wait the API asked for, or 0 }. In ch06/openrouter/errors.go, line 15.
func (e *APIError) Retryable() bool
Retryable reports whether the same request might succeed if sent again later: a timeout (408), too many requests (429), or trouble on the provider's side (5xx).
Retryable reports whether the same request might succeed if sent again later: a timeout (408), too many requests (429), or trouble on the provider's side (5xx). func (e *APIError) Retryable() bool. In ch06/openrouter/errors.go, line 32.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
func Sprintf(format string, a ...any) string
Sprintf formats according to a format specifier and returns the resulting string.
Sprintf formats according to a format specifier and returns the resulting string. func Sprintf(format string, a ...any) string. Documented at pkg.go.dev, fmt.Sprintf.
field Status int
HTTP status, or the code in the reply
HTTP status, or the code in the reply field Status int. In ch06/openrouter/errors.go, line 16.
func beforeTurn(ctx context.Context, res Result, lim Limits) error
beforeTurn checks what can stop a run before it spends another call: cancellation, and the cost budget.
beforeTurn checks what can stop a run before it spends another call: cancellation, and the cost budget. func beforeTurn(ctx context.Context, res Result, lim Limits) error. In ch06/agent/loop.go, line 41.
var ctx context.Context
var ctx context.Context. In ch06/agent/loop.go, line 41.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
type Result struct {
Messages []Message
Usage Usage // the run's total, over every model call (chapter 5)
}
Result is what a run produced, whether or not it ended in an error.
Result is what a run produced, whether or not it ended in an error. type Result struct { Messages []Message Usage Usage // the run's total, over every model call (chapter 5) }. In ch06/agent/types.go, line 116.
type Limits struct {
MaxTurns int
MaxCost float64 // in dollars; 0 means no cost budget (chapter 5)
}
Limits holds the settings that bound a run.
Limits holds the settings that bound a run. type Limits struct { MaxTurns int MaxCost float64 // in dollars; 0 means no cost budget (chapter 5) }. In ch06/agent/types.go, line 110.
func stopped(ctx context.Context) error
stopped returns the error for a run whose ctx is done, carrying the kind of cancellation and, when it says more, the cause.
stopped returns the error for a run whose ctx is done, carrying the kind of cancellation and, when it says more, the cause. func stopped(ctx context.Context) error. In ch06/agent/loop.go, line 55.
field MaxCost float64
in dollars; 0 means no cost budget (chapter 5)
in dollars; 0 means no cost budget (chapter 5) field MaxCost float64. In ch06/agent/types.go, line 112.
field Usage Usage
the run's total, over every model call (chapter 5)
the run's total, over every model call (chapter 5) field Usage Usage. In ch06/agent/types.go, line 118.
field Cost float64
in dollars, as the provider reported it
in dollars, as the provider reported it field Cost float64. In ch06/agent/types.go, line 80.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
var ctx context.Context
var ctx context.Context. In ch06/agent/loop.go, line 55.
package errors ("errors")
Package errors implements functions to manipulate errors.
Package errors implements functions to manipulate errors. package errors ("errors"). Documented at pkg.go.dev, errors.
func runTools(ctx context.Context, byName map[string]Tool,
calls []ToolCall, yield func(Message) bool) ([]Message, bool)
runTools answers every call in a reply, in order, passing each tool message to yield as it is made.
runTools answers every call in a reply, in order, passing each tool message to yield as it is made. func runTools(ctx context.Context, byName map[string]Tool, calls []ToolCall, yield func(Message) bool) ([]Message, bool). In ch06/agent/loop.go, line 126.
var ctx context.Context
var ctx context.Context. In ch06/agent/loop.go, line 126.
var byName map[string]Tool
var byName map[string]Tool. In ch06/agent/loop.go, line 126.
type Tool struct {
Def ToolDef
Run func(ctx context.Context, args jsontext.Value) (string, error)
}
Tool is the harness's side of a tool: the definition the model sees, and the Go function that runs it.
Tool is the harness's side of a tool: the definition the model sees, and the Go function that runs it. type Tool struct { Def ToolDef Run func(ctx context.Context, args jsontext.Value) (string, error) }. In ch06/agent/types.go, line 100.
type ToolCall struct {
ID string
Name string
Arguments jsontext.Value // JSON the model wrote; may be invalid
}
ToolCall is the model asking the harness to run a tool.
ToolCall is the model asking the harness to run a tool. type ToolCall struct { ID string Name string Arguments jsontext.Value // JSON the model wrote; may be invalid }. In ch06/agent/types.go, line 57.
var yield func(Message) bool
var yield func(Message) bool. In ch06/agent/loop.go, line 127.
type Message struct {
Role string // "system", "user", "assistant", or "tool"
Content string // empty when the message has tool calls
ToolCalls []ToolCall // set on assistant messages that call tools
ToolCallID string // on tool messages: the call this answers
IsError bool // set on tool messages that report a failure
// ReasoningDetails is a reasoning model's record of its thinking,
// sent back unchanged with the tool calls it led to (chapter 4).
ReasoningDetails jsontext.Value
}
Message is one entry in the conversation.
Message is one entry in the conversation. type Message struct { Role string // "system", "user", "assistant", or "tool" Content string // empty when the message has tool calls ToolCalls []ToolCall // set on assistant messages that call tools ToolCallID string // on tool messages: the call this answers IsError bool // set on tool messages that report a failure // ReasoningDetails is a reasoning model's record of its thinking, // sent back unchanged with the tool calls it led to (chapter 4). ReasoningDetails jsontext.Value }. In ch06/agent/types.go, line 33.
type bool bool
bool is the set of boolean values, true and false.
bool is the set of boolean values, true and false. type bool bool. Documented at pkg.go.dev, builtin.bool.
field Role string
"system", "user", "assistant", or "tool"
"system", "user", "assistant", or "tool" field Role string. In ch06/agent/types.go, line 34.
field ToolCallID string
on tool messages: the call this answers
on tool messages: the call this answers field ToolCallID string. In ch06/agent/types.go, line 37.
field IsError bool
set on tool messages that report a failure
set on tool messages that report a failure field IsError bool. In ch06/agent/types.go, line 38.
const true = 0 == 0
Untyped bool.
Untyped bool. const true = 0 == 0. Documented at pkg.go.dev, builtin.true.
field Content string
empty when the message has tool calls
empty when the message has tool calls field Content string. In ch06/agent/types.go, line 35.
func (error).Error() string
func (error).Error() string.
func runTool(ctx context.Context, byName map[string]Tool,
call ToolCall) Message
runTool runs one tool call and returns the tool message that answers it.
runTool runs one tool call and returns the tool message that answers it. func runTool(ctx context.Context, byName map[string]Tool, call ToolCall) Message. In ch06/agent/loop.go, line 151.
func append(slice []Type, elems ...Type) []Type
The append built-in function appends elements to the end of a slice.
The append built-in function appends elements to the end of a slice. func append(slice []Type, elems ...Type) []Type. Documented at pkg.go.dev, builtin.append.
const false = 0 != 0
Untyped bool.
Untyped bool. const false = 0 != 0. Documented at pkg.go.dev, builtin.false.
type Slots chan struct{}
Slots limits how many things run at once, such as the tool calls of one reply, or test runs across every agent in a program.
Slots limits how many things run at once, such as the tool calls of one reply, or test runs across every agent in a program. type Slots chan struct{}. In ch15/agent/slots.go, line 13.
func NewSlots(n int) Slots
NewSlots returns Slots that let n things run at once.
NewSlots returns Slots that let n things run at once. func NewSlots(n int) Slots. In ch15/agent/slots.go, line 16.
type int int
int is a signed integer type that is at least 32 bits in size.
int is a signed integer type that is at least 32 bits in size. type int int. Documented at pkg.go.dev, builtin.int.
func make(t Type, size ...IntegerType) Type
The make built-in function allocates and initializes an object of type slice, map, or chan (only).
The make built-in function allocates and initializes an object of type slice, map, or chan (only). func make(t Type, size ...IntegerType) Type. Documented at pkg.go.dev, builtin.make.
func max[T cmp.Ordered](x T, y ...T) T
The max built-in function returns the largest value of a fixed number of arguments of cmp.Ordered types.
The max built-in function returns the largest value of a fixed number of arguments of cmp.Ordered types. func max[T cmp.Ordered](x T, y ...T) T. Documented at pkg.go.dev, builtin.max.
func (s Slots) Acquire(ctx context.Context) error
Acquire waits for a free slot, and gives up when ctx is done, returning why.
Acquire waits for a free slot, and gives up when ctx is done, returning why. func (s Slots) Acquire(ctx context.Context) error. In ch15/agent/slots.go, line 20.
var ctx context.Context
var ctx context.Context. In ch15/agent/slots.go, line 20.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
func (Context) Done() <-chan struct{}
Done returns a channel that's closed when work done on behalf of this context should be canceled.
Done returns a channel that's closed when work done on behalf of this context should be canceled. func (Context) Done() <-chan struct{}. Documented at pkg.go.dev, context.Context.Done.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
func (s Slots) Release()
Release frees a slot that Acquire took.
Release frees a slot that Acquire took. func (s Slots) Release(). In ch15/agent/slots.go, line 30.
type Limiter struct {
Every time.Duration
mu sync.Mutex
next time.Time // when the next call may start
}
A Limiter paces model calls shared by runs going on at once, so six agents don't send six requests in the same instant: calls start at least Every apart, in the order they asked.
A Limiter paces model calls shared by runs going on at once, so six agents don't send six requests in the same instant: calls start at least Every apart, in the order they asked. type Limiter struct { Every time.Duration mu sync.Mutex next time.Time // when the next call may start }. In ch09/agent/ratelimit.go, line 17.
func (l *Limiter) Wait(ctx context.Context) error
Wait returns when the caller may start a call, or when ctx is done, with why.
Wait returns when the caller may start a call, or when ctx is done, with why. func (l *Limiter) Wait(ctx context.Context) error. In ch09/agent/ratelimit.go, line 31.
var ctx context.Context
var ctx context.Context. In ch09/agent/ratelimit.go, line 31.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
field mu sync.Mutex
field mu sync.Mutex. In ch09/agent/ratelimit.go, line 20.
func (m *Mutex) Lock()
Lock locks m.
Lock locks m. func (m *Mutex) Lock(). Documented at pkg.go.dev, sync.Mutex.Lock.
package time ("time")
Package time provides functionality for measuring and displaying time.
Package time provides functionality for measuring and displaying time. package time ("time"). Documented at pkg.go.dev, time.
func Now() Time
Now returns the current local time.
Now returns the current local time. func Now() Time. Documented at pkg.go.dev, time.Now.
field next time.Time
when the next call may start
when the next call may start field next time.Time. In ch09/agent/ratelimit.go, line 21.
func (t Time) Before(u Time) bool
Before reports whether the time instant t is before u.
Before reports whether the time instant t is before u. func (t Time) Before(u Time) bool. Documented at pkg.go.dev, time.Time.Before.
func (t Time) Add(d Duration) Time
Add returns the time t+d.
Add returns the time t+d. func (t Time) Add(d Duration) Time. Documented at pkg.go.dev, time.Time.Add.
field Every time.Duration
field Every time.Duration. In ch09/agent/ratelimit.go, line 18.
func (m *Mutex) Unlock()
Unlock unlocks m.
Unlock unlocks m. func (m *Mutex) Unlock(). Documented at pkg.go.dev, sync.Mutex.Unlock.
func (t Time) After(u Time) bool
After reports whether the time instant t is after u.
After reports whether the time instant t is after u. func (t Time) After(u Time) bool. Documented at pkg.go.dev, time.Time.After.
func NewTimer(d Duration) *Timer
NewTimer creates a new Timer that will send the current time on its channel after at least duration d.
NewTimer creates a new Timer that will send the current time on its channel after at least duration d. func NewTimer(d Duration) *Timer. Documented at pkg.go.dev, time.NewTimer.
func (t Time) Sub(u Time) Duration
Sub returns the duration t-u.
Sub returns the duration t-u. func (t Time) Sub(u Time) Duration. Documented at pkg.go.dev, time.Time.Sub.
func (t *Timer) Stop() bool
Stop prevents the [Timer] from firing.
Stop prevents the [Timer] from firing. func (t *Timer) Stop() bool. Documented at pkg.go.dev, time.Timer.Stop.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
var ctx context.Context
var ctx context.Context. In ch06/agent/gotest.go, line 39.
var cancel context.CancelFunc
var cancel context.CancelFunc. In ch06/agent/gotest.go, line 52.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
var timeout time.Duration
var timeout time.Duration. In ch06/agent/gotest.go, line 39.
var ErrTestsTimedOut = errors.New("tests timed out")
ErrTestsTimedOut means go test ran past the tool's deadline.
ErrTestsTimedOut means go test ran past the tool's deadline. var ErrTestsTimedOut = errors.New("tests timed out"). In ch06/agent/gotest.go, line 32.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
package exec ("os/exec")
Package exec runs external commands.
Package exec runs external commands. package exec ("os/exec"). Documented at pkg.go.dev, os/exec.
func CommandContext(ctx context.Context, name string, arg ...string) *Cmd
CommandContext is like [Command] but includes a context.
CommandContext is like [Command] but includes a context. func CommandContext(ctx context.Context, name string, arg ...string) *Cmd. Documented at pkg.go.dev, os/exec.CommandContext.
field Dir string
Dir specifies the working directory of the command.
Dir specifies the working directory of the command. field Dir string. Documented at pkg.go.dev, os/exec.Cmd.Dir.
field Env []string
Env specifies the environment of the process.
Env specifies the environment of the process. field Env []string. Documented at pkg.go.dev, os/exec.Cmd.Env.
func testEnv() []string
testEnv is the environment go test runs with: only what the go command needs, so the code under test can't read your API key, and settings that keep it offline and away from your other projects.
testEnv is the environment go test runs with: only what the go command needs, so the code under test can't read your API key, and settings that keep it offline and away from your other projects. func testEnv() []string. In ch06/agent/gotest.go, line 89.
field WaitDelay time.Duration
If WaitDelay is non-zero, it bounds the time spent waiting on two sources of unexpected delay in Wait: a child process that fails to exit after the associated Context is canceled, and a child process that exits but leaves its I/O pipes unclosed.
If WaitDelay is non-zero, it bounds the time spent waiting on two sources of unexpected delay in Wait: a child process that fails to exit after the associated Context is canceled, and a child process that exits but leaves its I/O pipes unclosed. field WaitDelay time.Duration. Documented at pkg.go.dev, os/exec.Cmd.WaitDelay.
package time ("time")
Package time provides functionality for measuring and displaying time.
Package time provides functionality for measuring and displaying time. package time ("time"). Documented at pkg.go.dev, time.
const Second = 1000 * Millisecond
const Second = 1000 * Millisecond. Documented at pkg.go.dev, time.Second.
var stdout bytes.Buffer
var stdout bytes.Buffer. In ch06/agent/gotest.go, line 61.
var stderr bytes.Buffer
var stderr bytes.Buffer. In ch06/agent/gotest.go, line 61.
package bytes ("bytes")
Package bytes implements functions for the manipulation of byte slices.
Package bytes implements functions for the manipulation of byte slices. package bytes ("bytes"). Documented at pkg.go.dev, bytes.
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
lastRead readOp // last read operation, so that Unread* can work correctly.
// Copying and modifying a non-zero Buffer is prone to error,
// but we cannot employ the noCopy trick used by WaitGroup and Mutex,
// which causes vet's copylocks checker to report misuse, as vet
// cannot reliably distinguish the zero and non-zero cases.
// See #26462, #25907, #47276, #48398 for history.
}
A Buffer is a variable-sized buffer of bytes with [Buffer.Read] and [Buffer.Write] methods.
A Buffer is a variable-sized buffer of bytes with [Buffer.Read] and [Buffer.Write] methods. type Buffer struct { buf []byte // contents are the bytes buf[off : len(buf)] off int // read at &buf[off], write at &buf[len(buf)] lastRead readOp // last read operation, so that Unread* can work correctly. // Copying and modifying a non-zero Buffer is prone to error, // but we cannot employ the noCopy trick used by WaitGroup and Mutex, // which causes vet's copylocks checker to report misuse, as vet // cannot reliably distinguish the zero and non-zero cases. // See #26462, #25907, #47276, #48398 for history. }. Documented at pkg.go.dev, bytes.Buffer.
field Stdout io.Writer
Stdout and Stderr specify the process's standard output and error.
Stdout and Stderr specify the process's standard output and error. field Stdout io.Writer. Documented at pkg.go.dev, os/exec.Cmd.Stdout.
field Stderr io.Writer
field Stderr io.Writer. Documented at pkg.go.dev, os/exec.Cmd.Stderr.
func (c *Cmd) Run() error
Run starts the specified command and waits for it to complete.
Run starts the specified command and waits for it to complete. func (c *Cmd) Run() error. Documented at pkg.go.dev, os/exec.Cmd.Run.
package errors ("errors")
Package errors implements functions to manipulate errors.
Package errors implements functions to manipulate errors. package errors ("errors"). Documented at pkg.go.dev, errors.
type ExitError struct {
*os.ProcessState
// Stderr holds a subset of the standard error output from the
// Cmd.Output method if standard error was not otherwise being
// collected.
//
// If the error output is long, Stderr may contain only a prefix
// and suffix of the output, with the middle replaced with
// text about the number of omitted bytes.
// ...
}
An ExitError reports an unsuccessful exit by a command.
An ExitError reports an unsuccessful exit by a command. type ExitError struct { *os.ProcessState // Stderr holds a subset of the standard error output from the // Cmd.Output method if standard error was not otherwise being // collected. // // If the error output is long, Stderr may contain only a prefix // and suffix of the output, with the middle replaced with // text about the number of omitted bytes. // ... }. Documented at pkg.go.dev, os/exec.ExitError.
func (b *Buffer) Len() int
Len returns the number of bytes of the unread portion of the buffer; b.Len() == len(b.Bytes()).
Len returns the number of bytes of the unread portion of the buffer; b.Len() == len(b.Bytes()). func (b *Buffer) Len() int. Documented at pkg.go.dev, bytes.Buffer.Len.
package strings ("strings")
Package strings implements simple functions to manipulate UTF-8 encoded strings.
Package strings implements simple functions to manipulate UTF-8 encoded strings. package strings ("strings"). Documented at pkg.go.dev, strings.
func TrimSpace(s string) string
TrimSpace returns a slice (substring) of the string s, with all leading and trailing white space removed, as defined by Unicode.
TrimSpace returns a slice (substring) of the string s, with all leading and trailing white space removed, as defined by Unicode. func TrimSpace(s string) string. Documented at pkg.go.dev, strings.TrimSpace.
func (b *Buffer) String() string
String returns the contents of the unread portion of the buffer as a string.
String returns the contents of the unread portion of the buffer as a string. func (b *Buffer) String() string. Documented at pkg.go.dev, bytes.Buffer.String.
func report(stdout io.Reader, stderr, dir string) string
report turns go test -json output into what a person would want to read: the output of failed tests, build errors, and each package's result, without the output of tests that passed or the path of the temporary directory.
report turns go test -json output into what a person would want to read: the output of failed tests, build errors, and each package's result, without the output of tests that passed or the path of the temporary directory. func report(stdout io.Reader, stderr, dir string) string. In ch06/agent/gotest.go, line 149.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
func AfterFunc(ctx Context, f func()) (stop func() bool)
AfterFunc arranges to call f in its own goroutine after ctx is canceled.
AfterFunc arranges to call f in its own goroutine after ctx is canceled. func AfterFunc(ctx Context, f func()) (stop func() bool). Documented at pkg.go.dev, context.AfterFunc.
var ctx context.Context
var ctx context.Context. In ch15/mcp/client.go, line 514.
func (c *Client) Close() error
Close stops the server, in the order the protocol asks: close its input, which tells it to exit; wait for it; and kill it if it hasn't exited after shutdownGrace.
Close stops the server, in the order the protocol asks: close its input, which tells it to exit; wait for it; and kill it if it hasn't exited after shutdownGrace. func (c *Client) Close() error. In ch15/mcp/client.go, line 569.
func (c *Client) connect(ctx context.Context) error
connect finds out which protocol the server speaks.
connect finds out which protocol the server speaks. func (c *Client) connect(ctx context.Context) error. In ch15/mcp/client.go, line 277.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
package errors ("errors")
Package errors implements functions to manipulate errors.
Package errors implements functions to manipulate errors. package errors ("errors"). Documented at pkg.go.dev, errors.
func Join(errs ...error) error
Join returns an error that wraps the given errors.
Join returns an error that wraps the given errors. func Join(errs ...error) error. Documented at pkg.go.dev, errors.Join.
func (c *Client) Stream(ctx context.Context,
req agent.Request) iter.Seq2[agent.Delta, error]
Stream sends the conversation and yields the reply in pieces as the model writes it.
Stream sends the conversation and yields the reply in pieces as the model writes it. func (c *Client) Stream(ctx context.Context, req agent.Request) iter.Seq2[agent.Delta, error]. In ch06/openrouter/stream.go, line 59.
var ctx context.Context
var ctx context.Context. In ch06/openrouter/stream.go, line 59.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
var req agent.Request
var req agent.Request. In ch06/openrouter/stream.go, line 60.
package agent ("github.com/blackwell-systems/go-agents-book/code/ch06/agent")
Package agent is the agent loop and the types it works with.
Package agent is the agent loop and the types it works with. package agent ("github.com/blackwell-systems/go-agents-book/code/ch06/agent"). In ch06/agent.
type Request struct {
Messages []Message
Tools []ToolDef
MaxTokens int // longest reply; 0 means the provider's default
}
Request is what the harness sends the model on each turn.
Request is what the harness sends the model on each turn. type Request struct { Messages []Message Tools []ToolDef MaxTokens int // longest reply; 0 means the provider's default }. In ch06/agent/types.go, line 24.
package iter ("iter")
Package iter provides basic definitions and operations related to iterators over sequences.
Package iter provides basic definitions and operations related to iterators over sequences. package iter ("iter"). Documented at pkg.go.dev, iter.
type Seq2[K, V any] func(yield func(K, V) bool)
Seq2 is an iterator over sequences of pairs of values, most commonly key-value pairs.
Seq2 is an iterator over sequences of pairs of values, most commonly key-value pairs. type Seq2[K, V any] func(yield func(K, V) bool). Documented at pkg.go.dev, iter.Seq2.
type Delta struct {
Text string // a piece of the reply's text
Call *CallDelta // a piece of one tool call
FinishReason string // why the reply ended, when it has
Usage *Usage // what the call consumed, at the end
// ReasoningDetails holds reasoning records, a JSON array, which the
// assembler joins into the reply's ReasoningDetails.
ReasoningDetails jsontext.Value
}
A Delta is one piece of a streamed reply.
A Delta is one piece of a streamed reply. type Delta struct { Text string // a piece of the reply's text Call *CallDelta // a piece of one tool call FinishReason string // why the reply ended, when it has Usage *Usage // what the call consumed, at the end // ReasoningDetails holds reasoning records, a JSON array, which the // assembler joins into the reply's ReasoningDetails. ReasoningDetails jsontext.Value }. In ch06/agent/stream.go, line 17.
var yield func(agent.Delta, error) bool
var yield func(agent.Delta, error) bool. In ch06/openrouter/stream.go, line 61.
var ctx context.Context
var ctx context.Context. In ch06/openrouter/stream.go, line 62.
var cancel context.CancelCauseFunc
var cancel context.CancelCauseFunc. In ch06/openrouter/stream.go, line 62.
func WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc)
WithCancelCause behaves like [WithCancel] but returns a [CancelCauseFunc] instead of a [CancelFunc].
WithCancelCause behaves like [WithCancel] but returns a [CancelCauseFunc] instead of a [CancelFunc]. func WithCancelCause(parent Context) (ctx Context, cancel CancelCauseFunc). Documented at pkg.go.dev, context.WithCancelCause.
var idle *time.Timer
var idle *time.Timer. In ch06/openrouter/stream.go, line 64.
package time ("time")
Package time provides functionality for measuring and displaying time.
Package time provides functionality for measuring and displaying time. package time ("time"). Documented at pkg.go.dev, time.
func AfterFunc(d Duration, f func()) *Timer
AfterFunc waits for the duration to elapse and then calls f in its own goroutine.
AfterFunc waits for the duration to elapse and then calls f in its own goroutine. func AfterFunc(d Duration, f func()) *Timer. Documented at pkg.go.dev, time.AfterFunc.
func (c *Client) idleTimeout() time.Duration
func (c *Client) idleTimeout() time.Duration. In ch06/openrouter/client.go, line 281.
type idleReader struct {
r io.Reader
timer *time.Timer
timeout time.Duration
}
idleReader runs an idle timer only while it waits for the network, so the timer fires when the stream itself has gone quiet for the whole timeout, not when the program is busy with what it already has.
idleReader runs an idle timer only while it waits for the network, so the timer fires when the stream itself has gone quiet for the whole timeout, not when the program is busy with what it already has. type idleReader struct { r io.Reader timer *time.Timer timeout time.Duration }. In ch06/openrouter/sse.go, line 53.
package io ("io")
Package io provides basic interfaces to I/O primitives.
Package io provides basic interfaces to I/O primitives. package io ("io"). Documented at pkg.go.dev, io.
type Reader interface {
Read(p []byte) (n int, err error)
}
Reader is the interface that wraps the basic Read method.
Reader is the interface that wraps the basic Read method. type Reader interface { Read(p []byte) (n int, err error) }. Documented at pkg.go.dev, io.Reader.
field timer *time.Timer
field timer *time.Timer. In ch06/openrouter/sse.go, line 55.
package time ("time")
Package time provides functionality for measuring and displaying time.
Package time provides functionality for measuring and displaying time. package time ("time"). Documented at pkg.go.dev, time.
type Timer struct {
C <-chan Time
initTimer bool
}
The Timer type represents a single event.
The Timer type represents a single event. type Timer struct { C <-chan Time initTimer bool }. Documented at pkg.go.dev, time.Timer.
field timeout time.Duration
field timeout time.Duration. In ch06/openrouter/sse.go, line 56.
type Duration int64
A Duration represents the elapsed time between two instants as an int64 nanosecond count.
A Duration represents the elapsed time between two instants as an int64 nanosecond count. type Duration int64. Documented at pkg.go.dev, time.Duration.
func (ir *idleReader) Read(p []byte) (int, error)
func (ir *idleReader) Read(p []byte) (int, error). In ch06/openrouter/sse.go, line 59.
type byte = uint8
byte is an alias for uint8 and is equivalent to uint8 in all ways.
byte is an alias for uint8 and is equivalent to uint8 in all ways. type byte = uint8. Documented at pkg.go.dev, builtin.byte.
func (t *Timer) Reset(d Duration) bool
Reset changes the timer to expire after duration d.
Reset changes the timer to expire after duration d. func (t *Timer) Reset(d Duration) bool. Documented at pkg.go.dev, time.Timer.Reset.
func (Reader) Read(p []byte) (n int, err error)
func (Reader) Read(p []byte) (n int, err error). Documented at pkg.go.dev, io.Reader.Read.
type journal struct {
cp Checkpointer
st State // markers, run ID, restarts, as saved
res *Result // the run so far
extra []Message // answers to this reply, not in res yet
old map[string]bool // calls with markers from an earlier process
// unmarked holds calls whose marker couldn't be saved, so they
// never started. Written on a call's goroutine, read after its
// stage ends.
// ...
}
A journal keeps a run's checkpoint up to date as the loop goes (chapter 15).
A journal keeps a run's checkpoint up to date as the loop goes (chapter 15). type journal struct { cp Checkpointer st State // markers, run ID, restarts, as saved res *Result // the run so far extra []Message // answers to this reply, not in res yet old map[string]bool // calls with markers from an earlier process // unmarked holds calls whose marker couldn't be saved, so they // never started. Written on a call's goroutine, read after its // stage ends. // ... }. In ch15/agent/journal.go, line 17.
func (j *journal) save(ctx context.Context, phase Phase) error
save writes the run as it is now.
save writes the run as it is now. func (j *journal) save(ctx context.Context, phase Phase) error. In ch15/agent/journal.go, line 74.
var ctx context.Context
var ctx context.Context. In ch15/agent/journal.go, line 74.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
type Phase string
A Phase says what a saved run does next (chapter 15).
A Phase says what a saved run does next (chapter 15). type Phase string. In ch15/agent/state.go, line 20.
field cp Checkpointer
field cp Checkpointer. In ch15/agent/journal.go, line 18.
field st State
markers, run ID, restarts, as saved
markers, run ID, restarts, as saved field st State. In ch15/agent/journal.go, line 19.
const StateVersion = 1
StateVersion is the version of State this code writes.
StateVersion is the version of State this code writes. const StateVersion = 1. In ch15/agent/state.go, line 37.
field Messages []Message
the conversation, without unsettled answers
the conversation, without unsettled answers field Messages []Message. In ch15/agent/state.go, line 47.
func (j *journal) settledMessages() []Message
settledMessages is the conversation as a save writes it: without the answers that don't settle their calls.
settledMessages is the conversation as a save writes it: without the answers that don't settle their calls. func (j *journal) settledMessages() []Message. In ch15/agent/journal.go, line 95.
field Usage Usage
saved, so a restart can't reset
saved, so a restart can't reset field Usage Usage. In ch15/agent/state.go, line 48.
field Turns int
the cost budget or the turn limit
the cost budget or the turn limit field Turns int. In ch15/agent/state.go, line 49.
field res *Result
the run so far
the run so far field res *Result. In ch15/agent/journal.go, line 20.
field Usage Usage
the run's total, over every model call (chapter 5)
the run's total, over every model call (chapter 5) field Usage Usage. In ch15/agent/types.go, line 250.
field Turns int
Turns counts the model calls the run made, and Duration how long it ran (chapter 12).
Turns counts the model calls the run made, and Duration how long it ran (chapter 12). field Turns int. In ch15/agent/types.go, line 262.
field Context ContextState
the context policy's summary and cuts
the context policy's summary and cuts field Context ContextState. In ch15/agent/state.go, line 50.
field Final jsontext.Value
field Final jsontext.Value. In ch15/agent/state.go, line 51.
field Context ContextState
Context is the context policy's state when the run ended, such as its latest summary (chapter 8).
Context is the context policy's state when the run ended, such as its latest summary (chapter 8). field Context ContextState. In ch15/agent/types.go, line 258.
field Final jsontext.Value
Final holds the arguments of the final tool's successful call, the run's structured answer (chapter 7).
Final holds the arguments of the final tool's successful call, the run's structured answer (chapter 7). field Final jsontext.Value. In ch15/agent/types.go, line 254.
field Pending []ToolCall
calls waiting for a person
calls waiting for a person field Pending []ToolCall. In ch15/agent/state.go, line 52.
field Pending []ToolCall
Pending holds the calls a paused run left waiting: the one that needs a decision, and the calls after it in the same reply (chapter 14).
Pending holds the calls a paused run left waiting: the one that needs a decision, and the calls after it in the same reply (chapter 14). field Pending []ToolCall. In ch15/agent/types.go, line 268.
func (Checkpointer) Save(ctx context.Context, st State) error
func (Checkpointer) Save(ctx context.Context, st State) error. In ch15/agent/state.go, line 91.
func WithoutCancel(parent Context) Context
WithoutCancel returns a derived context that points to the parent context and is not canceled when parent is canceled.
WithoutCancel returns a derived context that points to the parent context and is not canceled when parent is canceled. func WithoutCancel(parent Context) Context. Documented at pkg.go.dev, context.WithoutCancel.
package fmt ("fmt")
Package fmt implements formatted I/O with functions analogous to C's printf and scanf.
Package fmt implements formatted I/O with functions analogous to C's printf and scanf. package fmt ("fmt"). Documented at pkg.go.dev, fmt.
func graced(ctx context.Context, d time.Duration) (context.Context,
func())
graced returns a context that ctx's cancellation reaches d late if its cause is ErrShutdown, and at once otherwise.
graced returns a context that ctx's cancellation reaches d late if its cause is ErrShutdown, and at once otherwise. func graced(ctx context.Context, d time.Duration) (context.Context, func()). In ch15/agent/shutdown.go, line 41.
var ctx context.Context
var ctx context.Context. In ch15/agent/shutdown.go, line 41.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
var d time.Duration
var d time.Duration. In ch15/agent/shutdown.go, line 41.
package time ("time")
Package time provides functionality for measuring and displaying time.
Package time provides functionality for measuring and displaying time. package time ("time"). Documented at pkg.go.dev, time.
var inner context.Context
var inner context.Context. In ch15/agent/shutdown.go, line 43.
var cancel context.CancelCauseFunc
var cancel context.CancelCauseFunc. In ch15/agent/shutdown.go, line 43.
var done chan struct{}
var done chan struct{}. In ch15/agent/shutdown.go, line 45.
package errors ("errors")
Package errors implements functions to manipulate errors.
Package errors implements functions to manipulate errors. package errors ("errors"). Documented at pkg.go.dev, errors.
var ErrShutdown = errors.New("agent: shutting down")
ErrShutdown is the cause set on a run's context when the process is asked to stop.
ErrShutdown is the cause set on a run's context when the process is asked to stop. var ErrShutdown = errors.New("agent: shutting down"). In ch15/agent/state.go, line 104.
func After(d Duration) <-chan Time
After waits for the duration to elapse and then sends the current time on the returned channel.
After waits for the duration to elapse and then sends the current time on the returned channel. func After(d Duration) <-chan Time. Documented at pkg.go.dev, time.After.
func close(c chan<- Type)
The close built-in function closes a channel, which must be either bidirectional or send-only.
The close built-in function closes a channel, which must be either bidirectional or send-only. func close(c chan<- Type). Documented at pkg.go.dev, builtin.close.
func TestTimeoutSynctest(t *testing.T)
TestTimeoutSynctest checks the call deadline with testing/synctest, whose fake clock lets a two-minute timeout pass instantly.
ch06/openrouter/client_test.go:401
TestTimeoutSynctest checks the call deadline with testing/synctest, whose fake clock lets a two-minute timeout pass instantly. func TestTimeoutSynctest(t *testing.T). In ch06/openrouter/client_test.go, line 401.
var t *testing.T
ch06/openrouter/client_test.go:401
var t *testing.T. In ch06/openrouter/client_test.go, line 401.
package testing ("testing")
Package testing provides support for automated testing of Go packages.
Package testing provides support for automated testing of Go packages. package testing ("testing"). Documented at pkg.go.dev, testing.
type T struct {
common
denyParallel bool
tstate *testState // For running tests and subtests.
}
T is a type passed to Test functions to manage test state and support formatted test logs.
T is a type passed to Test functions to manage test state and support formatted test logs. type T struct { common denyParallel bool tstate *testState // For running tests and subtests. }. Documented at pkg.go.dev, testing.T.
package synctest ("testing/synctest")
Package synctest provides support for testing concurrent code.
Package synctest provides support for testing concurrent code. package synctest ("testing/synctest"). Documented at pkg.go.dev, testing/synctest.
func Test(t *testing.T, f func(*testing.T))
Test executes f in a new bubble.
Test executes f in a new bubble. func Test(t *testing.T, f func(*testing.T)). Documented at pkg.go.dev, testing/synctest.Test.
var t *testing.T
ch06/openrouter/client_test.go:402
var t *testing.T. In ch06/openrouter/client_test.go, line 402.
var c *Client
ch06/openrouter/client_test.go:403
var c *Client. In ch06/openrouter/client_test.go, line 403.
field HTTP *http.Client
http.DefaultClient if nil
http.DefaultClient if nil field HTTP *http.Client. In ch06/openrouter/client.go, line 44.
package http ("net/http")
Package http provides HTTP client and server implementations.
Package http provides HTTP client and server implementations. package http ("net/http"). Documented at pkg.go.dev, net/http.
type Client struct {
// Transport specifies the mechanism by which individual
// HTTP requests are made.
// If nil, DefaultTransport is used.
Transport RoundTripper
// CheckRedirect specifies the policy for handling redirects.
// If CheckRedirect is not nil, the client calls it before
// following an HTTP redirect. The arguments req and via are
// the upcoming request and the requests made already, oldest
// ...
}
A Client is an HTTP client.
A Client is an HTTP client. type Client struct { // Transport specifies the mechanism by which individual // HTTP requests are made. // If nil, DefaultTransport is used. Transport RoundTripper // CheckRedirect specifies the policy for handling redirects. // If CheckRedirect is not nil, the client calls it before // following an HTTP redirect. The arguments req and via are // the upcoming request and the requests made already, oldest // ... }. Documented at pkg.go.dev, net/http.Client.
field Transport RoundTripper
Transport specifies the mechanism by which individual HTTP requests are made.
Transport specifies the mechanism by which individual HTTP requests are made. field Transport RoundTripper. Documented at pkg.go.dev, net/http.Client.Transport.
type blockingTransport struct{}
blockingTransport answers no request: it waits until the request's context is done.
ch06/openrouter/client_test.go:390
blockingTransport answers no request: it waits until the request's context is done. type blockingTransport struct{}. In ch06/openrouter/client_test.go, line 390.
var start time.Time
ch06/openrouter/client_test.go:404
var start time.Time. In ch06/openrouter/client_test.go, line 404.
package time ("time")
Package time provides functionality for measuring and displaying time.
Package time provides functionality for measuring and displaying time. package time ("time"). Documented at pkg.go.dev, time.
var err error
ch06/openrouter/client_test.go:405
var err error. In ch06/openrouter/client_test.go, line 405.
func (c *Client) Generate(ctx context.Context,
req agent.Request) (agent.Reply, error)
Generate sends the conversation to the model and returns its reply.
Generate sends the conversation to the model and returns its reply. func (c *Client) Generate(ctx context.Context, req agent.Request) (agent.Reply, error). In ch06/openrouter/client.go, line 62.
func (c *common) Context() context.Context
Context returns a context that is canceled just before Cleanup-registered functions are called.
Context returns a context that is canceled just before Cleanup-registered functions are called. func (c *common) Context() context.Context. Documented at pkg.go.dev, testing.common.Context.
package agent ("github.com/blackwell-systems/go-agents-book/code/ch06/agent")
Package agent is the agent loop and the types it works with.
Package agent is the agent loop and the types it works with. package agent ("github.com/blackwell-systems/go-agents-book/code/ch06/agent"). In ch06/agent.
package errors ("errors")
Package errors implements functions to manipulate errors.
Package errors implements functions to manipulate errors. package errors ("errors"). Documented at pkg.go.dev, errors.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
func (c *common) Errorf(format string, args ...any)
Errorf is equivalent to Logf followed by Fail.
Errorf is equivalent to Logf followed by Fail. func (c *common) Errorf(format string, args ...any). Documented at pkg.go.dev, testing.common.Errorf.
var d time.Duration
ch06/openrouter/client_test.go:410
var d time.Duration. In ch06/openrouter/client_test.go, line 410.
func Since(t Time) Duration
Since returns the time elapsed since t.
Since returns the time elapsed since t. func Since(t Time) Duration. Documented at pkg.go.dev, time.Since.
const Minute = 60 * Second
const Minute = 60 * Second. Documented at pkg.go.dev, time.Minute.
type callKey struct{}
callKey carries the tool call a tool is running for, so a wrapper can name it; Tool.Run sees only the arguments.
callKey carries the tool call a tool is running for, so a wrapper can name it; Tool.Run sees only the arguments. type callKey struct{}. In ch12/agent/traced.go, line 14.
func CallFrom(ctx context.Context) (ToolCall, bool)
CallFrom returns the tool call the context's tool is running for.
CallFrom returns the tool call the context's tool is running for. func CallFrom(ctx context.Context) (ToolCall, bool). In ch12/agent/traced.go, line 17.
var ctx context.Context
var ctx context.Context. In ch12/agent/traced.go, line 17.
package context ("context")
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes.
Package context defines the Context type, which carries deadlines, cancellation signals, and other request-scoped values across API boundaries and between processes. package context ("context"). Documented at pkg.go.dev, context.
type ToolCall struct {
ID string
Name string
Arguments jsontext.Value // JSON the model wrote; may be invalid
}
ToolCall is the model asking the harness to run a tool.
ToolCall is the model asking the harness to run a tool. type ToolCall struct { ID string Name string Arguments jsontext.Value // JSON the model wrote; may be invalid }. In ch12/agent/types.go, line 82.
func (Context) Value(key any) any
Value returns the value associated with this context for key, or nil if no value is associated with key.
Value returns the value associated with this context for key, or nil if no value is associated with key. func (Context) Value(key any) any. Documented at pkg.go.dev, context.Context.Value.
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
WithCancel returns a derived context that points to the parent context but has a new Done channel.
WithCancel returns a derived context that points to the parent context but has a new Done channel. func WithCancel(parent Context) (ctx Context, cancel CancelFunc). Documented at pkg.go.dev, context.WithCancel.
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)).
WithTimeout returns WithDeadline(parent, time.Now().Add(timeout)). func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc). Documented at pkg.go.dev, context.WithTimeout.
func TODO() Context
TODO returns a non-nil, empty [Context].
TODO returns a non-nil, empty [Context]. func TODO() Context. Documented at pkg.go.dev, context.TODO.
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc)
WithDeadline returns a derived context that points to the parent context but has the deadline adjusted to be no later than d.
WithDeadline returns a derived context that points to the parent context but has the deadline adjusted to be no later than d. func WithDeadline(parent Context, d time.Time) (Context, CancelFunc). Documented at pkg.go.dev, context.WithDeadline.
func Until(t Time) Duration
Until returns the duration until t.
Until returns the duration until t. func Until(t Time) Duration. Documented at pkg.go.dev, time.Until.
func Sleep(d Duration)
Sleep pauses the current goroutine for at least the duration d.
Sleep pauses the current goroutine for at least the duration d. func Sleep(d Duration). Documented at pkg.go.dev, time.Sleep.