on main help sign in
chore: update vendor dependencies
commit11959dcd0b775cf6425cca3cb377c74d8b1e1f9c authorAyman Bagabas <ayman.bagabas@gmail.com> dateMon 7 Jul 2025, 10:05 (1 year ago) parentc668772
135 files changed+30756−9673
vendor/github.com/charmbracelet/bubbletea/v2/tea.go+4−11 vendor/github.com/charmbracelet/lipgloss/v2/get.go+1 vendor/github.com/charmbracelet/ultraviolet/LICENSE+5 vendor/github.com/charmbracelet/ultraviolet/README.md+5−11 vendor/github.com/charmbracelet/ultraviolet/terminal_renderer.go+26−26 vendor/github.com/charmbracelet/ultraviolet/terminal_renderer_hashmap.go+1−7 vendor/github.com/charmbracelet/ultraviolet/tty.go+5 vendor/github.com/charmbracelet/ultraviolet/tty_other.go+4 vendor/github.com/charmbracelet/ultraviolet/tty_unix.go+15−1 vendor/github.com/charmbracelet/ultraviolet/tty_windows.go+6 vendor/github.com/mark3labs/mcp-go/client/client.go+425−75 vendor/github.com/mark3labs/mcp-go/client/http.go+17 vendor/github.com/mark3labs/mcp-go/client/inprocess.go+12 vendor/github.com/mark3labs/mcp-go/client/interface.go+109 vendor/github.com/mark3labs/mcp-go/client/oauth.go+76 vendor/github.com/mark3labs/mcp-go/client/sse.go+17−563 vendor/github.com/mark3labs/mcp-go/client/stdio.go+17−415 vendor/github.com/mark3labs/mcp-go/client/transport/inprocess.go+70 vendor/github.com/mark3labs/mcp-go/client/transport/interface.go+50 vendor/github.com/mark3labs/mcp-go/client/transport/oauth.go+650 vendor/github.com/mark3labs/mcp-go/client/transport/oauth_utils.go+68 vendor/github.com/mark3labs/mcp-go/client/transport/sse.go+522 vendor/github.com/mark3labs/mcp-go/client/transport/stdio.go+288 vendor/github.com/mark3labs/mcp-go/client/transport/streamable_http.go+515 vendor/github.com/mark3labs/mcp-go/client/types.go−8 vendor/github.com/mark3labs/mcp-go/mcp/prompts.go+14−7 vendor/github.com/mark3labs/mcp-go/mcp/resources.go+2−8 vendor/github.com/mark3labs/mcp-go/mcp/tools.go+565−77 vendor/github.com/mark3labs/mcp-go/mcp/typed_tools.go+20 vendor/github.com/mark3labs/mcp-go/mcp/types.go+351−167 vendor/github.com/mark3labs/mcp-go/mcp/utils.go+231−15 vendor/github.com/mark3labs/mcp-go/server/errors.go+34 vendor/github.com/mark3labs/mcp-go/server/hooks.go+532 vendor/github.com/mark3labs/mcp-go/server/http_transport_options.go+11 vendor/github.com/mark3labs/mcp-go/server/request_handler.go+320 vendor/github.com/mark3labs/mcp-go/server/server.go+1079 vendor/github.com/mark3labs/mcp-go/server/session.go+380 vendor/github.com/mark3labs/mcp-go/server/sse.go+736 vendor/github.com/mark3labs/mcp-go/server/stdio.go+314 vendor/github.com/mark3labs/mcp-go/server/streamable_http.go+653 vendor/github.com/mark3labs/mcp-go/util/logger.go+33 vendor/github.com/openai/openai-go/.release-please-manifest.json+1−1 vendor/github.com/openai/openai-go/.stats.yml+4−2 vendor/github.com/openai/openai-go/CHANGELOG.md+352 vendor/github.com/openai/openai-go/CONTRIBUTING.md+1−1 vendor/github.com/openai/openai-go/MIGRATION.md+14−14 vendor/github.com/openai/openai-go/README.md+219−79 vendor/github.com/openai/openai-go/SECURITY.md+2−2 vendor/github.com/openai/openai-go/aliases.go+76−24 vendor/github.com/openai/openai-go/api.md+170−2 vendor/github.com/openai/openai-go/audiospeech.go+24−11 vendor/github.com/openai/openai-go/audiotranscription.go+332−54 vendor/github.com/openai/openai-go/audiotranslation.go+8−10 vendor/github.com/openai/openai-go/batch.go+43−52 vendor/github.com/openai/openai-go/beta.go+2−1 vendor/github.com/openai/openai-go/betaassistant.go+413−401 vendor/github.com/openai/openai-go/betathread.go+257−403 vendor/github.com/openai/openai-go/betathreadmessage.go+308−313 vendor/github.com/openai/openai-go/betathreadrun.go+133−171 vendor/github.com/openai/openai-go/betathreadrunstep.go+270−238 vendor/github.com/openai/openai-go/chatcompletion.go+457−537 vendor/github.com/openai/openai-go/chatcompletionmessage.go+1−5 vendor/github.com/openai/openai-go/client.go+25−10 vendor/github.com/openai/openai-go/completion.go+70−62 vendor/github.com/openai/openai-go/container.go+352 vendor/github.com/openai/openai-go/containerfile.go+286 vendor/github.com/openai/openai-go/containerfilecontent.go+49 vendor/github.com/openai/openai-go/embedding.go+27−30 vendor/github.com/openai/openai-go/file.go+22−29 vendor/github.com/openai/openai-go/finetuning.go+8−2 vendor/github.com/openai/openai-go/finetuningalpha.go+28 vendor/github.com/openai/openai-go/finetuningalphagrader.go+672 vendor/github.com/openai/openai-go/finetuningcheckpoint.go+28 vendor/github.com/openai/openai-go/finetuningcheckpointpermission.go+254 vendor/github.com/openai/openai-go/finetuningjob.go+160−796 vendor/github.com/openai/openai-go/finetuningjobcheckpoint.go+20−28 vendor/github.com/openai/openai-go/finetuningmethod.go+1487 vendor/github.com/openai/openai-go/grader.go+28 vendor/github.com/openai/openai-go/gradergradermodel.go+1179 vendor/github.com/openai/openai-go/image.go+386−89 vendor/github.com/openai/openai-go/internal/apierror/apierror.go+7−8 vendor/github.com/openai/openai-go/internal/apiform/encoder.go+96−32 vendor/github.com/openai/openai-go/internal/apiform/richparam.go+6−6 vendor/github.com/openai/openai-go/internal/apijson/decoder.go+91−79 vendor/github.com/openai/openai-go/internal/apijson/encoder.go+3−9 vendor/github.com/openai/openai-go/internal/apijson/enum.go+91−33 vendor/github.com/openai/openai-go/internal/apijson/registry.go+11−2 vendor/github.com/openai/openai-go/internal/apijson/subfield.go+9−9 vendor/github.com/openai/openai-go/internal/apijson/union.go+111−10 vendor/github.com/openai/openai-go/internal/apiquery/encoder.go+115−59 vendor/github.com/openai/openai-go/internal/apiquery/query.go+11−6 vendor/github.com/openai/openai-go/internal/apiquery/richparam.go+9−9 vendor/github.com/openai/openai-go/internal/encoding/json/encode.go+3−10 vendor/github.com/openai/openai-go/internal/encoding/json/sentinel/null.go+25−36 vendor/github.com/openai/openai-go/internal/encoding/json/time.go+12−10 vendor/github.com/openai/openai-go/internal/param/field.go−27 vendor/github.com/openai/openai-go/internal/paramutil/field.go+30 vendor/github.com/openai/openai-go/packages/param/union.go → vendor/github.com/openai/openai-go/internal/paramutil/union.go+3−2 vendor/github.com/openai/openai-go/internal/requestconfig/requestconfig.go+60−18 vendor/github.com/openai/openai-go/internal/version.go+1−1 vendor/github.com/openai/openai-go/model.go+12−14 vendor/github.com/openai/openai-go/moderation.go+108−102 vendor/github.com/openai/openai-go/option/middleware.go+38 vendor/github.com/openai/openai-go/option/requestoption.go+55−14 vendor/github.com/openai/openai-go/packages/pagination/pagination.go+21−13 vendor/github.com/openai/openai-go/packages/param/encoder.go+33−57 vendor/github.com/openai/openai-go/packages/param/null.go+19 vendor/github.com/openai/openai-go/packages/param/option.go+73−55 vendor/github.com/openai/openai-go/packages/param/param.go+109−48 vendor/github.com/openai/openai-go/packages/param/sentinel.go−31 vendor/github.com/openai/openai-go/packages/resp/resp.go−56 vendor/github.com/openai/openai-go/packages/respjson/respjson.go+88 vendor/github.com/openai/openai-go/packages/ssestream/ssestream.go+8−4 vendor/github.com/openai/openai-go/polling.go+2−41 vendor/github.com/openai/openai-go/responses/aliases.go+76−24 vendor/github.com/openai/openai-go/responses/inputitem.go+14−16 vendor/github.com/openai/openai-go/responses/response.go+8769−3514 vendor/github.com/openai/openai-go/shared/constant/constants.go+346−145 vendor/github.com/openai/openai-go/shared/shared.go+171−123 vendor/github.com/openai/openai-go/streamaccumulator.go+6−6 vendor/github.com/openai/openai-go/upload.go+18−21 vendor/github.com/openai/openai-go/uploadpart.go+11−14 vendor/github.com/openai/openai-go/vectorstore.go+129−150 vendor/github.com/openai/openai-go/vectorstorefile.go+43−57 vendor/github.com/openai/openai-go/vectorstorefilebatch.go+24−35 vendor/github.com/openai/openai-go/webhooks/aliases.go+440 vendor/github.com/openai/openai-go/webhooks/webhook.go+1208 vendor/github.com/spf13/cast/.gitignore+25 vendor/github.com/spf13/cast/LICENSE+21 vendor/github.com/spf13/cast/Makefile+40 vendor/github.com/spf13/cast/README.md+75 vendor/github.com/spf13/cast/cast.go+176 vendor/github.com/spf13/cast/caste.go+1510 vendor/github.com/spf13/cast/timeformattype_string.go+27 vendor/modules.txt+16−9
vendor/github.com/charmbracelet/bubbletea/v2/tea.go+4−11
@@ -83,13 +83,6 @@ type ViewableModel interface {
8383 View() View
8484}
8585
86−// StyledString returns a [Layer] that can be styled with ANSI escape
87−// codes. It is used to render text with different colors, styles, and other
88−// attributes on the terminal screen.
89−func StyledString(s string) *uv.StyledString {
90− return uv.NewStyledString(s)
91−}
92−
9386// Buffer represents a terminal cell buffer that defines the current state of
9487// the terminal screen.
9588type Buffer = uv.Buffer
@@ -127,13 +120,13 @@ func NewView(s any) View {
127120 var view View
128121 switch v := s.(type) {
129122 case string:
130− view.Layer = StyledString(v)
123+ view.Layer = uv.NewStyledString(v)
131124 case fmt.Stringer:
132− view.Layer = StyledString(v.String())
125+ view.Layer = uv.NewStyledString(v.String())
133126 case Layer:
134127 view.Layer = v
135128 default:
136− view.Layer = StyledString(fmt.Sprintf("%v", v))
129+ view.Layer = uv.NewStyledString(fmt.Sprintf("%v", v))
137130 }
138131 return view
139132}
@@ -867,7 +860,7 @@ func (p *Program) render(model Model) {
867860 case CursorModel:
868861 frame, view.Cursor = model.View()
869862 }
870− view.Layer = StyledString(frame)
863+ view.Layer = uv.NewStyledString(frame)
871864 view.BackgroundColor = p.lastBgColor
872865 view.ForegroundColor = p.lastFgColor
873866 view.WindowTitle = p.lastWindowTitle
vendor/github.com/charmbracelet/lipgloss/v2/get.go+1
@@ -543,6 +543,7 @@ func (s Style) getAsTransform(propKey) func(string) string {
543543// line.
544544func getLines(s string) (lines []string, widest int) {
545545 s = strings.ReplaceAll(s, "\t", " ")
546+ s = strings.ReplaceAll(s, "\r\n", "\n")
546547 lines = strings.Split(s, "\n")
547548
548549 for _, l := range lines {
vendor/github.com/charmbracelet/ultraviolet/LICENSEnew file+5
@@ -0,0 +1,5 @@
1+Copyright © 2025 Charmbracelet, Inc.
2+
3+This project is currently in development and is not yet licensed for public use.
4+
5+All rights reserved. No license is granted at this time.
vendor/github.com/charmbracelet/ultraviolet/README.md+5−11
@@ -9,18 +9,12 @@
99> [!CAUTION]
1010> This project is in very early development and may change significantly at any moment. Expect no API guarantees as of now.
1111
12−Ultraviolet is a Go library for building text-based applications with a focus
13−on terminal user interfaces (TUIs). It provides a set of tools and abstractions
14−to create interactive terminal applications that can handle user input and
15−display dynamic content in a cell-based manner.
12+Ultraviolet is a set of of primitives for manipulating terminal emulators with
13+a focus on terminal user interfaces (TUIs). It provides a set of tools and
14+abstractions for interactive terminal applications that can handle user input
15+and display dynamic, cell-based content.
1616
17−## Installation
18−
19−To install UV, you can simply run in your Go project:
20−
21−```bash
22−go get github.com/charmbracelet/ultraviolet
23−```
17+[Ultraviolet is not yet licensed.](https://github.com/charmbracelet/ultraviolet/raw/main/LICENSE)
2418
2519---
2620
vendor/github.com/charmbracelet/ultraviolet/terminal_renderer.go+26−26
@@ -378,7 +378,10 @@ func (s *TerminalRenderer) moveCursor(newbuf *Buffer, x, y int, overwrite bool)
378378 s.buf.WriteByte('\r') //nolint:errcheck
379379 s.cur.X, s.cur.Y = 0, 0
380380 }
381− s.buf.WriteString(moveCursor(s, newbuf, x, y, overwrite)) //nolint:errcheck
381+ seq, scrollHeight := moveCursor(s, newbuf, x, y, overwrite)
382+ // If we scrolled the screen, we need to update the scroll height.
383+ s.scrollHeight = max(s.scrollHeight, scrollHeight)
384+ s.buf.WriteString(seq) //nolint:errcheck
382385 s.cur.X, s.cur.Y = x, y
383386}
384387
@@ -1316,13 +1319,11 @@ func notLocal(cols, fx, fy, tx, ty int) bool {
13161319//
13171320// It is safe to call this function with a nil [Buffer]. In that case, it won't
13181321// use any optimizations that require the new buffer such as overwrite.
1319−func relativeCursorMove(s *TerminalRenderer, newbuf *Buffer, fx, fy, tx, ty int, overwrite, useTabs, useBackspace bool) string {
1322+func relativeCursorMove(s *TerminalRenderer, newbuf *Buffer, fx, fy, tx, ty int, overwrite, useTabs, useBackspace bool) (string, int) {
13201323 var seq strings.Builder
1321− height := -1
1324+ var scrollHeight int
13221325 if newbuf == nil {
13231326 overwrite = false // We can't overwrite the current buffer.
1324− } else {
1325− height = newbuf.Height()
13261327 }
13271328
13281329 if ty != fy {
@@ -1331,21 +1332,15 @@ func relativeCursorMove(s *TerminalRenderer, newbuf *Buffer, fx, fy, tx, ty int,
13311332 yseq = ansi.VerticalPositionAbsolute(ty + 1)
13321333 }
13331334
1334− // OPTIM: Use [ansi.LF] and [ansi.ReverseIndex] as optimizations.
1335−
13361335 if ty > fy {
13371336 n := ty - fy
13381337 if cud := ansi.CursorDown(n); yseq == "" || len(cud) < len(yseq) {
13391338 yseq = cud
13401339 }
13411340 shouldScroll := !s.flags.Contains(tAltScreen) && ty > s.scrollHeight
1342− if shouldScroll && ty == s.scrollHeight && ty < height {
1343− n = min(n, height-1-ty)
1344− }
1345− if lf := strings.Repeat("\n", n); shouldScroll ||
1346− ((ty < height || height == -1) && len(lf) < len(yseq)) {
1341+ if lf := strings.Repeat("\n", n); shouldScroll || len(lf) < len(yseq) {
13471342 yseq = lf
1348− s.scrollHeight = max(s.scrollHeight, ty)
1343+ scrollHeight = ty
13491344 if s.flags.Contains(tMapNewline) {
13501345 fx = 0
13511346 }
@@ -1468,7 +1463,7 @@ func relativeCursorMove(s *TerminalRenderer, newbuf *Buffer, fx, fy, tx, ty int,
14681463 seq.WriteString(xseq)
14691464 }
14701465
1471− return seq.String()
1466+ return seq.String(), scrollHeight
14721467}
14731468
14741469// moveCursor moves and returns the cursor movement sequence to move the cursor
@@ -1478,7 +1473,7 @@ func relativeCursorMove(s *TerminalRenderer, newbuf *Buffer, fx, fy, tx, ty int,
14781473//
14791474// It is safe to call this function with a nil [Buffer]. In that case, it won't
14801475// use any optimizations that require the new buffer such as overwrite.
1481−func moveCursor(s *TerminalRenderer, newbuf *Buffer, x, y int, overwrite bool) (seq string) {
1476+func moveCursor(s *TerminalRenderer, newbuf *Buffer, x, y int, overwrite bool) (seq string, scrollHeight int) {
14821477 fx, fy := s.cur.X, s.cur.Y
14831478
14841479 if !s.flags.Contains(tRelativeCursor) {
@@ -1496,7 +1491,7 @@ func moveCursor(s *TerminalRenderer, newbuf *Buffer, x, y int, overwrite bool) (
14961491 // Method #0: Use [ansi.CUP] if the distance is long.
14971492 seq = ansi.CursorPosition(x+1, y+1)
14981493 if fx == -1 || fy == -1 || width == -1 || notLocal(width, fx, fy, x, y) {
1499− return
1494+ return seq, 0
15001495 }
15011496 }
15021497
@@ -1520,27 +1515,32 @@ func moveCursor(s *TerminalRenderer, newbuf *Buffer, x, y int, overwrite bool) (
15201515 useBackspace := i&1 != 0
15211516
15221517 // Method #1: Use local movement sequences.
1523− nseq := relativeCursorMove(s, newbuf, fx, fy, x, y, overwrite, useHardTabs, useBackspace)
1524− if (i == 0 && len(seq) == 0) || len(nseq) < len(seq) {
1525− seq = nseq
1518+ nseq1, nscrollHeight1 := relativeCursorMove(s, newbuf, fx, fy, x, y, overwrite, useHardTabs, useBackspace)
1519+ if (i == 0 && len(seq) == 0) || len(nseq1) < len(seq) {
1520+ seq = nseq1
1521+ scrollHeight = max(scrollHeight, nscrollHeight1)
15261522 }
15271523
15281524 // Method #2: Use [ansi.CR] and local movement sequences.
1529− nseq = "\r" + relativeCursorMove(s, newbuf, 0, fy, x, y, overwrite, useHardTabs, useBackspace)
1530− if len(nseq) < len(seq) {
1531− seq = nseq
1525+ nseq2, nscrollHeight2 := relativeCursorMove(s, newbuf, 0, fy, x, y, overwrite, useHardTabs, useBackspace)
1526+ nseq2 = "\r" + nseq2
1527+ if len(nseq2) < len(seq) {
1528+ seq = nseq2
1529+ scrollHeight = max(scrollHeight, nscrollHeight2)
15321530 }
15331531
15341532 if !s.flags.Contains(tRelativeCursor) {
15351533 // Method #3: Use [ansi.CursorHomePosition] and local movement sequences.
1536− nseq = ansi.CursorHomePosition + relativeCursorMove(s, newbuf, 0, 0, x, y, overwrite, useHardTabs, useBackspace)
1537− if len(nseq) < len(seq) {
1538− seq = nseq
1534+ nseq3, nscrollHeight3 := relativeCursorMove(s, newbuf, 0, 0, x, y, overwrite, useHardTabs, useBackspace)
1535+ nseq3 = ansi.CursorHomePosition + nseq3
1536+ if len(nseq3) < len(seq) {
1537+ seq = nseq3
1538+ scrollHeight = max(scrollHeight, nscrollHeight3)
15391539 }
15401540 }
15411541 }
15421542
1543− return
1543+ return seq, scrollHeight
15441544}
15451545
15461546// xtermCaps returns whether the terminal is xterm-like. This means that the
vendor/github.com/charmbracelet/ultraviolet/terminal_renderer_hashmap.go+1−7
@@ -24,9 +24,6 @@ const newIndex = -1
2424// updateHashmap updates the hashmap with the new hash value.
2525func (s *TerminalRenderer) updateHashmap(newbuf *Buffer) {
2626 height := newbuf.Height()
27− if s.hashtab == nil || height >= len(s.hashtab) {
28− s.hashtab = make([]hashmap, (height+1)*2)
29− }
3027
3128 if len(s.oldhash) >= height && len(s.newhash) >= height {
3229 // rehash changed lines
@@ -53,10 +50,7 @@ func (s *TerminalRenderer) updateHashmap(newbuf *Buffer) {
5350 }
5451 }
5552
56− for i := 0; i < len(s.hashtab); i++ {
57− s.hashtab[i] = hashmap{}
58− }
59−
53+ s.hashtab = make([]hashmap, (height+1)*2)
6054 for i := 0; i < height; i++ {
6155 hashval := s.oldhash[i]
6256
vendor/github.com/charmbracelet/ultraviolet/tty.go+5
@@ -11,3 +11,8 @@ import "os"
1111func OpenTTY() (inTty, outTty *os.File, err error) {
1212 return openTTY()
1313}
14+
15+// Suspend suspends the current process group.
16+func Suspend() error {
17+ return suspend()
18+}
vendor/github.com/charmbracelet/ultraviolet/tty_other.go+4
@@ -8,3 +8,7 @@ import "os"
88func openTTY() (*os.File, *os.File, error) {
99 return nil, nil, ErrPlatformNotSupported
1010}
11+
12+func suspend() error {
13+ return ErrPlatformNotSupported
14+}
vendor/github.com/charmbracelet/ultraviolet/tty_unix.go+15−1
@@ -3,7 +3,11 @@
33
44package uv
55
6−import "os"
6+import (
7+ "os"
8+ "os/signal"
9+ "syscall"
10+)
711
812func openTTY() (inTty, outTty *os.File, err error) {
913 f, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
@@ -12,3 +16,13 @@ func openTTY() (inTty, outTty *os.File, err error) {
1216 }
1317 return f, f, nil
1418}
19+
20+func suspend() (err error) {
21+ // Send SIGTSTP to the entire process group.
22+ c := make(chan os.Signal, 1)
23+ signal.Notify(c, syscall.SIGCONT)
24+ err = syscall.Kill(0, syscall.SIGTSTP)
25+ // blocks until a CONT happens...
26+ <-c
27+ return
28+}
vendor/github.com/charmbracelet/ultraviolet/tty_windows.go+6
@@ -19,3 +19,9 @@ func openTTY() (inTty, outTty *os.File, err error) {
1919 }
2020 return inTty, outTty, nil
2121}
22+
23+func suspend() (err error) {
24+ // On Windows, suspending the process group is not supported in the same
25+ // way as Unix-like systems.
26+ return nil
27+}
vendor/github.com/mark3labs/mcp-go/client/client.go+425−75
@@ -1,84 +1,434 @@
1−// Package client provides MCP (Model Control Protocol) client implementations.
21package client
32
43import (
54 "context"
5+ "encoding/json"
6+ "errors"
7+ "fmt"
8+ "sync"
9+ "sync/atomic"
610
11+ "github.com/mark3labs/mcp-go/client/transport"
712 "github.com/mark3labs/mcp-go/mcp"
813)
914
10−// MCPClient represents an MCP client interface
11−type MCPClient interface {
12− // Initialize sends the initial connection request to the server
13− Initialize(
14− ctx context.Context,
15− request mcp.InitializeRequest,
16− ) (*mcp.InitializeResult, error)
17−
18− // Ping checks if the server is alive
19− Ping(ctx context.Context) error
20−
21− // ListResources requests a list of available resources from the server
22− ListResources(
23− ctx context.Context,
24− request mcp.ListResourcesRequest,
25− ) (*mcp.ListResourcesResult, error)
26−
27− // ListResourceTemplates requests a list of available resource templates from the server
28− ListResourceTemplates(
29− ctx context.Context,
30− request mcp.ListResourceTemplatesRequest,
31− ) (*mcp.ListResourceTemplatesResult,
32− error)
33−
34− // ReadResource reads a specific resource from the server
35− ReadResource(
36− ctx context.Context,
37− request mcp.ReadResourceRequest,
38− ) (*mcp.ReadResourceResult, error)
39−
40− // Subscribe requests notifications for changes to a specific resource
41− Subscribe(ctx context.Context, request mcp.SubscribeRequest) error
42−
43− // Unsubscribe cancels notifications for a specific resource
44− Unsubscribe(ctx context.Context, request mcp.UnsubscribeRequest) error
45−
46− // ListPrompts requests a list of available prompts from the server
47− ListPrompts(
48− ctx context.Context,
49− request mcp.ListPromptsRequest,
50− ) (*mcp.ListPromptsResult, error)
51−
52− // GetPrompt retrieves a specific prompt from the server
53− GetPrompt(
54− ctx context.Context,
55− request mcp.GetPromptRequest,
56− ) (*mcp.GetPromptResult, error)
57−
58− // ListTools requests a list of available tools from the server
59− ListTools(
60− ctx context.Context,
61− request mcp.ListToolsRequest,
62− ) (*mcp.ListToolsResult, error)
63−
64− // CallTool invokes a specific tool on the server
65− CallTool(
66− ctx context.Context,
67− request mcp.CallToolRequest,
68− ) (*mcp.CallToolResult, error)
69−
70− // SetLevel sets the logging level for the server
71− SetLevel(ctx context.Context, request mcp.SetLevelRequest) error
72−
73− // Complete requests completion options for a given argument
74− Complete(
75− ctx context.Context,
76− request mcp.CompleteRequest,
77− ) (*mcp.CompleteResult, error)
78−
79− // Close client connection and cleanup resources
80− Close() error
81−
82− // OnNotification registers a handler for notifications
83− OnNotification(handler func(notification mcp.JSONRPCNotification))
15+// Client implements the MCP client.
16+type Client struct {
17+ transport transport.Interface
18+
19+ initialized bool
20+ notifications []func(mcp.JSONRPCNotification)
21+ notifyMu sync.RWMutex
22+ requestID atomic.Int64
23+ clientCapabilities mcp.ClientCapabilities
24+ serverCapabilities mcp.ServerCapabilities
25+}
26+
27+type ClientOption func(*Client)
28+
29+// WithClientCapabilities sets the client capabilities for the client.
30+func WithClientCapabilities(capabilities mcp.ClientCapabilities) ClientOption {
31+ return func(c *Client) {
32+ c.clientCapabilities = capabilities
33+ }
34+}
35+
36+// NewClient creates a new MCP client with the given transport.
37+// Usage:
38+//
39+// stdio := transport.NewStdio("./mcp_server", nil, "xxx")
40+// client, err := NewClient(stdio)
41+// if err != nil {
42+// log.Fatalf("Failed to create client: %v", err)
43+// }
44+func NewClient(transport transport.Interface, options ...ClientOption) *Client {
45+ client := &Client{
46+ transport: transport,
47+ }
48+
49+ for _, opt := range options {
50+ opt(client)
51+ }
52+
53+ return client
54+}
55+
56+// Start initiates the connection to the server.
57+// Must be called before using the client.
58+func (c *Client) Start(ctx context.Context) error {
59+ if c.transport == nil {
60+ return fmt.Errorf("transport is nil")
61+ }
62+ err := c.transport.Start(ctx)
63+ if err != nil {
64+ return err
65+ }
66+
67+ c.transport.SetNotificationHandler(func(notification mcp.JSONRPCNotification) {
68+ c.notifyMu.RLock()
69+ defer c.notifyMu.RUnlock()
70+ for _, handler := range c.notifications {
71+ handler(notification)
72+ }
73+ })
74+ return nil
75+}
76+
77+// Close shuts down the client and closes the transport.
78+func (c *Client) Close() error {
79+ return c.transport.Close()
80+}
81+
82+// OnNotification registers a handler function to be called when notifications are received.
83+// Multiple handlers can be registered and will be called in the order they were added.
84+func (c *Client) OnNotification(
85+ handler func(notification mcp.JSONRPCNotification),
86+) {
87+ c.notifyMu.Lock()
88+ defer c.notifyMu.Unlock()
89+ c.notifications = append(c.notifications, handler)
90+}
91+
92+// sendRequest sends a JSON-RPC request to the server and waits for a response.
93+// Returns the raw JSON response message or an error if the request fails.
94+func (c *Client) sendRequest(
95+ ctx context.Context,
96+ method string,
97+ params any,
98+) (*json.RawMessage, error) {
99+ if !c.initialized && method != "initialize" {
100+ return nil, fmt.Errorf("client not initialized")
101+ }
102+
103+ id := c.requestID.Add(1)
104+
105+ request := transport.JSONRPCRequest{
106+ JSONRPC: mcp.JSONRPC_VERSION,
107+ ID: mcp.NewRequestId(id),
108+ Method: method,
109+ Params: params,
110+ }
111+
112+ response, err := c.transport.SendRequest(ctx, request)
113+ if err != nil {
114+ return nil, fmt.Errorf("transport error: %w", err)
115+ }
116+
117+ if response.Error != nil {
118+ return nil, errors.New(response.Error.Message)
119+ }
120+
121+ return &response.Result, nil
122+}
123+
124+// Initialize negotiates with the server.
125+// Must be called after Start, and before any request methods.
126+func (c *Client) Initialize(
127+ ctx context.Context,
128+ request mcp.InitializeRequest,
129+) (*mcp.InitializeResult, error) {
130+ // Ensure we send a params object with all required fields
131+ params := struct {
132+ ProtocolVersion string `json:"protocolVersion"`
133+ ClientInfo mcp.Implementation `json:"clientInfo"`
134+ Capabilities mcp.ClientCapabilities `json:"capabilities"`
135+ }{
136+ ProtocolVersion: request.Params.ProtocolVersion,
137+ ClientInfo: request.Params.ClientInfo,
138+ Capabilities: request.Params.Capabilities, // Will be empty struct if not set
139+ }
140+
141+ response, err := c.sendRequest(ctx, "initialize", params)
142+ if err != nil {
143+ return nil, err
144+ }
145+
146+ var result mcp.InitializeResult
147+ if err := json.Unmarshal(*response, &result); err != nil {
148+ return nil, fmt.Errorf("failed to unmarshal response: %w", err)
149+ }
150+
151+ // Store serverCapabilities
152+ c.serverCapabilities = result.Capabilities
153+
154+ // Send initialized notification
155+ notification := mcp.JSONRPCNotification{
156+ JSONRPC: mcp.JSONRPC_VERSION,
157+ Notification: mcp.Notification{
158+ Method: "notifications/initialized",
159+ },
160+ }
161+
162+ err = c.transport.SendNotification(ctx, notification)
163+ if err != nil {
164+ return nil, fmt.Errorf(
165+ "failed to send initialized notification: %w",
166+ err,
167+ )
168+ }
169+
170+ c.initialized = true
171+ return &result, nil
172+}
173+
174+func (c *Client) Ping(ctx context.Context) error {
175+ _, err := c.sendRequest(ctx, "ping", nil)
176+ return err
177+}
178+
179+// ListResourcesByPage manually list resources by page.
180+func (c *Client) ListResourcesByPage(
181+ ctx context.Context,
182+ request mcp.ListResourcesRequest,
183+) (*mcp.ListResourcesResult, error) {
184+ result, err := listByPage[mcp.ListResourcesResult](ctx, c, request.PaginatedRequest, "resources/list")
185+ if err != nil {
186+ return nil, err
187+ }
188+ return result, nil
189+}
190+
191+func (c *Client) ListResources(
192+ ctx context.Context,
193+ request mcp.ListResourcesRequest,
194+) (*mcp.ListResourcesResult, error) {
195+ result, err := c.ListResourcesByPage(ctx, request)
196+ if err != nil {
197+ return nil, err
198+ }
199+ for result.NextCursor != "" {
200+ select {
201+ case <-ctx.Done():
202+ return nil, ctx.Err()
203+ default:
204+ request.Params.Cursor = result.NextCursor
205+ newPageRes, err := c.ListResourcesByPage(ctx, request)
206+ if err != nil {
207+ return nil, err
208+ }
209+ result.Resources = append(result.Resources, newPageRes.Resources...)
210+ result.NextCursor = newPageRes.NextCursor
211+ }
212+ }
213+ return result, nil
214+}
215+
216+func (c *Client) ListResourceTemplatesByPage(
217+ ctx context.Context,
218+ request mcp.ListResourceTemplatesRequest,
219+) (*mcp.ListResourceTemplatesResult, error) {
220+ result, err := listByPage[mcp.ListResourceTemplatesResult](ctx, c, request.PaginatedRequest, "resources/templates/list")
221+ if err != nil {
222+ return nil, err
223+ }
224+ return result, nil
225+}
226+
227+func (c *Client) ListResourceTemplates(
228+ ctx context.Context,
229+ request mcp.ListResourceTemplatesRequest,
230+) (*mcp.ListResourceTemplatesResult, error) {
231+ result, err := c.ListResourceTemplatesByPage(ctx, request)
232+ if err != nil {
233+ return nil, err
234+ }
235+ for result.NextCursor != "" {
236+ select {
237+ case <-ctx.Done():
238+ return nil, ctx.Err()
239+ default:
240+ request.Params.Cursor = result.NextCursor
241+ newPageRes, err := c.ListResourceTemplatesByPage(ctx, request)
242+ if err != nil {
243+ return nil, err
244+ }
245+ result.ResourceTemplates = append(result.ResourceTemplates, newPageRes.ResourceTemplates...)
246+ result.NextCursor = newPageRes.NextCursor
247+ }
248+ }
249+ return result, nil
250+}
251+
252+func (c *Client) ReadResource(
253+ ctx context.Context,
254+ request mcp.ReadResourceRequest,
255+) (*mcp.ReadResourceResult, error) {
256+ response, err := c.sendRequest(ctx, "resources/read", request.Params)
257+ if err != nil {
258+ return nil, err
259+ }
260+
261+ return mcp.ParseReadResourceResult(response)
262+}
263+
264+func (c *Client) Subscribe(
265+ ctx context.Context,
266+ request mcp.SubscribeRequest,
267+) error {
268+ _, err := c.sendRequest(ctx, "resources/subscribe", request.Params)
269+ return err
270+}
271+
272+func (c *Client) Unsubscribe(
273+ ctx context.Context,
274+ request mcp.UnsubscribeRequest,
275+) error {
276+ _, err := c.sendRequest(ctx, "resources/unsubscribe", request.Params)
277+ return err
278+}
279+
280+func (c *Client) ListPromptsByPage(
281+ ctx context.Context,
282+ request mcp.ListPromptsRequest,
283+) (*mcp.ListPromptsResult, error) {
284+ result, err := listByPage[mcp.ListPromptsResult](ctx, c, request.PaginatedRequest, "prompts/list")
285+ if err != nil {
286+ return nil, err
287+ }
288+ return result, nil
289+}
290+
291+func (c *Client) ListPrompts(
292+ ctx context.Context,
293+ request mcp.ListPromptsRequest,
294+) (*mcp.ListPromptsResult, error) {
295+ result, err := c.ListPromptsByPage(ctx, request)
296+ if err != nil {
297+ return nil, err
298+ }
299+ for result.NextCursor != "" {
300+ select {
301+ case <-ctx.Done():
302+ return nil, ctx.Err()
303+ default:
304+ request.Params.Cursor = result.NextCursor
305+ newPageRes, err := c.ListPromptsByPage(ctx, request)
306+ if err != nil {
307+ return nil, err
308+ }
309+ result.Prompts = append(result.Prompts, newPageRes.Prompts...)
310+ result.NextCursor = newPageRes.NextCursor
311+ }
312+ }
313+ return result, nil
314+}
315+
316+func (c *Client) GetPrompt(
317+ ctx context.Context,
318+ request mcp.GetPromptRequest,
319+) (*mcp.GetPromptResult, error) {
320+ response, err := c.sendRequest(ctx, "prompts/get", request.Params)
321+ if err != nil {
322+ return nil, err
323+ }
324+
325+ return mcp.ParseGetPromptResult(response)
326+}
327+
328+func (c *Client) ListToolsByPage(
329+ ctx context.Context,
330+ request mcp.ListToolsRequest,
331+) (*mcp.ListToolsResult, error) {
332+ result, err := listByPage[mcp.ListToolsResult](ctx, c, request.PaginatedRequest, "tools/list")
333+ if err != nil {
334+ return nil, err
335+ }
336+ return result, nil
337+}
338+
339+func (c *Client) ListTools(
340+ ctx context.Context,
341+ request mcp.ListToolsRequest,
342+) (*mcp.ListToolsResult, error) {
343+ result, err := c.ListToolsByPage(ctx, request)
344+ if err != nil {
345+ return nil, err
346+ }
347+ for result.NextCursor != "" {
348+ select {
349+ case <-ctx.Done():
350+ return nil, ctx.Err()
351+ default:
352+ request.Params.Cursor = result.NextCursor
353+ newPageRes, err := c.ListToolsByPage(ctx, request)
354+ if err != nil {
355+ return nil, err
356+ }
357+ result.Tools = append(result.Tools, newPageRes.Tools...)
358+ result.NextCursor = newPageRes.NextCursor
359+ }
360+ }
361+ return result, nil
362+}
363+
364+func (c *Client) CallTool(
365+ ctx context.Context,
366+ request mcp.CallToolRequest,
367+) (*mcp.CallToolResult, error) {
368+ response, err := c.sendRequest(ctx, "tools/call", request.Params)
369+ if err != nil {
370+ return nil, err
371+ }
372+
373+ return mcp.ParseCallToolResult(response)
374+}
375+
376+func (c *Client) SetLevel(
377+ ctx context.Context,
378+ request mcp.SetLevelRequest,
379+) error {
380+ _, err := c.sendRequest(ctx, "logging/setLevel", request.Params)
381+ return err
382+}
383+
384+func (c *Client) Complete(
385+ ctx context.Context,
386+ request mcp.CompleteRequest,
387+) (*mcp.CompleteResult, error) {
388+ response, err := c.sendRequest(ctx, "completion/complete", request.Params)
389+ if err != nil {
390+ return nil, err
391+ }
392+
393+ var result mcp.CompleteResult
394+ if err := json.Unmarshal(*response, &result); err != nil {
395+ return nil, fmt.Errorf("failed to unmarshal response: %w", err)
396+ }
397+
398+ return &result, nil
399+}
400+
401+func listByPage[T any](
402+ ctx context.Context,
403+ client *Client,
404+ request mcp.PaginatedRequest,
405+ method string,
406+) (*T, error) {
407+ response, err := client.sendRequest(ctx, method, request.Params)
408+ if err != nil {
409+ return nil, err
410+ }
411+ var result T
412+ if err := json.Unmarshal(*response, &result); err != nil {
413+ return nil, fmt.Errorf("failed to unmarshal response: %w", err)
414+ }
415+ return &result, nil
416+}
417+
418+// Helper methods
419+
420+// GetTransport gives access to the underlying transport layer.
421+// Cast it to the specific transport type and obtain the other helper methods.
422+func (c *Client) GetTransport() transport.Interface {
423+ return c.transport
424+}
425+
426+// GetServerCapabilities returns the server capabilities.
427+func (c *Client) GetServerCapabilities() mcp.ServerCapabilities {
428+ return c.serverCapabilities
429+}
430+
431+// GetClientCapabilities returns the client capabilities.
432+func (c *Client) GetClientCapabilities() mcp.ClientCapabilities {
433+ return c.clientCapabilities
84434}
vendor/github.com/mark3labs/mcp-go/client/http.gonew file+17
@@ -0,0 +1,17 @@
1+package client
2+
3+import (
4+ "fmt"
5+
6+ "github.com/mark3labs/mcp-go/client/transport"
7+)
8+
9+// NewStreamableHttpClient is a convenience method that creates a new streamable-http-based MCP client
10+// with the given base URL. Returns an error if the URL is invalid.
11+func NewStreamableHttpClient(baseURL string, options ...transport.StreamableHTTPCOption) (*Client, error) {
12+ trans, err := transport.NewStreamableHTTP(baseURL, options...)
13+ if err != nil {
14+ return nil, fmt.Errorf("failed to create SSE transport: %w", err)
15+ }
16+ return NewClient(trans), nil
17+}
vendor/github.com/mark3labs/mcp-go/client/inprocess.gonew file+12
@@ -0,0 +1,12 @@
1+package client
2+
3+import (
4+ "github.com/mark3labs/mcp-go/client/transport"
5+ "github.com/mark3labs/mcp-go/server"
6+)
7+
8+// NewInProcessClient connect directly to a mcp server object in the same process
9+func NewInProcessClient(server *server.MCPServer) (*Client, error) {
10+ inProcessTransport := transport.NewInProcessTransport(server)
11+ return NewClient(inProcessTransport), nil
12+}
vendor/github.com/mark3labs/mcp-go/client/interface.gonew file+109
@@ -0,0 +1,109 @@
1+// Package client provides MCP (Model Context Protocol) client implementations.
2+package client
3+
4+import (
5+ "context"
6+
7+ "github.com/mark3labs/mcp-go/mcp"
8+)
9+
10+// MCPClient represents an MCP client interface
11+type MCPClient interface {
12+ // Initialize sends the initial connection request to the server
13+ Initialize(
14+ ctx context.Context,
15+ request mcp.InitializeRequest,
16+ ) (*mcp.InitializeResult, error)
17+
18+ // Ping checks if the server is alive
19+ Ping(ctx context.Context) error
20+
21+ // ListResourcesByPage manually list resources by page.
22+ ListResourcesByPage(
23+ ctx context.Context,
24+ request mcp.ListResourcesRequest,
25+ ) (*mcp.ListResourcesResult, error)
26+
27+ // ListResources requests a list of available resources from the server
28+ ListResources(
29+ ctx context.Context,
30+ request mcp.ListResourcesRequest,
31+ ) (*mcp.ListResourcesResult, error)
32+
33+ // ListResourceTemplatesByPage manually list resource templates by page.
34+ ListResourceTemplatesByPage(
35+ ctx context.Context,
36+ request mcp.ListResourceTemplatesRequest,
37+ ) (*mcp.ListResourceTemplatesResult,
38+ error)
39+
40+ // ListResourceTemplates requests a list of available resource templates from the server
41+ ListResourceTemplates(
42+ ctx context.Context,
43+ request mcp.ListResourceTemplatesRequest,
44+ ) (*mcp.ListResourceTemplatesResult,
45+ error)
46+
47+ // ReadResource reads a specific resource from the server
48+ ReadResource(
49+ ctx context.Context,
50+ request mcp.ReadResourceRequest,
51+ ) (*mcp.ReadResourceResult, error)
52+
53+ // Subscribe requests notifications for changes to a specific resource
54+ Subscribe(ctx context.Context, request mcp.SubscribeRequest) error
55+
56+ // Unsubscribe cancels notifications for a specific resource
57+ Unsubscribe(ctx context.Context, request mcp.UnsubscribeRequest) error
58+
59+ // ListPromptsByPage manually list prompts by page.
60+ ListPromptsByPage(
61+ ctx context.Context,
62+ request mcp.ListPromptsRequest,
63+ ) (*mcp.ListPromptsResult, error)
64+
65+ // ListPrompts requests a list of available prompts from the server
66+ ListPrompts(
67+ ctx context.Context,
68+ request mcp.ListPromptsRequest,
69+ ) (*mcp.ListPromptsResult, error)
70+
71+ // GetPrompt retrieves a specific prompt from the server
72+ GetPrompt(
73+ ctx context.Context,
74+ request mcp.GetPromptRequest,
75+ ) (*mcp.GetPromptResult, error)
76+
77+ // ListToolsByPage manually list tools by page.
78+ ListToolsByPage(
79+ ctx context.Context,
80+ request mcp.ListToolsRequest,
81+ ) (*mcp.ListToolsResult, error)
82+
83+ // ListTools requests a list of available tools from the server
84+ ListTools(
85+ ctx context.Context,
86+ request mcp.ListToolsRequest,
87+ ) (*mcp.ListToolsResult, error)
88+
89+ // CallTool invokes a specific tool on the server
90+ CallTool(
91+ ctx context.Context,
92+ request mcp.CallToolRequest,
93+ ) (*mcp.CallToolResult, error)
94+
95+ // SetLevel sets the logging level for the server
96+ SetLevel(ctx context.Context, request mcp.SetLevelRequest) error
97+
98+ // Complete requests completion options for a given argument
99+ Complete(
100+ ctx context.Context,
101+ request mcp.CompleteRequest,
102+ ) (*mcp.CompleteResult, error)
103+
104+ // Close client connection and cleanup resources
105+ Close() error
106+
107+ // OnNotification registers a handler for notifications
108+ OnNotification(handler func(notification mcp.JSONRPCNotification))
109+}
vendor/github.com/mark3labs/mcp-go/client/oauth.gonew file+76
@@ -0,0 +1,76 @@
1+package client
2+
3+import (
4+ "errors"
5+ "fmt"
6+
7+ "github.com/mark3labs/mcp-go/client/transport"
8+)
9+
10+// OAuthConfig is a convenience type that wraps transport.OAuthConfig
11+type OAuthConfig = transport.OAuthConfig
12+
13+// Token is a convenience type that wraps transport.Token
14+type Token = transport.Token
15+
16+// TokenStore is a convenience type that wraps transport.TokenStore
17+type TokenStore = transport.TokenStore
18+
19+// MemoryTokenStore is a convenience type that wraps transport.MemoryTokenStore
20+type MemoryTokenStore = transport.MemoryTokenStore
21+
22+// NewMemoryTokenStore is a convenience function that wraps transport.NewMemoryTokenStore
23+var NewMemoryTokenStore = transport.NewMemoryTokenStore
24+
25+// NewOAuthStreamableHttpClient creates a new streamable-http-based MCP client with OAuth support.
26+// Returns an error if the URL is invalid.
27+func NewOAuthStreamableHttpClient(baseURL string, oauthConfig OAuthConfig, options ...transport.StreamableHTTPCOption) (*Client, error) {
28+ // Add OAuth option to the list of options
29+ options = append(options, transport.WithHTTPOAuth(oauthConfig))
30+
31+ trans, err := transport.NewStreamableHTTP(baseURL, options...)
32+ if err != nil {
33+ return nil, fmt.Errorf("failed to create HTTP transport: %w", err)
34+ }
35+ return NewClient(trans), nil
36+}
37+
38+// NewOAuthStreamableHttpClient creates a new streamable-http-based MCP client with OAuth support.
39+// Returns an error if the URL is invalid.
40+func NewOAuthSSEClient(baseURL string, oauthConfig OAuthConfig, options ...transport.ClientOption) (*Client, error) {
41+ // Add OAuth option to the list of options
42+ options = append(options, transport.WithOAuth(oauthConfig))
43+
44+ trans, err := transport.NewSSE(baseURL, options...)
45+ if err != nil {
46+ return nil, fmt.Errorf("failed to create SSE transport: %w", err)
47+ }
48+ return NewClient(trans), nil
49+}
50+
51+// GenerateCodeVerifier generates a code verifier for PKCE
52+var GenerateCodeVerifier = transport.GenerateCodeVerifier
53+
54+// GenerateCodeChallenge generates a code challenge from a code verifier
55+var GenerateCodeChallenge = transport.GenerateCodeChallenge
56+
57+// GenerateState generates a state parameter for OAuth
58+var GenerateState = transport.GenerateState
59+
60+// OAuthAuthorizationRequiredError is returned when OAuth authorization is required
61+type OAuthAuthorizationRequiredError = transport.OAuthAuthorizationRequiredError
62+
63+// IsOAuthAuthorizationRequiredError checks if an error is an OAuthAuthorizationRequiredError
64+func IsOAuthAuthorizationRequiredError(err error) bool {
65+ var target *OAuthAuthorizationRequiredError
66+ return errors.As(err, &target)
67+}
68+
69+// GetOAuthHandler extracts the OAuthHandler from an OAuthAuthorizationRequiredError
70+func GetOAuthHandler(err error) *transport.OAuthHandler {
71+ var oauthErr *OAuthAuthorizationRequiredError
72+ if errors.As(err, &oauthErr) {
73+ return oauthErr.Handler
74+ }
75+ return nil
76+}
vendor/github.com/mark3labs/mcp-go/client/sse.go+17−563
@@ -1,588 +1,42 @@
11package client
22
33import (
4− "bufio"
5− "bytes"
6− "context"
7− "encoding/json"
8− "errors"
94 "fmt"
10− "io"
115 "net/http"
126 "net/url"
13− "strings"
14− "sync"
15− "sync/atomic"
16− "time"
177
18− "github.com/mark3labs/mcp-go/mcp"
8+ "github.com/mark3labs/mcp-go/client/transport"
199)
2010
21−// SSEMCPClient implements the MCPClient interface using Server-Sent Events (SSE).
22−// It maintains a persistent HTTP connection to receive server-pushed events
23−// while sending requests over regular HTTP POST calls. The client handles
24−// automatic reconnection and message routing between requests and responses.
25−type SSEMCPClient struct {
26− baseURL *url.URL
27− endpoint *url.URL
28− httpClient *http.Client
29− requestID atomic.Int64
30− responses map[int64]chan RPCResponse
31− mu sync.RWMutex
32− done chan struct{}
33− initialized bool
34− notifications []func(mcp.JSONRPCNotification)
35− notifyMu sync.RWMutex
36− endpointChan chan struct{}
37− capabilities mcp.ServerCapabilities
38− headers map[string]string
39− sseReadTimeout time.Duration
11+func WithHeaders(headers map[string]string) transport.ClientOption {
12+ return transport.WithHeaders(headers)
4013}
4114
42−type ClientOption func(*SSEMCPClient)
43−
44−func WithHeaders(headers map[string]string) ClientOption {
45− return func(sc *SSEMCPClient) {
46− sc.headers = headers
47− }
15+func WithHeaderFunc(headerFunc transport.HTTPHeaderFunc) transport.ClientOption {
16+ return transport.WithHeaderFunc(headerFunc)
4817}
4918
50−func WithSSEReadTimeout(timeout time.Duration) ClientOption {
51− return func(sc *SSEMCPClient) {
52− sc.sseReadTimeout = timeout
53− }
19+func WithHTTPClient(httpClient *http.Client) transport.ClientOption {
20+ return transport.WithHTTPClient(httpClient)
5421}
5522
5623// NewSSEMCPClient creates a new SSE-based MCP client with the given base URL.
5724// Returns an error if the URL is invalid.
58−func NewSSEMCPClient(baseURL string, options ...ClientOption) (*SSEMCPClient, error) {
59− parsedURL, err := url.Parse(baseURL)
60− if err != nil {
61− return nil, fmt.Errorf("invalid URL: %w", err)
62− }
63−
64− smc := &SSEMCPClient{
65− baseURL: parsedURL,
66− httpClient: &http.Client{},
67− responses: make(map[int64]chan RPCResponse),
68− done: make(chan struct{}),
69− endpointChan: make(chan struct{}),
70− sseReadTimeout: 30 * time.Second,
71− headers: make(map[string]string),
72− }
73−
74− for _, opt := range options {
75− opt(smc)
76− }
77−
78− return smc, nil
79−}
80−
81−// Start initiates the SSE connection to the server and waits for the endpoint information.
82−// Returns an error if the connection fails or times out waiting for the endpoint.
83−func (c *SSEMCPClient) Start(ctx context.Context) error {
84−
85− req, err := http.NewRequestWithContext(ctx, "GET", c.baseURL.String(), nil)
86−
87− if err != nil {
88−
89− return fmt.Errorf("failed to create request: %w", err)
90−
91− }
92−
93− req.Header.Set("Accept", "text/event-stream")
94− req.Header.Set("Cache-Control", "no-cache")
95− req.Header.Set("Connection", "keep-alive")
96−
97− resp, err := c.httpClient.Do(req)
98− if err != nil {
99− return fmt.Errorf("failed to connect to SSE stream: %w", err)
100− }
101−
102− if resp.StatusCode != http.StatusOK {
103− resp.Body.Close()
104− return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
105− }
106−
107− go c.readSSE(resp.Body)
108−
109− // Wait for the endpoint to be received
110−
111− select {
112− case <-c.endpointChan:
113− // Endpoint received, proceed
114− case <-ctx.Done():
115− return fmt.Errorf("context cancelled while waiting for endpoint")
116− case <-time.After(30 * time.Second): // Add a timeout
117− return fmt.Errorf("timeout waiting for endpoint")
118− }
119−
120− return nil
121−}
122−
123−// readSSE continuously reads the SSE stream and processes events.
124−// It runs until the connection is closed or an error occurs.
125−func (c *SSEMCPClient) readSSE(reader io.ReadCloser) {
126− defer reader.Close()
127−
128− br := bufio.NewReader(reader)
129− var event, data string
130−
131− ctx, cancel := context.WithTimeout(context.Background(), c.sseReadTimeout)
132− defer cancel()
133−
134− for {
135− select {
136− case <-ctx.Done():
137− return
138− default:
139− line, err := br.ReadString('\n')
140− if err != nil {
141− if err == io.EOF {
142− // Process any pending event before exit
143− if event != "" && data != "" {
144− c.handleSSEEvent(event, data)
145− }
146− break
147− }
148− select {
149− case <-c.done:
150− return
151− default:
152− fmt.Printf("SSE stream error: %v\n", err)
153− return
154− }
155− }
156−
157− // Remove only newline markers
158− line = strings.TrimRight(line, "\r\n")
159− if line == "" {
160− // Empty line means end of event
161− if event != "" && data != "" {
162− c.handleSSEEvent(event, data)
163− event = ""
164− data = ""
165− }
166− continue
167− }
168−
169− if strings.HasPrefix(line, "event:") {
170− event = strings.TrimSpace(strings.TrimPrefix(line, "event:"))
171− } else if strings.HasPrefix(line, "data:") {
172− data = strings.TrimSpace(strings.TrimPrefix(line, "data:"))
173− }
174− }
175− }
176−}
177−
178−// handleSSEEvent processes SSE events based on their type.
179−// Handles 'endpoint' events for connection setup and 'message' events for JSON-RPC communication.
180−func (c *SSEMCPClient) handleSSEEvent(event, data string) {
181− switch event {
182− case "endpoint":
183− endpoint, err := c.baseURL.Parse(data)
184− if err != nil {
185− fmt.Printf("Error parsing endpoint URL: %v\n", err)
186− return
187− }
188− if endpoint.Host != c.baseURL.Host {
189− fmt.Printf("Endpoint origin does not match connection origin\n")
190− return
191− }
192− c.endpoint = endpoint
193− close(c.endpointChan)
194−
195− case "message":
196− var baseMessage struct {
197− JSONRPC string `json:"jsonrpc"`
198− ID *int64 `json:"id,omitempty"`
199− Method string `json:"method,omitempty"`
200− Result json.RawMessage `json:"result,omitempty"`
201− Error *struct {
202− Code int `json:"code"`
203− Message string `json:"message"`
204− } `json:"error,omitempty"`
205− }
206−
207− if err := json.Unmarshal([]byte(data), &baseMessage); err != nil {
208− fmt.Printf("Error unmarshaling message: %v\n", err)
209− return
210− }
211−
212− // Handle notification
213− if baseMessage.ID == nil {
214− var notification mcp.JSONRPCNotification
215− if err := json.Unmarshal([]byte(data), &notification); err != nil {
216− return
217− }
218− c.notifyMu.RLock()
219− for _, handler := range c.notifications {
220− handler(notification)
221− }
222− c.notifyMu.RUnlock()
223− return
224− }
225−
226− c.mu.RLock()
227− ch, ok := c.responses[*baseMessage.ID]
228− c.mu.RUnlock()
229−
230− if ok {
231− if baseMessage.Error != nil {
232− ch <- RPCResponse{
233− Error: &baseMessage.Error.Message,
234− }
235− } else {
236− ch <- RPCResponse{
237− Response: &baseMessage.Result,
238− }
239− }
240− c.mu.Lock()
241− delete(c.responses, *baseMessage.ID)
242− c.mu.Unlock()
243− }
244− }
245−}
246−
247−// OnNotification registers a handler function to be called when notifications are received.
248−// Multiple handlers can be registered and will be called in the order they were added.
249−func (c *SSEMCPClient) OnNotification(
250− handler func(notification mcp.JSONRPCNotification),
251−) {
252− c.notifyMu.Lock()
253− defer c.notifyMu.Unlock()
254− c.notifications = append(c.notifications, handler)
255−}
256−
257−// sendRequest sends a JSON-RPC request to the server and waits for a response.
258−// Returns the raw JSON response message or an error if the request fails.
259−func (c *SSEMCPClient) sendRequest(
260− ctx context.Context,
261− method string,
262− params interface{},
263−) (*json.RawMessage, error) {
264− if !c.initialized && method != "initialize" {
265− return nil, fmt.Errorf("client not initialized")
266− }
267−
268− if c.endpoint == nil {
269− return nil, fmt.Errorf("endpoint not received")
270− }
271−
272− id := c.requestID.Add(1)
273−
274− request := mcp.JSONRPCRequest{
275− JSONRPC: mcp.JSONRPC_VERSION,
276− ID: id,
277− Request: mcp.Request{
278− Method: method,
279− },
280− Params: params,
281− }
282−
283− requestBytes, err := json.Marshal(request)
284− if err != nil {
285− return nil, fmt.Errorf("failed to marshal request: %w", err)
286− }
287−
288− responseChan := make(chan RPCResponse, 1)
289− c.mu.Lock()
290− c.responses[id] = responseChan
291− c.mu.Unlock()
292−
293− req, err := http.NewRequestWithContext(
294− ctx,
295− "POST",
296− c.endpoint.String(),
297− bytes.NewReader(requestBytes),
298− )
299− if err != nil {
300− return nil, fmt.Errorf("failed to create request: %w", err)
301− }
302−
303− req.Header.Set("Content-Type", "application/json")
304− // set custom http headers
305− for k, v := range c.headers {
306− req.Header.Set(k, v)
307− }
308−
309− resp, err := c.httpClient.Do(req)
310− if err != nil {
311− return nil, fmt.Errorf("failed to send request: %w", err)
312− }
313− defer resp.Body.Close()
314−
315− if resp.StatusCode != http.StatusOK &&
316− resp.StatusCode != http.StatusAccepted {
317− body, _ := io.ReadAll(resp.Body)
318− return nil, fmt.Errorf(
319− "request failed with status %d: %s",
320− resp.StatusCode,
321− body,
322− )
323− }
324−
325− select {
326− case <-ctx.Done():
327− c.mu.Lock()
328− delete(c.responses, id)
329− c.mu.Unlock()
330− return nil, ctx.Err()
331− case response := <-responseChan:
332− if response.Error != nil {
333− return nil, errors.New(*response.Error)
334− }
335− return response.Response, nil
336− }
337−}
338−
339−func (c *SSEMCPClient) Initialize(
340− ctx context.Context,
341− request mcp.InitializeRequest,
342−) (*mcp.InitializeResult, error) {
343− // Ensure we send a params object with all required fields
344− params := struct {
345− ProtocolVersion string `json:"protocolVersion"`
346− ClientInfo mcp.Implementation `json:"clientInfo"`
347− Capabilities mcp.ClientCapabilities `json:"capabilities"`
348− }{
349− ProtocolVersion: request.Params.ProtocolVersion,
350− ClientInfo: request.Params.ClientInfo,
351− Capabilities: request.Params.Capabilities, // Will be empty struct if not set
352− }
353−
354− response, err := c.sendRequest(ctx, "initialize", params)
355− if err != nil {
356− return nil, err
357− }
25+func NewSSEMCPClient(baseURL string, options ...transport.ClientOption) (*Client, error) {
35826
359− var result mcp.InitializeResult
360− if err := json.Unmarshal(*response, &result); err != nil {
361− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
362− }
363−
364− // Store capabilities
365− c.capabilities = result.Capabilities
366−
367− // Send initialized notification
368− notification := mcp.JSONRPCNotification{
369− JSONRPC: mcp.JSONRPC_VERSION,
370− Notification: mcp.Notification{
371− Method: "notifications/initialized",
372− },
373− }
374−
375− notificationBytes, err := json.Marshal(notification)
376− if err != nil {
377− return nil, fmt.Errorf(
378− "failed to marshal initialized notification: %w",
379− err,
380− )
381− }
382−
383− req, err := http.NewRequestWithContext(
384− ctx,
385− "POST",
386− c.endpoint.String(),
387− bytes.NewReader(notificationBytes),
388− )
389− if err != nil {
390− return nil, fmt.Errorf("failed to create notification request: %w", err)
391− }
392−
393− req.Header.Set("Content-Type", "application/json")
394−
395− resp, err := c.httpClient.Do(req)
27+ sseTransport, err := transport.NewSSE(baseURL, options...)
39628 if err != nil {
397− return nil, fmt.Errorf(
398− "failed to send initialized notification: %w",
399− err,
400− )
29+ return nil, fmt.Errorf("failed to create SSE transport: %w", err)
40130 }
402− resp.Body.Close()
40331
404− c.initialized = true
405− return &result, nil
32+ return NewClient(sseTransport), nil
40633}
40734
408−func (c *SSEMCPClient) Ping(ctx context.Context) error {
409− _, err := c.sendRequest(ctx, "ping", nil)
410− return err
411−}
412−
413−func (c *SSEMCPClient) ListResources(
414− ctx context.Context,
415− request mcp.ListResourcesRequest,
416−) (*mcp.ListResourcesResult, error) {
417− response, err := c.sendRequest(ctx, "resources/list", request.Params)
418− if err != nil {
419− return nil, err
420− }
421−
422− var result mcp.ListResourcesResult
423− if err := json.Unmarshal(*response, &result); err != nil {
424− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
425− }
426−
427− return &result, nil
428−}
429−
430−func (c *SSEMCPClient) ListResourceTemplates(
431− ctx context.Context,
432− request mcp.ListResourceTemplatesRequest,
433−) (*mcp.ListResourceTemplatesResult, error) {
434− response, err := c.sendRequest(
435− ctx,
436− "resources/templates/list",
437− request.Params,
438− )
439− if err != nil {
440− return nil, err
441− }
442−
443− var result mcp.ListResourceTemplatesResult
444− if err := json.Unmarshal(*response, &result); err != nil {
445− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
446− }
447−
448− return &result, nil
449−}
450−
451−func (c *SSEMCPClient) ReadResource(
452− ctx context.Context,
453− request mcp.ReadResourceRequest,
454−) (*mcp.ReadResourceResult, error) {
455− response, err := c.sendRequest(ctx, "resources/read", request.Params)
456− if err != nil {
457− return nil, err
458− }
459−
460− return mcp.ParseReadResourceResult(response)
461−}
462−
463−func (c *SSEMCPClient) Subscribe(
464− ctx context.Context,
465− request mcp.SubscribeRequest,
466−) error {
467− _, err := c.sendRequest(ctx, "resources/subscribe", request.Params)
468− return err
469−}
470−
471−func (c *SSEMCPClient) Unsubscribe(
472− ctx context.Context,
473− request mcp.UnsubscribeRequest,
474−) error {
475− _, err := c.sendRequest(ctx, "resources/unsubscribe", request.Params)
476− return err
477−}
478−
479−func (c *SSEMCPClient) ListPrompts(
480− ctx context.Context,
481− request mcp.ListPromptsRequest,
482−) (*mcp.ListPromptsResult, error) {
483− response, err := c.sendRequest(ctx, "prompts/list", request.Params)
484− if err != nil {
485− return nil, err
486− }
487−
488− var result mcp.ListPromptsResult
489− if err := json.Unmarshal(*response, &result); err != nil {
490− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
491− }
492−
493− return &result, nil
494−}
495−
496−func (c *SSEMCPClient) GetPrompt(
497− ctx context.Context,
498− request mcp.GetPromptRequest,
499−) (*mcp.GetPromptResult, error) {
500− response, err := c.sendRequest(ctx, "prompts/get", request.Params)
501− if err != nil {
502− return nil, err
503− }
504−
505− return mcp.ParseGetPromptResult(response)
506−}
507−
508−func (c *SSEMCPClient) ListTools(
509− ctx context.Context,
510− request mcp.ListToolsRequest,
511−) (*mcp.ListToolsResult, error) {
512− response, err := c.sendRequest(ctx, "tools/list", request.Params)
513− if err != nil {
514− return nil, err
515− }
516−
517− var result mcp.ListToolsResult
518− if err := json.Unmarshal(*response, &result); err != nil {
519− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
520− }
521−
522− return &result, nil
523−}
524−
525−func (c *SSEMCPClient) CallTool(
526− ctx context.Context,
527− request mcp.CallToolRequest,
528−) (*mcp.CallToolResult, error) {
529− response, err := c.sendRequest(ctx, "tools/call", request.Params)
530− if err != nil {
531− return nil, err
532− }
533−
534− return mcp.ParseCallToolResult(response)
535−}
536−
537−func (c *SSEMCPClient) SetLevel(
538− ctx context.Context,
539− request mcp.SetLevelRequest,
540−) error {
541− _, err := c.sendRequest(ctx, "logging/setLevel", request.Params)
542− return err
543−}
544−
545−func (c *SSEMCPClient) Complete(
546− ctx context.Context,
547− request mcp.CompleteRequest,
548−) (*mcp.CompleteResult, error) {
549− response, err := c.sendRequest(ctx, "completion/complete", request.Params)
550− if err != nil {
551− return nil, err
552− }
553−
554− var result mcp.CompleteResult
555− if err := json.Unmarshal(*response, &result); err != nil {
556− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
557− }
558−
559− return &result, nil
560−}
561−
562−// Helper methods
563−
56435// GetEndpoint returns the current endpoint URL for the SSE connection.
565−func (c *SSEMCPClient) GetEndpoint() *url.URL {
566− return c.endpoint
567−}
568−
569−// Close shuts down the SSE client connection and cleans up any pending responses.
570−// Returns an error if the shutdown process fails.
571−func (c *SSEMCPClient) Close() error {
572− select {
573− case <-c.done:
574− return nil // Already closed
575− default:
576− close(c.done)
577− }
578−
579− // Clean up any pending responses
580− c.mu.Lock()
581− for _, ch := range c.responses {
582− close(ch)
583− }
584− c.responses = make(map[int64]chan RPCResponse)
585− c.mu.Unlock()
586−
587− return nil
36+//
37+// Note: This method only works with SSE transport, or it will panic.
38+func GetEndpoint(c *Client) *url.URL {
39+ t := c.GetTransport()
40+ sse := t.(*transport.SSE)
41+ return sse.GetEndpoint()
58842}
vendor/github.com/mark3labs/mcp-go/client/stdio.go+17−415
@@ -1,441 +1,43 @@
11package client
22
33import (
4− "bufio"
54 "context"
6− "encoding/json"
7− "errors"
85 "fmt"
96 "io"
10− "os"
11− "os/exec"
12− "sync"
13− "sync/atomic"
147
15− "github.com/mark3labs/mcp-go/mcp"
8+ "github.com/mark3labs/mcp-go/client/transport"
169)
1710
18−// StdioMCPClient implements the MCPClient interface using stdio communication.
19−// It launches a subprocess and communicates with it via standard input/output streams
20−// using JSON-RPC messages. The client handles message routing between requests and
21−// responses, and supports asynchronous notifications.
22−type StdioMCPClient struct {
23− cmd *exec.Cmd
24− stdin io.WriteCloser
25− stdout *bufio.Reader
26− requestID atomic.Int64
27− responses map[int64]chan RPCResponse
28− mu sync.RWMutex
29− done chan struct{}
30− initialized bool
31− notifications []func(mcp.JSONRPCNotification)
32− notifyMu sync.RWMutex
33− capabilities mcp.ServerCapabilities
34−}
35−
3611// NewStdioMCPClient creates a new stdio-based MCP client that communicates with a subprocess.
3712// It launches the specified command with given arguments and sets up stdin/stdout pipes for communication.
3813// Returns an error if the subprocess cannot be started or the pipes cannot be created.
14+//
15+// NOTICE: NewStdioMCPClient will start the connection automatically. Don't call the Start method manually.
16+// This is for backward compatibility.
3917func NewStdioMCPClient(
4018 command string,
4119 env []string,
4220 args ...string,
43−) (*StdioMCPClient, error) {
44− cmd := exec.Command(command, args...)
45−
46− mergedEnv := os.Environ()
47− mergedEnv = append(mergedEnv, env...)
48−
49− cmd.Env = mergedEnv
50−
51− stdin, err := cmd.StdinPipe()
52− if err != nil {
53− return nil, fmt.Errorf("failed to create stdin pipe: %w", err)
54− }
21+) (*Client, error) {
5522
56− stdout, err := cmd.StdoutPipe()
23+ stdioTransport := transport.NewStdio(command, env, args...)
24+ err := stdioTransport.Start(context.Background())
5725 if err != nil {
58− return nil, fmt.Errorf("failed to create stdout pipe: %w", err)
59− }
60−
61− client := &StdioMCPClient{
62− cmd: cmd,
63− stdin: stdin,
64− stdout: bufio.NewReader(stdout),
65− responses: make(map[int64]chan RPCResponse),
66− done: make(chan struct{}),
67− }
68−
69− if err := cmd.Start(); err != nil {
70− return nil, fmt.Errorf("failed to start command: %w", err)
71− }
72−
73− // Start reading responses in a goroutine and wait for it to be ready
74− ready := make(chan struct{})
75− go func() {
76− close(ready)
77− client.readResponses()
78− }()
79− <-ready
80−
81− return client, nil
82−}
83−
84−// Close shuts down the stdio client, closing the stdin pipe and waiting for the subprocess to exit.
85−// Returns an error if there are issues closing stdin or waiting for the subprocess to terminate.
86−func (c *StdioMCPClient) Close() error {
87− close(c.done)
88− if err := c.stdin.Close(); err != nil {
89− return fmt.Errorf("failed to close stdin: %w", err)
26+ return nil, fmt.Errorf("failed to start stdio transport: %w", err)
9027 }
91− return c.cmd.Wait()
92−}
93−
94−// OnNotification registers a handler function to be called when notifications are received.
95−// Multiple handlers can be registered and will be called in the order they were added.
96−func (c *StdioMCPClient) OnNotification(
97− handler func(notification mcp.JSONRPCNotification),
98−) {
99− c.notifyMu.Lock()
100− defer c.notifyMu.Unlock()
101− c.notifications = append(c.notifications, handler)
102−}
103−
104−// readResponses continuously reads and processes responses from the server's stdout.
105−// It handles both responses to requests and notifications, routing them appropriately.
106−// Runs until the done channel is closed or an error occurs reading from stdout.
107−func (c *StdioMCPClient) readResponses() {
108− for {
109− select {
110− case <-c.done:
111− return
112− default:
113− line, err := c.stdout.ReadString('\n')
114− if err != nil {
115− if err != io.EOF {
116− fmt.Printf("Error reading response: %v\n", err)
117− }
118− return
119− }
120−
121− var baseMessage struct {
122− JSONRPC string `json:"jsonrpc"`
123− ID *int64 `json:"id,omitempty"`
124− Method string `json:"method,omitempty"`
125− Result json.RawMessage `json:"result,omitempty"`
126− Error *struct {
127− Code int `json:"code"`
128− Message string `json:"message"`
129− } `json:"error,omitempty"`
130− }
13128
132− if err := json.Unmarshal([]byte(line), &baseMessage); err != nil {
133− continue
134− }
135−
136− // Handle notification
137− if baseMessage.ID == nil {
138− var notification mcp.JSONRPCNotification
139− if err := json.Unmarshal([]byte(line), &notification); err != nil {
140− continue
141− }
142− c.notifyMu.RLock()
143− for _, handler := range c.notifications {
144− handler(notification)
145− }
146− c.notifyMu.RUnlock()
147− continue
148− }
149−
150− c.mu.RLock()
151− ch, ok := c.responses[*baseMessage.ID]
152− c.mu.RUnlock()
153−
154− if ok {
155− if baseMessage.Error != nil {
156− ch <- RPCResponse{
157− Error: &baseMessage.Error.Message,
158− }
159− } else {
160− ch <- RPCResponse{
161− Response: &baseMessage.Result,
162− }
163− }
164− c.mu.Lock()
165− delete(c.responses, *baseMessage.ID)
166− c.mu.Unlock()
167− }
168− }
169− }
29+ return NewClient(stdioTransport), nil
17030}
17131
172−// sendRequest sends a JSON-RPC request to the server and waits for a response.
173−// It creates a unique request ID, sends the request over stdin, and waits for
174−// the corresponding response or context cancellation.
175−// Returns the raw JSON response message or an error if the request fails.
176−func (c *StdioMCPClient) sendRequest(
177− ctx context.Context,
178− method string,
179− params interface{},
180−) (*json.RawMessage, error) {
181− if !c.initialized && method != "initialize" {
182− return nil, fmt.Errorf("client not initialized")
183− }
184−
185− id := c.requestID.Add(1)
186−
187− // Create the complete request structure
188− request := mcp.JSONRPCRequest{
189− JSONRPC: mcp.JSONRPC_VERSION,
190− ID: id,
191− Request: mcp.Request{
192− Method: method,
193− },
194− Params: params,
195− }
196−
197− responseChan := make(chan RPCResponse, 1)
198− c.mu.Lock()
199− c.responses[id] = responseChan
200− c.mu.Unlock()
201−
202− requestBytes, err := json.Marshal(request)
203− if err != nil {
204− return nil, fmt.Errorf("failed to marshal request: %w", err)
205− }
206− requestBytes = append(requestBytes, '\n')
207−
208− if _, err := c.stdin.Write(requestBytes); err != nil {
209− return nil, fmt.Errorf("failed to write request: %w", err)
210− }
211−
212− select {
213− case <-ctx.Done():
214− c.mu.Lock()
215− delete(c.responses, id)
216− c.mu.Unlock()
217− return nil, ctx.Err()
218− case response := <-responseChan:
219− if response.Error != nil {
220− return nil, errors.New(*response.Error)
221− }
222− return response.Response, nil
223− }
224−}
225−
226−func (c *StdioMCPClient) Ping(ctx context.Context) error {
227− _, err := c.sendRequest(ctx, "ping", nil)
228− return err
229−}
230−
231−func (c *StdioMCPClient) Initialize(
232− ctx context.Context,
233− request mcp.InitializeRequest,
234−) (*mcp.InitializeResult, error) {
235− // This structure ensures Capabilities is always included in JSON
236− params := struct {
237− ProtocolVersion string `json:"protocolVersion"`
238− ClientInfo mcp.Implementation `json:"clientInfo"`
239− Capabilities mcp.ClientCapabilities `json:"capabilities"`
240− }{
241− ProtocolVersion: request.Params.ProtocolVersion,
242− ClientInfo: request.Params.ClientInfo,
243− Capabilities: request.Params.Capabilities, // Will be empty struct if not set
244− }
245−
246− response, err := c.sendRequest(ctx, "initialize", params)
247− if err != nil {
248− return nil, err
249− }
250−
251− var result mcp.InitializeResult
252− if err := json.Unmarshal(*response, &result); err != nil {
253− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
254− }
255−
256− // Store capabilities
257− c.capabilities = result.Capabilities
258−
259− // Send initialized notification
260− notification := mcp.JSONRPCNotification{
261− JSONRPC: mcp.JSONRPC_VERSION,
262− Notification: mcp.Notification{
263− Method: "notifications/initialized",
264− },
265− }
266−
267− notificationBytes, err := json.Marshal(notification)
268− if err != nil {
269− return nil, fmt.Errorf(
270− "failed to marshal initialized notification: %w",
271− err,
272− )
273− }
274− notificationBytes = append(notificationBytes, '\n')
275−
276− if _, err := c.stdin.Write(notificationBytes); err != nil {
277− return nil, fmt.Errorf(
278− "failed to send initialized notification: %w",
279− err,
280− )
281− }
282−
283− c.initialized = true
284− return &result, nil
285−}
286−
287−func (c *StdioMCPClient) ListResources(
288− ctx context.Context,
289− request mcp.ListResourcesRequest,
290−) (*mcp.
291− ListResourcesResult, error) {
292− response, err := c.sendRequest(
293− ctx,
294− "resources/list",
295− request.Params,
296− )
297− if err != nil {
298− return nil, err
299− }
300−
301− var result mcp.ListResourcesResult
302− if err := json.Unmarshal(*response, &result); err != nil {
303− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
304− }
305−
306− return &result, nil
307−}
308−
309−func (c *StdioMCPClient) ListResourceTemplates(
310− ctx context.Context,
311− request mcp.ListResourceTemplatesRequest,
312−) (*mcp.
313− ListResourceTemplatesResult, error) {
314− response, err := c.sendRequest(
315− ctx,
316− "resources/templates/list",
317− request.Params,
318− )
319− if err != nil {
320− return nil, err
321− }
322−
323− var result mcp.ListResourceTemplatesResult
324− if err := json.Unmarshal(*response, &result); err != nil {
325− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
326− }
327−
328− return &result, nil
329−}
330−
331−func (c *StdioMCPClient) ReadResource(
332− ctx context.Context,
333− request mcp.ReadResourceRequest,
334−) (*mcp.ReadResourceResult,
335− error) {
336− response, err := c.sendRequest(ctx, "resources/read", request.Params)
337− if err != nil {
338− return nil, err
339− }
340−
341− return mcp.ParseReadResourceResult(response)
342−}
343−
344−func (c *StdioMCPClient) Subscribe(
345− ctx context.Context,
346− request mcp.SubscribeRequest,
347−) error {
348− _, err := c.sendRequest(ctx, "resources/subscribe", request.Params)
349− return err
350−}
351−
352−func (c *StdioMCPClient) Unsubscribe(
353− ctx context.Context,
354− request mcp.UnsubscribeRequest,
355−) error {
356− _, err := c.sendRequest(ctx, "resources/unsubscribe", request.Params)
357− return err
358−}
359−
360−func (c *StdioMCPClient) ListPrompts(
361− ctx context.Context,
362− request mcp.ListPromptsRequest,
363−) (*mcp.ListPromptsResult, error) {
364− response, err := c.sendRequest(ctx, "prompts/list", request.Params)
365− if err != nil {
366− return nil, err
367− }
368−
369− var result mcp.ListPromptsResult
370− if err := json.Unmarshal(*response, &result); err != nil {
371− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
372− }
373−
374− return &result, nil
375−}
376−
377−func (c *StdioMCPClient) GetPrompt(
378− ctx context.Context,
379− request mcp.GetPromptRequest,
380−) (*mcp.GetPromptResult, error) {
381− response, err := c.sendRequest(ctx, "prompts/get", request.Params)
382− if err != nil {
383− return nil, err
384− }
385−
386− return mcp.ParseGetPromptResult(response)
387−}
388−
389−func (c *StdioMCPClient) ListTools(
390− ctx context.Context,
391− request mcp.ListToolsRequest,
392−) (*mcp.ListToolsResult, error) {
393− response, err := c.sendRequest(ctx, "tools/list", request.Params)
394− if err != nil {
395− return nil, err
396− }
397−
398− var result mcp.ListToolsResult
399− if err := json.Unmarshal(*response, &result); err != nil {
400− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
401− }
402−
403− return &result, nil
404−}
405−
406−func (c *StdioMCPClient) CallTool(
407− ctx context.Context,
408− request mcp.CallToolRequest,
409−) (*mcp.CallToolResult, error) {
410− response, err := c.sendRequest(ctx, "tools/call", request.Params)
411− if err != nil {
412− return nil, err
413− }
414−
415− return mcp.ParseCallToolResult(response)
416−}
417−
418−func (c *StdioMCPClient) SetLevel(
419− ctx context.Context,
420− request mcp.SetLevelRequest,
421−) error {
422− _, err := c.sendRequest(ctx, "logging/setLevel", request.Params)
423− return err
424−}
425−
426−func (c *StdioMCPClient) Complete(
427− ctx context.Context,
428− request mcp.CompleteRequest,
429−) (*mcp.CompleteResult, error) {
430− response, err := c.sendRequest(ctx, "completion/complete", request.Params)
431− if err != nil {
432− return nil, err
433− }
32+// GetStderr returns a reader for the stderr output of the subprocess.
33+// This can be used to capture error messages or logs from the subprocess.
34+func GetStderr(c *Client) (io.Reader, bool) {
35+ t := c.GetTransport()
43436
435− var result mcp.CompleteResult
436− if err := json.Unmarshal(*response, &result); err != nil {
437− return nil, fmt.Errorf("failed to unmarshal response: %w", err)
37+ stdio, ok := t.(*transport.Stdio)
38+ if !ok {
39+ return nil, false
43840 }
43941
440− return &result, nil
42+ return stdio.Stderr(), true
44143}
vendor/github.com/mark3labs/mcp-go/client/transport/inprocess.gonew file+70
@@ -0,0 +1,70 @@
1+package transport
2+
3+import (
4+ "context"
5+ "encoding/json"
6+ "fmt"
7+ "sync"
8+
9+ "github.com/mark3labs/mcp-go/mcp"
10+ "github.com/mark3labs/mcp-go/server"
11+)
12+
13+type InProcessTransport struct {
14+ server *server.MCPServer
15+
16+ onNotification func(mcp.JSONRPCNotification)
17+ notifyMu sync.RWMutex
18+}
19+
20+func NewInProcessTransport(server *server.MCPServer) *InProcessTransport {
21+ return &InProcessTransport{
22+ server: server,
23+ }
24+}
25+
26+func (c *InProcessTransport) Start(ctx context.Context) error {
27+ return nil
28+}
29+
30+func (c *InProcessTransport) SendRequest(ctx context.Context, request JSONRPCRequest) (*JSONRPCResponse, error) {
31+ requestBytes, err := json.Marshal(request)
32+ if err != nil {
33+ return nil, fmt.Errorf("failed to marshal request: %w", err)
34+ }
35+ requestBytes = append(requestBytes, '\n')
36+
37+ respMessage := c.server.HandleMessage(ctx, requestBytes)
38+ respByte, err := json.Marshal(respMessage)
39+ if err != nil {
40+ return nil, fmt.Errorf("failed to marshal response message: %w", err)
41+ }
42+ rpcResp := JSONRPCResponse{}
43+ err = json.Unmarshal(respByte, &rpcResp)
44+ if err != nil {
45+ return nil, fmt.Errorf("failed to unmarshal response message: %w", err)
46+ }
47+
48+ return &rpcResp, nil
49+}
50+
51+func (c *InProcessTransport) SendNotification(ctx context.Context, notification mcp.JSONRPCNotification) error {
52+ notificationBytes, err := json.Marshal(notification)
53+ if err != nil {
54+ return fmt.Errorf("failed to marshal notification: %w", err)
55+ }
56+ notificationBytes = append(notificationBytes, '\n')
57+ c.server.HandleMessage(ctx, notificationBytes)
58+
59+ return nil
60+}
61+
62+func (c *InProcessTransport) SetNotificationHandler(handler func(notification mcp.JSONRPCNotification)) {
63+ c.notifyMu.Lock()
64+ defer c.notifyMu.Unlock()
65+ c.onNotification = handler
66+}
67+
68+func (*InProcessTransport) Close() error {
69+ return nil
70+}
vendor/github.com/mark3labs/mcp-go/client/transport/interface.gonew file+50
@@ -0,0 +1,50 @@
1+package transport
2+
3+import (
4+ "context"
5+ "encoding/json"
6+
7+ "github.com/mark3labs/mcp-go/mcp"
8+)
9+
10+// HTTPHeaderFunc is a function that extracts header entries from the given context
11+// and returns them as key-value pairs. This is typically used to add context values
12+// as HTTP headers in outgoing requests.
13+type HTTPHeaderFunc func(context.Context) map[string]string
14+
15+// Interface for the transport layer.
16+type Interface interface {
17+ // Start the connection. Start should only be called once.
18+ Start(ctx context.Context) error
19+
20+ // SendRequest sends a json RPC request and returns the response synchronously.
21+ SendRequest(ctx context.Context, request JSONRPCRequest) (*JSONRPCResponse, error)
22+
23+ // SendNotification sends a json RPC Notification to the server.
24+ SendNotification(ctx context.Context, notification mcp.JSONRPCNotification) error
25+
26+ // SetNotificationHandler sets the handler for notifications.
27+ // Any notification before the handler is set will be discarded.
28+ SetNotificationHandler(handler func(notification mcp.JSONRPCNotification))
29+
30+ // Close the connection.
31+ Close() error
32+}
33+
34+type JSONRPCRequest struct {
35+ JSONRPC string `json:"jsonrpc"`
36+ ID mcp.RequestId `json:"id"`
37+ Method string `json:"method"`
38+ Params any `json:"params,omitempty"`
39+}
40+
41+type JSONRPCResponse struct {
42+ JSONRPC string `json:"jsonrpc"`
43+ ID mcp.RequestId `json:"id"`
44+ Result json.RawMessage `json:"result"`
45+ Error *struct {
46+ Code int `json:"code"`
47+ Message string `json:"message"`
48+ Data json.RawMessage `json:"data"`
49+ } `json:"error"`
50+}
vendor/github.com/mark3labs/mcp-go/client/transport/oauth.gonew file+650
@@ -0,0 +1,650 @@
1+package transport
2+
3+import (
4+ "bytes"
5+ "context"
6+ "encoding/json"
7+ "errors"
8+ "fmt"
9+ "io"
10+ "net/http"
11+ "net/url"
12+ "strings"
13+ "sync"
14+ "time"
15+)
16+
17+// OAuthConfig holds the OAuth configuration for the client
18+type OAuthConfig struct {
19+ // ClientID is the OAuth client ID
20+ ClientID string
21+ // ClientSecret is the OAuth client secret (for confidential clients)
22+ ClientSecret string
23+ // RedirectURI is the redirect URI for the OAuth flow
24+ RedirectURI string
25+ // Scopes is the list of OAuth scopes to request
26+ Scopes []string
27+ // TokenStore is the storage for OAuth tokens
28+ TokenStore TokenStore
29+ // AuthServerMetadataURL is the URL to the OAuth server metadata
30+ // If empty, the client will attempt to discover it from the base URL
31+ AuthServerMetadataURL string
32+ // PKCEEnabled enables PKCE for the OAuth flow (recommended for public clients)
33+ PKCEEnabled bool
34+}
35+
36+// TokenStore is an interface for storing and retrieving OAuth tokens
37+type TokenStore interface {
38+ // GetToken returns the current token
39+ GetToken() (*Token, error)
40+ // SaveToken saves a token
41+ SaveToken(token *Token) error
42+}
43+
44+// Token represents an OAuth token
45+type Token struct {
46+ // AccessToken is the OAuth access token
47+ AccessToken string `json:"access_token"`
48+ // TokenType is the type of token (usually "Bearer")
49+ TokenType string `json:"token_type"`
50+ // RefreshToken is the OAuth refresh token
51+ RefreshToken string `json:"refresh_token,omitempty"`
52+ // ExpiresIn is the number of seconds until the token expires
53+ ExpiresIn int64 `json:"expires_in,omitempty"`
54+ // Scope is the scope of the token
55+ Scope string `json:"scope,omitempty"`
56+ // ExpiresAt is the time when the token expires
57+ ExpiresAt time.Time `json:"expires_at,omitempty"`
58+}
59+
60+// IsExpired returns true if the token is expired
61+func (t *Token) IsExpired() bool {
62+ if t.ExpiresAt.IsZero() {
63+ return false
64+ }
65+ return time.Now().After(t.ExpiresAt)
66+}
67+
68+// MemoryTokenStore is a simple in-memory token store
69+type MemoryTokenStore struct {
70+ token *Token
71+ mu sync.RWMutex
72+}
73+
74+// NewMemoryTokenStore creates a new in-memory token store
75+func NewMemoryTokenStore() *MemoryTokenStore {
76+ return &MemoryTokenStore{}
77+}
78+
79+// GetToken returns the current token
80+func (s *MemoryTokenStore) GetToken() (*Token, error) {
81+ s.mu.RLock()
82+ defer s.mu.RUnlock()
83+ if s.token == nil {
84+ return nil, errors.New("no token available")
85+ }
86+ return s.token, nil
87+}
88+
89+// SaveToken saves a token
90+func (s *MemoryTokenStore) SaveToken(token *Token) error {
91+ s.mu.Lock()
92+ defer s.mu.Unlock()
93+ s.token = token
94+ return nil
95+}
96+
97+// AuthServerMetadata represents the OAuth 2.0 Authorization Server Metadata
98+type AuthServerMetadata struct {
99+ Issuer string `json:"issuer"`
100+ AuthorizationEndpoint string `json:"authorization_endpoint"`
101+ TokenEndpoint string `json:"token_endpoint"`
102+ RegistrationEndpoint string `json:"registration_endpoint,omitempty"`
103+ JwksURI string `json:"jwks_uri,omitempty"`
104+ ScopesSupported []string `json:"scopes_supported,omitempty"`
105+ ResponseTypesSupported []string `json:"response_types_supported"`
106+ GrantTypesSupported []string `json:"grant_types_supported,omitempty"`
107+ TokenEndpointAuthMethodsSupported []string `json:"token_endpoint_auth_methods_supported,omitempty"`
108+}
109+
110+// OAuthHandler handles OAuth authentication for HTTP requests
111+type OAuthHandler struct {
112+ config OAuthConfig
113+ httpClient *http.Client
114+ serverMetadata *AuthServerMetadata
115+ metadataFetchErr error
116+ metadataOnce sync.Once
117+ baseURL string
118+ expectedState string // Expected state value for CSRF protection
119+}
120+
121+// NewOAuthHandler creates a new OAuth handler
122+func NewOAuthHandler(config OAuthConfig) *OAuthHandler {
123+ if config.TokenStore == nil {
124+ config.TokenStore = NewMemoryTokenStore()
125+ }
126+
127+ return &OAuthHandler{
128+ config: config,
129+ httpClient: &http.Client{Timeout: 30 * time.Second},
130+ }
131+}
132+
133+// GetAuthorizationHeader returns the Authorization header value for a request
134+func (h *OAuthHandler) GetAuthorizationHeader(ctx context.Context) (string, error) {
135+ token, err := h.getValidToken(ctx)
136+ if err != nil {
137+ return "", err
138+ }
139+
140+ // Some auth implementations are strict about token type
141+ tokenType := token.TokenType
142+ if tokenType == "bearer" {
143+ tokenType = "Bearer"
144+ }
145+
146+ return fmt.Sprintf("%s %s", tokenType, token.AccessToken), nil
147+}
148+
149+// getValidToken returns a valid token, refreshing if necessary
150+func (h *OAuthHandler) getValidToken(ctx context.Context) (*Token, error) {
151+ token, err := h.config.TokenStore.GetToken()
152+ if err == nil && !token.IsExpired() && token.AccessToken != "" {
153+ return token, nil
154+ }
155+
156+ // If we have a refresh token, try to use it
157+ if err == nil && token.RefreshToken != "" {
158+ newToken, err := h.refreshToken(ctx, token.RefreshToken)
159+ if err == nil {
160+ return newToken, nil
161+ }
162+ // If refresh fails, continue to authorization flow
163+ }
164+
165+ // We need to get a new token through the authorization flow
166+ return nil, ErrOAuthAuthorizationRequired
167+}
168+
169+// refreshToken refreshes an OAuth token
170+func (h *OAuthHandler) refreshToken(ctx context.Context, refreshToken string) (*Token, error) {
171+ metadata, err := h.getServerMetadata(ctx)
172+ if err != nil {
173+ return nil, fmt.Errorf("failed to get server metadata: %w", err)
174+ }
175+
176+ data := url.Values{}
177+ data.Set("grant_type", "refresh_token")
178+ data.Set("refresh_token", refreshToken)
179+ data.Set("client_id", h.config.ClientID)
180+ if h.config.ClientSecret != "" {
181+ data.Set("client_secret", h.config.ClientSecret)
182+ }
183+
184+ req, err := http.NewRequestWithContext(
185+ ctx,
186+ http.MethodPost,
187+ metadata.TokenEndpoint,
188+ strings.NewReader(data.Encode()),
189+ )
190+ if err != nil {
191+ return nil, fmt.Errorf("failed to create refresh token request: %w", err)
192+ }
193+
194+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
195+ req.Header.Set("Accept", "application/json")
196+
197+ resp, err := h.httpClient.Do(req)
198+ if err != nil {
199+ return nil, fmt.Errorf("failed to send refresh token request: %w", err)
200+ }
201+ defer resp.Body.Close()
202+
203+ if resp.StatusCode != http.StatusOK {
204+ body, _ := io.ReadAll(resp.Body)
205+ return nil, extractOAuthError(body, resp.StatusCode, "refresh token request failed")
206+ }
207+
208+ var tokenResp Token
209+ if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
210+ return nil, fmt.Errorf("failed to decode token response: %w", err)
211+ }
212+
213+ // Set expiration time
214+ if tokenResp.ExpiresIn > 0 {
215+ tokenResp.ExpiresAt = time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second)
216+ }
217+
218+ // If no new refresh token is provided, keep the old one
219+ oldToken, _ := h.config.TokenStore.GetToken()
220+ if tokenResp.RefreshToken == "" && oldToken != nil {
221+ tokenResp.RefreshToken = oldToken.RefreshToken
222+ }
223+
224+ // Save the token
225+ if err := h.config.TokenStore.SaveToken(&tokenResp); err != nil {
226+ return nil, fmt.Errorf("failed to save token: %w", err)
227+ }
228+
229+ return &tokenResp, nil
230+}
231+
232+// RefreshToken is a public wrapper for refreshToken
233+func (h *OAuthHandler) RefreshToken(ctx context.Context, refreshToken string) (*Token, error) {
234+ return h.refreshToken(ctx, refreshToken)
235+}
236+
237+// GetClientID returns the client ID
238+func (h *OAuthHandler) GetClientID() string {
239+ return h.config.ClientID
240+}
241+
242+// extractOAuthError attempts to parse an OAuth error response from the response body
243+func extractOAuthError(body []byte, statusCode int, context string) error {
244+ // Try to parse the error as an OAuth error response
245+ var oauthErr OAuthError
246+ if err := json.Unmarshal(body, &oauthErr); err == nil && oauthErr.ErrorCode != "" {
247+ return fmt.Errorf("%s: %w", context, oauthErr)
248+ }
249+
250+ // If not a valid OAuth error, return the raw response
251+ return fmt.Errorf("%s with status %d: %s", context, statusCode, body)
252+}
253+
254+// GetClientSecret returns the client secret
255+func (h *OAuthHandler) GetClientSecret() string {
256+ return h.config.ClientSecret
257+}
258+
259+// SetBaseURL sets the base URL for the API server
260+func (h *OAuthHandler) SetBaseURL(baseURL string) {
261+ h.baseURL = baseURL
262+}
263+
264+// GetExpectedState returns the expected state value (for testing purposes)
265+func (h *OAuthHandler) GetExpectedState() string {
266+ return h.expectedState
267+}
268+
269+// OAuthError represents a standard OAuth 2.0 error response
270+type OAuthError struct {
271+ ErrorCode string `json:"error"`
272+ ErrorDescription string `json:"error_description,omitempty"`
273+ ErrorURI string `json:"error_uri,omitempty"`
274+}
275+
276+// Error implements the error interface
277+func (e OAuthError) Error() string {
278+ if e.ErrorDescription != "" {
279+ return fmt.Sprintf("OAuth error: %s - %s", e.ErrorCode, e.ErrorDescription)
280+ }
281+ return fmt.Sprintf("OAuth error: %s", e.ErrorCode)
282+}
283+
284+// OAuthProtectedResource represents the response from /.well-known/oauth-protected-resource
285+type OAuthProtectedResource struct {
286+ AuthorizationServers []string `json:"authorization_servers"`
287+ Resource string `json:"resource"`
288+ ResourceName string `json:"resource_name,omitempty"`
289+}
290+
291+// getServerMetadata fetches the OAuth server metadata
292+func (h *OAuthHandler) getServerMetadata(ctx context.Context) (*AuthServerMetadata, error) {
293+ h.metadataOnce.Do(func() {
294+ // If AuthServerMetadataURL is explicitly provided, use it directly
295+ if h.config.AuthServerMetadataURL != "" {
296+ h.fetchMetadataFromURL(ctx, h.config.AuthServerMetadataURL)
297+ return
298+ }
299+
300+ // Try to discover the authorization server via OAuth Protected Resource
301+ // as per RFC 9728 (https://datatracker.ietf.org/doc/html/rfc9728)
302+ baseURL, err := h.extractBaseURL()
303+ if err != nil {
304+ h.metadataFetchErr = fmt.Errorf("failed to extract base URL: %w", err)
305+ return
306+ }
307+
308+ // Try to fetch the OAuth Protected Resource metadata
309+ protectedResourceURL := baseURL + "/.well-known/oauth-protected-resource"
310+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, protectedResourceURL, nil)
311+ if err != nil {
312+ h.metadataFetchErr = fmt.Errorf("failed to create protected resource request: %w", err)
313+ return
314+ }
315+
316+ req.Header.Set("Accept", "application/json")
317+ req.Header.Set("MCP-Protocol-Version", "2025-03-26")
318+
319+ resp, err := h.httpClient.Do(req)
320+ if err != nil {
321+ h.metadataFetchErr = fmt.Errorf("failed to send protected resource request: %w", err)
322+ return
323+ }
324+ defer resp.Body.Close()
325+
326+ // If we can't get the protected resource metadata, fall back to default endpoints
327+ if resp.StatusCode != http.StatusOK {
328+ metadata, err := h.getDefaultEndpoints(baseURL)
329+ if err != nil {
330+ h.metadataFetchErr = fmt.Errorf("failed to get default endpoints: %w", err)
331+ return
332+ }
333+ h.serverMetadata = metadata
334+ return
335+ }
336+
337+ // Parse the protected resource metadata
338+ var protectedResource OAuthProtectedResource
339+ if err := json.NewDecoder(resp.Body).Decode(&protectedResource); err != nil {
340+ h.metadataFetchErr = fmt.Errorf("failed to decode protected resource response: %w", err)
341+ return
342+ }
343+
344+ // If no authorization servers are specified, fall back to default endpoints
345+ if len(protectedResource.AuthorizationServers) == 0 {
346+ metadata, err := h.getDefaultEndpoints(baseURL)
347+ if err != nil {
348+ h.metadataFetchErr = fmt.Errorf("failed to get default endpoints: %w", err)
349+ return
350+ }
351+ h.serverMetadata = metadata
352+ return
353+ }
354+
355+ // Use the first authorization server
356+ authServerURL := protectedResource.AuthorizationServers[0]
357+
358+ // Try OpenID Connect discovery first
359+ h.fetchMetadataFromURL(ctx, authServerURL+"/.well-known/openid-configuration")
360+ if h.serverMetadata != nil {
361+ return
362+ }
363+
364+ // If OpenID Connect discovery fails, try OAuth Authorization Server Metadata
365+ h.fetchMetadataFromURL(ctx, authServerURL+"/.well-known/oauth-authorization-server")
366+ if h.serverMetadata != nil {
367+ return
368+ }
369+
370+ // If both discovery methods fail, use default endpoints based on the authorization server URL
371+ metadata, err := h.getDefaultEndpoints(authServerURL)
372+ if err != nil {
373+ h.metadataFetchErr = fmt.Errorf("failed to get default endpoints: %w", err)
374+ return
375+ }
376+ h.serverMetadata = metadata
377+ })
378+
379+ if h.metadataFetchErr != nil {
380+ return nil, h.metadataFetchErr
381+ }
382+
383+ return h.serverMetadata, nil
384+}
385+
386+// fetchMetadataFromURL fetches and parses OAuth server metadata from a URL
387+func (h *OAuthHandler) fetchMetadataFromURL(ctx context.Context, metadataURL string) {
388+ req, err := http.NewRequestWithContext(ctx, http.MethodGet, metadataURL, nil)
389+ if err != nil {
390+ h.metadataFetchErr = fmt.Errorf("failed to create metadata request: %w", err)
391+ return
392+ }
393+
394+ req.Header.Set("Accept", "application/json")
395+ req.Header.Set("MCP-Protocol-Version", "2025-03-26")
396+
397+ resp, err := h.httpClient.Do(req)
398+ if err != nil {
399+ h.metadataFetchErr = fmt.Errorf("failed to send metadata request: %w", err)
400+ return
401+ }
402+ defer resp.Body.Close()
403+
404+ if resp.StatusCode != http.StatusOK {
405+ // If metadata discovery fails, don't set any metadata
406+ return
407+ }
408+
409+ var metadata AuthServerMetadata
410+ if err := json.NewDecoder(resp.Body).Decode(&metadata); err != nil {
411+ h.metadataFetchErr = fmt.Errorf("failed to decode metadata response: %w", err)
412+ return
413+ }
414+
415+ h.serverMetadata = &metadata
416+}
417+
418+// extractBaseURL extracts the base URL from the first request
419+func (h *OAuthHandler) extractBaseURL() (string, error) {
420+ // If we have a base URL from a previous request, use it
421+ if h.baseURL != "" {
422+ return h.baseURL, nil
423+ }
424+
425+ // Otherwise, we need to infer it from the redirect URI
426+ if h.config.RedirectURI == "" {
427+ return "", fmt.Errorf("no base URL available and no redirect URI provided")
428+ }
429+
430+ // Parse the redirect URI to extract the authority
431+ parsedURL, err := url.Parse(h.config.RedirectURI)
432+ if err != nil {
433+ return "", fmt.Errorf("failed to parse redirect URI: %w", err)
434+ }
435+
436+ // Use the scheme and host from the redirect URI
437+ baseURL := fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host)
438+ return baseURL, nil
439+}
440+
441+// GetServerMetadata is a public wrapper for getServerMetadata
442+func (h *OAuthHandler) GetServerMetadata(ctx context.Context) (*AuthServerMetadata, error) {
443+ return h.getServerMetadata(ctx)
444+}
445+
446+// getDefaultEndpoints returns default OAuth endpoints based on the base URL
447+func (h *OAuthHandler) getDefaultEndpoints(baseURL string) (*AuthServerMetadata, error) {
448+ // Parse the base URL to extract the authority
449+ parsedURL, err := url.Parse(baseURL)
450+ if err != nil {
451+ return nil, fmt.Errorf("failed to parse base URL: %w", err)
452+ }
453+
454+ // Discard any path component to get the authorization base URL
455+ parsedURL.Path = ""
456+ authBaseURL := parsedURL.String()
457+
458+ // Validate that the URL has a scheme and host
459+ if parsedURL.Scheme == "" || parsedURL.Host == "" {
460+ return nil, fmt.Errorf("invalid base URL: missing scheme or host in %q", baseURL)
461+ }
462+
463+ return &AuthServerMetadata{
464+ Issuer: authBaseURL,
465+ AuthorizationEndpoint: authBaseURL + "/authorize",
466+ TokenEndpoint: authBaseURL + "/token",
467+ RegistrationEndpoint: authBaseURL + "/register",
468+ }, nil
469+}
470+
471+// RegisterClient performs dynamic client registration
472+func (h *OAuthHandler) RegisterClient(ctx context.Context, clientName string) error {
473+ metadata, err := h.getServerMetadata(ctx)
474+ if err != nil {
475+ return fmt.Errorf("failed to get server metadata: %w", err)
476+ }
477+
478+ if metadata.RegistrationEndpoint == "" {
479+ return errors.New("server does not support dynamic client registration")
480+ }
481+
482+ // Prepare registration request
483+ regRequest := map[string]any{
484+ "client_name": clientName,
485+ "redirect_uris": []string{h.config.RedirectURI},
486+ "token_endpoint_auth_method": "none", // For public clients
487+ "grant_types": []string{"authorization_code", "refresh_token"},
488+ "response_types": []string{"code"},
489+ "scope": strings.Join(h.config.Scopes, " "),
490+ }
491+
492+ // Add client_secret if this is a confidential client
493+ if h.config.ClientSecret != "" {
494+ regRequest["token_endpoint_auth_method"] = "client_secret_basic"
495+ }
496+
497+ reqBody, err := json.Marshal(regRequest)
498+ if err != nil {
499+ return fmt.Errorf("failed to marshal registration request: %w", err)
500+ }
501+
502+ req, err := http.NewRequestWithContext(
503+ ctx,
504+ http.MethodPost,
505+ metadata.RegistrationEndpoint,
506+ bytes.NewReader(reqBody),
507+ )
508+ if err != nil {
509+ return fmt.Errorf("failed to create registration request: %w", err)
510+ }
511+
512+ req.Header.Set("Content-Type", "application/json")
513+ req.Header.Set("Accept", "application/json")
514+
515+ resp, err := h.httpClient.Do(req)
516+ if err != nil {
517+ return fmt.Errorf("failed to send registration request: %w", err)
518+ }
519+ defer resp.Body.Close()
520+
521+ if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK {
522+ body, _ := io.ReadAll(resp.Body)
523+ return extractOAuthError(body, resp.StatusCode, "registration request failed")
524+ }
525+
526+ var regResponse struct {
527+ ClientID string `json:"client_id"`
528+ ClientSecret string `json:"client_secret,omitempty"`
529+ }
530+
531+ if err := json.NewDecoder(resp.Body).Decode(&regResponse); err != nil {
532+ return fmt.Errorf("failed to decode registration response: %w", err)
533+ }
534+
535+ // Update the client configuration
536+ h.config.ClientID = regResponse.ClientID
537+ if regResponse.ClientSecret != "" {
538+ h.config.ClientSecret = regResponse.ClientSecret
539+ }
540+
541+ return nil
542+}
543+
544+// ErrInvalidState is returned when the state parameter doesn't match the expected value
545+var ErrInvalidState = errors.New("invalid state parameter, possible CSRF attack")
546+
547+// ProcessAuthorizationResponse processes the authorization response and exchanges the code for a token
548+func (h *OAuthHandler) ProcessAuthorizationResponse(ctx context.Context, code, state, codeVerifier string) error {
549+ // Validate the state parameter to prevent CSRF attacks
550+ if h.expectedState == "" {
551+ return errors.New("no expected state found, authorization flow may not have been initiated properly")
552+ }
553+
554+ if state != h.expectedState {
555+ return ErrInvalidState
556+ }
557+
558+ // Clear the expected state after validation
559+ defer func() {
560+ h.expectedState = ""
561+ }()
562+
563+ metadata, err := h.getServerMetadata(ctx)
564+ if err != nil {
565+ return fmt.Errorf("failed to get server metadata: %w", err)
566+ }
567+
568+ data := url.Values{}
569+ data.Set("grant_type", "authorization_code")
570+ data.Set("code", code)
571+ data.Set("client_id", h.config.ClientID)
572+ data.Set("redirect_uri", h.config.RedirectURI)
573+
574+ if h.config.ClientSecret != "" {
575+ data.Set("client_secret", h.config.ClientSecret)
576+ }
577+
578+ if h.config.PKCEEnabled && codeVerifier != "" {
579+ data.Set("code_verifier", codeVerifier)
580+ }
581+
582+ req, err := http.NewRequestWithContext(
583+ ctx,
584+ http.MethodPost,
585+ metadata.TokenEndpoint,
586+ strings.NewReader(data.Encode()),
587+ )
588+ if err != nil {
589+ return fmt.Errorf("failed to create token request: %w", err)
590+ }
591+
592+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
593+ req.Header.Set("Accept", "application/json")
594+
595+ resp, err := h.httpClient.Do(req)
596+ if err != nil {
597+ return fmt.Errorf("failed to send token request: %w", err)
598+ }
599+ defer resp.Body.Close()
600+
601+ if resp.StatusCode != http.StatusOK {
602+ body, _ := io.ReadAll(resp.Body)
603+ return extractOAuthError(body, resp.StatusCode, "token request failed")
604+ }
605+
606+ var tokenResp Token
607+ if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
608+ return fmt.Errorf("failed to decode token response: %w", err)
609+ }
610+
611+ // Set expiration time
612+ if tokenResp.ExpiresIn > 0 {
613+ tokenResp.ExpiresAt = time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second)
614+ }
615+
616+ // Save the token
617+ if err := h.config.TokenStore.SaveToken(&tokenResp); err != nil {
618+ return fmt.Errorf("failed to save token: %w", err)
619+ }
620+
621+ return nil
622+}
623+
624+// GetAuthorizationURL returns the URL for the authorization endpoint
625+func (h *OAuthHandler) GetAuthorizationURL(ctx context.Context, state, codeChallenge string) (string, error) {
626+ metadata, err := h.getServerMetadata(ctx)
627+ if err != nil {
628+ return "", fmt.Errorf("failed to get server metadata: %w", err)
629+ }
630+
631+ // Store the state for later validation
632+ h.expectedState = state
633+
634+ params := url.Values{}
635+ params.Set("response_type", "code")
636+ params.Set("client_id", h.config.ClientID)
637+ params.Set("redirect_uri", h.config.RedirectURI)
638+ params.Set("state", state)
639+
640+ if len(h.config.Scopes) > 0 {
641+ params.Set("scope", strings.Join(h.config.Scopes, " "))
642+ }
643+
644+ if h.config.PKCEEnabled && codeChallenge != "" {
645+ params.Set("code_challenge", codeChallenge)
646+ params.Set("code_challenge_method", "S256")
647+ }
648+
649+ return metadata.AuthorizationEndpoint + "?" + params.Encode(), nil
650+}
vendor/github.com/mark3labs/mcp-go/client/transport/oauth_utils.gonew file+68
@@ -0,0 +1,68 @@
1+package transport
2+
3+import (
4+ "crypto/rand"
5+ "crypto/sha256"
6+ "encoding/base64"
7+ "fmt"
8+ "net/url"
9+)
10+
11+// GenerateRandomString generates a random string of the specified length
12+func GenerateRandomString(length int) (string, error) {
13+ bytes := make([]byte, length)
14+ if _, err := rand.Read(bytes); err != nil {
15+ return "", err
16+ }
17+ return base64.RawURLEncoding.EncodeToString(bytes)[:length], nil
18+}
19+
20+// GenerateCodeVerifier generates a code verifier for PKCE
21+func GenerateCodeVerifier() (string, error) {
22+ // According to RFC 7636, the code verifier should be between 43 and 128 characters
23+ return GenerateRandomString(64)
24+}
25+
26+// GenerateCodeChallenge generates a code challenge from a code verifier
27+func GenerateCodeChallenge(codeVerifier string) string {
28+ // SHA256 hash the code verifier
29+ hash := sha256.Sum256([]byte(codeVerifier))
30+ // Base64url encode the hash
31+ return base64.RawURLEncoding.EncodeToString(hash[:])
32+}
33+
34+// GenerateState generates a state parameter for OAuth
35+func GenerateState() (string, error) {
36+ return GenerateRandomString(32)
37+}
38+
39+// ValidateRedirectURI validates that a redirect URI is secure
40+func ValidateRedirectURI(redirectURI string) error {
41+ // According to the spec, redirect URIs must be either localhost URLs or HTTPS URLs
42+ if redirectURI == "" {
43+ return fmt.Errorf("redirect URI cannot be empty")
44+ }
45+
46+ // Parse the URL
47+ parsedURL, err := url.Parse(redirectURI)
48+ if err != nil {
49+ return fmt.Errorf("invalid redirect URI: %w", err)
50+ }
51+
52+ // Check if it's a localhost URL
53+ if parsedURL.Scheme == "http" {
54+ hostname := parsedURL.Hostname()
55+ // Check for various forms of localhost
56+ if hostname == "localhost" || hostname == "127.0.0.1" || hostname == "::1" || hostname == "[::1]" {
57+ return nil
58+ }
59+ return fmt.Errorf("HTTP redirect URI must use localhost or 127.0.0.1")
60+ }
61+
62+ // Check if it's an HTTPS URL
63+ if parsedURL.Scheme == "https" {
64+ return nil
65+ }
66+
67+ return fmt.Errorf("redirect URI must use either HTTP with localhost or HTTPS")
68+}
vendor/github.com/mark3labs/mcp-go/client/transport/sse.gonew file+522
@@ -0,0 +1,522 @@
1+package transport
2+
3+import (
4+ "bufio"
5+ "bytes"
6+ "context"
7+ "encoding/json"
8+ "errors"
9+ "fmt"
10+ "io"
11+ "net/http"
12+ "net/url"
13+ "strings"
14+ "sync"
15+ "sync/atomic"
16+ "time"
17+
18+ "github.com/mark3labs/mcp-go/mcp"
19+)
20+
21+// SSE implements the transport layer of the MCP protocol using Server-Sent Events (SSE).
22+// It maintains a persistent HTTP connection to receive server-pushed events
23+// while sending requests over regular HTTP POST calls. The client handles
24+// automatic reconnection and message routing between requests and responses.
25+type SSE struct {
26+ baseURL *url.URL
27+ endpoint *url.URL
28+ httpClient *http.Client
29+ responses map[string]chan *JSONRPCResponse
30+ mu sync.RWMutex
31+ onNotification func(mcp.JSONRPCNotification)
32+ notifyMu sync.RWMutex
33+ endpointChan chan struct{}
34+ headers map[string]string
35+ headerFunc HTTPHeaderFunc
36+
37+ started atomic.Bool
38+ closed atomic.Bool
39+ cancelSSEStream context.CancelFunc
40+
41+ // OAuth support
42+ oauthHandler *OAuthHandler
43+}
44+
45+type ClientOption func(*SSE)
46+
47+func WithHeaders(headers map[string]string) ClientOption {
48+ return func(sc *SSE) {
49+ sc.headers = headers
50+ }
51+}
52+
53+func WithHeaderFunc(headerFunc HTTPHeaderFunc) ClientOption {
54+ return func(sc *SSE) {
55+ sc.headerFunc = headerFunc
56+ }
57+}
58+
59+func WithHTTPClient(httpClient *http.Client) ClientOption {
60+ return func(sc *SSE) {
61+ sc.httpClient = httpClient
62+ }
63+}
64+
65+func WithOAuth(config OAuthConfig) ClientOption {
66+ return func(sc *SSE) {
67+ sc.oauthHandler = NewOAuthHandler(config)
68+ }
69+}
70+
71+// NewSSE creates a new SSE-based MCP client with the given base URL.
72+// Returns an error if the URL is invalid.
73+func NewSSE(baseURL string, options ...ClientOption) (*SSE, error) {
74+ parsedURL, err := url.Parse(baseURL)
75+ if err != nil {
76+ return nil, fmt.Errorf("invalid URL: %w", err)
77+ }
78+
79+ smc := &SSE{
80+ baseURL: parsedURL,
81+ httpClient: &http.Client{},
82+ responses: make(map[string]chan *JSONRPCResponse),
83+ endpointChan: make(chan struct{}),
84+ headers: make(map[string]string),
85+ }
86+
87+ for _, opt := range options {
88+ opt(smc)
89+ }
90+
91+ // If OAuth is configured, set the base URL for metadata discovery
92+ if smc.oauthHandler != nil {
93+ // Extract base URL from server URL for metadata discovery
94+ baseURL := fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host)
95+ smc.oauthHandler.SetBaseURL(baseURL)
96+ }
97+
98+ return smc, nil
99+}
100+
101+// Start initiates the SSE connection to the server and waits for the endpoint information.
102+// Returns an error if the connection fails or times out waiting for the endpoint.
103+func (c *SSE) Start(ctx context.Context) error {
104+
105+ if c.started.Load() {
106+ return fmt.Errorf("has already started")
107+ }
108+
109+ ctx, cancel := context.WithCancel(ctx)
110+ c.cancelSSEStream = cancel
111+
112+ req, err := http.NewRequestWithContext(ctx, "GET", c.baseURL.String(), nil)
113+
114+ if err != nil {
115+ return fmt.Errorf("failed to create request: %w", err)
116+ }
117+
118+ req.Header.Set("Accept", "text/event-stream")
119+ req.Header.Set("Cache-Control", "no-cache")
120+ req.Header.Set("Connection", "keep-alive")
121+
122+ // set custom http headers
123+ for k, v := range c.headers {
124+ req.Header.Set(k, v)
125+ }
126+ if c.headerFunc != nil {
127+ for k, v := range c.headerFunc(ctx) {
128+ req.Header.Set(k, v)
129+ }
130+ }
131+
132+ // Add OAuth authorization if configured
133+ if c.oauthHandler != nil {
134+ authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx)
135+ if err != nil {
136+ // If we get an authorization error, return a specific error that can be handled by the client
137+ if err.Error() == "no valid token available, authorization required" {
138+ return &OAuthAuthorizationRequiredError{
139+ Handler: c.oauthHandler,
140+ }
141+ }
142+ return fmt.Errorf("failed to get authorization header: %w", err)
143+ }
144+ req.Header.Set("Authorization", authHeader)
145+ }
146+
147+ resp, err := c.httpClient.Do(req)
148+ if err != nil {
149+ return fmt.Errorf("failed to connect to SSE stream: %w", err)
150+ }
151+
152+ if resp.StatusCode != http.StatusOK {
153+ resp.Body.Close()
154+ // Handle OAuth unauthorized error
155+ if resp.StatusCode == http.StatusUnauthorized && c.oauthHandler != nil {
156+ return &OAuthAuthorizationRequiredError{
157+ Handler: c.oauthHandler,
158+ }
159+ }
160+ return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
161+ }
162+
163+ go c.readSSE(resp.Body)
164+
165+ // Wait for the endpoint to be received
166+ timeout := time.NewTimer(30 * time.Second)
167+ defer timeout.Stop()
168+ select {
169+ case <-c.endpointChan:
170+ // Endpoint received, proceed
171+ case <-ctx.Done():
172+ return fmt.Errorf("context cancelled while waiting for endpoint")
173+ case <-timeout.C: // Add a timeout
174+ cancel()
175+ return fmt.Errorf("timeout waiting for endpoint")
176+ }
177+
178+ c.started.Store(true)
179+ return nil
180+}
181+
182+// readSSE continuously reads the SSE stream and processes events.
183+// It runs until the connection is closed or an error occurs.
184+func (c *SSE) readSSE(reader io.ReadCloser) {
185+ defer reader.Close()
186+
187+ br := bufio.NewReader(reader)
188+ var event, data string
189+
190+ for {
191+ // when close or start's ctx cancel, the reader will be closed
192+ // and the for loop will break.
193+ line, err := br.ReadString('\n')
194+ if err != nil {
195+ if err == io.EOF {
196+ // Process any pending event before exit
197+ if data != "" {
198+ // If no event type is specified, use empty string (default event type)
199+ if event == "" {
200+ event = "message"
201+ }
202+ c.handleSSEEvent(event, data)
203+ }
204+ break
205+ }
206+ if !c.closed.Load() {
207+ fmt.Printf("SSE stream error: %v\n", err)
208+ }
209+ return
210+ }
211+
212+ // Remove only newline markers
213+ line = strings.TrimRight(line, "\r\n")
214+ if line == "" {
215+ // Empty line means end of event
216+ if data != "" {
217+ // If no event type is specified, use empty string (default event type)
218+ if event == "" {
219+ event = "message"
220+ }
221+ c.handleSSEEvent(event, data)
222+ event = ""
223+ data = ""
224+ }
225+ continue
226+ }
227+
228+ if strings.HasPrefix(line, "event:") {
229+ event = strings.TrimSpace(strings.TrimPrefix(line, "event:"))
230+ } else if strings.HasPrefix(line, "data:") {
231+ data = strings.TrimSpace(strings.TrimPrefix(line, "data:"))
232+ }
233+ }
234+}
235+
236+// handleSSEEvent processes SSE events based on their type.
237+// Handles 'endpoint' events for connection setup and 'message' events for JSON-RPC communication.
238+func (c *SSE) handleSSEEvent(event, data string) {
239+ switch event {
240+ case "endpoint":
241+ endpoint, err := c.baseURL.Parse(data)
242+ if err != nil {
243+ fmt.Printf("Error parsing endpoint URL: %v\n", err)
244+ return
245+ }
246+ if endpoint.Host != c.baseURL.Host {
247+ fmt.Printf("Endpoint origin does not match connection origin\n")
248+ return
249+ }
250+ c.endpoint = endpoint
251+ close(c.endpointChan)
252+
253+ case "message":
254+ var baseMessage JSONRPCResponse
255+ if err := json.Unmarshal([]byte(data), &baseMessage); err != nil {
256+ fmt.Printf("Error unmarshaling message: %v\n", err)
257+ return
258+ }
259+
260+ // Handle notification
261+ if baseMessage.ID.IsNil() {
262+ var notification mcp.JSONRPCNotification
263+ if err := json.Unmarshal([]byte(data), &notification); err != nil {
264+ return
265+ }
266+ c.notifyMu.RLock()
267+ if c.onNotification != nil {
268+ c.onNotification(notification)
269+ }
270+ c.notifyMu.RUnlock()
271+ return
272+ }
273+
274+ // Create string key for map lookup
275+ idKey := baseMessage.ID.String()
276+
277+ c.mu.RLock()
278+ ch, exists := c.responses[idKey]
279+ c.mu.RUnlock()
280+
281+ if exists {
282+ ch <- &baseMessage
283+ c.mu.Lock()
284+ delete(c.responses, idKey)
285+ c.mu.Unlock()
286+ }
287+ }
288+}
289+
290+func (c *SSE) SetNotificationHandler(handler func(notification mcp.JSONRPCNotification)) {
291+ c.notifyMu.Lock()
292+ defer c.notifyMu.Unlock()
293+ c.onNotification = handler
294+}
295+
296+// SendRequest sends a JSON-RPC request to the server and waits for a response.
297+// Returns the raw JSON response message or an error if the request fails.
298+func (c *SSE) SendRequest(
299+ ctx context.Context,
300+ request JSONRPCRequest,
301+) (*JSONRPCResponse, error) {
302+
303+ if !c.started.Load() {
304+ return nil, fmt.Errorf("transport not started yet")
305+ }
306+ if c.closed.Load() {
307+ return nil, fmt.Errorf("transport has been closed")
308+ }
309+ if c.endpoint == nil {
310+ return nil, fmt.Errorf("endpoint not received")
311+ }
312+
313+ // Marshal request
314+ requestBytes, err := json.Marshal(request)
315+ if err != nil {
316+ return nil, fmt.Errorf("failed to marshal request: %w", err)
317+ }
318+
319+ // Create HTTP request
320+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.endpoint.String(), bytes.NewReader(requestBytes))
321+ if err != nil {
322+ return nil, fmt.Errorf("failed to create request: %w", err)
323+ }
324+
325+ // Set headers
326+ req.Header.Set("Content-Type", "application/json")
327+ for k, v := range c.headers {
328+ req.Header.Set(k, v)
329+ }
330+
331+ // Add OAuth authorization if configured
332+ if c.oauthHandler != nil {
333+ authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx)
334+ if err != nil {
335+ // If we get an authorization error, return a specific error that can be handled by the client
336+ if err.Error() == "no valid token available, authorization required" {
337+ return nil, &OAuthAuthorizationRequiredError{
338+ Handler: c.oauthHandler,
339+ }
340+ }
341+ return nil, fmt.Errorf("failed to get authorization header: %w", err)
342+ }
343+ req.Header.Set("Authorization", authHeader)
344+ }
345+
346+ if c.headerFunc != nil {
347+ for k, v := range c.headerFunc(ctx) {
348+ req.Header.Set(k, v)
349+ }
350+ }
351+
352+ // Create string key for map lookup
353+ idKey := request.ID.String()
354+
355+ // Register response channel
356+ responseChan := make(chan *JSONRPCResponse, 1)
357+ c.mu.Lock()
358+ c.responses[idKey] = responseChan
359+ c.mu.Unlock()
360+ deleteResponseChan := func() {
361+ c.mu.Lock()
362+ delete(c.responses, idKey)
363+ c.mu.Unlock()
364+ }
365+
366+ // Send request
367+ resp, err := c.httpClient.Do(req)
368+ if err != nil {
369+ deleteResponseChan()
370+ return nil, fmt.Errorf("failed to send request: %w", err)
371+ }
372+
373+ // Drain any outstanding io
374+ body, err := io.ReadAll(resp.Body)
375+ resp.Body.Close()
376+
377+ if err != nil {
378+ return nil, fmt.Errorf("failed to read response body: %w", err)
379+ }
380+
381+ // Check if we got an error response
382+ if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
383+ deleteResponseChan()
384+
385+ // Handle OAuth unauthorized error
386+ if resp.StatusCode == http.StatusUnauthorized && c.oauthHandler != nil {
387+ return nil, &OAuthAuthorizationRequiredError{
388+ Handler: c.oauthHandler,
389+ }
390+ }
391+
392+ return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, body)
393+ }
394+
395+ select {
396+ case <-ctx.Done():
397+ deleteResponseChan()
398+ return nil, ctx.Err()
399+ case response, ok := <-responseChan:
400+ if ok {
401+ return response, nil
402+ }
403+ return nil, fmt.Errorf("connection has been closed")
404+ }
405+}
406+
407+// Close shuts down the SSE client connection and cleans up any pending responses.
408+// Returns an error if the shutdown process fails.
409+func (c *SSE) Close() error {
410+ if !c.closed.CompareAndSwap(false, true) {
411+ return nil // Already closed
412+ }
413+
414+ if c.cancelSSEStream != nil {
415+ // It could stop the sse stream body, to quit the readSSE loop immediately
416+ // Also, it could quit start() immediately if not receiving the endpoint
417+ c.cancelSSEStream()
418+ }
419+
420+ // Clean up any pending responses
421+ c.mu.Lock()
422+ for _, ch := range c.responses {
423+ close(ch)
424+ }
425+ c.responses = make(map[string]chan *JSONRPCResponse)
426+ c.mu.Unlock()
427+
428+ return nil
429+}
430+
431+// SendNotification sends a JSON-RPC notification to the server without expecting a response.
432+func (c *SSE) SendNotification(ctx context.Context, notification mcp.JSONRPCNotification) error {
433+ if c.endpoint == nil {
434+ return fmt.Errorf("endpoint not received")
435+ }
436+
437+ notificationBytes, err := json.Marshal(notification)
438+ if err != nil {
439+ return fmt.Errorf("failed to marshal notification: %w", err)
440+ }
441+
442+ req, err := http.NewRequestWithContext(
443+ ctx,
444+ "POST",
445+ c.endpoint.String(),
446+ bytes.NewReader(notificationBytes),
447+ )
448+ if err != nil {
449+ return fmt.Errorf("failed to create notification request: %w", err)
450+ }
451+
452+ req.Header.Set("Content-Type", "application/json")
453+ // Set custom HTTP headers
454+ for k, v := range c.headers {
455+ req.Header.Set(k, v)
456+ }
457+
458+ // Add OAuth authorization if configured
459+ if c.oauthHandler != nil {
460+ authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx)
461+ if err != nil {
462+ // If we get an authorization error, return a specific error that can be handled by the client
463+ if errors.Is(err, ErrOAuthAuthorizationRequired) {
464+ return &OAuthAuthorizationRequiredError{
465+ Handler: c.oauthHandler,
466+ }
467+ }
468+ return fmt.Errorf("failed to get authorization header: %w", err)
469+ }
470+ req.Header.Set("Authorization", authHeader)
471+ }
472+
473+ if c.headerFunc != nil {
474+ for k, v := range c.headerFunc(ctx) {
475+ req.Header.Set(k, v)
476+ }
477+ }
478+
479+ resp, err := c.httpClient.Do(req)
480+ if err != nil {
481+ return fmt.Errorf("failed to send notification: %w", err)
482+ }
483+ defer resp.Body.Close()
484+
485+ if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
486+ // Handle OAuth unauthorized error
487+ if resp.StatusCode == http.StatusUnauthorized && c.oauthHandler != nil {
488+ return &OAuthAuthorizationRequiredError{
489+ Handler: c.oauthHandler,
490+ }
491+ }
492+
493+ body, _ := io.ReadAll(resp.Body)
494+ return fmt.Errorf(
495+ "notification failed with status %d: %s",
496+ resp.StatusCode,
497+ body,
498+ )
499+ }
500+
501+ return nil
502+}
503+
504+// GetEndpoint returns the current endpoint URL for the SSE connection.
505+func (c *SSE) GetEndpoint() *url.URL {
506+ return c.endpoint
507+}
508+
509+// GetBaseURL returns the base URL set in the SSE constructor.
510+func (c *SSE) GetBaseURL() *url.URL {
511+ return c.baseURL
512+}
513+
514+// GetOAuthHandler returns the OAuth handler if configured
515+func (c *SSE) GetOAuthHandler() *OAuthHandler {
516+ return c.oauthHandler
517+}
518+
519+// IsOAuthEnabled returns true if OAuth is enabled
520+func (c *SSE) IsOAuthEnabled() bool {
521+ return c.oauthHandler != nil
522+}
vendor/github.com/mark3labs/mcp-go/client/transport/stdio.gonew file+288
@@ -0,0 +1,288 @@
1+package transport
2+
3+import (
4+ "bufio"
5+ "context"
6+ "encoding/json"
7+ "fmt"
8+ "io"
9+ "os"
10+ "os/exec"
11+ "sync"
12+
13+ "github.com/mark3labs/mcp-go/mcp"
14+)
15+
16+// Stdio implements the transport layer of the MCP protocol using stdio communication.
17+// It launches a subprocess and communicates with it via standard input/output streams
18+// using JSON-RPC messages. The client handles message routing between requests and
19+// responses, and supports asynchronous notifications.
20+type Stdio struct {
21+ command string
22+ args []string
23+ env []string
24+
25+ cmd *exec.Cmd
26+ stdin io.WriteCloser
27+ stdout *bufio.Reader
28+ stderr io.ReadCloser
29+ responses map[string]chan *JSONRPCResponse
30+ mu sync.RWMutex
31+ done chan struct{}
32+ onNotification func(mcp.JSONRPCNotification)
33+ notifyMu sync.RWMutex
34+}
35+
36+// NewIO returns a new stdio-based transport using existing input, output, and
37+// logging streams instead of spawning a subprocess.
38+// This is useful for testing and simulating client behavior.
39+func NewIO(input io.Reader, output io.WriteCloser, logging io.ReadCloser) *Stdio {
40+ return &Stdio{
41+ stdin: output,
42+ stdout: bufio.NewReader(input),
43+ stderr: logging,
44+
45+ responses: make(map[string]chan *JSONRPCResponse),
46+ done: make(chan struct{}),
47+ }
48+}
49+
50+// NewStdio creates a new stdio transport to communicate with a subprocess.
51+// It launches the specified command with given arguments and sets up stdin/stdout pipes for communication.
52+// Returns an error if the subprocess cannot be started or the pipes cannot be created.
53+func NewStdio(
54+ command string,
55+ env []string,
56+ args ...string,
57+) *Stdio {
58+
59+ client := &Stdio{
60+ command: command,
61+ args: args,
62+ env: env,
63+
64+ responses: make(map[string]chan *JSONRPCResponse),
65+ done: make(chan struct{}),
66+ }
67+
68+ return client
69+}
70+
71+func (c *Stdio) Start(ctx context.Context) error {
72+ if err := c.spawnCommand(ctx); err != nil {
73+ return err
74+ }
75+
76+ ready := make(chan struct{})
77+ go func() {
78+ close(ready)
79+ c.readResponses()
80+ }()
81+ <-ready
82+
83+ return nil
84+}
85+
86+// spawnCommand spawns a new process running c.command.
87+func (c *Stdio) spawnCommand(ctx context.Context) error {
88+ if c.command == "" {
89+ return nil
90+ }
91+
92+ cmd := exec.CommandContext(ctx, c.command, c.args...)
93+
94+ mergedEnv := os.Environ()
95+ mergedEnv = append(mergedEnv, c.env...)
96+
97+ cmd.Env = mergedEnv
98+
99+ stdin, err := cmd.StdinPipe()
100+ if err != nil {
101+ return fmt.Errorf("failed to create stdin pipe: %w", err)
102+ }
103+
104+ stdout, err := cmd.StdoutPipe()
105+ if err != nil {
106+ return fmt.Errorf("failed to create stdout pipe: %w", err)
107+ }
108+
109+ stderr, err := cmd.StderrPipe()
110+ if err != nil {
111+ return fmt.Errorf("failed to create stderr pipe: %w", err)
112+ }
113+
114+ c.cmd = cmd
115+ c.stdin = stdin
116+ c.stderr = stderr
117+ c.stdout = bufio.NewReader(stdout)
118+
119+ if err := cmd.Start(); err != nil {
120+ return fmt.Errorf("failed to start command: %w", err)
121+ }
122+
123+ return nil
124+}
125+
126+// Close shuts down the stdio client, closing the stdin pipe and waiting for the subprocess to exit.
127+// Returns an error if there are issues closing stdin or waiting for the subprocess to terminate.
128+func (c *Stdio) Close() error {
129+ select {
130+ case <-c.done:
131+ return nil
132+ default:
133+ }
134+ // cancel all in-flight request
135+ close(c.done)
136+
137+ if err := c.stdin.Close(); err != nil {
138+ return fmt.Errorf("failed to close stdin: %w", err)
139+ }
140+ if err := c.stderr.Close(); err != nil {
141+ return fmt.Errorf("failed to close stderr: %w", err)
142+ }
143+
144+ if c.cmd != nil {
145+ return c.cmd.Wait()
146+ }
147+
148+ return nil
149+}
150+
151+// SetNotificationHandler sets the handler function to be called when a notification is received.
152+// Only one handler can be set at a time; setting a new one replaces the previous handler.
153+func (c *Stdio) SetNotificationHandler(
154+ handler func(notification mcp.JSONRPCNotification),
155+) {
156+ c.notifyMu.Lock()
157+ defer c.notifyMu.Unlock()
158+ c.onNotification = handler
159+}
160+
161+// readResponses continuously reads and processes responses from the server's stdout.
162+// It handles both responses to requests and notifications, routing them appropriately.
163+// Runs until the done channel is closed or an error occurs reading from stdout.
164+func (c *Stdio) readResponses() {
165+ for {
166+ select {
167+ case <-c.done:
168+ return
169+ default:
170+ line, err := c.stdout.ReadString('\n')
171+ if err != nil {
172+ if err != io.EOF {
173+ fmt.Printf("Error reading response: %v\n", err)
174+ }
175+ return
176+ }
177+
178+ var baseMessage JSONRPCResponse
179+ if err := json.Unmarshal([]byte(line), &baseMessage); err != nil {
180+ continue
181+ }
182+
183+ // Handle notification
184+ if baseMessage.ID.IsNil() {
185+ var notification mcp.JSONRPCNotification
186+ if err := json.Unmarshal([]byte(line), &notification); err != nil {
187+ continue
188+ }
189+ c.notifyMu.RLock()
190+ if c.onNotification != nil {
191+ c.onNotification(notification)
192+ }
193+ c.notifyMu.RUnlock()
194+ continue
195+ }
196+
197+ // Create string key for map lookup
198+ idKey := baseMessage.ID.String()
199+
200+ c.mu.RLock()
201+ ch, exists := c.responses[idKey]
202+ c.mu.RUnlock()
203+
204+ if exists {
205+ ch <- &baseMessage
206+ c.mu.Lock()
207+ delete(c.responses, idKey)
208+ c.mu.Unlock()
209+ }
210+ }
211+ }
212+}
213+
214+// SendRequest sends a JSON-RPC request to the server and waits for a response.
215+// It creates a unique request ID, sends the request over stdin, and waits for
216+// the corresponding response or context cancellation.
217+// Returns the raw JSON response message or an error if the request fails.
218+func (c *Stdio) SendRequest(
219+ ctx context.Context,
220+ request JSONRPCRequest,
221+) (*JSONRPCResponse, error) {
222+ if c.stdin == nil {
223+ return nil, fmt.Errorf("stdio client not started")
224+ }
225+
226+ // Marshal request
227+ requestBytes, err := json.Marshal(request)
228+ if err != nil {
229+ return nil, fmt.Errorf("failed to marshal request: %w", err)
230+ }
231+ requestBytes = append(requestBytes, '\n')
232+
233+ // Create string key for map lookup
234+ idKey := request.ID.String()
235+
236+ // Register response channel
237+ responseChan := make(chan *JSONRPCResponse, 1)
238+ c.mu.Lock()
239+ c.responses[idKey] = responseChan
240+ c.mu.Unlock()
241+ deleteResponseChan := func() {
242+ c.mu.Lock()
243+ delete(c.responses, idKey)
244+ c.mu.Unlock()
245+ }
246+
247+ // Send request
248+ if _, err := c.stdin.Write(requestBytes); err != nil {
249+ deleteResponseChan()
250+ return nil, fmt.Errorf("failed to write request: %w", err)
251+ }
252+
253+ select {
254+ case <-ctx.Done():
255+ deleteResponseChan()
256+ return nil, ctx.Err()
257+ case response := <-responseChan:
258+ return response, nil
259+ }
260+}
261+
262+// SendNotification sends a json RPC Notification to the server.
263+func (c *Stdio) SendNotification(
264+ ctx context.Context,
265+ notification mcp.JSONRPCNotification,
266+) error {
267+ if c.stdin == nil {
268+ return fmt.Errorf("stdio client not started")
269+ }
270+
271+ notificationBytes, err := json.Marshal(notification)
272+ if err != nil {
273+ return fmt.Errorf("failed to marshal notification: %w", err)
274+ }
275+ notificationBytes = append(notificationBytes, '\n')
276+
277+ if _, err := c.stdin.Write(notificationBytes); err != nil {
278+ return fmt.Errorf("failed to write notification: %w", err)
279+ }
280+
281+ return nil
282+}
283+
284+// Stderr returns a reader for the stderr output of the subprocess.
285+// This can be used to capture error messages or logs from the subprocess.
286+func (c *Stdio) Stderr() io.Reader {
287+ return c.stderr
288+}
vendor/github.com/mark3labs/mcp-go/client/transport/streamable_http.gonew file+515
@@ -0,0 +1,515 @@
1+package transport
2+
3+import (
4+ "bufio"
5+ "bytes"
6+ "context"
7+ "encoding/json"
8+ "errors"
9+ "fmt"
10+ "io"
11+ "mime"
12+ "net/http"
13+ "net/url"
14+ "strings"
15+ "sync"
16+ "sync/atomic"
17+ "time"
18+
19+ "github.com/mark3labs/mcp-go/mcp"
20+)
21+
22+type StreamableHTTPCOption func(*StreamableHTTP)
23+
24+// WithHTTPClient sets a custom HTTP client on the StreamableHTTP transport.
25+func WithHTTPBasicClient(client *http.Client) StreamableHTTPCOption {
26+ return func(sc *StreamableHTTP) {
27+ sc.httpClient = client
28+ }
29+}
30+
31+func WithHTTPHeaders(headers map[string]string) StreamableHTTPCOption {
32+ return func(sc *StreamableHTTP) {
33+ sc.headers = headers
34+ }
35+}
36+
37+func WithHTTPHeaderFunc(headerFunc HTTPHeaderFunc) StreamableHTTPCOption {
38+ return func(sc *StreamableHTTP) {
39+ sc.headerFunc = headerFunc
40+ }
41+}
42+
43+// WithHTTPTimeout sets the timeout for a HTTP request and stream.
44+func WithHTTPTimeout(timeout time.Duration) StreamableHTTPCOption {
45+ return func(sc *StreamableHTTP) {
46+ sc.httpClient.Timeout = timeout
47+ }
48+}
49+
50+// WithHTTPOAuth enables OAuth authentication for the client.
51+func WithHTTPOAuth(config OAuthConfig) StreamableHTTPCOption {
52+ return func(sc *StreamableHTTP) {
53+ sc.oauthHandler = NewOAuthHandler(config)
54+ }
55+}
56+
57+// StreamableHTTP implements Streamable HTTP transport.
58+//
59+// It transmits JSON-RPC messages over individual HTTP requests. One message per request.
60+// The HTTP response body can either be a single JSON-RPC response,
61+// or an upgraded SSE stream that concludes with a JSON-RPC response for the same request.
62+//
63+// https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
64+//
65+// The current implementation does not support the following features:
66+// - batching
67+// - continuously listening for server notifications when no request is in flight
68+// (https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#listening-for-messages-from-the-server)
69+// - resuming stream
70+// (https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#resumability-and-redelivery)
71+// - server -> client request
72+type StreamableHTTP struct {
73+ serverURL *url.URL
74+ httpClient *http.Client
75+ headers map[string]string
76+ headerFunc HTTPHeaderFunc
77+
78+ sessionID atomic.Value // string
79+
80+ notificationHandler func(mcp.JSONRPCNotification)
81+ notifyMu sync.RWMutex
82+
83+ closed chan struct{}
84+
85+ // OAuth support
86+ oauthHandler *OAuthHandler
87+}
88+
89+// NewStreamableHTTP creates a new Streamable HTTP transport with the given server URL.
90+// Returns an error if the URL is invalid.
91+func NewStreamableHTTP(serverURL string, options ...StreamableHTTPCOption) (*StreamableHTTP, error) {
92+ parsedURL, err := url.Parse(serverURL)
93+ if err != nil {
94+ return nil, fmt.Errorf("invalid URL: %w", err)
95+ }
96+
97+ smc := &StreamableHTTP{
98+ serverURL: parsedURL,
99+ httpClient: &http.Client{},
100+ headers: make(map[string]string),
101+ closed: make(chan struct{}),
102+ }
103+ smc.sessionID.Store("") // set initial value to simplify later usage
104+
105+ for _, opt := range options {
106+ opt(smc)
107+ }
108+
109+ // If OAuth is configured, set the base URL for metadata discovery
110+ if smc.oauthHandler != nil {
111+ // Extract base URL from server URL for metadata discovery
112+ baseURL := fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host)
113+ smc.oauthHandler.SetBaseURL(baseURL)
114+ }
115+
116+ return smc, nil
117+}
118+
119+// Start initiates the HTTP connection to the server.
120+func (c *StreamableHTTP) Start(ctx context.Context) error {
121+ // For Streamable HTTP, we don't need to establish a persistent connection
122+ return nil
123+}
124+
125+// Close closes the all the HTTP connections to the server.
126+func (c *StreamableHTTP) Close() error {
127+ select {
128+ case <-c.closed:
129+ return nil
130+ default:
131+ }
132+ // Cancel all in-flight requests
133+ close(c.closed)
134+
135+ sessionId := c.sessionID.Load().(string)
136+ if sessionId != "" {
137+ c.sessionID.Store("")
138+
139+ // notify server session closed
140+ go func() {
141+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
142+ defer cancel()
143+ req, err := http.NewRequestWithContext(ctx, http.MethodDelete, c.serverURL.String(), nil)
144+ if err != nil {
145+ fmt.Printf("failed to create close request\n: %v", err)
146+ return
147+ }
148+ req.Header.Set(headerKeySessionID, sessionId)
149+ res, err := c.httpClient.Do(req)
150+ if err != nil {
151+ fmt.Printf("failed to send close request\n: %v", err)
152+ return
153+ }
154+ res.Body.Close()
155+ }()
156+ }
157+
158+ return nil
159+}
160+
161+const (
162+ headerKeySessionID = "Mcp-Session-Id"
163+)
164+
165+// ErrOAuthAuthorizationRequired is a sentinel error for OAuth authorization required
166+var ErrOAuthAuthorizationRequired = errors.New("no valid token available, authorization required")
167+
168+// OAuthAuthorizationRequiredError is returned when OAuth authorization is required
169+type OAuthAuthorizationRequiredError struct {
170+ Handler *OAuthHandler
171+}
172+
173+func (e *OAuthAuthorizationRequiredError) Error() string {
174+ return ErrOAuthAuthorizationRequired.Error()
175+}
176+
177+func (e *OAuthAuthorizationRequiredError) Unwrap() error {
178+ return ErrOAuthAuthorizationRequired
179+}
180+
181+// SendRequest sends a JSON-RPC request to the server and waits for a response.
182+// Returns the raw JSON response message or an error if the request fails.
183+func (c *StreamableHTTP) SendRequest(
184+ ctx context.Context,
185+ request JSONRPCRequest,
186+) (*JSONRPCResponse, error) {
187+
188+ // Create a combined context that could be canceled when the client is closed
189+ newCtx, cancel := context.WithCancel(ctx)
190+ defer cancel()
191+ go func() {
192+ select {
193+ case <-c.closed:
194+ cancel()
195+ case <-newCtx.Done():
196+ // The original context was canceled, no need to do anything
197+ }
198+ }()
199+ ctx = newCtx
200+
201+ // Marshal request
202+ requestBody, err := json.Marshal(request)
203+ if err != nil {
204+ return nil, fmt.Errorf("failed to marshal request: %w", err)
205+ }
206+
207+ // Create HTTP request
208+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.serverURL.String(), bytes.NewReader(requestBody))
209+ if err != nil {
210+ return nil, fmt.Errorf("failed to create request: %w", err)
211+ }
212+
213+ // Set headers
214+ req.Header.Set("Content-Type", "application/json")
215+ req.Header.Set("Accept", "application/json, text/event-stream")
216+ sessionID := c.sessionID.Load()
217+ if sessionID != "" {
218+ req.Header.Set(headerKeySessionID, sessionID.(string))
219+ }
220+ for k, v := range c.headers {
221+ req.Header.Set(k, v)
222+ }
223+
224+ // Add OAuth authorization if configured
225+ if c.oauthHandler != nil {
226+ authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx)
227+ if err != nil {
228+ // If we get an authorization error, return a specific error that can be handled by the client
229+ if err.Error() == "no valid token available, authorization required" {
230+ return nil, &OAuthAuthorizationRequiredError{
231+ Handler: c.oauthHandler,
232+ }
233+ }
234+ return nil, fmt.Errorf("failed to get authorization header: %w", err)
235+ }
236+ req.Header.Set("Authorization", authHeader)
237+ }
238+
239+ if c.headerFunc != nil {
240+ for k, v := range c.headerFunc(ctx) {
241+ req.Header.Set(k, v)
242+ }
243+ }
244+
245+ // Send request
246+ resp, err := c.httpClient.Do(req)
247+ if err != nil {
248+ return nil, fmt.Errorf("failed to send request: %w", err)
249+ }
250+ defer resp.Body.Close()
251+
252+ // Check if we got an error response
253+ if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
254+ // handle session closed
255+ if resp.StatusCode == http.StatusNotFound {
256+ c.sessionID.CompareAndSwap(sessionID, "")
257+ return nil, fmt.Errorf("session terminated (404). need to re-initialize")
258+ }
259+
260+ // Handle OAuth unauthorized error
261+ if resp.StatusCode == http.StatusUnauthorized && c.oauthHandler != nil {
262+ return nil, &OAuthAuthorizationRequiredError{
263+ Handler: c.oauthHandler,
264+ }
265+ }
266+
267+ // handle error response
268+ var errResponse JSONRPCResponse
269+ body, _ := io.ReadAll(resp.Body)
270+ if err := json.Unmarshal(body, &errResponse); err == nil {
271+ return &errResponse, nil
272+ }
273+ return nil, fmt.Errorf("request failed with status %d: %s", resp.StatusCode, body)
274+ }
275+
276+ if request.Method == string(mcp.MethodInitialize) {
277+ // saved the received session ID in the response
278+ // empty session ID is allowed
279+ if sessionID := resp.Header.Get(headerKeySessionID); sessionID != "" {
280+ c.sessionID.Store(sessionID)
281+ }
282+ }
283+
284+ // Handle different response types
285+ mediaType, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
286+ switch mediaType {
287+ case "application/json":
288+ // Single response
289+ var response JSONRPCResponse
290+ if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
291+ return nil, fmt.Errorf("failed to decode response: %w", err)
292+ }
293+
294+ // should not be a notification
295+ if response.ID.IsNil() {
296+ return nil, fmt.Errorf("response should contain RPC id: %v", response)
297+ }
298+
299+ return &response, nil
300+
301+ case "text/event-stream":
302+ // Server is using SSE for streaming responses
303+ return c.handleSSEResponse(ctx, resp.Body)
304+
305+ default:
306+ return nil, fmt.Errorf("unexpected content type: %s", resp.Header.Get("Content-Type"))
307+ }
308+}
309+
310+// handleSSEResponse processes an SSE stream for a specific request.
311+// It returns the final result for the request once received, or an error.
312+func (c *StreamableHTTP) handleSSEResponse(ctx context.Context, reader io.ReadCloser) (*JSONRPCResponse, error) {
313+
314+ // Create a channel for this specific request
315+ responseChan := make(chan *JSONRPCResponse, 1)
316+
317+ ctx, cancel := context.WithCancel(ctx)
318+ defer cancel()
319+
320+ // Start a goroutine to process the SSE stream
321+ go func() {
322+ // only close responseChan after readingSSE()
323+ defer close(responseChan)
324+
325+ c.readSSE(ctx, reader, func(event, data string) {
326+
327+ // (unsupported: batching)
328+
329+ var message JSONRPCResponse
330+ if err := json.Unmarshal([]byte(data), &message); err != nil {
331+ fmt.Printf("failed to unmarshal message: %v\n", err)
332+ return
333+ }
334+
335+ // Handle notification
336+ if message.ID.IsNil() {
337+ var notification mcp.JSONRPCNotification
338+ if err := json.Unmarshal([]byte(data), &notification); err != nil {
339+ fmt.Printf("failed to unmarshal notification: %v\n", err)
340+ return
341+ }
342+ c.notifyMu.RLock()
343+ if c.notificationHandler != nil {
344+ c.notificationHandler(notification)
345+ }
346+ c.notifyMu.RUnlock()
347+ return
348+ }
349+
350+ responseChan <- &message
351+ })
352+ }()
353+
354+ // Wait for the response or context cancellation
355+ select {
356+ case response := <-responseChan:
357+ if response == nil {
358+ return nil, fmt.Errorf("unexpected nil response")
359+ }
360+ return response, nil
361+ case <-ctx.Done():
362+ return nil, ctx.Err()
363+ }
364+}
365+
366+// readSSE reads the SSE stream(reader) and calls the handler for each event and data pair.
367+// It will end when the reader is closed (or the context is done).
368+func (c *StreamableHTTP) readSSE(ctx context.Context, reader io.ReadCloser, handler func(event, data string)) {
369+ defer reader.Close()
370+
371+ br := bufio.NewReader(reader)
372+ var event, data string
373+
374+ for {
375+ select {
376+ case <-ctx.Done():
377+ return
378+ default:
379+ line, err := br.ReadString('\n')
380+ if err != nil {
381+ if err == io.EOF {
382+ // Process any pending event before exit
383+ if data != "" {
384+ // If no event type is specified, use empty string (default event type)
385+ if event == "" {
386+ event = "message"
387+ }
388+ handler(event, data)
389+ }
390+ return
391+ }
392+ select {
393+ case <-ctx.Done():
394+ return
395+ default:
396+ fmt.Printf("SSE stream error: %v\n", err)
397+ return
398+ }
399+ }
400+
401+ // Remove only newline markers
402+ line = strings.TrimRight(line, "\r\n")
403+ if line == "" {
404+ // Empty line means end of event
405+ if data != "" {
406+ // If no event type is specified, use empty string (default event type)
407+ if event == "" {
408+ event = "message"
409+ }
410+ handler(event, data)
411+ event = ""
412+ data = ""
413+ }
414+ continue
415+ }
416+
417+ if strings.HasPrefix(line, "event:") {
418+ event = strings.TrimSpace(strings.TrimPrefix(line, "event:"))
419+ } else if strings.HasPrefix(line, "data:") {
420+ data = strings.TrimSpace(strings.TrimPrefix(line, "data:"))
421+ }
422+ }
423+ }
424+}
425+
426+func (c *StreamableHTTP) SendNotification(ctx context.Context, notification mcp.JSONRPCNotification) error {
427+
428+ // Marshal request
429+ requestBody, err := json.Marshal(notification)
430+ if err != nil {
431+ return fmt.Errorf("failed to marshal notification: %w", err)
432+ }
433+
434+ // Create HTTP request
435+ req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.serverURL.String(), bytes.NewReader(requestBody))
436+ if err != nil {
437+ return fmt.Errorf("failed to create request: %w", err)
438+ }
439+
440+ // Set headers
441+ req.Header.Set("Content-Type", "application/json")
442+ req.Header.Set("Accept", "application/json, text/event-stream")
443+ if sessionID := c.sessionID.Load(); sessionID != "" {
444+ req.Header.Set(headerKeySessionID, sessionID.(string))
445+ }
446+ for k, v := range c.headers {
447+ req.Header.Set(k, v)
448+ }
449+
450+ // Add OAuth authorization if configured
451+ if c.oauthHandler != nil {
452+ authHeader, err := c.oauthHandler.GetAuthorizationHeader(ctx)
453+ if err != nil {
454+ // If we get an authorization error, return a specific error that can be handled by the client
455+ if errors.Is(err, ErrOAuthAuthorizationRequired) {
456+ return &OAuthAuthorizationRequiredError{
457+ Handler: c.oauthHandler,
458+ }
459+ }
460+ return fmt.Errorf("failed to get authorization header: %w", err)
461+ }
462+ req.Header.Set("Authorization", authHeader)
463+ }
464+
465+ if c.headerFunc != nil {
466+ for k, v := range c.headerFunc(ctx) {
467+ req.Header.Set(k, v)
468+ }
469+ }
470+
471+ // Send request
472+ resp, err := c.httpClient.Do(req)
473+ if err != nil {
474+ return fmt.Errorf("failed to send request: %w", err)
475+ }
476+ defer resp.Body.Close()
477+
478+ if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusAccepted {
479+ // Handle OAuth unauthorized error
480+ if resp.StatusCode == http.StatusUnauthorized && c.oauthHandler != nil {
481+ return &OAuthAuthorizationRequiredError{
482+ Handler: c.oauthHandler,
483+ }
484+ }
485+
486+ body, _ := io.ReadAll(resp.Body)
487+ return fmt.Errorf(
488+ "notification failed with status %d: %s",
489+ resp.StatusCode,
490+ body,
491+ )
492+ }
493+
494+ return nil
495+}
496+
497+func (c *StreamableHTTP) SetNotificationHandler(handler func(mcp.JSONRPCNotification)) {
498+ c.notifyMu.Lock()
499+ defer c.notifyMu.Unlock()
500+ c.notificationHandler = handler
501+}
502+
503+func (c *StreamableHTTP) GetSessionId() string {
504+ return c.sessionID.Load().(string)
505+}
506+
507+// GetOAuthHandler returns the OAuth handler if configured
508+func (c *StreamableHTTP) GetOAuthHandler() *OAuthHandler {
509+ return c.oauthHandler
510+}
511+
512+// IsOAuthEnabled returns true if OAuth is enabled
513+func (c *StreamableHTTP) IsOAuthEnabled() bool {
514+ return c.oauthHandler != nil
515+}
vendor/github.com/mark3labs/mcp-go/client/types.godeleted−8
@@ -1,8 +0,0 @@
1−package client
2−
3−import "encoding/json"
4−
5−type RPCResponse struct {
6− Error *string
7− Response *json.RawMessage
8−}
vendor/github.com/mark3labs/mcp-go/mcp/prompts.go+14−7
@@ -19,12 +19,14 @@ type ListPromptsResult struct {
1919// server.
2020type GetPromptRequest struct {
2121 Request
22− Params struct {
23− // The name of the prompt or prompt template.
24− Name string `json:"name"`
25− // Arguments to use for templating the prompt.
26− Arguments map[string]string `json:"arguments,omitempty"`
27− } `json:"params"`
22+ Params GetPromptParams `json:"params"`
23+}
24+
25+type GetPromptParams struct {
26+ // The name of the prompt or prompt template.
27+ Name string `json:"name"`
28+ // Arguments to use for templating the prompt.
29+ Arguments map[string]string `json:"arguments,omitempty"`
2830}
2931
3032// GetPromptResult is the server's response to a prompts/get request from the
@@ -50,6 +52,11 @@ type Prompt struct {
5052 Arguments []PromptArgument `json:"arguments,omitempty"`
5153}
5254
55+// GetName returns the name of the prompt.
56+func (p Prompt) GetName() string {
57+ return p.Name
58+}
59+
5360// PromptArgument describes an argument that a prompt template can accept.
5461// When a prompt includes arguments, clients must provide values for all
5562// required arguments when making a prompts/get request.
@@ -78,7 +85,7 @@ const (
7885// resources from the MCP server.
7986type PromptMessage struct {
8087 Role Role `json:"role"`
81− Content Content `json:"content"` // Can be TextContent, ImageContent, or EmbeddedResource
88+ Content Content `json:"content"` // Can be TextContent, ImageContent, AudioContent or EmbeddedResource
8289}
8390
8491// PromptListChangedNotification is an optional notification from the server
vendor/github.com/mark3labs/mcp-go/mcp/resources.go+2−8
@@ -43,10 +43,7 @@ func WithMIMEType(mimeType string) ResourceOption {
4343func WithAnnotations(audience []Role, priority float64) ResourceOption {
4444 return func(r *Resource) {
4545 if r.Annotations == nil {
46− r.Annotations = &struct {
47− Audience []Role `json:"audience,omitempty"`
48− Priority float64 `json:"priority,omitempty"`
49− }{}
46+ r.Annotations = &Annotations{}
5047 }
5148 r.Annotations.Audience = audience
5249 r.Annotations.Priority = priority
@@ -94,10 +91,7 @@ func WithTemplateMIMEType(mimeType string) ResourceTemplateOption {
9491func WithTemplateAnnotations(audience []Role, priority float64) ResourceTemplateOption {
9592 return func(t *ResourceTemplate) {
9693 if t.Annotations == nil {
97− t.Annotations = &struct {
98− Audience []Role `json:"audience,omitempty"`
99− Priority float64 `json:"priority,omitempty"`
100− }{}
94+ t.Annotations = &Annotations{}
10195 }
10296 t.Annotations.Audience = audience
10397 t.Annotations.Priority = priority
vendor/github.com/mark3labs/mcp-go/mcp/tools.go+565−77
@@ -4,6 +4,8 @@ import (
44 "encoding/json"
55 "errors"
66 "fmt"
7+ "reflect"
8+ "strconv"
79)
810
911var errToolSchemaConflict = errors.New("provide either InputSchema or RawInputSchema, not both")
@@ -33,7 +35,7 @@ type ListToolsResult struct {
3335// should be reported as an MCP error response.
3436type CallToolResult struct {
3537 Result
36− Content []Content `json:"content"` // Can be TextContent, ImageContent, or EmbeddedResource
38+ Content []Content `json:"content"` // Can be TextContent, ImageContent, AudioContent, or EmbeddedResource
3739 // Whether the tool call ended in an error.
3840 //
3941 // If not set, this is assumed to be false (the call was successful).
@@ -43,19 +45,420 @@ type CallToolResult struct {
4345// CallToolRequest is used by the client to invoke a tool provided by the server.
4446type CallToolRequest struct {
4547 Request
46− Params struct {
47− Name string `json:"name"`
48− Arguments map[string]interface{} `json:"arguments,omitempty"`
49− Meta *struct {
50− // If specified, the caller is requesting out-of-band progress
51− // notifications for this request (as represented by
52− // notifications/progress). The value of this parameter is an
53− // opaque token that will be attached to any subsequent
54− // notifications. The receiver is not obligated to provide these
55− // notifications.
56− ProgressToken ProgressToken `json:"progressToken,omitempty"`
57− } `json:"_meta,omitempty"`
58− } `json:"params"`
48+ Params CallToolParams `json:"params"`
49+}
50+
51+type CallToolParams struct {
52+ Name string `json:"name"`
53+ Arguments any `json:"arguments,omitempty"`
54+ Meta *Meta `json:"_meta,omitempty"`
55+}
56+
57+// GetArguments returns the Arguments as map[string]any for backward compatibility
58+// If Arguments is not a map, it returns an empty map
59+func (r CallToolRequest) GetArguments() map[string]any {
60+ if args, ok := r.Params.Arguments.(map[string]any); ok {
61+ return args
62+ }
63+ return nil
64+}
65+
66+// GetRawArguments returns the Arguments as-is without type conversion
67+// This allows users to access the raw arguments in any format
68+func (r CallToolRequest) GetRawArguments() any {
69+ return r.Params.Arguments
70+}
71+
72+// BindArguments unmarshals the Arguments into the provided struct
73+// This is useful for working with strongly-typed arguments
74+func (r CallToolRequest) BindArguments(target any) error {
75+ if target == nil || reflect.ValueOf(target).Kind() != reflect.Ptr {
76+ return fmt.Errorf("target must be a non-nil pointer")
77+ }
78+
79+ // Fast-path: already raw JSON
80+ if raw, ok := r.Params.Arguments.(json.RawMessage); ok {
81+ return json.Unmarshal(raw, target)
82+ }
83+
84+ data, err := json.Marshal(r.Params.Arguments)
85+ if err != nil {
86+ return fmt.Errorf("failed to marshal arguments: %w", err)
87+ }
88+
89+ return json.Unmarshal(data, target)
90+}
91+
92+// GetString returns a string argument by key, or the default value if not found
93+func (r CallToolRequest) GetString(key string, defaultValue string) string {
94+ args := r.GetArguments()
95+ if val, ok := args[key]; ok {
96+ if str, ok := val.(string); ok {
97+ return str
98+ }
99+ }
100+ return defaultValue
101+}
102+
103+// RequireString returns a string argument by key, or an error if not found or not a string
104+func (r CallToolRequest) RequireString(key string) (string, error) {
105+ args := r.GetArguments()
106+ if val, ok := args[key]; ok {
107+ if str, ok := val.(string); ok {
108+ return str, nil
109+ }
110+ return "", fmt.Errorf("argument %q is not a string", key)
111+ }
112+ return "", fmt.Errorf("required argument %q not found", key)
113+}
114+
115+// GetInt returns an int argument by key, or the default value if not found
116+func (r CallToolRequest) GetInt(key string, defaultValue int) int {
117+ args := r.GetArguments()
118+ if val, ok := args[key]; ok {
119+ switch v := val.(type) {
120+ case int:
121+ return v
122+ case float64:
123+ return int(v)
124+ case string:
125+ if i, err := strconv.Atoi(v); err == nil {
126+ return i
127+ }
128+ }
129+ }
130+ return defaultValue
131+}
132+
133+// RequireInt returns an int argument by key, or an error if not found or not convertible to int
134+func (r CallToolRequest) RequireInt(key string) (int, error) {
135+ args := r.GetArguments()
136+ if val, ok := args[key]; ok {
137+ switch v := val.(type) {
138+ case int:
139+ return v, nil
140+ case float64:
141+ return int(v), nil
142+ case string:
143+ if i, err := strconv.Atoi(v); err == nil {
144+ return i, nil
145+ }
146+ return 0, fmt.Errorf("argument %q cannot be converted to int", key)
147+ default:
148+ return 0, fmt.Errorf("argument %q is not an int", key)
149+ }
150+ }
151+ return 0, fmt.Errorf("required argument %q not found", key)
152+}
153+
154+// GetFloat returns a float64 argument by key, or the default value if not found
155+func (r CallToolRequest) GetFloat(key string, defaultValue float64) float64 {
156+ args := r.GetArguments()
157+ if val, ok := args[key]; ok {
158+ switch v := val.(type) {
159+ case float64:
160+ return v
161+ case int:
162+ return float64(v)
163+ case string:
164+ if f, err := strconv.ParseFloat(v, 64); err == nil {
165+ return f
166+ }
167+ }
168+ }
169+ return defaultValue
170+}
171+
172+// RequireFloat returns a float64 argument by key, or an error if not found or not convertible to float64
173+func (r CallToolRequest) RequireFloat(key string) (float64, error) {
174+ args := r.GetArguments()
175+ if val, ok := args[key]; ok {
176+ switch v := val.(type) {
177+ case float64:
178+ return v, nil
179+ case int:
180+ return float64(v), nil
181+ case string:
182+ if f, err := strconv.ParseFloat(v, 64); err == nil {
183+ return f, nil
184+ }
185+ return 0, fmt.Errorf("argument %q cannot be converted to float64", key)
186+ default:
187+ return 0, fmt.Errorf("argument %q is not a float64", key)
188+ }
189+ }
190+ return 0, fmt.Errorf("required argument %q not found", key)
191+}
192+
193+// GetBool returns a bool argument by key, or the default value if not found
194+func (r CallToolRequest) GetBool(key string, defaultValue bool) bool {
195+ args := r.GetArguments()
196+ if val, ok := args[key]; ok {
197+ switch v := val.(type) {
198+ case bool:
199+ return v
200+ case string:
201+ if b, err := strconv.ParseBool(v); err == nil {
202+ return b
203+ }
204+ case int:
205+ return v != 0
206+ case float64:
207+ return v != 0
208+ }
209+ }
210+ return defaultValue
211+}
212+
213+// RequireBool returns a bool argument by key, or an error if not found or not convertible to bool
214+func (r CallToolRequest) RequireBool(key string) (bool, error) {
215+ args := r.GetArguments()
216+ if val, ok := args[key]; ok {
217+ switch v := val.(type) {
218+ case bool:
219+ return v, nil
220+ case string:
221+ if b, err := strconv.ParseBool(v); err == nil {
222+ return b, nil
223+ }
224+ return false, fmt.Errorf("argument %q cannot be converted to bool", key)
225+ case int:
226+ return v != 0, nil
227+ case float64:
228+ return v != 0, nil
229+ default:
230+ return false, fmt.Errorf("argument %q is not a bool", key)
231+ }
232+ }
233+ return false, fmt.Errorf("required argument %q not found", key)
234+}
235+
236+// GetStringSlice returns a string slice argument by key, or the default value if not found
237+func (r CallToolRequest) GetStringSlice(key string, defaultValue []string) []string {
238+ args := r.GetArguments()
239+ if val, ok := args[key]; ok {
240+ switch v := val.(type) {
241+ case []string:
242+ return v
243+ case []any:
244+ result := make([]string, 0, len(v))
245+ for _, item := range v {
246+ if str, ok := item.(string); ok {
247+ result = append(result, str)
248+ }
249+ }
250+ return result
251+ }
252+ }
253+ return defaultValue
254+}
255+
256+// RequireStringSlice returns a string slice argument by key, or an error if not found or not convertible to string slice
257+func (r CallToolRequest) RequireStringSlice(key string) ([]string, error) {
258+ args := r.GetArguments()
259+ if val, ok := args[key]; ok {
260+ switch v := val.(type) {
261+ case []string:
262+ return v, nil
263+ case []any:
264+ result := make([]string, 0, len(v))
265+ for i, item := range v {
266+ if str, ok := item.(string); ok {
267+ result = append(result, str)
268+ } else {
269+ return nil, fmt.Errorf("item %d in argument %q is not a string", i, key)
270+ }
271+ }
272+ return result, nil
273+ default:
274+ return nil, fmt.Errorf("argument %q is not a string slice", key)
275+ }
276+ }
277+ return nil, fmt.Errorf("required argument %q not found", key)
278+}
279+
280+// GetIntSlice returns an int slice argument by key, or the default value if not found
281+func (r CallToolRequest) GetIntSlice(key string, defaultValue []int) []int {
282+ args := r.GetArguments()
283+ if val, ok := args[key]; ok {
284+ switch v := val.(type) {
285+ case []int:
286+ return v
287+ case []any:
288+ result := make([]int, 0, len(v))
289+ for _, item := range v {
290+ switch num := item.(type) {
291+ case int:
292+ result = append(result, num)
293+ case float64:
294+ result = append(result, int(num))
295+ case string:
296+ if i, err := strconv.Atoi(num); err == nil {
297+ result = append(result, i)
298+ }
299+ }
300+ }
301+ return result
302+ }
303+ }
304+ return defaultValue
305+}
306+
307+// RequireIntSlice returns an int slice argument by key, or an error if not found or not convertible to int slice
308+func (r CallToolRequest) RequireIntSlice(key string) ([]int, error) {
309+ args := r.GetArguments()
310+ if val, ok := args[key]; ok {
311+ switch v := val.(type) {
312+ case []int:
313+ return v, nil
314+ case []any:
315+ result := make([]int, 0, len(v))
316+ for i, item := range v {
317+ switch num := item.(type) {
318+ case int:
319+ result = append(result, num)
320+ case float64:
321+ result = append(result, int(num))
322+ case string:
323+ if i, err := strconv.Atoi(num); err == nil {
324+ result = append(result, i)
325+ } else {
326+ return nil, fmt.Errorf("item %d in argument %q cannot be converted to int", i, key)
327+ }
328+ default:
329+ return nil, fmt.Errorf("item %d in argument %q is not an int", i, key)
330+ }
331+ }
332+ return result, nil
333+ default:
334+ return nil, fmt.Errorf("argument %q is not an int slice", key)
335+ }
336+ }
337+ return nil, fmt.Errorf("required argument %q not found", key)
338+}
339+
340+// GetFloatSlice returns a float64 slice argument by key, or the default value if not found
341+func (r CallToolRequest) GetFloatSlice(key string, defaultValue []float64) []float64 {
342+ args := r.GetArguments()
343+ if val, ok := args[key]; ok {
344+ switch v := val.(type) {
345+ case []float64:
346+ return v
347+ case []any:
348+ result := make([]float64, 0, len(v))
349+ for _, item := range v {
350+ switch num := item.(type) {
351+ case float64:
352+ result = append(result, num)
353+ case int:
354+ result = append(result, float64(num))
355+ case string:
356+ if f, err := strconv.ParseFloat(num, 64); err == nil {
357+ result = append(result, f)
358+ }
359+ }
360+ }
361+ return result
362+ }
363+ }
364+ return defaultValue
365+}
366+
367+// RequireFloatSlice returns a float64 slice argument by key, or an error if not found or not convertible to float64 slice
368+func (r CallToolRequest) RequireFloatSlice(key string) ([]float64, error) {
369+ args := r.GetArguments()
370+ if val, ok := args[key]; ok {
371+ switch v := val.(type) {
372+ case []float64:
373+ return v, nil
374+ case []any:
375+ result := make([]float64, 0, len(v))
376+ for i, item := range v {
377+ switch num := item.(type) {
378+ case float64:
379+ result = append(result, num)
380+ case int:
381+ result = append(result, float64(num))
382+ case string:
383+ if f, err := strconv.ParseFloat(num, 64); err == nil {
384+ result = append(result, f)
385+ } else {
386+ return nil, fmt.Errorf("item %d in argument %q cannot be converted to float64", i, key)
387+ }
388+ default:
389+ return nil, fmt.Errorf("item %d in argument %q is not a float64", i, key)
390+ }
391+ }
392+ return result, nil
393+ default:
394+ return nil, fmt.Errorf("argument %q is not a float64 slice", key)
395+ }
396+ }
397+ return nil, fmt.Errorf("required argument %q not found", key)
398+}
399+
400+// GetBoolSlice returns a bool slice argument by key, or the default value if not found
401+func (r CallToolRequest) GetBoolSlice(key string, defaultValue []bool) []bool {
402+ args := r.GetArguments()
403+ if val, ok := args[key]; ok {
404+ switch v := val.(type) {
405+ case []bool:
406+ return v
407+ case []any:
408+ result := make([]bool, 0, len(v))
409+ for _, item := range v {
410+ switch b := item.(type) {
411+ case bool:
412+ result = append(result, b)
413+ case string:
414+ if parsed, err := strconv.ParseBool(b); err == nil {
415+ result = append(result, parsed)
416+ }
417+ case int:
418+ result = append(result, b != 0)
419+ case float64:
420+ result = append(result, b != 0)
421+ }
422+ }
423+ return result
424+ }
425+ }
426+ return defaultValue
427+}
428+
429+// RequireBoolSlice returns a bool slice argument by key, or an error if not found or not convertible to bool slice
430+func (r CallToolRequest) RequireBoolSlice(key string) ([]bool, error) {
431+ args := r.GetArguments()
432+ if val, ok := args[key]; ok {
433+ switch v := val.(type) {
434+ case []bool:
435+ return v, nil
436+ case []any:
437+ result := make([]bool, 0, len(v))
438+ for i, item := range v {
439+ switch b := item.(type) {
440+ case bool:
441+ result = append(result, b)
442+ case string:
443+ if parsed, err := strconv.ParseBool(b); err == nil {
444+ result = append(result, parsed)
445+ } else {
446+ return nil, fmt.Errorf("item %d in argument %q cannot be converted to bool", i, key)
447+ }
448+ case int:
449+ result = append(result, b != 0)
450+ case float64:
451+ result = append(result, b != 0)
452+ default:
453+ return nil, fmt.Errorf("item %d in argument %q is not a bool", i, key)
454+ }
455+ }
456+ return result, nil
457+ default:
458+ return nil, fmt.Errorf("argument %q is not a bool slice", key)
459+ }
460+ }
461+ return nil, fmt.Errorf("required argument %q not found", key)
59462}
60463
61464// ToolListChangedNotification is an optional notification from the server to
@@ -75,13 +478,20 @@ type Tool struct {
75478 InputSchema ToolInputSchema `json:"inputSchema"`
76479 // Alternative to InputSchema - allows arbitrary JSON Schema to be provided
77480 RawInputSchema json.RawMessage `json:"-"` // Hide this from JSON marshaling
481+ // Optional properties describing tool behavior
482+ Annotations ToolAnnotation `json:"annotations"`
483+}
484+
485+// GetName returns the name of the tool.
486+func (t Tool) GetName() string {
487+ return t.Name
78488}
79489
80490// MarshalJSON implements the json.Marshaler interface for Tool.
81491// It handles marshaling either InputSchema or RawInputSchema based on which is set.
82492func (t Tool) MarshalJSON() ([]byte, error) {
83493 // Create a map to build the JSON structure
84− m := make(map[string]interface{}, 3)
494+ m := make(map[string]any, 3)
85495
86496 // Add the name and description
87497 m["name"] = t.Name
@@ -100,13 +510,45 @@ func (t Tool) MarshalJSON() ([]byte, error) {
100510 m["inputSchema"] = t.InputSchema
101511 }
102512
513+ m["annotations"] = t.Annotations
514+
103515 return json.Marshal(m)
104516}
105517
106518type ToolInputSchema struct {
107− Type string `json:"type"`
108− Properties map[string]interface{} `json:"properties"`
109− Required []string `json:"required,omitempty"`
519+ Type string `json:"type"`
520+ Properties map[string]any `json:"properties,omitempty"`
521+ Required []string `json:"required,omitempty"`
522+}
523+
524+// MarshalJSON implements the json.Marshaler interface for ToolInputSchema.
525+func (tis ToolInputSchema) MarshalJSON() ([]byte, error) {
526+ m := make(map[string]any)
527+ m["type"] = tis.Type
528+
529+ // Marshal Properties to '{}' rather than `nil` when its length equals zero
530+ if tis.Properties != nil {
531+ m["properties"] = tis.Properties
532+ }
533+
534+ if len(tis.Required) > 0 {
535+ m["required"] = tis.Required
536+ }
537+
538+ return json.Marshal(m)
539+}
540+
541+type ToolAnnotation struct {
542+ // Human-readable title for the tool
543+ Title string `json:"title,omitempty"`
544+ // If true, the tool does not modify its environment
545+ ReadOnlyHint *bool `json:"readOnlyHint,omitempty"`
546+ // If true, the tool may perform destructive updates
547+ DestructiveHint *bool `json:"destructiveHint,omitempty"`
548+ // If true, repeated calls with same args have no additional effect
549+ IdempotentHint *bool `json:"idempotentHint,omitempty"`
550+ // If true, tool interacts with external entities
551+ OpenWorldHint *bool `json:"openWorldHint,omitempty"`
110552}
111553
112554// ToolOption is a function that configures a Tool.
@@ -115,7 +557,7 @@ type ToolOption func(*Tool)
115557
116558// PropertyOption is a function that configures a property in a Tool's input schema.
117559// It allows for flexible configuration of JSON Schema properties using the functional options pattern.
118−type PropertyOption func(map[string]interface{})
560+type PropertyOption func(map[string]any)
119561
120562//
121563// Core Tool Functions
@@ -129,9 +571,16 @@ func NewTool(name string, opts ...ToolOption) Tool {
129571 Name: name,
130572 InputSchema: ToolInputSchema{
131573 Type: "object",
132− Properties: make(map[string]interface{}),
574+ Properties: make(map[string]any),
133575 Required: nil, // Will be omitted from JSON if empty
134576 },
577+ Annotations: ToolAnnotation{
578+ Title: "",
579+ ReadOnlyHint: ToBoolPtr(false),
580+ DestructiveHint: ToBoolPtr(true),
581+ IdempotentHint: ToBoolPtr(false),
582+ OpenWorldHint: ToBoolPtr(true),
583+ },
135584 }
136585
137586 for _, opt := range opts {
@@ -166,6 +615,53 @@ func WithDescription(description string) ToolOption {
166615 }
167616}
168617
618+// WithToolAnnotation adds optional hints about the Tool.
619+func WithToolAnnotation(annotation ToolAnnotation) ToolOption {
620+ return func(t *Tool) {
621+ t.Annotations = annotation
622+ }
623+}
624+
625+// WithTitleAnnotation sets the Title field of the Tool's Annotations.
626+// It provides a human-readable title for the tool.
627+func WithTitleAnnotation(title string) ToolOption {
628+ return func(t *Tool) {
629+ t.Annotations.Title = title
630+ }
631+}
632+
633+// WithReadOnlyHintAnnotation sets the ReadOnlyHint field of the Tool's Annotations.
634+// If true, it indicates the tool does not modify its environment.
635+func WithReadOnlyHintAnnotation(value bool) ToolOption {
636+ return func(t *Tool) {
637+ t.Annotations.ReadOnlyHint = &value
638+ }
639+}
640+
641+// WithDestructiveHintAnnotation sets the DestructiveHint field of the Tool's Annotations.
642+// If true, it indicates the tool may perform destructive updates.
643+func WithDestructiveHintAnnotation(value bool) ToolOption {
644+ return func(t *Tool) {
645+ t.Annotations.DestructiveHint = &value
646+ }
647+}
648+
649+// WithIdempotentHintAnnotation sets the IdempotentHint field of the Tool's Annotations.
650+// If true, it indicates repeated calls with the same arguments have no additional effect.
651+func WithIdempotentHintAnnotation(value bool) ToolOption {
652+ return func(t *Tool) {
653+ t.Annotations.IdempotentHint = &value
654+ }
655+}
656+
657+// WithOpenWorldHintAnnotation sets the OpenWorldHint field of the Tool's Annotations.
658+// If true, it indicates the tool interacts with external entities.
659+func WithOpenWorldHintAnnotation(value bool) ToolOption {
660+ return func(t *Tool) {
661+ t.Annotations.OpenWorldHint = &value
662+ }
663+}
664+
169665//
170666// Common Property Options
171667//
@@ -173,7 +669,7 @@ func WithDescription(description string) ToolOption {
173669// Description adds a description to a property in the JSON Schema.
174670// The description should explain the purpose and expected values of the property.
175671func Description(desc string) PropertyOption {
176− return func(schema map[string]interface{}) {
672+ return func(schema map[string]any) {
177673 schema["description"] = desc
178674 }
179675}
@@ -181,7 +677,7 @@ func Description(desc string) PropertyOption {
181677// Required marks a property as required in the tool's input schema.
182678// Required properties must be provided when using the tool.
183679func Required() PropertyOption {
184− return func(schema map[string]interface{}) {
680+ return func(schema map[string]any) {
185681 schema["required"] = true
186682 }
187683}
@@ -189,7 +685,7 @@ func Required() PropertyOption {
189685// Title adds a display-friendly title to a property in the JSON Schema.
190686// This title can be used by UI components to show a more readable property name.
191687func Title(title string) PropertyOption {
192− return func(schema map[string]interface{}) {
688+ return func(schema map[string]any) {
193689 schema["title"] = title
194690 }
195691}
@@ -201,7 +697,7 @@ func Title(title string) PropertyOption {
201697// DefaultString sets the default value for a string property.
202698// This value will be used if the property is not explicitly provided.
203699func DefaultString(value string) PropertyOption {
204− return func(schema map[string]interface{}) {
700+ return func(schema map[string]any) {
205701 schema["default"] = value
206702 }
207703}
@@ -209,7 +705,7 @@ func DefaultString(value string) PropertyOption {
209705// Enum specifies a list of allowed values for a string property.
210706// The property value must be one of the specified enum values.
211707func Enum(values ...string) PropertyOption {
212− return func(schema map[string]interface{}) {
708+ return func(schema map[string]any) {
213709 schema["enum"] = values
214710 }
215711}
@@ -217,7 +713,7 @@ func Enum(values ...string) PropertyOption {
217713// MaxLength sets the maximum length for a string property.
218714// The string value must not exceed this length.
219715func MaxLength(max int) PropertyOption {
220− return func(schema map[string]interface{}) {
716+ return func(schema map[string]any) {
221717 schema["maxLength"] = max
222718 }
223719}
@@ -225,7 +721,7 @@ func MaxLength(max int) PropertyOption {
225721// MinLength sets the minimum length for a string property.
226722// The string value must be at least this length.
227723func MinLength(min int) PropertyOption {
228− return func(schema map[string]interface{}) {
724+ return func(schema map[string]any) {
229725 schema["minLength"] = min
230726 }
231727}
@@ -233,7 +729,7 @@ func MinLength(min int) PropertyOption {
233729// Pattern sets a regex pattern that a string property must match.
234730// The string value must conform to the specified regular expression.
235731func Pattern(pattern string) PropertyOption {
236− return func(schema map[string]interface{}) {
732+ return func(schema map[string]any) {
237733 schema["pattern"] = pattern
238734 }
239735}
@@ -245,7 +741,7 @@ func Pattern(pattern string) PropertyOption {
245741// DefaultNumber sets the default value for a number property.
246742// This value will be used if the property is not explicitly provided.
247743func DefaultNumber(value float64) PropertyOption {
248− return func(schema map[string]interface{}) {
744+ return func(schema map[string]any) {
249745 schema["default"] = value
250746 }
251747}
@@ -253,7 +749,7 @@ func DefaultNumber(value float64) PropertyOption {
253749// Max sets the maximum value for a number property.
254750// The number value must not exceed this maximum.
255751func Max(max float64) PropertyOption {
256− return func(schema map[string]interface{}) {
752+ return func(schema map[string]any) {
257753 schema["maximum"] = max
258754 }
259755}
@@ -261,7 +757,7 @@ func Max(max float64) PropertyOption {
261757// Min sets the minimum value for a number property.
262758// The number value must not be less than this minimum.
263759func Min(min float64) PropertyOption {
264− return func(schema map[string]interface{}) {
760+ return func(schema map[string]any) {
265761 schema["minimum"] = min
266762 }
267763}
@@ -269,7 +765,7 @@ func Min(min float64) PropertyOption {
269765// MultipleOf specifies that a number must be a multiple of the given value.
270766// The number value must be divisible by this value.
271767func MultipleOf(value float64) PropertyOption {
272− return func(schema map[string]interface{}) {
768+ return func(schema map[string]any) {
273769 schema["multipleOf"] = value
274770 }
275771}
@@ -281,7 +777,19 @@ func MultipleOf(value float64) PropertyOption {
281777// DefaultBool sets the default value for a boolean property.
282778// This value will be used if the property is not explicitly provided.
283779func DefaultBool(value bool) PropertyOption {
284− return func(schema map[string]interface{}) {
780+ return func(schema map[string]any) {
781+ schema["default"] = value
782+ }
783+}
784+
785+//
786+// Array Property Options
787+//
788+
789+// DefaultArray sets the default value for an array property.
790+// This value will be used if the property is not explicitly provided.
791+func DefaultArray[T any](value []T) PropertyOption {
792+ return func(schema map[string]any) {
285793 schema["default"] = value
286794 }
287795}
@@ -294,7 +802,7 @@ func DefaultBool(value bool) PropertyOption {
294802// It accepts property options to configure the boolean property's behavior and constraints.
295803func WithBoolean(name string, opts ...PropertyOption) ToolOption {
296804 return func(t *Tool) {
297− schema := map[string]interface{}{
805+ schema := map[string]any{
298806 "type": "boolean",
299807 }
300808
@@ -305,11 +813,7 @@ func WithBoolean(name string, opts ...PropertyOption) ToolOption {
305813 // Remove required from property schema and add to InputSchema.required
306814 if required, ok := schema["required"].(bool); ok && required {
307815 delete(schema, "required")
308− if t.InputSchema.Required == nil {
309− t.InputSchema.Required = []string{name}
310− } else {
311− t.InputSchema.Required = append(t.InputSchema.Required, name)
312− }
816+ t.InputSchema.Required = append(t.InputSchema.Required, name)
313817 }
314818
315819 t.InputSchema.Properties[name] = schema
@@ -320,7 +824,7 @@ func WithBoolean(name string, opts ...PropertyOption) ToolOption {
320824// It accepts property options to configure the number property's behavior and constraints.
321825func WithNumber(name string, opts ...PropertyOption) ToolOption {
322826 return func(t *Tool) {
323− schema := map[string]interface{}{
827+ schema := map[string]any{
324828 "type": "number",
325829 }
326830
@@ -331,11 +835,7 @@ func WithNumber(name string, opts ...PropertyOption) ToolOption {
331835 // Remove required from property schema and add to InputSchema.required
332836 if required, ok := schema["required"].(bool); ok && required {
333837 delete(schema, "required")
334− if t.InputSchema.Required == nil {
335− t.InputSchema.Required = []string{name}
336− } else {
337− t.InputSchema.Required = append(t.InputSchema.Required, name)
338− }
838+ t.InputSchema.Required = append(t.InputSchema.Required, name)
339839 }
340840
341841 t.InputSchema.Properties[name] = schema
@@ -346,7 +846,7 @@ func WithNumber(name string, opts ...PropertyOption) ToolOption {
346846// It accepts property options to configure the string property's behavior and constraints.
347847func WithString(name string, opts ...PropertyOption) ToolOption {
348848 return func(t *Tool) {
349− schema := map[string]interface{}{
849+ schema := map[string]any{
350850 "type": "string",
351851 }
352852
@@ -357,11 +857,7 @@ func WithString(name string, opts ...PropertyOption) ToolOption {
357857 // Remove required from property schema and add to InputSchema.required
358858 if required, ok := schema["required"].(bool); ok && required {
359859 delete(schema, "required")
360− if t.InputSchema.Required == nil {
361− t.InputSchema.Required = []string{name}
362− } else {
363− t.InputSchema.Required = append(t.InputSchema.Required, name)
364− }
860+ t.InputSchema.Required = append(t.InputSchema.Required, name)
365861 }
366862
367863 t.InputSchema.Properties[name] = schema
@@ -372,9 +868,9 @@ func WithString(name string, opts ...PropertyOption) ToolOption {
372868// It accepts property options to configure the object property's behavior and constraints.
373869func WithObject(name string, opts ...PropertyOption) ToolOption {
374870 return func(t *Tool) {
375− schema := map[string]interface{}{
871+ schema := map[string]any{
376872 "type": "object",
377− "properties": map[string]interface{}{},
873+ "properties": map[string]any{},
378874 }
379875
380876 for _, opt := range opts {
@@ -384,11 +880,7 @@ func WithObject(name string, opts ...PropertyOption) ToolOption {
384880 // Remove required from property schema and add to InputSchema.required
385881 if required, ok := schema["required"].(bool); ok && required {
386882 delete(schema, "required")
387− if t.InputSchema.Required == nil {
388− t.InputSchema.Required = []string{name}
389− } else {
390− t.InputSchema.Required = append(t.InputSchema.Required, name)
391− }
883+ t.InputSchema.Required = append(t.InputSchema.Required, name)
392884 }
393885
394886 t.InputSchema.Properties[name] = schema
@@ -399,7 +891,7 @@ func WithObject(name string, opts ...PropertyOption) ToolOption {
399891// It accepts property options to configure the array property's behavior and constraints.
400892func WithArray(name string, opts ...PropertyOption) ToolOption {
401893 return func(t *Tool) {
402− schema := map[string]interface{}{
894+ schema := map[string]any{
403895 "type": "array",
404896 }
405897
@@ -410,11 +902,7 @@ func WithArray(name string, opts ...PropertyOption) ToolOption {
410902 // Remove required from property schema and add to InputSchema.required
411903 if required, ok := schema["required"].(bool); ok && required {
412904 delete(schema, "required")
413− if t.InputSchema.Required == nil {
414− t.InputSchema.Required = []string{name}
415− } else {
416− t.InputSchema.Required = append(t.InputSchema.Required, name)
417− }
905+ t.InputSchema.Required = append(t.InputSchema.Required, name)
418906 }
419907
420908 t.InputSchema.Properties[name] = schema
@@ -422,65 +910,65 @@ func WithArray(name string, opts ...PropertyOption) ToolOption {
422910}
423911
424912// Properties defines the properties for an object schema
425−func Properties(props map[string]interface{}) PropertyOption {
426− return func(schema map[string]interface{}) {
913+func Properties(props map[string]any) PropertyOption {
914+ return func(schema map[string]any) {
427915 schema["properties"] = props
428916 }
429917}
430918
431919// AdditionalProperties specifies whether additional properties are allowed in the object
432920// or defines a schema for additional properties
433−func AdditionalProperties(schema interface{}) PropertyOption {
434− return func(schemaMap map[string]interface{}) {
921+func AdditionalProperties(schema any) PropertyOption {
922+ return func(schemaMap map[string]any) {
435923 schemaMap["additionalProperties"] = schema
436924 }
437925}
438926
439927// MinProperties sets the minimum number of properties for an object
440928func MinProperties(min int) PropertyOption {
441− return func(schema map[string]interface{}) {
929+ return func(schema map[string]any) {
442930 schema["minProperties"] = min
443931 }
444932}
445933
446934// MaxProperties sets the maximum number of properties for an object
447935func MaxProperties(max int) PropertyOption {
448− return func(schema map[string]interface{}) {
936+ return func(schema map[string]any) {
449937 schema["maxProperties"] = max
450938 }
451939}
452940
453941// PropertyNames defines a schema for property names in an object
454−func PropertyNames(schema map[string]interface{}) PropertyOption {
455− return func(schemaMap map[string]interface{}) {
942+func PropertyNames(schema map[string]any) PropertyOption {
943+ return func(schemaMap map[string]any) {
456944 schemaMap["propertyNames"] = schema
457945 }
458946}
459947
460948// Items defines the schema for array items
461−func Items(schema interface{}) PropertyOption {
462− return func(schemaMap map[string]interface{}) {
949+func Items(schema any) PropertyOption {
950+ return func(schemaMap map[string]any) {
463951 schemaMap["items"] = schema
464952 }
465953}
466954
467955// MinItems sets the minimum number of items for an array
468956func MinItems(min int) PropertyOption {
469− return func(schema map[string]interface{}) {
957+ return func(schema map[string]any) {
470958 schema["minItems"] = min
471959 }
472960}
473961
474962// MaxItems sets the maximum number of items for an array
475963func MaxItems(max int) PropertyOption {
476− return func(schema map[string]interface{}) {
964+ return func(schema map[string]any) {
477965 schema["maxItems"] = max
478966 }
479967}
480968
481969// UniqueItems specifies whether array items must be unique
482970func UniqueItems(unique bool) PropertyOption {
483− return func(schema map[string]interface{}) {
971+ return func(schema map[string]any) {
484972 schema["uniqueItems"] = unique
485973 }
486974}
vendor/github.com/mark3labs/mcp-go/mcp/typed_tools.gonew file+20
@@ -0,0 +1,20 @@
1+package mcp
2+
3+import (
4+ "context"
5+ "fmt"
6+)
7+
8+// TypedToolHandlerFunc is a function that handles a tool call with typed arguments
9+type TypedToolHandlerFunc[T any] func(ctx context.Context, request CallToolRequest, args T) (*CallToolResult, error)
10+
11+// NewTypedToolHandler creates a ToolHandlerFunc that automatically binds arguments to a typed struct
12+func NewTypedToolHandler[T any](handler TypedToolHandlerFunc[T]) func(ctx context.Context, request CallToolRequest) (*CallToolResult, error) {
13+ return func(ctx context.Context, request CallToolRequest) (*CallToolResult, error) {
14+ var args T
15+ if err := request.BindArguments(&args); err != nil {
16+ return NewToolResultError(fmt.Sprintf("failed to bind arguments: %v", err)), nil
17+ }
18+ return handler(ctx, request, args)
19+ }
20+}
vendor/github.com/mark3labs/mcp-go/mcp/types.go+351−167
@@ -1,9 +1,12 @@
1−// Package mcp defines the core types and interfaces for the Model Control Protocol (MCP).
1+// Package mcp defines the core types and interfaces for the Model Context Protocol (MCP).
22// MCP is a protocol for communication between LLM-powered applications and their supporting services.
33package mcp
44
55import (
66 "encoding/json"
7+ "fmt"
8+ "maps"
9+ "strconv"
710
811 "github.com/yosida95/uritemplate/v3"
912)
@@ -11,41 +14,59 @@ import (
1114type MCPMethod string
1215
1316const (
14− // Initiates connection and negotiates protocol capabilities.
15− // https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle/#initialization
17+ // MethodInitialize initiates connection and negotiates protocol capabilities.
18+ // https://modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle/#initialization
1619 MethodInitialize MCPMethod = "initialize"
1720
18− // Verifies connection liveness between client and server.
19− // https://spec.modelcontextprotocol.io/specification/2024-11-05/basic/utilities/ping/
21+ // MethodPing verifies connection liveness between client and server.
22+ // https://modelcontextprotocol.io/specification/2024-11-05/basic/utilities/ping/
2023 MethodPing MCPMethod = "ping"
2124
22− // Lists all available server resources.
23− // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/
25+ // MethodResourcesList lists all available server resources.
26+ // https://modelcontextprotocol.io/specification/2024-11-05/server/resources/
2427 MethodResourcesList MCPMethod = "resources/list"
2528
26− // Provides URI templates for constructing resource URIs.
27− // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/
29+ // MethodResourcesTemplatesList provides URI templates for constructing resource URIs.
30+ // https://modelcontextprotocol.io/specification/2024-11-05/server/resources/
2831 MethodResourcesTemplatesList MCPMethod = "resources/templates/list"
2932
30− // Retrieves content of a specific resource by URI.
31− // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/resources/
33+ // MethodResourcesRead retrieves content of a specific resource by URI.
34+ // https://modelcontextprotocol.io/specification/2024-11-05/server/resources/
3235 MethodResourcesRead MCPMethod = "resources/read"
3336
34− // Lists all available prompt templates.
35− // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/
37+ // MethodPromptsList lists all available prompt templates.
38+ // https://modelcontextprotocol.io/specification/2024-11-05/server/prompts/
3639 MethodPromptsList MCPMethod = "prompts/list"
3740
38− // Retrieves a specific prompt template with filled parameters.
39− // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/
41+ // MethodPromptsGet retrieves a specific prompt template with filled parameters.
42+ // https://modelcontextprotocol.io/specification/2024-11-05/server/prompts/
4043 MethodPromptsGet MCPMethod = "prompts/get"
4144
42− // Lists all available executable tools.
43− // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/
45+ // MethodToolsList lists all available executable tools.
46+ // https://modelcontextprotocol.io/specification/2024-11-05/server/tools/
4447 MethodToolsList MCPMethod = "tools/list"
4548
46− // Invokes a specific tool with provided parameters.
47− // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/
49+ // MethodToolsCall invokes a specific tool with provided parameters.
50+ // https://modelcontextprotocol.io/specification/2024-11-05/server/tools/
4851 MethodToolsCall MCPMethod = "tools/call"
52+
53+ // MethodSetLogLevel configures the minimum log level for client
54+ // https://modelcontextprotocol.io/specification/2025-03-26/server/utilities/logging
55+ MethodSetLogLevel MCPMethod = "logging/setLevel"
56+
57+ // MethodNotificationResourcesListChanged notifies when the list of available resources changes.
58+ // https://modelcontextprotocol.io/specification/2025-03-26/server/resources#list-changed-notification
59+ MethodNotificationResourcesListChanged = "notifications/resources/list_changed"
60+
61+ MethodNotificationResourceUpdated = "notifications/resources/updated"
62+
63+ // MethodNotificationPromptsListChanged notifies when the list of available prompt templates changes.
64+ // https://modelcontextprotocol.io/specification/2025-03-26/server/prompts#list-changed-notification
65+ MethodNotificationPromptsListChanged = "notifications/prompts/list_changed"
66+
67+ // MethodNotificationToolsListChanged notifies when the list of available tools changes.
68+ // https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/list_changed/
69+ MethodNotificationToolsListChanged = "notifications/tools/list_changed"
4970)
5071
5172type URITemplate struct {
@@ -53,7 +74,7 @@ type URITemplate struct {
5374}
5475
5576func (t *URITemplate) MarshalJSON() ([]byte, error) {
56− return json.Marshal(t.Template.Raw())
77+ return json.Marshal(t.Raw())
5778}
5879
5980func (t *URITemplate) UnmarshalJSON(data []byte) error {
@@ -72,36 +93,73 @@ func (t *URITemplate) UnmarshalJSON(data []byte) error {
7293/* JSON-RPC types */
7394
7495// JSONRPCMessage represents either a JSONRPCRequest, JSONRPCNotification, JSONRPCResponse, or JSONRPCError
75−type JSONRPCMessage interface{}
96+type JSONRPCMessage any
7697
7798// LATEST_PROTOCOL_VERSION is the most recent version of the MCP protocol.
78−const LATEST_PROTOCOL_VERSION = "2024-11-05"
99+const LATEST_PROTOCOL_VERSION = "2025-03-26"
100+
101+// ValidProtocolVersions lists all known valid MCP protocol versions.
102+var ValidProtocolVersions = []string{
103+ "2024-11-05",
104+ LATEST_PROTOCOL_VERSION,
105+}
79106
80107// JSONRPC_VERSION is the version of JSON-RPC used by MCP.
81108const JSONRPC_VERSION = "2.0"
82109
83110// ProgressToken is used to associate progress notifications with the original request.
84−type ProgressToken interface{}
111+type ProgressToken any
85112
86113// Cursor is an opaque token used to represent a cursor for pagination.
87114type Cursor string
88115
116+// Meta is metadata attached to a request's parameters. This can include fields
117+// formally defined by the protocol or other arbitrary data.
118+type Meta struct {
119+ // If specified, the caller is requesting out-of-band progress
120+ // notifications for this request (as represented by
121+ // notifications/progress). The value of this parameter is an
122+ // opaque token that will be attached to any subsequent
123+ // notifications. The receiver is not obligated to provide these
124+ // notifications.
125+ ProgressToken ProgressToken
126+
127+ // AdditionalFields are any fields present in the Meta that are not
128+ // otherwise defined in the protocol.
129+ AdditionalFields map[string]any
130+}
131+
132+func (m *Meta) MarshalJSON() ([]byte, error) {
133+ raw := make(map[string]any)
134+ if m.ProgressToken != nil {
135+ raw["progressToken"] = m.ProgressToken
136+ }
137+ maps.Copy(raw, m.AdditionalFields)
138+
139+ return json.Marshal(raw)
140+}
141+
142+func (m *Meta) UnmarshalJSON(data []byte) error {
143+ raw := make(map[string]any)
144+ if err := json.Unmarshal(data, &raw); err != nil {
145+ return err
146+ }
147+ m.ProgressToken = raw["progressToken"]
148+ delete(raw, "progressToken")
149+ m.AdditionalFields = raw
150+ return nil
151+}
152+
89153type Request struct {
90− Method string `json:"method"`
91− Params struct {
92− Meta *struct {
93− // If specified, the caller is requesting out-of-band progress
94− // notifications for this request (as represented by
95− // notifications/progress). The value of this parameter is an
96− // opaque token that will be attached to any subsequent
97− // notifications. The receiver is not obligated to provide these
98− // notifications.
99− ProgressToken ProgressToken `json:"progressToken,omitempty"`
100− } `json:"_meta,omitempty"`
101− } `json:"params,omitempty"`
102−}
103−
104−type Params map[string]interface{}
154+ Method string `json:"method"`
155+ Params RequestParams `json:"params,omitempty"`
156+}
157+
158+type RequestParams struct {
159+ Meta *Meta `json:"_meta,omitempty"`
160+}
161+
162+type Params map[string]any
105163
106164type Notification struct {
107165 Method string `json:"method"`
@@ -111,16 +169,16 @@ type Notification struct {
111169type NotificationParams struct {
112170 // This parameter name is reserved by MCP to allow clients and
113171 // servers to attach additional metadata to their notifications.
114− Meta map[string]interface{} `json:"_meta,omitempty"`
172+ Meta map[string]any `json:"_meta,omitempty"`
115173
116174 // Additional fields can be added to this map
117− AdditionalFields map[string]interface{} `json:"-"`
175+ AdditionalFields map[string]any `json:"-"`
118176}
119177
120178// MarshalJSON implements custom JSON marshaling
121179func (p NotificationParams) MarshalJSON() ([]byte, error) {
122180 // Create a map to hold all fields
123− m := make(map[string]interface{})
181+ m := make(map[string]any)
124182
125183 // Add Meta if it exists
126184 if p.Meta != nil {
@@ -141,24 +199,24 @@ func (p NotificationParams) MarshalJSON() ([]byte, error) {
141199// UnmarshalJSON implements custom JSON unmarshaling
142200func (p *NotificationParams) UnmarshalJSON(data []byte) error {
143201 // Create a map to hold all fields
144− var m map[string]interface{}
202+ var m map[string]any
145203 if err := json.Unmarshal(data, &m); err != nil {
146204 return err
147205 }
148206
149207 // Initialize maps if they're nil
150208 if p.Meta == nil {
151− p.Meta = make(map[string]interface{})
209+ p.Meta = make(map[string]any)
152210 }
153211 if p.AdditionalFields == nil {
154− p.AdditionalFields = make(map[string]interface{})
212+ p.AdditionalFields = make(map[string]any)
155213 }
156214
157215 // Process all fields
158216 for k, v := range m {
159217 if k == "_meta" {
160218 // Handle Meta field
161− if meta, ok := v.(map[string]interface{}); ok {
219+ if meta, ok := v.(map[string]any); ok {
162220 p.Meta = meta
163221 }
164222 } else {
@@ -173,18 +231,86 @@ func (p *NotificationParams) UnmarshalJSON(data []byte) error {
173231type Result struct {
174232 // This result property is reserved by the protocol to allow clients and
175233 // servers to attach additional metadata to their responses.
176− Meta map[string]interface{} `json:"_meta,omitempty"`
234+ Meta map[string]any `json:"_meta,omitempty"`
177235}
178236
179237// RequestId is a uniquely identifying ID for a request in JSON-RPC.
180238// It can be any JSON-serializable value, typically a number or string.
181−type RequestId interface{}
239+type RequestId struct {
240+ value any
241+}
242+
243+// NewRequestId creates a new RequestId with the given value
244+func NewRequestId(value any) RequestId {
245+ return RequestId{value: value}
246+}
247+
248+// Value returns the underlying value of the RequestId
249+func (r RequestId) Value() any {
250+ return r.value
251+}
252+
253+// String returns a string representation of the RequestId
254+func (r RequestId) String() string {
255+ switch v := r.value.(type) {
256+ case string:
257+ return "string:" + v
258+ case int64:
259+ return "int64:" + strconv.FormatInt(v, 10)
260+ case float64:
261+ if v == float64(int64(v)) {
262+ return "int64:" + strconv.FormatInt(int64(v), 10)
263+ }
264+ return "float64:" + strconv.FormatFloat(v, 'f', -1, 64)
265+ case nil:
266+ return "<nil>"
267+ default:
268+ return "unknown:" + fmt.Sprintf("%v", v)
269+ }
270+}
271+
272+// IsNil returns true if the RequestId is nil
273+func (r RequestId) IsNil() bool {
274+ return r.value == nil
275+}
276+
277+func (r RequestId) MarshalJSON() ([]byte, error) {
278+ return json.Marshal(r.value)
279+}
280+
281+func (r *RequestId) UnmarshalJSON(data []byte) error {
282+
283+ if string(data) == "null" {
284+ r.value = nil
285+ return nil
286+ }
287+
288+ // Try unmarshaling as string first
289+ var s string
290+ if err := json.Unmarshal(data, &s); err == nil {
291+ r.value = s
292+ return nil
293+ }
294+
295+ // JSON numbers are unmarshaled as float64 in Go
296+ var f float64
297+ if err := json.Unmarshal(data, &f); err == nil {
298+ if f == float64(int64(f)) {
299+ r.value = int64(f)
300+ } else {
301+ r.value = f
302+ }
303+ return nil
304+ }
305+
306+ return fmt.Errorf("invalid request id: %s", string(data))
307+}
182308
183309// JSONRPCRequest represents a request that expects a response.
184310type JSONRPCRequest struct {
185− JSONRPC string `json:"jsonrpc"`
186− ID RequestId `json:"id"`
187− Params interface{} `json:"params,omitempty"`
311+ JSONRPC string `json:"jsonrpc"`
312+ ID RequestId `json:"id"`
313+ Params any `json:"params,omitempty"`
188314 Request
189315}
190316
@@ -196,9 +322,9 @@ type JSONRPCNotification struct {
196322
197323// JSONRPCResponse represents a successful (non-error) response to a request.
198324type JSONRPCResponse struct {
199− JSONRPC string `json:"jsonrpc"`
200− ID RequestId `json:"id"`
201− Result interface{} `json:"result"`
325+ JSONRPC string `json:"jsonrpc"`
326+ ID RequestId `json:"id"`
327+ Result any `json:"result"`
202328}
203329
204330// JSONRPCError represents a non-successful (error) response to a request.
@@ -213,7 +339,7 @@ type JSONRPCError struct {
213339 Message string `json:"message"`
214340 // Additional information about the error. The value of this member
215341 // is defined by the sender (e.g. detailed error information, nested errors etc.).
216− Data interface{} `json:"data,omitempty"`
342+ Data any `json:"data,omitempty"`
217343 } `json:"error"`
218344}
219345
@@ -226,6 +352,11 @@ const (
226352 INTERNAL_ERROR = -32603
227353)
228354
355+// MCP error codes
356+const (
357+ RESOURCE_NOT_FOUND = -32002
358+)
359+
229360/* Empty result */
230361
231362// EmptyResult represents a response that indicates success but carries no data.
@@ -246,17 +377,19 @@ type EmptyResult Result
246377// A client MUST NOT attempt to cancel its `initialize` request.
247378type CancelledNotification struct {
248379 Notification
249− Params struct {
250− // The ID of the request to cancel.
251− //
252− // This MUST correspond to the ID of a request previously issued
253− // in the same direction.
254− RequestId RequestId `json:"requestId"`
380+ Params CancelledNotificationParams `json:"params"`
381+}
382+
383+type CancelledNotificationParams struct {
384+ // The ID of the request to cancel.
385+ //
386+ // This MUST correspond to the ID of a request previously issued
387+ // in the same direction.
388+ RequestId RequestId `json:"requestId"`
255389
256− // An optional string describing the reason for the cancellation. This MAY
257− // be logged or presented to the user.
258− Reason string `json:"reason,omitempty"`
259− } `json:"params"`
390+ // An optional string describing the reason for the cancellation. This MAY
391+ // be logged or presented to the user.
392+ Reason string `json:"reason,omitempty"`
260393}
261394
262395/* Initialization */
@@ -265,13 +398,15 @@ type CancelledNotification struct {
265398// connects, asking it to begin initialization.
266399type InitializeRequest struct {
267400 Request
268− Params struct {
269− // The latest version of the Model Context Protocol that the client supports.
270− // The client MAY decide to support older versions as well.
271− ProtocolVersion string `json:"protocolVersion"`
272− Capabilities ClientCapabilities `json:"capabilities"`
273− ClientInfo Implementation `json:"clientInfo"`
274− } `json:"params"`
401+ Params InitializeParams `json:"params"`
402+}
403+
404+type InitializeParams struct {
405+ // The latest version of the Model Context Protocol that the client supports.
406+ // The client MAY decide to support older versions as well.
407+ ProtocolVersion string `json:"protocolVersion"`
408+ Capabilities ClientCapabilities `json:"capabilities"`
409+ ClientInfo Implementation `json:"clientInfo"`
275410}
276411
277412// InitializeResult is sent after receiving an initialize request from the
@@ -303,7 +438,7 @@ type InitializedNotification struct {
303438// client can define its own, additional capabilities.
304439type ClientCapabilities struct {
305440 // Experimental, non-standard capabilities that the client supports.
306− Experimental map[string]interface{} `json:"experimental,omitempty"`
441+ Experimental map[string]any `json:"experimental,omitempty"`
307442 // Present if the client supports listing roots.
308443 Roots *struct {
309444 // Whether the client supports notifications for changes to the roots list.
@@ -318,7 +453,7 @@ type ClientCapabilities struct {
318453// server can define its own, additional capabilities.
319454type ServerCapabilities struct {
320455 // Experimental, non-standard capabilities that the server supports.
321− Experimental map[string]interface{} `json:"experimental,omitempty"`
456+ Experimental map[string]any `json:"experimental,omitempty"`
322457 // Present if the server supports sending log messages to the client.
323458 Logging *struct{} `json:"logging,omitempty"`
324459 // Present if the server offers any prompt templates.
@@ -362,27 +497,34 @@ type PingRequest struct {
362497// receiver of a progress update for a long-running request.
363498type ProgressNotification struct {
364499 Notification
365− Params struct {
366− // The progress token which was given in the initial request, used to
367− // associate this notification with the request that is proceeding.
368− ProgressToken ProgressToken `json:"progressToken"`
369− // The progress thus far. This should increase every time progress is made,
370− // even if the total is unknown.
371− Progress float64 `json:"progress"`
372− // Total number of items to process (or total progress required), if known.
373− Total float64 `json:"total,omitempty"`
374− } `json:"params"`
500+ Params ProgressNotificationParams `json:"params"`
501+}
502+
503+type ProgressNotificationParams struct {
504+ // The progress token which was given in the initial request, used to
505+ // associate this notification with the request that is proceeding.
506+ ProgressToken ProgressToken `json:"progressToken"`
507+ // The progress thus far. This should increase every time progress is made,
508+ // even if the total is unknown.
509+ Progress float64 `json:"progress"`
510+ // Total number of items to process (or total progress required), if known.
511+ Total float64 `json:"total,omitempty"`
512+ // Message related to progress. This should provide relevant human-readable
513+ // progress information.
514+ Message string `json:"message,omitempty"`
375515}
376516
377517/* Pagination */
378518
379519type PaginatedRequest struct {
380520 Request
381− Params struct {
382− // An opaque token representing the current pagination position.
383− // If provided, the server should return results starting after this cursor.
384− Cursor Cursor `json:"cursor,omitempty"`
385− } `json:"params,omitempty"`
521+ Params PaginatedParams `json:"params,omitempty"`
522+}
523+
524+type PaginatedParams struct {
525+ // An opaque token representing the current pagination position.
526+ // If provided, the server should return results starting after this cursor.
527+ Cursor Cursor `json:"cursor,omitempty"`
386528}
387529
388530type PaginatedResult struct {
@@ -425,13 +567,15 @@ type ListResourceTemplatesResult struct {
425567// specific resource URI.
426568type ReadResourceRequest struct {
427569 Request
428− Params struct {
429− // The URI of the resource to read. The URI can use any protocol; it is up
430− // to the server how to interpret it.
431− URI string `json:"uri"`
432− // Arguments to pass to the resource handler
433− Arguments map[string]interface{} `json:"arguments,omitempty"`
434− } `json:"params"`
570+ Params ReadResourceParams `json:"params"`
571+}
572+
573+type ReadResourceParams struct {
574+ // The URI of the resource to read. The URI can use any protocol; it is up
575+ // to the server how to interpret it.
576+ URI string `json:"uri"`
577+ // Arguments to pass to the resource handler
578+ Arguments map[string]any `json:"arguments,omitempty"`
435579}
436580
437581// ReadResourceResult is the server's response to a resources/read request
@@ -453,11 +597,13 @@ type ResourceListChangedNotification struct {
453597// notifications from the server whenever a particular resource changes.
454598type SubscribeRequest struct {
455599 Request
456− Params struct {
457− // The URI of the resource to subscribe to. The URI can use any protocol; it
458− // is up to the server how to interpret it.
459− URI string `json:"uri"`
460− } `json:"params"`
600+ Params SubscribeParams `json:"params"`
601+}
602+
603+type SubscribeParams struct {
604+ // The URI of the resource to subscribe to. The URI can use any protocol; it
605+ // is up to the server how to interpret it.
606+ URI string `json:"uri"`
461607}
462608
463609// UnsubscribeRequest is sent from the client to request cancellation of
@@ -465,10 +611,12 @@ type SubscribeRequest struct {
465611// resources/subscribe request.
466612type UnsubscribeRequest struct {
467613 Request
468− Params struct {
469− // The URI of the resource to unsubscribe from.
470− URI string `json:"uri"`
471− } `json:"params"`
614+ Params UnsubscribeParams `json:"params"`
615+}
616+
617+type UnsubscribeParams struct {
618+ // The URI of the resource to unsubscribe from.
619+ URI string `json:"uri"`
472620}
473621
474622// ResourceUpdatedNotification is a notification from the server to the client,
@@ -476,11 +624,12 @@ type UnsubscribeRequest struct {
476624// should only be sent if the client previously sent a resources/subscribe request.
477625type ResourceUpdatedNotification struct {
478626 Notification
479− Params struct {
480− // The URI of the resource that has been updated. This might be a sub-
481− // resource of the one that the client actually subscribed to.
482− URI string `json:"uri"`
483− } `json:"params"`
627+ Params ResourceUpdatedNotificationParams `json:"params"`
628+}
629+type ResourceUpdatedNotificationParams struct {
630+ // The URI of the resource that has been updated. This might be a sub-
631+ // resource of the one that the client actually subscribed to.
632+ URI string `json:"uri"`
484633}
485634
486635// Resource represents a known resource that the server is capable of reading.
@@ -501,6 +650,11 @@ type Resource struct {
501650 MIMEType string `json:"mimeType,omitempty"`
502651}
503652
653+// GetName returns the name of the resource.
654+func (r Resource) GetName() string {
655+ return r.Name
656+}
657+
504658// ResourceTemplate represents a template description for resources available
505659// on the server.
506660type ResourceTemplate struct {
@@ -522,6 +676,11 @@ type ResourceTemplate struct {
522676 MIMEType string `json:"mimeType,omitempty"`
523677}
524678
679+// GetName returns the name of the resourceTemplate.
680+func (rt ResourceTemplate) GetName() string {
681+ return rt.Name
682+}
683+
525684// ResourceContents represents the contents of a specific resource or sub-
526685// resource.
527686type ResourceContents interface {
@@ -557,12 +716,14 @@ func (BlobResourceContents) isResourceContents() {}
557716// adjust logging.
558717type SetLevelRequest struct {
559718 Request
560− Params struct {
561− // The level of logging that the client wants to receive from the server.
562− // The server should send all logs at this level and higher (i.e., more severe) to
563− // the client as notifications/logging/message.
564− Level LoggingLevel `json:"level"`
565− } `json:"params"`
719+ Params SetLevelParams `json:"params"`
720+}
721+
722+type SetLevelParams struct {
723+ // The level of logging that the client wants to receive from the server.
724+ // The server should send all logs at this level and higher (i.e., more severe) to
725+ // the client as notifications/logging/message.
726+ Level LoggingLevel `json:"level"`
566727}
567728
568729// LoggingMessageNotification is a notification of a log message passed from
@@ -570,15 +731,17 @@ type SetLevelRequest struct {
570731// the server MAY decide which messages to send automatically.
571732type LoggingMessageNotification struct {
572733 Notification
573− Params struct {
574− // The severity of this log message.
575− Level LoggingLevel `json:"level"`
576− // An optional name of the logger issuing this message.
577− Logger string `json:"logger,omitempty"`
578− // The data to be logged, such as a string message or an object. Any JSON
579− // serializable type is allowed here.
580− Data interface{} `json:"data"`
581− } `json:"params"`
734+ Params LoggingMessageNotificationParams `json:"params"`
735+}
736+
737+type LoggingMessageNotificationParams struct {
738+ // The severity of this log message.
739+ Level LoggingLevel `json:"level"`
740+ // An optional name of the logger issuing this message.
741+ Logger string `json:"logger,omitempty"`
742+ // The data to be logged, such as a string message or an object. Any JSON
743+ // serializable type is allowed here.
744+ Data any `json:"data"`
582745}
583746
584747// LoggingLevel represents the severity of a log message.
@@ -606,16 +769,18 @@ const (
606769// the request (human in the loop) and decide whether to approve it.
607770type CreateMessageRequest struct {
608771 Request
609− Params struct {
610− Messages []SamplingMessage `json:"messages"`
611− ModelPreferences *ModelPreferences `json:"modelPreferences,omitempty"`
612− SystemPrompt string `json:"systemPrompt,omitempty"`
613− IncludeContext string `json:"includeContext,omitempty"`
614− Temperature float64 `json:"temperature,omitempty"`
615− MaxTokens int `json:"maxTokens"`
616− StopSequences []string `json:"stopSequences,omitempty"`
617− Metadata interface{} `json:"metadata,omitempty"`
618− } `json:"params"`
772+ CreateMessageParams `json:"params"`
773+}
774+
775+type CreateMessageParams struct {
776+ Messages []SamplingMessage `json:"messages"`
777+ ModelPreferences *ModelPreferences `json:"modelPreferences,omitempty"`
778+ SystemPrompt string `json:"systemPrompt,omitempty"`
779+ IncludeContext string `json:"includeContext,omitempty"`
780+ Temperature float64 `json:"temperature,omitempty"`
781+ MaxTokens int `json:"maxTokens"`
782+ StopSequences []string `json:"stopSequences,omitempty"`
783+ Metadata any `json:"metadata,omitempty"`
619784}
620785
621786// CreateMessageResult is the client's response to a sampling/create_message
@@ -633,28 +798,30 @@ type CreateMessageResult struct {
633798
634799// SamplingMessage describes a message issued to or received from an LLM API.
635800type SamplingMessage struct {
636− Role Role `json:"role"`
637− Content interface{} `json:"content"` // Can be TextContent or ImageContent
801+ Role Role `json:"role"`
802+ Content any `json:"content"` // Can be TextContent, ImageContent or AudioContent
803+}
804+
805+type Annotations struct {
806+ // Describes who the intended customer of this object or data is.
807+ //
808+ // It can include multiple entries to indicate content useful for multiple
809+ // audiences (e.g., `["user", "assistant"]`).
810+ Audience []Role `json:"audience,omitempty"`
811+
812+ // Describes how important this data is for operating the server.
813+ //
814+ // A value of 1 means "most important," and indicates that the data is
815+ // effectively required, while 0 means "least important," and indicates that
816+ // the data is entirely optional.
817+ Priority float64 `json:"priority,omitempty"`
638818}
639819
640820// Annotated is the base for objects that include optional annotations for the
641821// client. The client can use annotations to inform how objects are used or
642822// displayed
643823type Annotated struct {
644− Annotations *struct {
645− // Describes who the intended customer of this object or data is.
646− //
647− // It can include multiple entries to indicate content useful for multiple
648− // audiences (e.g., `["user", "assistant"]`).
649− Audience []Role `json:"audience,omitempty"`
650−
651− // Describes how important this data is for operating the server.
652− //
653− // A value of 1 means "most important," and indicates that the data is
654− // effectively required, while 0 means "least important," and indicates that
655− // the data is entirely optional.
656− Priority float64 `json:"priority,omitempty"`
657− } `json:"annotations,omitempty"`
824+ Annotations *Annotations `json:"annotations,omitempty"`
658825}
659826
660827type Content interface {
@@ -685,6 +852,19 @@ type ImageContent struct {
685852
686853func (ImageContent) isContent() {}
687854
855+// AudioContent represents the contents of audio, embedded into a prompt or tool call result.
856+// It must have Type set to "audio".
857+type AudioContent struct {
858+ Annotated
859+ Type string `json:"type"` // Must be "audio"
860+ // The base64-encoded audio data.
861+ Data string `json:"data"`
862+ // The MIME type of the audio. Different providers may support different audio types.
863+ MIMEType string `json:"mimeType"`
864+}
865+
866+func (AudioContent) isContent() {}
867+
688868// EmbeddedResource represents the contents of a resource, embedded into a prompt or tool call result.
689869//
690870// It is up to the client how best to render embedded resources for the
@@ -758,15 +938,17 @@ type ModelHint struct {
758938// CompleteRequest is a request from the client to the server, to ask for completion options.
759939type CompleteRequest struct {
760940 Request
761− Params struct {
762− Ref interface{} `json:"ref"` // Can be PromptReference or ResourceReference
763− Argument struct {
764− // The name of the argument
765− Name string `json:"name"`
766− // The value of the argument to use for completion matching.
767− Value string `json:"value"`
768− } `json:"argument"`
769− } `json:"params"`
941+ Params CompleteParams `json:"params"`
942+}
943+
944+type CompleteParams struct {
945+ Ref any `json:"ref"` // Can be PromptReference or ResourceReference
946+ Argument struct {
947+ // The name of the argument
948+ Name string `json:"name"`
949+ // The value of the argument to use for completion matching.
950+ Value string `json:"value"`
951+ } `json:"argument"`
770952}
771953
772954// CompleteResult is the server's response to a completion/complete request
@@ -839,22 +1021,24 @@ type RootsListChangedNotification struct {
8391021 Notification
8401022}
8411023
842−/* Client messages */
8431024// ClientRequest represents any request that can be sent from client to server.
844−type ClientRequest interface{}
1025+type ClientRequest any
8451026
8461027// ClientNotification represents any notification that can be sent from client to server.
847−type ClientNotification interface{}
1028+type ClientNotification any
8481029
8491030// ClientResult represents any result that can be sent from client to server.
850−type ClientResult interface{}
1031+type ClientResult any
8511032
852−/* Server messages */
8531033// ServerRequest represents any request that can be sent from server to client.
854−type ServerRequest interface{}
1034+type ServerRequest any
8551035
8561036// ServerNotification represents any notification that can be sent from server to client.
857−type ServerNotification interface{}
1037+type ServerNotification any
8581038
8591039// ServerResult represents any result that can be sent from server to client.
860−type ServerResult interface{}
1040+type ServerResult any
1041+
1042+type Named interface {
1043+ GetName() string
1044+}
vendor/github.com/mark3labs/mcp-go/mcp/utils.go+231−15
@@ -3,6 +3,8 @@ package mcp
33import (
44 "encoding/json"
55 "fmt"
6+
7+ "github.com/spf13/cast"
68)
79
810// ClientRequest types
@@ -58,7 +60,7 @@ var _ ServerResult = &ListToolsResult{}
5860// Helper functions for type assertions
5961
6062// asType attempts to cast the given interface to the given type
61−func asType[T any](content interface{}) (*T, bool) {
63+func asType[T any](content any) (*T, bool) {
6264 tc, ok := content.(T)
6365 if !ok {
6466 return nil, false
@@ -67,27 +69,32 @@ func asType[T any](content interface{}) (*T, bool) {
6769}
6870
6971// AsTextContent attempts to cast the given interface to TextContent
70−func AsTextContent(content interface{}) (*TextContent, bool) {
72+func AsTextContent(content any) (*TextContent, bool) {
7173 return asType[TextContent](content)
7274}
7375
7476// AsImageContent attempts to cast the given interface to ImageContent
75−func AsImageContent(content interface{}) (*ImageContent, bool) {
77+func AsImageContent(content any) (*ImageContent, bool) {
7678 return asType[ImageContent](content)
7779}
7880
81+// AsAudioContent attempts to cast the given interface to AudioContent
82+func AsAudioContent(content any) (*AudioContent, bool) {
83+ return asType[AudioContent](content)
84+}
85+
7986// AsEmbeddedResource attempts to cast the given interface to EmbeddedResource
80−func AsEmbeddedResource(content interface{}) (*EmbeddedResource, bool) {
87+func AsEmbeddedResource(content any) (*EmbeddedResource, bool) {
8188 return asType[EmbeddedResource](content)
8289}
8390
8491// AsTextResourceContents attempts to cast the given interface to TextResourceContents
85−func AsTextResourceContents(content interface{}) (*TextResourceContents, bool) {
92+func AsTextResourceContents(content any) (*TextResourceContents, bool) {
8693 return asType[TextResourceContents](content)
8794}
8895
8996// AsBlobResourceContents attempts to cast the given interface to BlobResourceContents
90−func AsBlobResourceContents(content interface{}) (*BlobResourceContents, bool) {
97+func AsBlobResourceContents(content any) (*BlobResourceContents, bool) {
9198 return asType[BlobResourceContents](content)
9299}
93100
@@ -107,15 +114,15 @@ func NewJSONRPCError(
107114 id RequestId,
108115 code int,
109116 message string,
110− data interface{},
117+ data any,
111118) JSONRPCError {
112119 return JSONRPCError{
113120 JSONRPC: JSONRPC_VERSION,
114121 ID: id,
115122 Error: struct {
116− Code int `json:"code"`
117− Message string `json:"message"`
118− Data interface{} `json:"data,omitempty"`
123+ Code int `json:"code"`
124+ Message string `json:"message"`
125+ Data any `json:"data,omitempty"`
119126 }{
120127 Code: code,
121128 Message: message,
@@ -124,11 +131,13 @@ func NewJSONRPCError(
124131 }
125132}
126133
134+// NewProgressNotification
127135// Helper function for creating a progress notification
128136func NewProgressNotification(
129137 token ProgressToken,
130138 progress float64,
131139 total *float64,
140+ message *string,
132141) ProgressNotification {
133142 notification := ProgressNotification{
134143 Notification: Notification{
@@ -138,6 +147,7 @@ func NewProgressNotification(
138147 ProgressToken ProgressToken `json:"progressToken"`
139148 Progress float64 `json:"progress"`
140149 Total float64 `json:"total,omitempty"`
150+ Message string `json:"message,omitempty"`
141151 }{
142152 ProgressToken: token,
143153 Progress: progress,
@@ -146,14 +156,18 @@ func NewProgressNotification(
146156 if total != nil {
147157 notification.Params.Total = *total
148158 }
159+ if message != nil {
160+ notification.Params.Message = *message
161+ }
149162 return notification
150163}
151164
165+// NewLoggingMessageNotification
152166// Helper function for creating a logging message notification
153167func NewLoggingMessageNotification(
154168 level LoggingLevel,
155169 logger string,
156− data interface{},
170+ data any,
157171) LoggingMessageNotification {
158172 return LoggingMessageNotification{
159173 Notification: Notification{
@@ -162,7 +176,7 @@ func NewLoggingMessageNotification(
162176 Params: struct {
163177 Level LoggingLevel `json:"level"`
164178 Logger string `json:"logger,omitempty"`
165− Data interface{} `json:"data"`
179+ Data any `json:"data"`
166180 }{
167181 Level: level,
168182 Logger: logger,
@@ -171,6 +185,7 @@ func NewLoggingMessageNotification(
171185 }
172186}
173187
188+// NewPromptMessage
174189// Helper function to create a new PromptMessage
175190func NewPromptMessage(role Role, content Content) PromptMessage {
176191 return PromptMessage{
@@ -179,6 +194,7 @@ func NewPromptMessage(role Role, content Content) PromptMessage {
179194 }
180195}
181196
197+// NewTextContent
182198// Helper function to create a new TextContent
183199func NewTextContent(text string) TextContent {
184200 return TextContent{
@@ -187,6 +203,7 @@ func NewTextContent(text string) TextContent {
187203 }
188204}
189205
206+// NewImageContent
190207// Helper function to create a new ImageContent
191208func NewImageContent(data, mimeType string) ImageContent {
192209 return ImageContent{
@@ -196,6 +213,15 @@ func NewImageContent(data, mimeType string) ImageContent {
196213 }
197214}
198215
216+// Helper function to create a new AudioContent
217+func NewAudioContent(data, mimeType string) AudioContent {
218+ return AudioContent{
219+ Type: "audio",
220+ Data: data,
221+ MIMEType: mimeType,
222+ }
223+}
224+
199225// Helper function to create a new EmbeddedResource
200226func NewEmbeddedResource(resource ResourceContents) EmbeddedResource {
201227 return EmbeddedResource{
@@ -233,6 +259,23 @@ func NewToolResultImage(text, imageData, mimeType string) *CallToolResult {
233259 }
234260}
235261
262+// NewToolResultAudio creates a new CallToolResult with both text and audio content
263+func NewToolResultAudio(text, imageData, mimeType string) *CallToolResult {
264+ return &CallToolResult{
265+ Content: []Content{
266+ TextContent{
267+ Type: "text",
268+ Text: text,
269+ },
270+ AudioContent{
271+ Type: "audio",
272+ Data: imageData,
273+ MIMEType: mimeType,
274+ },
275+ },
276+ }
277+}
278+
236279// NewToolResultResource creates a new CallToolResult with an embedded resource
237280func NewToolResultResource(
238281 text string,
@@ -252,6 +295,53 @@ func NewToolResultResource(
252295 }
253296}
254297
298+// NewToolResultError creates a new CallToolResult with an error message.
299+// Any errors that originate from the tool SHOULD be reported inside the result object.
300+func NewToolResultError(text string) *CallToolResult {
301+ return &CallToolResult{
302+ Content: []Content{
303+ TextContent{
304+ Type: "text",
305+ Text: text,
306+ },
307+ },
308+ IsError: true,
309+ }
310+}
311+
312+// NewToolResultErrorFromErr creates a new CallToolResult with an error message.
313+// If an error is provided, its details will be appended to the text message.
314+// Any errors that originate from the tool SHOULD be reported inside the result object.
315+func NewToolResultErrorFromErr(text string, err error) *CallToolResult {
316+ if err != nil {
317+ text = fmt.Sprintf("%s: %v", text, err)
318+ }
319+ return &CallToolResult{
320+ Content: []Content{
321+ TextContent{
322+ Type: "text",
323+ Text: text,
324+ },
325+ },
326+ IsError: true,
327+ }
328+}
329+
330+// NewToolResultErrorf creates a new CallToolResult with an error message.
331+// The error message is formatted using the fmt package.
332+// Any errors that originate from the tool SHOULD be reported inside the result object.
333+func NewToolResultErrorf(format string, a ...any) *CallToolResult {
334+ return &CallToolResult{
335+ Content: []Content{
336+ TextContent{
337+ Type: "text",
338+ Text: fmt.Sprintf(format, a...),
339+ },
340+ },
341+ IsError: true,
342+ }
343+}
344+
255345// NewListResourcesResult creates a new ListResourcesResult
256346func NewListResourcesResult(
257347 resources []Resource,
@@ -338,6 +428,7 @@ func NewInitializeResult(
338428 }
339429}
340430
431+// FormatNumberResult
341432// Helper for formatting numbers in tool results
342433func FormatNumberResult(value float64) *CallToolResult {
343434 return NewToolResultText(fmt.Sprintf("%.2f", value))
@@ -367,9 +458,6 @@ func ParseContent(contentMap map[string]any) (Content, error) {
367458 switch contentType {
368459 case "text":
369460 text := ExtractString(contentMap, "text")
370− if text == "" {
371− return nil, fmt.Errorf("text is missing")
372− }
373461 return NewTextContent(text), nil
374462
375463 case "image":
@@ -380,6 +468,14 @@ func ParseContent(contentMap map[string]any) (Content, error) {
380468 }
381469 return NewImageContent(data, mimeType), nil
382470
471+ case "audio":
472+ data := ExtractString(contentMap, "data")
473+ mimeType := ExtractString(contentMap, "mimeType")
474+ if data == "" || mimeType == "" {
475+ return nil, fmt.Errorf("audio data or mimeType is missing")
476+ }
477+ return NewAudioContent(data, mimeType), nil
478+
383479 case "resource":
384480 resourceMap := ExtractMap(contentMap, "resource")
385481 if resourceMap == nil {
@@ -398,6 +494,10 @@ func ParseContent(contentMap map[string]any) (Content, error) {
398494}
399495
400496func ParseGetPromptResult(rawMessage *json.RawMessage) (*GetPromptResult, error) {
497+ if rawMessage == nil {
498+ return nil, fmt.Errorf("response is nil")
499+ }
500+
401501 var jsonContent map[string]any
402502 if err := json.Unmarshal(*rawMessage, &jsonContent); err != nil {
403503 return nil, fmt.Errorf("failed to unmarshal response: %w", err)
@@ -460,6 +560,10 @@ func ParseGetPromptResult(rawMessage *json.RawMessage) (*GetPromptResult, error)
460560}
461561
462562func ParseCallToolResult(rawMessage *json.RawMessage) (*CallToolResult, error) {
563+ if rawMessage == nil {
564+ return nil, fmt.Errorf("response is nil")
565+ }
566+
463567 var jsonContent map[string]any
464568 if err := json.Unmarshal(*rawMessage, &jsonContent); err != nil {
465569 return nil, fmt.Errorf("failed to unmarshal response: %w", err)
@@ -538,6 +642,10 @@ func ParseResourceContents(contentMap map[string]any) (ResourceContents, error)
538642}
539643
540644func ParseReadResourceResult(rawMessage *json.RawMessage) (*ReadResourceResult, error) {
645+ if rawMessage == nil {
646+ return nil, fmt.Errorf("response is nil")
647+ }
648+
541649 var jsonContent map[string]any
542650 if err := json.Unmarshal(*rawMessage, &jsonContent); err != nil {
543651 return nil, fmt.Errorf("failed to unmarshal response: %w", err)
@@ -580,3 +688,111 @@ func ParseReadResourceResult(rawMessage *json.RawMessage) (*ReadResourceResult,
580688
581689 return &result, nil
582690}
691+
692+func ParseArgument(request CallToolRequest, key string, defaultVal any) any {
693+ args := request.GetArguments()
694+ if _, ok := args[key]; !ok {
695+ return defaultVal
696+ } else {
697+ return args[key]
698+ }
699+}
700+
701+// ParseBoolean extracts and converts a boolean parameter from a CallToolRequest.
702+// If the key is not found in the Arguments map, the defaultValue is returned.
703+// The function uses cast.ToBool for conversion which handles various string representations
704+// such as "true", "yes", "1", etc.
705+func ParseBoolean(request CallToolRequest, key string, defaultValue bool) bool {
706+ v := ParseArgument(request, key, defaultValue)
707+ return cast.ToBool(v)
708+}
709+
710+// ParseInt64 extracts and converts an int64 parameter from a CallToolRequest.
711+// If the key is not found in the Arguments map, the defaultValue is returned.
712+func ParseInt64(request CallToolRequest, key string, defaultValue int64) int64 {
713+ v := ParseArgument(request, key, defaultValue)
714+ return cast.ToInt64(v)
715+}
716+
717+// ParseInt32 extracts and converts an int32 parameter from a CallToolRequest.
718+func ParseInt32(request CallToolRequest, key string, defaultValue int32) int32 {
719+ v := ParseArgument(request, key, defaultValue)
720+ return cast.ToInt32(v)
721+}
722+
723+// ParseInt16 extracts and converts an int16 parameter from a CallToolRequest.
724+func ParseInt16(request CallToolRequest, key string, defaultValue int16) int16 {
725+ v := ParseArgument(request, key, defaultValue)
726+ return cast.ToInt16(v)
727+}
728+
729+// ParseInt8 extracts and converts an int8 parameter from a CallToolRequest.
730+func ParseInt8(request CallToolRequest, key string, defaultValue int8) int8 {
731+ v := ParseArgument(request, key, defaultValue)
732+ return cast.ToInt8(v)
733+}
734+
735+// ParseInt extracts and converts an int parameter from a CallToolRequest.
736+func ParseInt(request CallToolRequest, key string, defaultValue int) int {
737+ v := ParseArgument(request, key, defaultValue)
738+ return cast.ToInt(v)
739+}
740+
741+// ParseUInt extracts and converts an uint parameter from a CallToolRequest.
742+func ParseUInt(request CallToolRequest, key string, defaultValue uint) uint {
743+ v := ParseArgument(request, key, defaultValue)
744+ return cast.ToUint(v)
745+}
746+
747+// ParseUInt64 extracts and converts an uint64 parameter from a CallToolRequest.
748+func ParseUInt64(request CallToolRequest, key string, defaultValue uint64) uint64 {
749+ v := ParseArgument(request, key, defaultValue)
750+ return cast.ToUint64(v)
751+}
752+
753+// ParseUInt32 extracts and converts an uint32 parameter from a CallToolRequest.
754+func ParseUInt32(request CallToolRequest, key string, defaultValue uint32) uint32 {
755+ v := ParseArgument(request, key, defaultValue)
756+ return cast.ToUint32(v)
757+}
758+
759+// ParseUInt16 extracts and converts an uint16 parameter from a CallToolRequest.
760+func ParseUInt16(request CallToolRequest, key string, defaultValue uint16) uint16 {
761+ v := ParseArgument(request, key, defaultValue)
762+ return cast.ToUint16(v)
763+}
764+
765+// ParseUInt8 extracts and converts an uint8 parameter from a CallToolRequest.
766+func ParseUInt8(request CallToolRequest, key string, defaultValue uint8) uint8 {
767+ v := ParseArgument(request, key, defaultValue)
768+ return cast.ToUint8(v)
769+}
770+
771+// ParseFloat32 extracts and converts a float32 parameter from a CallToolRequest.
772+func ParseFloat32(request CallToolRequest, key string, defaultValue float32) float32 {
773+ v := ParseArgument(request, key, defaultValue)
774+ return cast.ToFloat32(v)
775+}
776+
777+// ParseFloat64 extracts and converts a float64 parameter from a CallToolRequest.
778+func ParseFloat64(request CallToolRequest, key string, defaultValue float64) float64 {
779+ v := ParseArgument(request, key, defaultValue)
780+ return cast.ToFloat64(v)
781+}
782+
783+// ParseString extracts and converts a string parameter from a CallToolRequest.
784+func ParseString(request CallToolRequest, key string, defaultValue string) string {
785+ v := ParseArgument(request, key, defaultValue)
786+ return cast.ToString(v)
787+}
788+
789+// ParseStringMap extracts and converts a string map parameter from a CallToolRequest.
790+func ParseStringMap(request CallToolRequest, key string, defaultValue map[string]any) map[string]any {
791+ v := ParseArgument(request, key, defaultValue)
792+ return cast.ToStringMap(v)
793+}
794+
795+// ToBoolPtr returns a pointer to the given boolean value
796+func ToBoolPtr(b bool) *bool {
797+ return &b
798+}
vendor/github.com/mark3labs/mcp-go/server/errors.gonew file+34
@@ -0,0 +1,34 @@
1+package server
2+
3+import (
4+ "errors"
5+ "fmt"
6+)
7+
8+var (
9+ // Common server errors
10+ ErrUnsupported = errors.New("not supported")
11+ ErrResourceNotFound = errors.New("resource not found")
12+ ErrPromptNotFound = errors.New("prompt not found")
13+ ErrToolNotFound = errors.New("tool not found")
14+
15+ // Session-related errors
16+ ErrSessionNotFound = errors.New("session not found")
17+ ErrSessionExists = errors.New("session already exists")
18+ ErrSessionNotInitialized = errors.New("session not properly initialized")
19+ ErrSessionDoesNotSupportTools = errors.New("session does not support per-session tools")
20+ ErrSessionDoesNotSupportLogging = errors.New("session does not support setting logging level")
21+
22+ // Notification-related errors
23+ ErrNotificationNotInitialized = errors.New("notification channel not initialized")
24+ ErrNotificationChannelBlocked = errors.New("notification channel full or blocked")
25+)
26+
27+// ErrDynamicPathConfig is returned when attempting to use static path methods with dynamic path configuration
28+type ErrDynamicPathConfig struct {
29+ Method string
30+}
31+
32+func (e *ErrDynamicPathConfig) Error() string {
33+ return fmt.Sprintf("%s cannot be used with WithDynamicBasePath. Use dynamic path logic in your router.", e.Method)
34+}
vendor/github.com/mark3labs/mcp-go/server/hooks.gonew file+532
@@ -0,0 +1,532 @@
1+// Code generated by `go generate`. DO NOT EDIT.
2+// source: server/internal/gen/hooks.go.tmpl
3+package server
4+
5+import (
6+ "context"
7+
8+ "github.com/mark3labs/mcp-go/mcp"
9+)
10+
11+// OnRegisterSessionHookFunc is a hook that will be called when a new session is registered.
12+type OnRegisterSessionHookFunc func(ctx context.Context, session ClientSession)
13+
14+// OnUnregisterSessionHookFunc is a hook that will be called when a session is being unregistered.
15+type OnUnregisterSessionHookFunc func(ctx context.Context, session ClientSession)
16+
17+// BeforeAnyHookFunc is a function that is called after the request is
18+// parsed but before the method is called.
19+type BeforeAnyHookFunc func(ctx context.Context, id any, method mcp.MCPMethod, message any)
20+
21+// OnSuccessHookFunc is a hook that will be called after the request
22+// successfully generates a result, but before the result is sent to the client.
23+type OnSuccessHookFunc func(ctx context.Context, id any, method mcp.MCPMethod, message any, result any)
24+
25+// OnErrorHookFunc is a hook that will be called when an error occurs,
26+// either during the request parsing or the method execution.
27+//
28+// Example usage:
29+// ```
30+//
31+// hooks.AddOnError(func(ctx context.Context, id any, method mcp.MCPMethod, message any, err error) {
32+// // Check for specific error types using errors.Is
33+// if errors.Is(err, ErrUnsupported) {
34+// // Handle capability not supported errors
35+// log.Printf("Capability not supported: %v", err)
36+// }
37+//
38+// // Use errors.As to get specific error types
39+// var parseErr = &UnparsableMessageError{}
40+// if errors.As(err, &parseErr) {
41+// // Access specific methods/fields of the error type
42+// log.Printf("Failed to parse message for method %s: %v",
43+// parseErr.GetMethod(), parseErr.Unwrap())
44+// // Access the raw message that failed to parse
45+// rawMsg := parseErr.GetMessage()
46+// }
47+//
48+// // Check for specific resource/prompt/tool errors
49+// switch {
50+// case errors.Is(err, ErrResourceNotFound):
51+// log.Printf("Resource not found: %v", err)
52+// case errors.Is(err, ErrPromptNotFound):
53+// log.Printf("Prompt not found: %v", err)
54+// case errors.Is(err, ErrToolNotFound):
55+// log.Printf("Tool not found: %v", err)
56+// }
57+// })
58+type OnErrorHookFunc func(ctx context.Context, id any, method mcp.MCPMethod, message any, err error)
59+
60+// OnRequestInitializationFunc is a function that called before handle diff request method
61+// Should any errors arise during func execution, the service will promptly return the corresponding error message.
62+type OnRequestInitializationFunc func(ctx context.Context, id any, message any) error
63+
64+type OnBeforeInitializeFunc func(ctx context.Context, id any, message *mcp.InitializeRequest)
65+type OnAfterInitializeFunc func(ctx context.Context, id any, message *mcp.InitializeRequest, result *mcp.InitializeResult)
66+
67+type OnBeforePingFunc func(ctx context.Context, id any, message *mcp.PingRequest)
68+type OnAfterPingFunc func(ctx context.Context, id any, message *mcp.PingRequest, result *mcp.EmptyResult)
69+
70+type OnBeforeSetLevelFunc func(ctx context.Context, id any, message *mcp.SetLevelRequest)
71+type OnAfterSetLevelFunc func(ctx context.Context, id any, message *mcp.SetLevelRequest, result *mcp.EmptyResult)
72+
73+type OnBeforeListResourcesFunc func(ctx context.Context, id any, message *mcp.ListResourcesRequest)
74+type OnAfterListResourcesFunc func(ctx context.Context, id any, message *mcp.ListResourcesRequest, result *mcp.ListResourcesResult)
75+
76+type OnBeforeListResourceTemplatesFunc func(ctx context.Context, id any, message *mcp.ListResourceTemplatesRequest)
77+type OnAfterListResourceTemplatesFunc func(ctx context.Context, id any, message *mcp.ListResourceTemplatesRequest, result *mcp.ListResourceTemplatesResult)
78+
79+type OnBeforeReadResourceFunc func(ctx context.Context, id any, message *mcp.ReadResourceRequest)
80+type OnAfterReadResourceFunc func(ctx context.Context, id any, message *mcp.ReadResourceRequest, result *mcp.ReadResourceResult)
81+
82+type OnBeforeListPromptsFunc func(ctx context.Context, id any, message *mcp.ListPromptsRequest)
83+type OnAfterListPromptsFunc func(ctx context.Context, id any, message *mcp.ListPromptsRequest, result *mcp.ListPromptsResult)
84+
85+type OnBeforeGetPromptFunc func(ctx context.Context, id any, message *mcp.GetPromptRequest)
86+type OnAfterGetPromptFunc func(ctx context.Context, id any, message *mcp.GetPromptRequest, result *mcp.GetPromptResult)
87+
88+type OnBeforeListToolsFunc func(ctx context.Context, id any, message *mcp.ListToolsRequest)
89+type OnAfterListToolsFunc func(ctx context.Context, id any, message *mcp.ListToolsRequest, result *mcp.ListToolsResult)
90+
91+type OnBeforeCallToolFunc func(ctx context.Context, id any, message *mcp.CallToolRequest)
92+type OnAfterCallToolFunc func(ctx context.Context, id any, message *mcp.CallToolRequest, result *mcp.CallToolResult)
93+
94+type Hooks struct {
95+ OnRegisterSession []OnRegisterSessionHookFunc
96+ OnUnregisterSession []OnUnregisterSessionHookFunc
97+ OnBeforeAny []BeforeAnyHookFunc
98+ OnSuccess []OnSuccessHookFunc
99+ OnError []OnErrorHookFunc
100+ OnRequestInitialization []OnRequestInitializationFunc
101+ OnBeforeInitialize []OnBeforeInitializeFunc
102+ OnAfterInitialize []OnAfterInitializeFunc
103+ OnBeforePing []OnBeforePingFunc
104+ OnAfterPing []OnAfterPingFunc
105+ OnBeforeSetLevel []OnBeforeSetLevelFunc
106+ OnAfterSetLevel []OnAfterSetLevelFunc
107+ OnBeforeListResources []OnBeforeListResourcesFunc
108+ OnAfterListResources []OnAfterListResourcesFunc
109+ OnBeforeListResourceTemplates []OnBeforeListResourceTemplatesFunc
110+ OnAfterListResourceTemplates []OnAfterListResourceTemplatesFunc
111+ OnBeforeReadResource []OnBeforeReadResourceFunc
112+ OnAfterReadResource []OnAfterReadResourceFunc
113+ OnBeforeListPrompts []OnBeforeListPromptsFunc
114+ OnAfterListPrompts []OnAfterListPromptsFunc
115+ OnBeforeGetPrompt []OnBeforeGetPromptFunc
116+ OnAfterGetPrompt []OnAfterGetPromptFunc
117+ OnBeforeListTools []OnBeforeListToolsFunc
118+ OnAfterListTools []OnAfterListToolsFunc
119+ OnBeforeCallTool []OnBeforeCallToolFunc
120+ OnAfterCallTool []OnAfterCallToolFunc
121+}
122+
123+func (c *Hooks) AddBeforeAny(hook BeforeAnyHookFunc) {
124+ c.OnBeforeAny = append(c.OnBeforeAny, hook)
125+}
126+
127+func (c *Hooks) AddOnSuccess(hook OnSuccessHookFunc) {
128+ c.OnSuccess = append(c.OnSuccess, hook)
129+}
130+
131+// AddOnError registers a hook function that will be called when an error occurs.
132+// The error parameter contains the actual error object, which can be interrogated
133+// using Go's error handling patterns like errors.Is and errors.As.
134+//
135+// Example:
136+// ```
137+// // Create a channel to receive errors for testing
138+// errChan := make(chan error, 1)
139+//
140+// // Register hook to capture and inspect errors
141+// hooks := &Hooks{}
142+//
143+// hooks.AddOnError(func(ctx context.Context, id any, method mcp.MCPMethod, message any, err error) {
144+// // For capability-related errors
145+// if errors.Is(err, ErrUnsupported) {
146+// // Handle capability not supported
147+// errChan <- err
148+// return
149+// }
150+//
151+// // For parsing errors
152+// var parseErr = &UnparsableMessageError{}
153+// if errors.As(err, &parseErr) {
154+// // Handle unparsable message errors
155+// fmt.Printf("Failed to parse %s request: %v\n",
156+// parseErr.GetMethod(), parseErr.Unwrap())
157+// errChan <- parseErr
158+// return
159+// }
160+//
161+// // For resource/prompt/tool not found errors
162+// if errors.Is(err, ErrResourceNotFound) ||
163+// errors.Is(err, ErrPromptNotFound) ||
164+// errors.Is(err, ErrToolNotFound) {
165+// // Handle not found errors
166+// errChan <- err
167+// return
168+// }
169+//
170+// // For other errors
171+// errChan <- err
172+// })
173+//
174+// server := NewMCPServer("test-server", "1.0.0", WithHooks(hooks))
175+// ```
176+func (c *Hooks) AddOnError(hook OnErrorHookFunc) {
177+ c.OnError = append(c.OnError, hook)
178+}
179+
180+func (c *Hooks) beforeAny(ctx context.Context, id any, method mcp.MCPMethod, message any) {
181+ if c == nil {
182+ return
183+ }
184+ for _, hook := range c.OnBeforeAny {
185+ hook(ctx, id, method, message)
186+ }
187+}
188+
189+func (c *Hooks) onSuccess(ctx context.Context, id any, method mcp.MCPMethod, message any, result any) {
190+ if c == nil {
191+ return
192+ }
193+ for _, hook := range c.OnSuccess {
194+ hook(ctx, id, method, message, result)
195+ }
196+}
197+
198+// onError calls all registered error hooks with the error object.
199+// The err parameter contains the actual error that occurred, which implements
200+// the standard error interface and may be a wrapped error or custom error type.
201+//
202+// This allows consumer code to use Go's error handling patterns:
203+// - errors.Is(err, ErrUnsupported) to check for specific sentinel errors
204+// - errors.As(err, &customErr) to extract custom error types
205+//
206+// Common error types include:
207+// - ErrUnsupported: When a capability is not enabled
208+// - UnparsableMessageError: When request parsing fails
209+// - ErrResourceNotFound: When a resource is not found
210+// - ErrPromptNotFound: When a prompt is not found
211+// - ErrToolNotFound: When a tool is not found
212+func (c *Hooks) onError(ctx context.Context, id any, method mcp.MCPMethod, message any, err error) {
213+ if c == nil {
214+ return
215+ }
216+ for _, hook := range c.OnError {
217+ hook(ctx, id, method, message, err)
218+ }
219+}
220+
221+func (c *Hooks) AddOnRegisterSession(hook OnRegisterSessionHookFunc) {
222+ c.OnRegisterSession = append(c.OnRegisterSession, hook)
223+}
224+
225+func (c *Hooks) RegisterSession(ctx context.Context, session ClientSession) {
226+ if c == nil {
227+ return
228+ }
229+ for _, hook := range c.OnRegisterSession {
230+ hook(ctx, session)
231+ }
232+}
233+
234+func (c *Hooks) AddOnUnregisterSession(hook OnUnregisterSessionHookFunc) {
235+ c.OnUnregisterSession = append(c.OnUnregisterSession, hook)
236+}
237+
238+func (c *Hooks) UnregisterSession(ctx context.Context, session ClientSession) {
239+ if c == nil {
240+ return
241+ }
242+ for _, hook := range c.OnUnregisterSession {
243+ hook(ctx, session)
244+ }
245+}
246+
247+func (c *Hooks) AddOnRequestInitialization(hook OnRequestInitializationFunc) {
248+ c.OnRequestInitialization = append(c.OnRequestInitialization, hook)
249+}
250+
251+func (c *Hooks) onRequestInitialization(ctx context.Context, id any, message any) error {
252+ if c == nil {
253+ return nil
254+ }
255+ for _, hook := range c.OnRequestInitialization {
256+ err := hook(ctx, id, message)
257+ if err != nil {
258+ return err
259+ }
260+ }
261+ return nil
262+}
263+func (c *Hooks) AddBeforeInitialize(hook OnBeforeInitializeFunc) {
264+ c.OnBeforeInitialize = append(c.OnBeforeInitialize, hook)
265+}
266+
267+func (c *Hooks) AddAfterInitialize(hook OnAfterInitializeFunc) {
268+ c.OnAfterInitialize = append(c.OnAfterInitialize, hook)
269+}
270+
271+func (c *Hooks) beforeInitialize(ctx context.Context, id any, message *mcp.InitializeRequest) {
272+ c.beforeAny(ctx, id, mcp.MethodInitialize, message)
273+ if c == nil {
274+ return
275+ }
276+ for _, hook := range c.OnBeforeInitialize {
277+ hook(ctx, id, message)
278+ }
279+}
280+
281+func (c *Hooks) afterInitialize(ctx context.Context, id any, message *mcp.InitializeRequest, result *mcp.InitializeResult) {
282+ c.onSuccess(ctx, id, mcp.MethodInitialize, message, result)
283+ if c == nil {
284+ return
285+ }
286+ for _, hook := range c.OnAfterInitialize {
287+ hook(ctx, id, message, result)
288+ }
289+}
290+func (c *Hooks) AddBeforePing(hook OnBeforePingFunc) {
291+ c.OnBeforePing = append(c.OnBeforePing, hook)
292+}
293+
294+func (c *Hooks) AddAfterPing(hook OnAfterPingFunc) {
295+ c.OnAfterPing = append(c.OnAfterPing, hook)
296+}
297+
298+func (c *Hooks) beforePing(ctx context.Context, id any, message *mcp.PingRequest) {
299+ c.beforeAny(ctx, id, mcp.MethodPing, message)
300+ if c == nil {
301+ return
302+ }
303+ for _, hook := range c.OnBeforePing {
304+ hook(ctx, id, message)
305+ }
306+}
307+
308+func (c *Hooks) afterPing(ctx context.Context, id any, message *mcp.PingRequest, result *mcp.EmptyResult) {
309+ c.onSuccess(ctx, id, mcp.MethodPing, message, result)
310+ if c == nil {
311+ return
312+ }
313+ for _, hook := range c.OnAfterPing {
314+ hook(ctx, id, message, result)
315+ }
316+}
317+func (c *Hooks) AddBeforeSetLevel(hook OnBeforeSetLevelFunc) {
318+ c.OnBeforeSetLevel = append(c.OnBeforeSetLevel, hook)
319+}
320+
321+func (c *Hooks) AddAfterSetLevel(hook OnAfterSetLevelFunc) {
322+ c.OnAfterSetLevel = append(c.OnAfterSetLevel, hook)
323+}
324+
325+func (c *Hooks) beforeSetLevel(ctx context.Context, id any, message *mcp.SetLevelRequest) {
326+ c.beforeAny(ctx, id, mcp.MethodSetLogLevel, message)
327+ if c == nil {
328+ return
329+ }
330+ for _, hook := range c.OnBeforeSetLevel {
331+ hook(ctx, id, message)
332+ }
333+}
334+
335+func (c *Hooks) afterSetLevel(ctx context.Context, id any, message *mcp.SetLevelRequest, result *mcp.EmptyResult) {
336+ c.onSuccess(ctx, id, mcp.MethodSetLogLevel, message, result)
337+ if c == nil {
338+ return
339+ }
340+ for _, hook := range c.OnAfterSetLevel {
341+ hook(ctx, id, message, result)
342+ }
343+}
344+func (c *Hooks) AddBeforeListResources(hook OnBeforeListResourcesFunc) {
345+ c.OnBeforeListResources = append(c.OnBeforeListResources, hook)
346+}
347+
348+func (c *Hooks) AddAfterListResources(hook OnAfterListResourcesFunc) {
349+ c.OnAfterListResources = append(c.OnAfterListResources, hook)
350+}
351+
352+func (c *Hooks) beforeListResources(ctx context.Context, id any, message *mcp.ListResourcesRequest) {
353+ c.beforeAny(ctx, id, mcp.MethodResourcesList, message)
354+ if c == nil {
355+ return
356+ }
357+ for _, hook := range c.OnBeforeListResources {
358+ hook(ctx, id, message)
359+ }
360+}
361+
362+func (c *Hooks) afterListResources(ctx context.Context, id any, message *mcp.ListResourcesRequest, result *mcp.ListResourcesResult) {
363+ c.onSuccess(ctx, id, mcp.MethodResourcesList, message, result)
364+ if c == nil {
365+ return
366+ }
367+ for _, hook := range c.OnAfterListResources {
368+ hook(ctx, id, message, result)
369+ }
370+}
371+func (c *Hooks) AddBeforeListResourceTemplates(hook OnBeforeListResourceTemplatesFunc) {
372+ c.OnBeforeListResourceTemplates = append(c.OnBeforeListResourceTemplates, hook)
373+}
374+
375+func (c *Hooks) AddAfterListResourceTemplates(hook OnAfterListResourceTemplatesFunc) {
376+ c.OnAfterListResourceTemplates = append(c.OnAfterListResourceTemplates, hook)
377+}
378+
379+func (c *Hooks) beforeListResourceTemplates(ctx context.Context, id any, message *mcp.ListResourceTemplatesRequest) {
380+ c.beforeAny(ctx, id, mcp.MethodResourcesTemplatesList, message)
381+ if c == nil {
382+ return
383+ }
384+ for _, hook := range c.OnBeforeListResourceTemplates {
385+ hook(ctx, id, message)
386+ }
387+}
388+
389+func (c *Hooks) afterListResourceTemplates(ctx context.Context, id any, message *mcp.ListResourceTemplatesRequest, result *mcp.ListResourceTemplatesResult) {
390+ c.onSuccess(ctx, id, mcp.MethodResourcesTemplatesList, message, result)
391+ if c == nil {
392+ return
393+ }
394+ for _, hook := range c.OnAfterListResourceTemplates {
395+ hook(ctx, id, message, result)
396+ }
397+}
398+func (c *Hooks) AddBeforeReadResource(hook OnBeforeReadResourceFunc) {
399+ c.OnBeforeReadResource = append(c.OnBeforeReadResource, hook)
400+}
401+
402+func (c *Hooks) AddAfterReadResource(hook OnAfterReadResourceFunc) {
403+ c.OnAfterReadResource = append(c.OnAfterReadResource, hook)
404+}
405+
406+func (c *Hooks) beforeReadResource(ctx context.Context, id any, message *mcp.ReadResourceRequest) {
407+ c.beforeAny(ctx, id, mcp.MethodResourcesRead, message)
408+ if c == nil {
409+ return
410+ }
411+ for _, hook := range c.OnBeforeReadResource {
412+ hook(ctx, id, message)
413+ }
414+}
415+
416+func (c *Hooks) afterReadResource(ctx context.Context, id any, message *mcp.ReadResourceRequest, result *mcp.ReadResourceResult) {
417+ c.onSuccess(ctx, id, mcp.MethodResourcesRead, message, result)
418+ if c == nil {
419+ return
420+ }
421+ for _, hook := range c.OnAfterReadResource {
422+ hook(ctx, id, message, result)
423+ }
424+}
425+func (c *Hooks) AddBeforeListPrompts(hook OnBeforeListPromptsFunc) {
426+ c.OnBeforeListPrompts = append(c.OnBeforeListPrompts, hook)
427+}
428+
429+func (c *Hooks) AddAfterListPrompts(hook OnAfterListPromptsFunc) {
430+ c.OnAfterListPrompts = append(c.OnAfterListPrompts, hook)
431+}
432+
433+func (c *Hooks) beforeListPrompts(ctx context.Context, id any, message *mcp.ListPromptsRequest) {
434+ c.beforeAny(ctx, id, mcp.MethodPromptsList, message)
435+ if c == nil {
436+ return
437+ }
438+ for _, hook := range c.OnBeforeListPrompts {
439+ hook(ctx, id, message)
440+ }
441+}
442+
443+func (c *Hooks) afterListPrompts(ctx context.Context, id any, message *mcp.ListPromptsRequest, result *mcp.ListPromptsResult) {
444+ c.onSuccess(ctx, id, mcp.MethodPromptsList, message, result)
445+ if c == nil {
446+ return
447+ }
448+ for _, hook := range c.OnAfterListPrompts {
449+ hook(ctx, id, message, result)
450+ }
451+}
452+func (c *Hooks) AddBeforeGetPrompt(hook OnBeforeGetPromptFunc) {
453+ c.OnBeforeGetPrompt = append(c.OnBeforeGetPrompt, hook)
454+}
455+
456+func (c *Hooks) AddAfterGetPrompt(hook OnAfterGetPromptFunc) {
457+ c.OnAfterGetPrompt = append(c.OnAfterGetPrompt, hook)
458+}
459+
460+func (c *Hooks) beforeGetPrompt(ctx context.Context, id any, message *mcp.GetPromptRequest) {
461+ c.beforeAny(ctx, id, mcp.MethodPromptsGet, message)
462+ if c == nil {
463+ return
464+ }
465+ for _, hook := range c.OnBeforeGetPrompt {
466+ hook(ctx, id, message)
467+ }
468+}
469+
470+func (c *Hooks) afterGetPrompt(ctx context.Context, id any, message *mcp.GetPromptRequest, result *mcp.GetPromptResult) {
471+ c.onSuccess(ctx, id, mcp.MethodPromptsGet, message, result)
472+ if c == nil {
473+ return
474+ }
475+ for _, hook := range c.OnAfterGetPrompt {
476+ hook(ctx, id, message, result)
477+ }
478+}
479+func (c *Hooks) AddBeforeListTools(hook OnBeforeListToolsFunc) {
480+ c.OnBeforeListTools = append(c.OnBeforeListTools, hook)
481+}
482+
483+func (c *Hooks) AddAfterListTools(hook OnAfterListToolsFunc) {
484+ c.OnAfterListTools = append(c.OnAfterListTools, hook)
485+}
486+
487+func (c *Hooks) beforeListTools(ctx context.Context, id any, message *mcp.ListToolsRequest) {
488+ c.beforeAny(ctx, id, mcp.MethodToolsList, message)
489+ if c == nil {
490+ return
491+ }
492+ for _, hook := range c.OnBeforeListTools {
493+ hook(ctx, id, message)
494+ }
495+}
496+
497+func (c *Hooks) afterListTools(ctx context.Context, id any, message *mcp.ListToolsRequest, result *mcp.ListToolsResult) {
498+ c.onSuccess(ctx, id, mcp.MethodToolsList, message, result)
499+ if c == nil {
500+ return
501+ }
502+ for _, hook := range c.OnAfterListTools {
503+ hook(ctx, id, message, result)
504+ }
505+}
506+func (c *Hooks) AddBeforeCallTool(hook OnBeforeCallToolFunc) {
507+ c.OnBeforeCallTool = append(c.OnBeforeCallTool, hook)
508+}
509+
510+func (c *Hooks) AddAfterCallTool(hook OnAfterCallToolFunc) {
511+ c.OnAfterCallTool = append(c.OnAfterCallTool, hook)
512+}
513+
514+func (c *Hooks) beforeCallTool(ctx context.Context, id any, message *mcp.CallToolRequest) {
515+ c.beforeAny(ctx, id, mcp.MethodToolsCall, message)
516+ if c == nil {
517+ return
518+ }
519+ for _, hook := range c.OnBeforeCallTool {
520+ hook(ctx, id, message)
521+ }
522+}
523+
524+func (c *Hooks) afterCallTool(ctx context.Context, id any, message *mcp.CallToolRequest, result *mcp.CallToolResult) {
525+ c.onSuccess(ctx, id, mcp.MethodToolsCall, message, result)
526+ if c == nil {
527+ return
528+ }
529+ for _, hook := range c.OnAfterCallTool {
530+ hook(ctx, id, message, result)
531+ }
532+}
vendor/github.com/mark3labs/mcp-go/server/http_transport_options.gonew file+11
@@ -0,0 +1,11 @@
1+package server
2+
3+import (
4+ "context"
5+ "net/http"
6+)
7+
8+// HTTPContextFunc is a function that takes an existing context and the current
9+// request and returns a potentially modified context based on the request
10+// content. This can be used to inject context values from headers, for example.
11+type HTTPContextFunc func(ctx context.Context, r *http.Request) context.Context
vendor/github.com/mark3labs/mcp-go/server/request_handler.gonew file+320
@@ -0,0 +1,320 @@
1+// Code generated by `go generate`. DO NOT EDIT.
2+// source: server/internal/gen/request_handler.go.tmpl
3+package server
4+
5+import (
6+ "context"
7+ "encoding/json"
8+ "fmt"
9+
10+ "github.com/mark3labs/mcp-go/mcp"
11+)
12+
13+// HandleMessage processes an incoming JSON-RPC message and returns an appropriate response
14+func (s *MCPServer) HandleMessage(
15+ ctx context.Context,
16+ message json.RawMessage,
17+) mcp.JSONRPCMessage {
18+ // Add server to context
19+ ctx = context.WithValue(ctx, serverKey{}, s)
20+ var err *requestError
21+
22+ var baseMessage struct {
23+ JSONRPC string `json:"jsonrpc"`
24+ Method mcp.MCPMethod `json:"method"`
25+ ID any `json:"id,omitempty"`
26+ Result any `json:"result,omitempty"`
27+ }
28+
29+ if err := json.Unmarshal(message, &baseMessage); err != nil {
30+ return createErrorResponse(
31+ nil,
32+ mcp.PARSE_ERROR,
33+ "Failed to parse message",
34+ )
35+ }
36+
37+ // Check for valid JSONRPC version
38+ if baseMessage.JSONRPC != mcp.JSONRPC_VERSION {
39+ return createErrorResponse(
40+ baseMessage.ID,
41+ mcp.INVALID_REQUEST,
42+ "Invalid JSON-RPC version",
43+ )
44+ }
45+
46+ if baseMessage.ID == nil {
47+ var notification mcp.JSONRPCNotification
48+ if err := json.Unmarshal(message, &notification); err != nil {
49+ return createErrorResponse(
50+ nil,
51+ mcp.PARSE_ERROR,
52+ "Failed to parse notification",
53+ )
54+ }
55+ s.handleNotification(ctx, notification)
56+ return nil // Return nil for notifications
57+ }
58+
59+ if baseMessage.Result != nil {
60+ // this is a response to a request sent by the server (e.g. from a ping
61+ // sent due to WithKeepAlive option)
62+ return nil
63+ }
64+
65+ handleErr := s.hooks.onRequestInitialization(ctx, baseMessage.ID, message)
66+ if handleErr != nil {
67+ return createErrorResponse(
68+ baseMessage.ID,
69+ mcp.INVALID_REQUEST,
70+ handleErr.Error(),
71+ )
72+ }
73+
74+ switch baseMessage.Method {
75+ case mcp.MethodInitialize:
76+ var request mcp.InitializeRequest
77+ var result *mcp.InitializeResult
78+ if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
79+ err = &requestError{
80+ id: baseMessage.ID,
81+ code: mcp.INVALID_REQUEST,
82+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
83+ }
84+ } else {
85+ s.hooks.beforeInitialize(ctx, baseMessage.ID, &request)
86+ result, err = s.handleInitialize(ctx, baseMessage.ID, request)
87+ }
88+ if err != nil {
89+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
90+ return err.ToJSONRPCError()
91+ }
92+ s.hooks.afterInitialize(ctx, baseMessage.ID, &request, result)
93+ return createResponse(baseMessage.ID, *result)
94+ case mcp.MethodPing:
95+ var request mcp.PingRequest
96+ var result *mcp.EmptyResult
97+ if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
98+ err = &requestError{
99+ id: baseMessage.ID,
100+ code: mcp.INVALID_REQUEST,
101+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
102+ }
103+ } else {
104+ s.hooks.beforePing(ctx, baseMessage.ID, &request)
105+ result, err = s.handlePing(ctx, baseMessage.ID, request)
106+ }
107+ if err != nil {
108+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
109+ return err.ToJSONRPCError()
110+ }
111+ s.hooks.afterPing(ctx, baseMessage.ID, &request, result)
112+ return createResponse(baseMessage.ID, *result)
113+ case mcp.MethodSetLogLevel:
114+ var request mcp.SetLevelRequest
115+ var result *mcp.EmptyResult
116+ if s.capabilities.logging == nil {
117+ err = &requestError{
118+ id: baseMessage.ID,
119+ code: mcp.METHOD_NOT_FOUND,
120+ err: fmt.Errorf("logging %w", ErrUnsupported),
121+ }
122+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
123+ err = &requestError{
124+ id: baseMessage.ID,
125+ code: mcp.INVALID_REQUEST,
126+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
127+ }
128+ } else {
129+ s.hooks.beforeSetLevel(ctx, baseMessage.ID, &request)
130+ result, err = s.handleSetLevel(ctx, baseMessage.ID, request)
131+ }
132+ if err != nil {
133+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
134+ return err.ToJSONRPCError()
135+ }
136+ s.hooks.afterSetLevel(ctx, baseMessage.ID, &request, result)
137+ return createResponse(baseMessage.ID, *result)
138+ case mcp.MethodResourcesList:
139+ var request mcp.ListResourcesRequest
140+ var result *mcp.ListResourcesResult
141+ if s.capabilities.resources == nil {
142+ err = &requestError{
143+ id: baseMessage.ID,
144+ code: mcp.METHOD_NOT_FOUND,
145+ err: fmt.Errorf("resources %w", ErrUnsupported),
146+ }
147+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
148+ err = &requestError{
149+ id: baseMessage.ID,
150+ code: mcp.INVALID_REQUEST,
151+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
152+ }
153+ } else {
154+ s.hooks.beforeListResources(ctx, baseMessage.ID, &request)
155+ result, err = s.handleListResources(ctx, baseMessage.ID, request)
156+ }
157+ if err != nil {
158+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
159+ return err.ToJSONRPCError()
160+ }
161+ s.hooks.afterListResources(ctx, baseMessage.ID, &request, result)
162+ return createResponse(baseMessage.ID, *result)
163+ case mcp.MethodResourcesTemplatesList:
164+ var request mcp.ListResourceTemplatesRequest
165+ var result *mcp.ListResourceTemplatesResult
166+ if s.capabilities.resources == nil {
167+ err = &requestError{
168+ id: baseMessage.ID,
169+ code: mcp.METHOD_NOT_FOUND,
170+ err: fmt.Errorf("resources %w", ErrUnsupported),
171+ }
172+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
173+ err = &requestError{
174+ id: baseMessage.ID,
175+ code: mcp.INVALID_REQUEST,
176+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
177+ }
178+ } else {
179+ s.hooks.beforeListResourceTemplates(ctx, baseMessage.ID, &request)
180+ result, err = s.handleListResourceTemplates(ctx, baseMessage.ID, request)
181+ }
182+ if err != nil {
183+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
184+ return err.ToJSONRPCError()
185+ }
186+ s.hooks.afterListResourceTemplates(ctx, baseMessage.ID, &request, result)
187+ return createResponse(baseMessage.ID, *result)
188+ case mcp.MethodResourcesRead:
189+ var request mcp.ReadResourceRequest
190+ var result *mcp.ReadResourceResult
191+ if s.capabilities.resources == nil {
192+ err = &requestError{
193+ id: baseMessage.ID,
194+ code: mcp.METHOD_NOT_FOUND,
195+ err: fmt.Errorf("resources %w", ErrUnsupported),
196+ }
197+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
198+ err = &requestError{
199+ id: baseMessage.ID,
200+ code: mcp.INVALID_REQUEST,
201+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
202+ }
203+ } else {
204+ s.hooks.beforeReadResource(ctx, baseMessage.ID, &request)
205+ result, err = s.handleReadResource(ctx, baseMessage.ID, request)
206+ }
207+ if err != nil {
208+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
209+ return err.ToJSONRPCError()
210+ }
211+ s.hooks.afterReadResource(ctx, baseMessage.ID, &request, result)
212+ return createResponse(baseMessage.ID, *result)
213+ case mcp.MethodPromptsList:
214+ var request mcp.ListPromptsRequest
215+ var result *mcp.ListPromptsResult
216+ if s.capabilities.prompts == nil {
217+ err = &requestError{
218+ id: baseMessage.ID,
219+ code: mcp.METHOD_NOT_FOUND,
220+ err: fmt.Errorf("prompts %w", ErrUnsupported),
221+ }
222+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
223+ err = &requestError{
224+ id: baseMessage.ID,
225+ code: mcp.INVALID_REQUEST,
226+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
227+ }
228+ } else {
229+ s.hooks.beforeListPrompts(ctx, baseMessage.ID, &request)
230+ result, err = s.handleListPrompts(ctx, baseMessage.ID, request)
231+ }
232+ if err != nil {
233+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
234+ return err.ToJSONRPCError()
235+ }
236+ s.hooks.afterListPrompts(ctx, baseMessage.ID, &request, result)
237+ return createResponse(baseMessage.ID, *result)
238+ case mcp.MethodPromptsGet:
239+ var request mcp.GetPromptRequest
240+ var result *mcp.GetPromptResult
241+ if s.capabilities.prompts == nil {
242+ err = &requestError{
243+ id: baseMessage.ID,
244+ code: mcp.METHOD_NOT_FOUND,
245+ err: fmt.Errorf("prompts %w", ErrUnsupported),
246+ }
247+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
248+ err = &requestError{
249+ id: baseMessage.ID,
250+ code: mcp.INVALID_REQUEST,
251+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
252+ }
253+ } else {
254+ s.hooks.beforeGetPrompt(ctx, baseMessage.ID, &request)
255+ result, err = s.handleGetPrompt(ctx, baseMessage.ID, request)
256+ }
257+ if err != nil {
258+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
259+ return err.ToJSONRPCError()
260+ }
261+ s.hooks.afterGetPrompt(ctx, baseMessage.ID, &request, result)
262+ return createResponse(baseMessage.ID, *result)
263+ case mcp.MethodToolsList:
264+ var request mcp.ListToolsRequest
265+ var result *mcp.ListToolsResult
266+ if s.capabilities.tools == nil {
267+ err = &requestError{
268+ id: baseMessage.ID,
269+ code: mcp.METHOD_NOT_FOUND,
270+ err: fmt.Errorf("tools %w", ErrUnsupported),
271+ }
272+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
273+ err = &requestError{
274+ id: baseMessage.ID,
275+ code: mcp.INVALID_REQUEST,
276+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
277+ }
278+ } else {
279+ s.hooks.beforeListTools(ctx, baseMessage.ID, &request)
280+ result, err = s.handleListTools(ctx, baseMessage.ID, request)
281+ }
282+ if err != nil {
283+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
284+ return err.ToJSONRPCError()
285+ }
286+ s.hooks.afterListTools(ctx, baseMessage.ID, &request, result)
287+ return createResponse(baseMessage.ID, *result)
288+ case mcp.MethodToolsCall:
289+ var request mcp.CallToolRequest
290+ var result *mcp.CallToolResult
291+ if s.capabilities.tools == nil {
292+ err = &requestError{
293+ id: baseMessage.ID,
294+ code: mcp.METHOD_NOT_FOUND,
295+ err: fmt.Errorf("tools %w", ErrUnsupported),
296+ }
297+ } else if unmarshalErr := json.Unmarshal(message, &request); unmarshalErr != nil {
298+ err = &requestError{
299+ id: baseMessage.ID,
300+ code: mcp.INVALID_REQUEST,
301+ err: &UnparsableMessageError{message: message, err: unmarshalErr, method: baseMessage.Method},
302+ }
303+ } else {
304+ s.hooks.beforeCallTool(ctx, baseMessage.ID, &request)
305+ result, err = s.handleToolCall(ctx, baseMessage.ID, request)
306+ }
307+ if err != nil {
308+ s.hooks.onError(ctx, baseMessage.ID, baseMessage.Method, &request, err)
309+ return err.ToJSONRPCError()
310+ }
311+ s.hooks.afterCallTool(ctx, baseMessage.ID, &request, result)
312+ return createResponse(baseMessage.ID, *result)
313+ default:
314+ return createErrorResponse(
315+ baseMessage.ID,
316+ mcp.METHOD_NOT_FOUND,
317+ fmt.Sprintf("Method %s not found", baseMessage.Method),
318+ )
319+ }
320+}
vendor/github.com/mark3labs/mcp-go/server/server.gonew file+1079
@@ -0,0 +1,1079 @@
1+// Package server provides MCP (Model Context Protocol) server implementations.
2+package server
3+
4+import (
5+ "context"
6+ "encoding/base64"
7+ "encoding/json"
8+ "fmt"
9+ "slices"
10+ "sort"
11+ "sync"
12+
13+ "github.com/mark3labs/mcp-go/mcp"
14+)
15+
16+// resourceEntry holds both a resource and its handler
17+type resourceEntry struct {
18+ resource mcp.Resource
19+ handler ResourceHandlerFunc
20+}
21+
22+// resourceTemplateEntry holds both a template and its handler
23+type resourceTemplateEntry struct {
24+ template mcp.ResourceTemplate
25+ handler ResourceTemplateHandlerFunc
26+}
27+
28+// ServerOption is a function that configures an MCPServer.
29+type ServerOption func(*MCPServer)
30+
31+// ResourceHandlerFunc is a function that returns resource contents.
32+type ResourceHandlerFunc func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error)
33+
34+// ResourceTemplateHandlerFunc is a function that returns a resource template.
35+type ResourceTemplateHandlerFunc func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error)
36+
37+// PromptHandlerFunc handles prompt requests with given arguments.
38+type PromptHandlerFunc func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error)
39+
40+// ToolHandlerFunc handles tool calls with given arguments.
41+type ToolHandlerFunc func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error)
42+
43+// ToolHandlerMiddleware is a middleware function that wraps a ToolHandlerFunc.
44+type ToolHandlerMiddleware func(ToolHandlerFunc) ToolHandlerFunc
45+
46+// ToolFilterFunc is a function that filters tools based on context, typically using session information.
47+type ToolFilterFunc func(ctx context.Context, tools []mcp.Tool) []mcp.Tool
48+
49+// ServerTool combines a Tool with its ToolHandlerFunc.
50+type ServerTool struct {
51+ Tool mcp.Tool
52+ Handler ToolHandlerFunc
53+}
54+
55+// ServerPrompt combines a Prompt with its handler function.
56+type ServerPrompt struct {
57+ Prompt mcp.Prompt
58+ Handler PromptHandlerFunc
59+}
60+
61+// ServerResource combines a Resource with its handler function.
62+type ServerResource struct {
63+ Resource mcp.Resource
64+ Handler ResourceHandlerFunc
65+}
66+
67+// serverKey is the context key for storing the server instance
68+type serverKey struct{}
69+
70+// ServerFromContext retrieves the MCPServer instance from a context
71+func ServerFromContext(ctx context.Context) *MCPServer {
72+ if srv, ok := ctx.Value(serverKey{}).(*MCPServer); ok {
73+ return srv
74+ }
75+ return nil
76+}
77+
78+// UnparsableMessageError is attached to the RequestError when json.Unmarshal
79+// fails on the request.
80+type UnparsableMessageError struct {
81+ message json.RawMessage
82+ method mcp.MCPMethod
83+ err error
84+}
85+
86+func (e *UnparsableMessageError) Error() string {
87+ return fmt.Sprintf("unparsable %s request: %s", e.method, e.err)
88+}
89+
90+func (e *UnparsableMessageError) Unwrap() error {
91+ return e.err
92+}
93+
94+func (e *UnparsableMessageError) GetMessage() json.RawMessage {
95+ return e.message
96+}
97+
98+func (e *UnparsableMessageError) GetMethod() mcp.MCPMethod {
99+ return e.method
100+}
101+
102+// RequestError is an error that can be converted to a JSON-RPC error.
103+// Implements Unwrap() to allow inspecting the error chain.
104+type requestError struct {
105+ id any
106+ code int
107+ err error
108+}
109+
110+func (e *requestError) Error() string {
111+ return fmt.Sprintf("request error: %s", e.err)
112+}
113+
114+func (e *requestError) ToJSONRPCError() mcp.JSONRPCError {
115+ return mcp.JSONRPCError{
116+ JSONRPC: mcp.JSONRPC_VERSION,
117+ ID: mcp.NewRequestId(e.id),
118+ Error: struct {
119+ Code int `json:"code"`
120+ Message string `json:"message"`
121+ Data any `json:"data,omitempty"`
122+ }{
123+ Code: e.code,
124+ Message: e.err.Error(),
125+ },
126+ }
127+}
128+
129+func (e *requestError) Unwrap() error {
130+ return e.err
131+}
132+
133+// NotificationHandlerFunc handles incoming notifications.
134+type NotificationHandlerFunc func(ctx context.Context, notification mcp.JSONRPCNotification)
135+
136+// MCPServer implements a Model Context Protocol server that can handle various types of requests
137+// including resources, prompts, and tools.
138+type MCPServer struct {
139+ // Separate mutexes for different resource types
140+ resourcesMu sync.RWMutex
141+ promptsMu sync.RWMutex
142+ toolsMu sync.RWMutex
143+ middlewareMu sync.RWMutex
144+ notificationHandlersMu sync.RWMutex
145+ capabilitiesMu sync.RWMutex
146+ toolFiltersMu sync.RWMutex
147+
148+ name string
149+ version string
150+ instructions string
151+ resources map[string]resourceEntry
152+ resourceTemplates map[string]resourceTemplateEntry
153+ prompts map[string]mcp.Prompt
154+ promptHandlers map[string]PromptHandlerFunc
155+ tools map[string]ServerTool
156+ toolHandlerMiddlewares []ToolHandlerMiddleware
157+ toolFilters []ToolFilterFunc
158+ notificationHandlers map[string]NotificationHandlerFunc
159+ capabilities serverCapabilities
160+ paginationLimit *int
161+ sessions sync.Map
162+ hooks *Hooks
163+}
164+
165+// WithPaginationLimit sets the pagination limit for the server.
166+func WithPaginationLimit(limit int) ServerOption {
167+ return func(s *MCPServer) {
168+ s.paginationLimit = &limit
169+ }
170+}
171+
172+// serverCapabilities defines the supported features of the MCP server
173+type serverCapabilities struct {
174+ tools *toolCapabilities
175+ resources *resourceCapabilities
176+ prompts *promptCapabilities
177+ logging *bool
178+}
179+
180+// resourceCapabilities defines the supported resource-related features
181+type resourceCapabilities struct {
182+ subscribe bool
183+ listChanged bool
184+}
185+
186+// promptCapabilities defines the supported prompt-related features
187+type promptCapabilities struct {
188+ listChanged bool
189+}
190+
191+// toolCapabilities defines the supported tool-related features
192+type toolCapabilities struct {
193+ listChanged bool
194+}
195+
196+// WithResourceCapabilities configures resource-related server capabilities
197+func WithResourceCapabilities(subscribe, listChanged bool) ServerOption {
198+ return func(s *MCPServer) {
199+ // Always create a non-nil capability object
200+ s.capabilities.resources = &resourceCapabilities{
201+ subscribe: subscribe,
202+ listChanged: listChanged,
203+ }
204+ }
205+}
206+
207+// WithToolHandlerMiddleware allows adding a middleware for the
208+// tool handler call chain.
209+func WithToolHandlerMiddleware(
210+ toolHandlerMiddleware ToolHandlerMiddleware,
211+) ServerOption {
212+ return func(s *MCPServer) {
213+ s.middlewareMu.Lock()
214+ s.toolHandlerMiddlewares = append(s.toolHandlerMiddlewares, toolHandlerMiddleware)
215+ s.middlewareMu.Unlock()
216+ }
217+}
218+
219+// WithToolFilter adds a filter function that will be applied to tools before they are returned in list_tools
220+func WithToolFilter(
221+ toolFilter ToolFilterFunc,
222+) ServerOption {
223+ return func(s *MCPServer) {
224+ s.toolFiltersMu.Lock()
225+ s.toolFilters = append(s.toolFilters, toolFilter)
226+ s.toolFiltersMu.Unlock()
227+ }
228+}
229+
230+// WithRecovery adds a middleware that recovers from panics in tool handlers.
231+func WithRecovery() ServerOption {
232+ return WithToolHandlerMiddleware(func(next ToolHandlerFunc) ToolHandlerFunc {
233+ return func(ctx context.Context, request mcp.CallToolRequest) (result *mcp.CallToolResult, err error) {
234+ defer func() {
235+ if r := recover(); r != nil {
236+ err = fmt.Errorf(
237+ "panic recovered in %s tool handler: %v",
238+ request.Params.Name,
239+ r,
240+ )
241+ }
242+ }()
243+ return next(ctx, request)
244+ }
245+ })
246+}
247+
248+// WithHooks allows adding hooks that will be called before or after
249+// either [all] requests or before / after specific request methods, or else
250+// prior to returning an error to the client.
251+func WithHooks(hooks *Hooks) ServerOption {
252+ return func(s *MCPServer) {
253+ s.hooks = hooks
254+ }
255+}
256+
257+// WithPromptCapabilities configures prompt-related server capabilities
258+func WithPromptCapabilities(listChanged bool) ServerOption {
259+ return func(s *MCPServer) {
260+ // Always create a non-nil capability object
261+ s.capabilities.prompts = &promptCapabilities{
262+ listChanged: listChanged,
263+ }
264+ }
265+}
266+
267+// WithToolCapabilities configures tool-related server capabilities
268+func WithToolCapabilities(listChanged bool) ServerOption {
269+ return func(s *MCPServer) {
270+ // Always create a non-nil capability object
271+ s.capabilities.tools = &toolCapabilities{
272+ listChanged: listChanged,
273+ }
274+ }
275+}
276+
277+// WithLogging enables logging capabilities for the server
278+func WithLogging() ServerOption {
279+ return func(s *MCPServer) {
280+ s.capabilities.logging = mcp.ToBoolPtr(true)
281+ }
282+}
283+
284+// WithInstructions sets the server instructions for the client returned in the initialize response
285+func WithInstructions(instructions string) ServerOption {
286+ return func(s *MCPServer) {
287+ s.instructions = instructions
288+ }
289+}
290+
291+// NewMCPServer creates a new MCP server instance with the given name, version and options
292+func NewMCPServer(
293+ name, version string,
294+ opts ...ServerOption,
295+) *MCPServer {
296+ s := &MCPServer{
297+ resources: make(map[string]resourceEntry),
298+ resourceTemplates: make(map[string]resourceTemplateEntry),
299+ prompts: make(map[string]mcp.Prompt),
300+ promptHandlers: make(map[string]PromptHandlerFunc),
301+ tools: make(map[string]ServerTool),
302+ name: name,
303+ version: version,
304+ notificationHandlers: make(map[string]NotificationHandlerFunc),
305+ capabilities: serverCapabilities{
306+ tools: nil,
307+ resources: nil,
308+ prompts: nil,
309+ logging: nil,
310+ },
311+ }
312+
313+ for _, opt := range opts {
314+ opt(s)
315+ }
316+
317+ return s
318+}
319+
320+// AddResources registers multiple resources at once
321+func (s *MCPServer) AddResources(resources ...ServerResource) {
322+ s.implicitlyRegisterResourceCapabilities()
323+
324+ s.resourcesMu.Lock()
325+ for _, entry := range resources {
326+ s.resources[entry.Resource.URI] = resourceEntry{
327+ resource: entry.Resource,
328+ handler: entry.Handler,
329+ }
330+ }
331+ s.resourcesMu.Unlock()
332+
333+ // When the list of available resources changes, servers that declared the listChanged capability SHOULD send a notification
334+ if s.capabilities.resources.listChanged {
335+ // Send notification to all initialized sessions
336+ s.SendNotificationToAllClients(mcp.MethodNotificationResourcesListChanged, nil)
337+ }
338+}
339+
340+// AddResource registers a new resource and its handler
341+func (s *MCPServer) AddResource(
342+ resource mcp.Resource,
343+ handler ResourceHandlerFunc,
344+) {
345+ s.AddResources(ServerResource{Resource: resource, Handler: handler})
346+}
347+
348+// RemoveResource removes a resource from the server
349+func (s *MCPServer) RemoveResource(uri string) {
350+ s.resourcesMu.Lock()
351+ _, exists := s.resources[uri]
352+ if exists {
353+ delete(s.resources, uri)
354+ }
355+ s.resourcesMu.Unlock()
356+
357+ // Send notification to all initialized sessions if listChanged capability is enabled and we actually remove a resource
358+ if exists && s.capabilities.resources != nil && s.capabilities.resources.listChanged {
359+ s.SendNotificationToAllClients(mcp.MethodNotificationResourcesListChanged, nil)
360+ }
361+}
362+
363+// AddResourceTemplate registers a new resource template and its handler
364+func (s *MCPServer) AddResourceTemplate(
365+ template mcp.ResourceTemplate,
366+ handler ResourceTemplateHandlerFunc,
367+) {
368+ s.implicitlyRegisterResourceCapabilities()
369+
370+ s.resourcesMu.Lock()
371+ s.resourceTemplates[template.URITemplate.Raw()] = resourceTemplateEntry{
372+ template: template,
373+ handler: handler,
374+ }
375+ s.resourcesMu.Unlock()
376+
377+ // When the list of available resources changes, servers that declared the listChanged capability SHOULD send a notification
378+ if s.capabilities.resources.listChanged {
379+ // Send notification to all initialized sessions
380+ s.SendNotificationToAllClients(mcp.MethodNotificationResourcesListChanged, nil)
381+ }
382+}
383+
384+// AddPrompts registers multiple prompts at once
385+func (s *MCPServer) AddPrompts(prompts ...ServerPrompt) {
386+ s.implicitlyRegisterPromptCapabilities()
387+
388+ s.promptsMu.Lock()
389+ for _, entry := range prompts {
390+ s.prompts[entry.Prompt.Name] = entry.Prompt
391+ s.promptHandlers[entry.Prompt.Name] = entry.Handler
392+ }
393+ s.promptsMu.Unlock()
394+
395+ // When the list of available prompts changes, servers that declared the listChanged capability SHOULD send a notification.
396+ if s.capabilities.prompts.listChanged {
397+ // Send notification to all initialized sessions
398+ s.SendNotificationToAllClients(mcp.MethodNotificationPromptsListChanged, nil)
399+ }
400+}
401+
402+// AddPrompt registers a new prompt handler with the given name
403+func (s *MCPServer) AddPrompt(prompt mcp.Prompt, handler PromptHandlerFunc) {
404+ s.AddPrompts(ServerPrompt{Prompt: prompt, Handler: handler})
405+}
406+
407+// DeletePrompts removes prompts from the server
408+func (s *MCPServer) DeletePrompts(names ...string) {
409+ s.promptsMu.Lock()
410+ var exists bool
411+ for _, name := range names {
412+ if _, ok := s.prompts[name]; ok {
413+ delete(s.prompts, name)
414+ delete(s.promptHandlers, name)
415+ exists = true
416+ }
417+ }
418+ s.promptsMu.Unlock()
419+
420+ // Send notification to all initialized sessions if listChanged capability is enabled, and we actually remove a prompt
421+ if exists && s.capabilities.prompts != nil && s.capabilities.prompts.listChanged {
422+ // Send notification to all initialized sessions
423+ s.SendNotificationToAllClients(mcp.MethodNotificationPromptsListChanged, nil)
424+ }
425+}
426+
427+// AddTool registers a new tool and its handler
428+func (s *MCPServer) AddTool(tool mcp.Tool, handler ToolHandlerFunc) {
429+ s.AddTools(ServerTool{Tool: tool, Handler: handler})
430+}
431+
432+// Register tool capabilities due to a tool being added. Default to
433+// listChanged: true, but don't change the value if we've already explicitly
434+// registered tools.listChanged false.
435+func (s *MCPServer) implicitlyRegisterToolCapabilities() {
436+ s.implicitlyRegisterCapabilities(
437+ func() bool { return s.capabilities.tools != nil },
438+ func() { s.capabilities.tools = &toolCapabilities{listChanged: true} },
439+ )
440+}
441+
442+func (s *MCPServer) implicitlyRegisterResourceCapabilities() {
443+ s.implicitlyRegisterCapabilities(
444+ func() bool { return s.capabilities.resources != nil },
445+ func() { s.capabilities.resources = &resourceCapabilities{} },
446+ )
447+}
448+
449+func (s *MCPServer) implicitlyRegisterPromptCapabilities() {
450+ s.implicitlyRegisterCapabilities(
451+ func() bool { return s.capabilities.prompts != nil },
452+ func() { s.capabilities.prompts = &promptCapabilities{} },
453+ )
454+}
455+
456+func (s *MCPServer) implicitlyRegisterCapabilities(check func() bool, register func()) {
457+ s.capabilitiesMu.RLock()
458+ if check() {
459+ s.capabilitiesMu.RUnlock()
460+ return
461+ }
462+ s.capabilitiesMu.RUnlock()
463+
464+ s.capabilitiesMu.Lock()
465+ if !check() {
466+ register()
467+ }
468+ s.capabilitiesMu.Unlock()
469+}
470+
471+// AddTools registers multiple tools at once
472+func (s *MCPServer) AddTools(tools ...ServerTool) {
473+ s.implicitlyRegisterToolCapabilities()
474+
475+ s.toolsMu.Lock()
476+ for _, entry := range tools {
477+ s.tools[entry.Tool.Name] = entry
478+ }
479+ s.toolsMu.Unlock()
480+
481+ // When the list of available tools changes, servers that declared the listChanged capability SHOULD send a notification.
482+ if s.capabilities.tools.listChanged {
483+ // Send notification to all initialized sessions
484+ s.SendNotificationToAllClients(mcp.MethodNotificationToolsListChanged, nil)
485+ }
486+}
487+
488+// SetTools replaces all existing tools with the provided list
489+func (s *MCPServer) SetTools(tools ...ServerTool) {
490+ s.toolsMu.Lock()
491+ s.tools = make(map[string]ServerTool, len(tools))
492+ s.toolsMu.Unlock()
493+ s.AddTools(tools...)
494+}
495+
496+// DeleteTools removes tools from the server
497+func (s *MCPServer) DeleteTools(names ...string) {
498+ s.toolsMu.Lock()
499+ var exists bool
500+ for _, name := range names {
501+ if _, ok := s.tools[name]; ok {
502+ delete(s.tools, name)
503+ exists = true
504+ }
505+ }
506+ s.toolsMu.Unlock()
507+
508+ // When the list of available tools changes, servers that declared the listChanged capability SHOULD send a notification.
509+ if exists && s.capabilities.tools != nil && s.capabilities.tools.listChanged {
510+ // Send notification to all initialized sessions
511+ s.SendNotificationToAllClients(mcp.MethodNotificationToolsListChanged, nil)
512+ }
513+}
514+
515+// AddNotificationHandler registers a new handler for incoming notifications
516+func (s *MCPServer) AddNotificationHandler(
517+ method string,
518+ handler NotificationHandlerFunc,
519+) {
520+ s.notificationHandlersMu.Lock()
521+ defer s.notificationHandlersMu.Unlock()
522+ s.notificationHandlers[method] = handler
523+}
524+
525+func (s *MCPServer) handleInitialize(
526+ ctx context.Context,
527+ _ any,
528+ request mcp.InitializeRequest,
529+) (*mcp.InitializeResult, *requestError) {
530+ capabilities := mcp.ServerCapabilities{}
531+
532+ // Only add resource capabilities if they're configured
533+ if s.capabilities.resources != nil {
534+ capabilities.Resources = &struct {
535+ Subscribe bool `json:"subscribe,omitempty"`
536+ ListChanged bool `json:"listChanged,omitempty"`
537+ }{
538+ Subscribe: s.capabilities.resources.subscribe,
539+ ListChanged: s.capabilities.resources.listChanged,
540+ }
541+ }
542+
543+ // Only add prompt capabilities if they're configured
544+ if s.capabilities.prompts != nil {
545+ capabilities.Prompts = &struct {
546+ ListChanged bool `json:"listChanged,omitempty"`
547+ }{
548+ ListChanged: s.capabilities.prompts.listChanged,
549+ }
550+ }
551+
552+ // Only add tool capabilities if they're configured
553+ if s.capabilities.tools != nil {
554+ capabilities.Tools = &struct {
555+ ListChanged bool `json:"listChanged,omitempty"`
556+ }{
557+ ListChanged: s.capabilities.tools.listChanged,
558+ }
559+ }
560+
561+ if s.capabilities.logging != nil && *s.capabilities.logging {
562+ capabilities.Logging = &struct{}{}
563+ }
564+
565+ result := mcp.InitializeResult{
566+ ProtocolVersion: s.protocolVersion(request.Params.ProtocolVersion),
567+ ServerInfo: mcp.Implementation{
568+ Name: s.name,
569+ Version: s.version,
570+ },
571+ Capabilities: capabilities,
572+ Instructions: s.instructions,
573+ }
574+
575+ if session := ClientSessionFromContext(ctx); session != nil {
576+ session.Initialize()
577+
578+ // Store client info if the session supports it
579+ if sessionWithClientInfo, ok := session.(SessionWithClientInfo); ok {
580+ sessionWithClientInfo.SetClientInfo(request.Params.ClientInfo)
581+ }
582+ }
583+ return &result, nil
584+}
585+
586+func (s *MCPServer) protocolVersion(clientVersion string) string {
587+ if slices.Contains(mcp.ValidProtocolVersions, clientVersion) {
588+ return clientVersion
589+ }
590+
591+ return mcp.LATEST_PROTOCOL_VERSION
592+}
593+
594+func (s *MCPServer) handlePing(
595+ _ context.Context,
596+ _ any,
597+ _ mcp.PingRequest,
598+) (*mcp.EmptyResult, *requestError) {
599+ return &mcp.EmptyResult{}, nil
600+}
601+
602+func (s *MCPServer) handleSetLevel(
603+ ctx context.Context,
604+ id any,
605+ request mcp.SetLevelRequest,
606+) (*mcp.EmptyResult, *requestError) {
607+ clientSession := ClientSessionFromContext(ctx)
608+ if clientSession == nil || !clientSession.Initialized() {
609+ return nil, &requestError{
610+ id: id,
611+ code: mcp.INTERNAL_ERROR,
612+ err: ErrSessionNotInitialized,
613+ }
614+ }
615+
616+ sessionLogging, ok := clientSession.(SessionWithLogging)
617+ if !ok {
618+ return nil, &requestError{
619+ id: id,
620+ code: mcp.INTERNAL_ERROR,
621+ err: ErrSessionDoesNotSupportLogging,
622+ }
623+ }
624+
625+ level := request.Params.Level
626+ // Validate logging level
627+ switch level {
628+ case mcp.LoggingLevelDebug, mcp.LoggingLevelInfo, mcp.LoggingLevelNotice,
629+ mcp.LoggingLevelWarning, mcp.LoggingLevelError, mcp.LoggingLevelCritical,
630+ mcp.LoggingLevelAlert, mcp.LoggingLevelEmergency:
631+ // Valid level
632+ default:
633+ return nil, &requestError{
634+ id: id,
635+ code: mcp.INVALID_PARAMS,
636+ err: fmt.Errorf("invalid logging level '%s'", level),
637+ }
638+ }
639+
640+ sessionLogging.SetLogLevel(level)
641+
642+ return &mcp.EmptyResult{}, nil
643+}
644+
645+func listByPagination[T mcp.Named](
646+ _ context.Context,
647+ s *MCPServer,
648+ cursor mcp.Cursor,
649+ allElements []T,
650+) ([]T, mcp.Cursor, error) {
651+ startPos := 0
652+ if cursor != "" {
653+ c, err := base64.StdEncoding.DecodeString(string(cursor))
654+ if err != nil {
655+ return nil, "", err
656+ }
657+ cString := string(c)
658+ startPos = sort.Search(len(allElements), func(i int) bool {
659+ return allElements[i].GetName() > cString
660+ })
661+ }
662+ endPos := len(allElements)
663+ if s.paginationLimit != nil {
664+ if len(allElements) > startPos+*s.paginationLimit {
665+ endPos = startPos + *s.paginationLimit
666+ }
667+ }
668+ elementsToReturn := allElements[startPos:endPos]
669+ // set the next cursor
670+ nextCursor := func() mcp.Cursor {
671+ if s.paginationLimit != nil && len(elementsToReturn) >= *s.paginationLimit {
672+ nc := elementsToReturn[len(elementsToReturn)-1].GetName()
673+ toString := base64.StdEncoding.EncodeToString([]byte(nc))
674+ return mcp.Cursor(toString)
675+ }
676+ return ""
677+ }()
678+ return elementsToReturn, nextCursor, nil
679+}
680+
681+func (s *MCPServer) handleListResources(
682+ ctx context.Context,
683+ id any,
684+ request mcp.ListResourcesRequest,
685+) (*mcp.ListResourcesResult, *requestError) {
686+ s.resourcesMu.RLock()
687+ resources := make([]mcp.Resource, 0, len(s.resources))
688+ for _, entry := range s.resources {
689+ resources = append(resources, entry.resource)
690+ }
691+ s.resourcesMu.RUnlock()
692+
693+ // Sort the resources by name
694+ sort.Slice(resources, func(i, j int) bool {
695+ return resources[i].Name < resources[j].Name
696+ })
697+ resourcesToReturn, nextCursor, err := listByPagination(
698+ ctx,
699+ s,
700+ request.Params.Cursor,
701+ resources,
702+ )
703+ if err != nil {
704+ return nil, &requestError{
705+ id: id,
706+ code: mcp.INVALID_PARAMS,
707+ err: err,
708+ }
709+ }
710+ result := mcp.ListResourcesResult{
711+ Resources: resourcesToReturn,
712+ PaginatedResult: mcp.PaginatedResult{
713+ NextCursor: nextCursor,
714+ },
715+ }
716+ return &result, nil
717+}
718+
719+func (s *MCPServer) handleListResourceTemplates(
720+ ctx context.Context,
721+ id any,
722+ request mcp.ListResourceTemplatesRequest,
723+) (*mcp.ListResourceTemplatesResult, *requestError) {
724+ s.resourcesMu.RLock()
725+ templates := make([]mcp.ResourceTemplate, 0, len(s.resourceTemplates))
726+ for _, entry := range s.resourceTemplates {
727+ templates = append(templates, entry.template)
728+ }
729+ s.resourcesMu.RUnlock()
730+ sort.Slice(templates, func(i, j int) bool {
731+ return templates[i].Name < templates[j].Name
732+ })
733+ templatesToReturn, nextCursor, err := listByPagination(
734+ ctx,
735+ s,
736+ request.Params.Cursor,
737+ templates,
738+ )
739+ if err != nil {
740+ return nil, &requestError{
741+ id: id,
742+ code: mcp.INVALID_PARAMS,
743+ err: err,
744+ }
745+ }
746+ result := mcp.ListResourceTemplatesResult{
747+ ResourceTemplates: templatesToReturn,
748+ PaginatedResult: mcp.PaginatedResult{
749+ NextCursor: nextCursor,
750+ },
751+ }
752+ return &result, nil
753+}
754+
755+func (s *MCPServer) handleReadResource(
756+ ctx context.Context,
757+ id any,
758+ request mcp.ReadResourceRequest,
759+) (*mcp.ReadResourceResult, *requestError) {
760+ s.resourcesMu.RLock()
761+ // First try direct resource handlers
762+ if entry, ok := s.resources[request.Params.URI]; ok {
763+ handler := entry.handler
764+ s.resourcesMu.RUnlock()
765+ contents, err := handler(ctx, request)
766+ if err != nil {
767+ return nil, &requestError{
768+ id: id,
769+ code: mcp.INTERNAL_ERROR,
770+ err: err,
771+ }
772+ }
773+ return &mcp.ReadResourceResult{Contents: contents}, nil
774+ }
775+
776+ // If no direct handler found, try matching against templates
777+ var matchedHandler ResourceTemplateHandlerFunc
778+ var matched bool
779+ for _, entry := range s.resourceTemplates {
780+ template := entry.template
781+ if matchesTemplate(request.Params.URI, template.URITemplate) {
782+ matchedHandler = entry.handler
783+ matched = true
784+ matchedVars := template.URITemplate.Match(request.Params.URI)
785+ // Convert matched variables to a map
786+ request.Params.Arguments = make(map[string]any, len(matchedVars))
787+ for name, value := range matchedVars {
788+ request.Params.Arguments[name] = value.V
789+ }
790+ break
791+ }
792+ }
793+ s.resourcesMu.RUnlock()
794+
795+ if matched {
796+ contents, err := matchedHandler(ctx, request)
797+ if err != nil {
798+ return nil, &requestError{
799+ id: id,
800+ code: mcp.INTERNAL_ERROR,
801+ err: err,
802+ }
803+ }
804+ return &mcp.ReadResourceResult{Contents: contents}, nil
805+ }
806+
807+ return nil, &requestError{
808+ id: id,
809+ code: mcp.RESOURCE_NOT_FOUND,
810+ err: fmt.Errorf(
811+ "handler not found for resource URI '%s': %w",
812+ request.Params.URI,
813+ ErrResourceNotFound,
814+ ),
815+ }
816+}
817+
818+// matchesTemplate checks if a URI matches a URI template pattern
819+func matchesTemplate(uri string, template *mcp.URITemplate) bool {
820+ return template.Regexp().MatchString(uri)
821+}
822+
823+func (s *MCPServer) handleListPrompts(
824+ ctx context.Context,
825+ id any,
826+ request mcp.ListPromptsRequest,
827+) (*mcp.ListPromptsResult, *requestError) {
828+ s.promptsMu.RLock()
829+ prompts := make([]mcp.Prompt, 0, len(s.prompts))
830+ for _, prompt := range s.prompts {
831+ prompts = append(prompts, prompt)
832+ }
833+ s.promptsMu.RUnlock()
834+
835+ // sort prompts by name
836+ sort.Slice(prompts, func(i, j int) bool {
837+ return prompts[i].Name < prompts[j].Name
838+ })
839+ promptsToReturn, nextCursor, err := listByPagination(
840+ ctx,
841+ s,
842+ request.Params.Cursor,
843+ prompts,
844+ )
845+ if err != nil {
846+ return nil, &requestError{
847+ id: id,
848+ code: mcp.INVALID_PARAMS,
849+ err: err,
850+ }
851+ }
852+ result := mcp.ListPromptsResult{
853+ Prompts: promptsToReturn,
854+ PaginatedResult: mcp.PaginatedResult{
855+ NextCursor: nextCursor,
856+ },
857+ }
858+ return &result, nil
859+}
860+
861+func (s *MCPServer) handleGetPrompt(
862+ ctx context.Context,
863+ id any,
864+ request mcp.GetPromptRequest,
865+) (*mcp.GetPromptResult, *requestError) {
866+ s.promptsMu.RLock()
867+ handler, ok := s.promptHandlers[request.Params.Name]
868+ s.promptsMu.RUnlock()
869+
870+ if !ok {
871+ return nil, &requestError{
872+ id: id,
873+ code: mcp.INVALID_PARAMS,
874+ err: fmt.Errorf("prompt '%s' not found: %w", request.Params.Name, ErrPromptNotFound),
875+ }
876+ }
877+
878+ result, err := handler(ctx, request)
879+ if err != nil {
880+ return nil, &requestError{
881+ id: id,
882+ code: mcp.INTERNAL_ERROR,
883+ err: err,
884+ }
885+ }
886+
887+ return result, nil
888+}
889+
890+func (s *MCPServer) handleListTools(
891+ ctx context.Context,
892+ id any,
893+ request mcp.ListToolsRequest,
894+) (*mcp.ListToolsResult, *requestError) {
895+ // Get the base tools from the server
896+ s.toolsMu.RLock()
897+ tools := make([]mcp.Tool, 0, len(s.tools))
898+
899+ // Get all tool names for consistent ordering
900+ toolNames := make([]string, 0, len(s.tools))
901+ for name := range s.tools {
902+ toolNames = append(toolNames, name)
903+ }
904+
905+ // Sort the tool names for consistent ordering
906+ sort.Strings(toolNames)
907+
908+ // Add tools in sorted order
909+ for _, name := range toolNames {
910+ tools = append(tools, s.tools[name].Tool)
911+ }
912+ s.toolsMu.RUnlock()
913+
914+ // Check if there are session-specific tools
915+ session := ClientSessionFromContext(ctx)
916+ if session != nil {
917+ if sessionWithTools, ok := session.(SessionWithTools); ok {
918+ if sessionTools := sessionWithTools.GetSessionTools(); sessionTools != nil {
919+ // Override or add session-specific tools
920+ // We need to create a map first to merge the tools properly
921+ toolMap := make(map[string]mcp.Tool)
922+
923+ // Add global tools first
924+ for _, tool := range tools {
925+ toolMap[tool.Name] = tool
926+ }
927+
928+ // Then override with session-specific tools
929+ for name, serverTool := range sessionTools {
930+ toolMap[name] = serverTool.Tool
931+ }
932+
933+ // Convert back to slice
934+ tools = make([]mcp.Tool, 0, len(toolMap))
935+ for _, tool := range toolMap {
936+ tools = append(tools, tool)
937+ }
938+
939+ // Sort again to maintain consistent ordering
940+ sort.Slice(tools, func(i, j int) bool {
941+ return tools[i].Name < tools[j].Name
942+ })
943+ }
944+ }
945+ }
946+
947+ // Apply tool filters if any are defined
948+ s.toolFiltersMu.RLock()
949+ if len(s.toolFilters) > 0 {
950+ for _, filter := range s.toolFilters {
951+ tools = filter(ctx, tools)
952+ }
953+ }
954+ s.toolFiltersMu.RUnlock()
955+
956+ // Apply pagination
957+ toolsToReturn, nextCursor, err := listByPagination(
958+ ctx,
959+ s,
960+ request.Params.Cursor,
961+ tools,
962+ )
963+ if err != nil {
964+ return nil, &requestError{
965+ id: id,
966+ code: mcp.INVALID_PARAMS,
967+ err: err,
968+ }
969+ }
970+
971+ result := mcp.ListToolsResult{
972+ Tools: toolsToReturn,
973+ PaginatedResult: mcp.PaginatedResult{
974+ NextCursor: nextCursor,
975+ },
976+ }
977+ return &result, nil
978+}
979+
980+func (s *MCPServer) handleToolCall(
981+ ctx context.Context,
982+ id any,
983+ request mcp.CallToolRequest,
984+) (*mcp.CallToolResult, *requestError) {
985+ // First check session-specific tools
986+ var tool ServerTool
987+ var ok bool
988+
989+ session := ClientSessionFromContext(ctx)
990+ if session != nil {
991+ if sessionWithTools, typeAssertOk := session.(SessionWithTools); typeAssertOk {
992+ if sessionTools := sessionWithTools.GetSessionTools(); sessionTools != nil {
993+ var sessionOk bool
994+ tool, sessionOk = sessionTools[request.Params.Name]
995+ if sessionOk {
996+ ok = true
997+ }
998+ }
999+ }
1000+ }
1001+
1002+ // If not found in session tools, check global tools
1003+ if !ok {
1004+ s.toolsMu.RLock()
1005+ tool, ok = s.tools[request.Params.Name]
1006+ s.toolsMu.RUnlock()
1007+ }
1008+
1009+ if !ok {
1010+ return nil, &requestError{
1011+ id: id,
1012+ code: mcp.INVALID_PARAMS,
1013+ err: fmt.Errorf("tool '%s' not found: %w", request.Params.Name, ErrToolNotFound),
1014+ }
1015+ }
1016+
1017+ finalHandler := tool.Handler
1018+
1019+ s.middlewareMu.RLock()
1020+ mw := s.toolHandlerMiddlewares
1021+ s.middlewareMu.RUnlock()
1022+
1023+ // Apply middlewares in reverse order
1024+ for i := len(mw) - 1; i >= 0; i-- {
1025+ finalHandler = mw[i](finalHandler)
1026+ }
1027+
1028+ result, err := finalHandler(ctx, request)
1029+ if err != nil {
1030+ return nil, &requestError{
1031+ id: id,
1032+ code: mcp.INTERNAL_ERROR,
1033+ err: err,
1034+ }
1035+ }
1036+
1037+ return result, nil
1038+}
1039+
1040+func (s *MCPServer) handleNotification(
1041+ ctx context.Context,
1042+ notification mcp.JSONRPCNotification,
1043+) mcp.JSONRPCMessage {
1044+ s.notificationHandlersMu.RLock()
1045+ handler, ok := s.notificationHandlers[notification.Method]
1046+ s.notificationHandlersMu.RUnlock()
1047+
1048+ if ok {
1049+ handler(ctx, notification)
1050+ }
1051+ return nil
1052+}
1053+
1054+func createResponse(id any, result any) mcp.JSONRPCMessage {
1055+ return mcp.JSONRPCResponse{
1056+ JSONRPC: mcp.JSONRPC_VERSION,
1057+ ID: mcp.NewRequestId(id),
1058+ Result: result,
1059+ }
1060+}
1061+
1062+func createErrorResponse(
1063+ id any,
1064+ code int,
1065+ message string,
1066+) mcp.JSONRPCMessage {
1067+ return mcp.JSONRPCError{
1068+ JSONRPC: mcp.JSONRPC_VERSION,
1069+ ID: mcp.NewRequestId(id),
1070+ Error: struct {
1071+ Code int `json:"code"`
1072+ Message string `json:"message"`
1073+ Data any `json:"data,omitempty"`
1074+ }{
1075+ Code: code,
1076+ Message: message,
1077+ },
1078+ }
1079+}
vendor/github.com/mark3labs/mcp-go/server/session.gonew file+380
@@ -0,0 +1,380 @@
1+package server
2+
3+import (
4+ "context"
5+ "fmt"
6+
7+ "github.com/mark3labs/mcp-go/mcp"
8+)
9+
10+// ClientSession represents an active session that can be used by MCPServer to interact with client.
11+type ClientSession interface {
12+ // Initialize marks session as fully initialized and ready for notifications
13+ Initialize()
14+ // Initialized returns if session is ready to accept notifications
15+ Initialized() bool
16+ // NotificationChannel provides a channel suitable for sending notifications to client.
17+ NotificationChannel() chan<- mcp.JSONRPCNotification
18+ // SessionID is a unique identifier used to track user session.
19+ SessionID() string
20+}
21+
22+// SessionWithLogging is an extension of ClientSession that can receive log message notifications and set log level
23+type SessionWithLogging interface {
24+ ClientSession
25+ // SetLogLevel sets the minimum log level
26+ SetLogLevel(level mcp.LoggingLevel)
27+ // GetLogLevel retrieves the minimum log level
28+ GetLogLevel() mcp.LoggingLevel
29+}
30+
31+// SessionWithTools is an extension of ClientSession that can store session-specific tool data
32+type SessionWithTools interface {
33+ ClientSession
34+ // GetSessionTools returns the tools specific to this session, if any
35+ // This method must be thread-safe for concurrent access
36+ GetSessionTools() map[string]ServerTool
37+ // SetSessionTools sets tools specific to this session
38+ // This method must be thread-safe for concurrent access
39+ SetSessionTools(tools map[string]ServerTool)
40+}
41+
42+// SessionWithClientInfo is an extension of ClientSession that can store client info
43+type SessionWithClientInfo interface {
44+ ClientSession
45+ // GetClientInfo returns the client information for this session
46+ GetClientInfo() mcp.Implementation
47+ // SetClientInfo sets the client information for this session
48+ SetClientInfo(clientInfo mcp.Implementation)
49+}
50+
51+// SessionWithStreamableHTTPConfig extends ClientSession to support streamable HTTP transport configurations
52+type SessionWithStreamableHTTPConfig interface {
53+ ClientSession
54+ // UpgradeToSSEWhenReceiveNotification upgrades the client-server communication to SSE stream when the server
55+ // sends notifications to the client
56+ //
57+ // The protocol specification:
58+ // - If the server response contains any JSON-RPC notifications, it MUST either:
59+ // - Return Content-Type: text/event-stream to initiate an SSE stream, OR
60+ // - Return Content-Type: application/json for a single JSON object
61+ // - The client MUST support both response types.
62+ //
63+ // Reference: https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#sending-messages-to-the-server
64+ UpgradeToSSEWhenReceiveNotification()
65+}
66+
67+// clientSessionKey is the context key for storing current client notification channel.
68+type clientSessionKey struct{}
69+
70+// ClientSessionFromContext retrieves current client notification context from context.
71+func ClientSessionFromContext(ctx context.Context) ClientSession {
72+ if session, ok := ctx.Value(clientSessionKey{}).(ClientSession); ok {
73+ return session
74+ }
75+ return nil
76+}
77+
78+// WithContext sets the current client session and returns the provided context
79+func (s *MCPServer) WithContext(
80+ ctx context.Context,
81+ session ClientSession,
82+) context.Context {
83+ return context.WithValue(ctx, clientSessionKey{}, session)
84+}
85+
86+// RegisterSession saves session that should be notified in case if some server attributes changed.
87+func (s *MCPServer) RegisterSession(
88+ ctx context.Context,
89+ session ClientSession,
90+) error {
91+ sessionID := session.SessionID()
92+ if _, exists := s.sessions.LoadOrStore(sessionID, session); exists {
93+ return ErrSessionExists
94+ }
95+ s.hooks.RegisterSession(ctx, session)
96+ return nil
97+}
98+
99+// UnregisterSession removes from storage session that is shut down.
100+func (s *MCPServer) UnregisterSession(
101+ ctx context.Context,
102+ sessionID string,
103+) {
104+ sessionValue, ok := s.sessions.LoadAndDelete(sessionID)
105+ if !ok {
106+ return
107+ }
108+ if session, ok := sessionValue.(ClientSession); ok {
109+ s.hooks.UnregisterSession(ctx, session)
110+ }
111+}
112+
113+// SendNotificationToAllClients sends a notification to all the currently active clients.
114+func (s *MCPServer) SendNotificationToAllClients(
115+ method string,
116+ params map[string]any,
117+) {
118+ notification := mcp.JSONRPCNotification{
119+ JSONRPC: mcp.JSONRPC_VERSION,
120+ Notification: mcp.Notification{
121+ Method: method,
122+ Params: mcp.NotificationParams{
123+ AdditionalFields: params,
124+ },
125+ },
126+ }
127+
128+ s.sessions.Range(func(k, v any) bool {
129+ if session, ok := v.(ClientSession); ok && session.Initialized() {
130+ select {
131+ case session.NotificationChannel() <- notification:
132+ // Successfully sent notification
133+ default:
134+ // Channel is blocked, if there's an error hook, use it
135+ if s.hooks != nil && len(s.hooks.OnError) > 0 {
136+ err := ErrNotificationChannelBlocked
137+ // Copy hooks pointer to local variable to avoid race condition
138+ hooks := s.hooks
139+ go func(sessionID string, hooks *Hooks) {
140+ ctx := context.Background()
141+ // Use the error hook to report the blocked channel
142+ hooks.onError(ctx, nil, "notification", map[string]any{
143+ "method": method,
144+ "sessionID": sessionID,
145+ }, fmt.Errorf("notification channel blocked for session %s: %w", sessionID, err))
146+ }(session.SessionID(), hooks)
147+ }
148+ }
149+ }
150+ return true
151+ })
152+}
153+
154+// SendNotificationToClient sends a notification to the current client
155+func (s *MCPServer) SendNotificationToClient(
156+ ctx context.Context,
157+ method string,
158+ params map[string]any,
159+) error {
160+ session := ClientSessionFromContext(ctx)
161+ if session == nil || !session.Initialized() {
162+ return ErrNotificationNotInitialized
163+ }
164+
165+ // upgrades the client-server communication to SSE stream when the server sends notifications to the client
166+ if sessionWithStreamableHTTPConfig, ok := session.(SessionWithStreamableHTTPConfig); ok {
167+ sessionWithStreamableHTTPConfig.UpgradeToSSEWhenReceiveNotification()
168+ }
169+
170+ notification := mcp.JSONRPCNotification{
171+ JSONRPC: mcp.JSONRPC_VERSION,
172+ Notification: mcp.Notification{
173+ Method: method,
174+ Params: mcp.NotificationParams{
175+ AdditionalFields: params,
176+ },
177+ },
178+ }
179+
180+ select {
181+ case session.NotificationChannel() <- notification:
182+ return nil
183+ default:
184+ // Channel is blocked, if there's an error hook, use it
185+ if s.hooks != nil && len(s.hooks.OnError) > 0 {
186+ err := ErrNotificationChannelBlocked
187+ // Copy hooks pointer to local variable to avoid race condition
188+ hooks := s.hooks
189+ go func(sessionID string, hooks *Hooks) {
190+ // Use the error hook to report the blocked channel
191+ hooks.onError(ctx, nil, "notification", map[string]any{
192+ "method": method,
193+ "sessionID": sessionID,
194+ }, fmt.Errorf("notification channel blocked for session %s: %w", sessionID, err))
195+ }(session.SessionID(), hooks)
196+ }
197+ return ErrNotificationChannelBlocked
198+ }
199+}
200+
201+// SendNotificationToSpecificClient sends a notification to a specific client by session ID
202+func (s *MCPServer) SendNotificationToSpecificClient(
203+ sessionID string,
204+ method string,
205+ params map[string]any,
206+) error {
207+ sessionValue, ok := s.sessions.Load(sessionID)
208+ if !ok {
209+ return ErrSessionNotFound
210+ }
211+
212+ session, ok := sessionValue.(ClientSession)
213+ if !ok || !session.Initialized() {
214+ return ErrSessionNotInitialized
215+ }
216+
217+ // upgrades the client-server communication to SSE stream when the server sends notifications to the client
218+ if sessionWithStreamableHTTPConfig, ok := session.(SessionWithStreamableHTTPConfig); ok {
219+ sessionWithStreamableHTTPConfig.UpgradeToSSEWhenReceiveNotification()
220+ }
221+
222+ notification := mcp.JSONRPCNotification{
223+ JSONRPC: mcp.JSONRPC_VERSION,
224+ Notification: mcp.Notification{
225+ Method: method,
226+ Params: mcp.NotificationParams{
227+ AdditionalFields: params,
228+ },
229+ },
230+ }
231+
232+ select {
233+ case session.NotificationChannel() <- notification:
234+ return nil
235+ default:
236+ // Channel is blocked, if there's an error hook, use it
237+ if s.hooks != nil && len(s.hooks.OnError) > 0 {
238+ err := ErrNotificationChannelBlocked
239+ ctx := context.Background()
240+ // Copy hooks pointer to local variable to avoid race condition
241+ hooks := s.hooks
242+ go func(sID string, hooks *Hooks) {
243+ // Use the error hook to report the blocked channel
244+ hooks.onError(ctx, nil, "notification", map[string]any{
245+ "method": method,
246+ "sessionID": sID,
247+ }, fmt.Errorf("notification channel blocked for session %s: %w", sID, err))
248+ }(sessionID, hooks)
249+ }
250+ return ErrNotificationChannelBlocked
251+ }
252+}
253+
254+// AddSessionTool adds a tool for a specific session
255+func (s *MCPServer) AddSessionTool(sessionID string, tool mcp.Tool, handler ToolHandlerFunc) error {
256+ return s.AddSessionTools(sessionID, ServerTool{Tool: tool, Handler: handler})
257+}
258+
259+// AddSessionTools adds tools for a specific session
260+func (s *MCPServer) AddSessionTools(sessionID string, tools ...ServerTool) error {
261+ sessionValue, ok := s.sessions.Load(sessionID)
262+ if !ok {
263+ return ErrSessionNotFound
264+ }
265+
266+ session, ok := sessionValue.(SessionWithTools)
267+ if !ok {
268+ return ErrSessionDoesNotSupportTools
269+ }
270+
271+ s.implicitlyRegisterToolCapabilities()
272+
273+ // Get existing tools (this should return a thread-safe copy)
274+ sessionTools := session.GetSessionTools()
275+
276+ // Create a new map to avoid concurrent modification issues
277+ newSessionTools := make(map[string]ServerTool, len(sessionTools)+len(tools))
278+
279+ // Copy existing tools
280+ for k, v := range sessionTools {
281+ newSessionTools[k] = v
282+ }
283+
284+ // Add new tools
285+ for _, tool := range tools {
286+ newSessionTools[tool.Tool.Name] = tool
287+ }
288+
289+ // Set the tools (this should be thread-safe)
290+ session.SetSessionTools(newSessionTools)
291+
292+ // It only makes sense to send tool notifications to initialized sessions --
293+ // if we're not initialized yet the client can't possibly have sent their
294+ // initial tools/list message.
295+ //
296+ // For initialized sessions, honor tools.listChanged, which is specifically
297+ // about whether notifications will be sent or not.
298+ // see <https://modelcontextprotocol.io/specification/2025-03-26/server/tools#capabilities>
299+ if session.Initialized() && s.capabilities.tools != nil && s.capabilities.tools.listChanged {
300+ // Send notification only to this session
301+ if err := s.SendNotificationToSpecificClient(sessionID, "notifications/tools/list_changed", nil); err != nil {
302+ // Log the error but don't fail the operation
303+ // The tools were successfully added, but notification failed
304+ if s.hooks != nil && len(s.hooks.OnError) > 0 {
305+ hooks := s.hooks
306+ go func(sID string, hooks *Hooks) {
307+ ctx := context.Background()
308+ hooks.onError(ctx, nil, "notification", map[string]any{
309+ "method": "notifications/tools/list_changed",
310+ "sessionID": sID,
311+ }, fmt.Errorf("failed to send notification after adding tools: %w", err))
312+ }(sessionID, hooks)
313+ }
314+ }
315+ }
316+
317+ return nil
318+}
319+
320+// DeleteSessionTools removes tools from a specific session
321+func (s *MCPServer) DeleteSessionTools(sessionID string, names ...string) error {
322+ sessionValue, ok := s.sessions.Load(sessionID)
323+ if !ok {
324+ return ErrSessionNotFound
325+ }
326+
327+ session, ok := sessionValue.(SessionWithTools)
328+ if !ok {
329+ return ErrSessionDoesNotSupportTools
330+ }
331+
332+ // Get existing tools (this should return a thread-safe copy)
333+ sessionTools := session.GetSessionTools()
334+ if sessionTools == nil {
335+ return nil
336+ }
337+
338+ // Create a new map to avoid concurrent modification issues
339+ newSessionTools := make(map[string]ServerTool, len(sessionTools))
340+
341+ // Copy existing tools except those being deleted
342+ for k, v := range sessionTools {
343+ newSessionTools[k] = v
344+ }
345+
346+ // Remove specified tools
347+ for _, name := range names {
348+ delete(newSessionTools, name)
349+ }
350+
351+ // Set the tools (this should be thread-safe)
352+ session.SetSessionTools(newSessionTools)
353+
354+ // It only makes sense to send tool notifications to initialized sessions --
355+ // if we're not initialized yet the client can't possibly have sent their
356+ // initial tools/list message.
357+ //
358+ // For initialized sessions, honor tools.listChanged, which is specifically
359+ // about whether notifications will be sent or not.
360+ // see <https://modelcontextprotocol.io/specification/2025-03-26/server/tools#capabilities>
361+ if session.Initialized() && s.capabilities.tools != nil && s.capabilities.tools.listChanged {
362+ // Send notification only to this session
363+ if err := s.SendNotificationToSpecificClient(sessionID, "notifications/tools/list_changed", nil); err != nil {
364+ // Log the error but don't fail the operation
365+ // The tools were successfully deleted, but notification failed
366+ if s.hooks != nil && len(s.hooks.OnError) > 0 {
367+ hooks := s.hooks
368+ go func(sID string, hooks *Hooks) {
369+ ctx := context.Background()
370+ hooks.onError(ctx, nil, "notification", map[string]any{
371+ "method": "notifications/tools/list_changed",
372+ "sessionID": sID,
373+ }, fmt.Errorf("failed to send notification after deleting tools: %w", err))
374+ }(sessionID, hooks)
375+ }
376+ }
377+ }
378+
379+ return nil
380+}
vendor/github.com/mark3labs/mcp-go/server/sse.gonew file+736
@@ -0,0 +1,736 @@
1+package server
2+
3+import (
4+ "context"
5+ "encoding/json"
6+ "fmt"
7+ "log"
8+ "net/http"
9+ "net/http/httptest"
10+ "net/url"
11+ "path"
12+ "strings"
13+ "sync"
14+ "sync/atomic"
15+ "time"
16+
17+ "github.com/google/uuid"
18+
19+ "github.com/mark3labs/mcp-go/mcp"
20+)
21+
22+// sseSession represents an active SSE connection.
23+type sseSession struct {
24+ done chan struct{}
25+ eventQueue chan string // Channel for queuing events
26+ sessionID string
27+ requestID atomic.Int64
28+ notificationChannel chan mcp.JSONRPCNotification
29+ initialized atomic.Bool
30+ loggingLevel atomic.Value
31+ tools sync.Map // stores session-specific tools
32+ clientInfo atomic.Value // stores session-specific client info
33+}
34+
35+// SSEContextFunc is a function that takes an existing context and the current
36+// request and returns a potentially modified context based on the request
37+// content. This can be used to inject context values from headers, for example.
38+type SSEContextFunc func(ctx context.Context, r *http.Request) context.Context
39+
40+// DynamicBasePathFunc allows the user to provide a function to generate the
41+// base path for a given request and sessionID. This is useful for cases where
42+// the base path is not known at the time of SSE server creation, such as when
43+// using a reverse proxy or when the base path is dynamically generated. The
44+// function should return the base path (e.g., "/mcp/tenant123").
45+type DynamicBasePathFunc func(r *http.Request, sessionID string) string
46+
47+func (s *sseSession) SessionID() string {
48+ return s.sessionID
49+}
50+
51+func (s *sseSession) NotificationChannel() chan<- mcp.JSONRPCNotification {
52+ return s.notificationChannel
53+}
54+
55+func (s *sseSession) Initialize() {
56+ // set default logging level
57+ s.loggingLevel.Store(mcp.LoggingLevelError)
58+ s.initialized.Store(true)
59+}
60+
61+func (s *sseSession) Initialized() bool {
62+ return s.initialized.Load()
63+}
64+
65+func (s *sseSession) SetLogLevel(level mcp.LoggingLevel) {
66+ s.loggingLevel.Store(level)
67+}
68+
69+func (s *sseSession) GetLogLevel() mcp.LoggingLevel {
70+ level := s.loggingLevel.Load()
71+ if level == nil {
72+ return mcp.LoggingLevelError
73+ }
74+ return level.(mcp.LoggingLevel)
75+}
76+
77+func (s *sseSession) GetSessionTools() map[string]ServerTool {
78+ tools := make(map[string]ServerTool)
79+ s.tools.Range(func(key, value any) bool {
80+ if tool, ok := value.(ServerTool); ok {
81+ tools[key.(string)] = tool
82+ }
83+ return true
84+ })
85+ return tools
86+}
87+
88+func (s *sseSession) SetSessionTools(tools map[string]ServerTool) {
89+ // Clear existing tools
90+ s.tools.Clear()
91+
92+ // Set new tools
93+ for name, tool := range tools {
94+ s.tools.Store(name, tool)
95+ }
96+}
97+
98+func (s *sseSession) GetClientInfo() mcp.Implementation {
99+ if value := s.clientInfo.Load(); value != nil {
100+ if clientInfo, ok := value.(mcp.Implementation); ok {
101+ return clientInfo
102+ }
103+ }
104+ return mcp.Implementation{}
105+}
106+
107+func (s *sseSession) SetClientInfo(clientInfo mcp.Implementation) {
108+ s.clientInfo.Store(clientInfo)
109+}
110+
111+var (
112+ _ ClientSession = (*sseSession)(nil)
113+ _ SessionWithTools = (*sseSession)(nil)
114+ _ SessionWithLogging = (*sseSession)(nil)
115+ _ SessionWithClientInfo = (*sseSession)(nil)
116+)
117+
118+// SSEServer implements a Server-Sent Events (SSE) based MCP server.
119+// It provides real-time communication capabilities over HTTP using the SSE protocol.
120+type SSEServer struct {
121+ server *MCPServer
122+ baseURL string
123+ basePath string
124+ appendQueryToMessageEndpoint bool
125+ useFullURLForMessageEndpoint bool
126+ messageEndpoint string
127+ sseEndpoint string
128+ sessions sync.Map
129+ srv *http.Server
130+ contextFunc SSEContextFunc
131+ dynamicBasePathFunc DynamicBasePathFunc
132+
133+ keepAlive bool
134+ keepAliveInterval time.Duration
135+
136+ mu sync.RWMutex
137+}
138+
139+// SSEOption defines a function type for configuring SSEServer
140+type SSEOption func(*SSEServer)
141+
142+// WithBaseURL sets the base URL for the SSE server
143+func WithBaseURL(baseURL string) SSEOption {
144+ return func(s *SSEServer) {
145+ if baseURL != "" {
146+ u, err := url.Parse(baseURL)
147+ if err != nil {
148+ return
149+ }
150+ if u.Scheme != "http" && u.Scheme != "https" {
151+ return
152+ }
153+ // Check if the host is empty or only contains a port
154+ if u.Host == "" || strings.HasPrefix(u.Host, ":") {
155+ return
156+ }
157+ if len(u.Query()) > 0 {
158+ return
159+ }
160+ }
161+ s.baseURL = strings.TrimSuffix(baseURL, "/")
162+ }
163+}
164+
165+// WithStaticBasePath adds a new option for setting a static base path
166+func WithStaticBasePath(basePath string) SSEOption {
167+ return func(s *SSEServer) {
168+ s.basePath = normalizeURLPath(basePath)
169+ }
170+}
171+
172+// WithBasePath adds a new option for setting a static base path.
173+//
174+// Deprecated: Use WithStaticBasePath instead. This will be removed in a future version.
175+//
176+//go:deprecated
177+func WithBasePath(basePath string) SSEOption {
178+ return WithStaticBasePath(basePath)
179+}
180+
181+// WithDynamicBasePath accepts a function for generating the base path. This is
182+// useful for cases where the base path is not known at the time of SSE server
183+// creation, such as when using a reverse proxy or when the server is mounted
184+// at a dynamic path.
185+func WithDynamicBasePath(fn DynamicBasePathFunc) SSEOption {
186+ return func(s *SSEServer) {
187+ if fn != nil {
188+ s.dynamicBasePathFunc = func(r *http.Request, sid string) string {
189+ bp := fn(r, sid)
190+ return normalizeURLPath(bp)
191+ }
192+ }
193+ }
194+}
195+
196+// WithMessageEndpoint sets the message endpoint path
197+func WithMessageEndpoint(endpoint string) SSEOption {
198+ return func(s *SSEServer) {
199+ s.messageEndpoint = endpoint
200+ }
201+}
202+
203+// WithAppendQueryToMessageEndpoint configures the SSE server to append the original request's
204+// query parameters to the message endpoint URL that is sent to clients during the SSE connection
205+// initialization. This is useful when you need to preserve query parameters from the initial
206+// SSE connection request and carry them over to subsequent message requests, maintaining
207+// context or authentication details across the communication channel.
208+func WithAppendQueryToMessageEndpoint() SSEOption {
209+ return func(s *SSEServer) {
210+ s.appendQueryToMessageEndpoint = true
211+ }
212+}
213+
214+// WithUseFullURLForMessageEndpoint controls whether the SSE server returns a complete URL (including baseURL)
215+// or just the path portion for the message endpoint. Set to false when clients will concatenate
216+// the baseURL themselves to avoid malformed URLs like "http://localhost/mcphttp://localhost/mcp/message".
217+func WithUseFullURLForMessageEndpoint(useFullURLForMessageEndpoint bool) SSEOption {
218+ return func(s *SSEServer) {
219+ s.useFullURLForMessageEndpoint = useFullURLForMessageEndpoint
220+ }
221+}
222+
223+// WithSSEEndpoint sets the SSE endpoint path
224+func WithSSEEndpoint(endpoint string) SSEOption {
225+ return func(s *SSEServer) {
226+ s.sseEndpoint = endpoint
227+ }
228+}
229+
230+// WithHTTPServer sets the HTTP server instance.
231+// NOTE: When providing a custom HTTP server, you must handle routing yourself
232+// If routing is not set up, the server will start but won't handle any MCP requests.
233+func WithHTTPServer(srv *http.Server) SSEOption {
234+ return func(s *SSEServer) {
235+ s.srv = srv
236+ }
237+}
238+
239+func WithKeepAliveInterval(keepAliveInterval time.Duration) SSEOption {
240+ return func(s *SSEServer) {
241+ s.keepAlive = true
242+ s.keepAliveInterval = keepAliveInterval
243+ }
244+}
245+
246+func WithKeepAlive(keepAlive bool) SSEOption {
247+ return func(s *SSEServer) {
248+ s.keepAlive = keepAlive
249+ }
250+}
251+
252+// WithSSEContextFunc sets a function that will be called to customise the context
253+// to the server using the incoming request.
254+func WithSSEContextFunc(fn SSEContextFunc) SSEOption {
255+ return func(s *SSEServer) {
256+ s.contextFunc = fn
257+ }
258+}
259+
260+// NewSSEServer creates a new SSE server instance with the given MCP server and options.
261+func NewSSEServer(server *MCPServer, opts ...SSEOption) *SSEServer {
262+ s := &SSEServer{
263+ server: server,
264+ sseEndpoint: "/sse",
265+ messageEndpoint: "/message",
266+ useFullURLForMessageEndpoint: true,
267+ keepAlive: false,
268+ keepAliveInterval: 10 * time.Second,
269+ }
270+
271+ // Apply all options
272+ for _, opt := range opts {
273+ opt(s)
274+ }
275+
276+ return s
277+}
278+
279+// NewTestServer creates a test server for testing purposes
280+func NewTestServer(server *MCPServer, opts ...SSEOption) *httptest.Server {
281+ sseServer := NewSSEServer(server, opts...)
282+
283+ testServer := httptest.NewServer(sseServer)
284+ sseServer.baseURL = testServer.URL
285+ return testServer
286+}
287+
288+// Start begins serving SSE connections on the specified address.
289+// It sets up HTTP handlers for SSE and message endpoints.
290+func (s *SSEServer) Start(addr string) error {
291+ s.mu.Lock()
292+ if s.srv == nil {
293+ s.srv = &http.Server{
294+ Addr: addr,
295+ Handler: s,
296+ }
297+ } else {
298+ if s.srv.Addr == "" {
299+ s.srv.Addr = addr
300+ } else if s.srv.Addr != addr {
301+ return fmt.Errorf("conflicting listen address: WithHTTPServer(%q) vs Start(%q)", s.srv.Addr, addr)
302+ }
303+ }
304+ srv := s.srv
305+ s.mu.Unlock()
306+
307+ return srv.ListenAndServe()
308+}
309+
310+// Shutdown gracefully stops the SSE server, closing all active sessions
311+// and shutting down the HTTP server.
312+func (s *SSEServer) Shutdown(ctx context.Context) error {
313+ s.mu.RLock()
314+ srv := s.srv
315+ s.mu.RUnlock()
316+
317+ if srv != nil {
318+ s.sessions.Range(func(key, value any) bool {
319+ if session, ok := value.(*sseSession); ok {
320+ close(session.done)
321+ }
322+ s.sessions.Delete(key)
323+ return true
324+ })
325+
326+ return srv.Shutdown(ctx)
327+ }
328+ return nil
329+}
330+
331+// handleSSE handles incoming SSE connection requests.
332+// It sets up appropriate headers and creates a new session for the client.
333+func (s *SSEServer) handleSSE(w http.ResponseWriter, r *http.Request) {
334+ if r.Method != http.MethodGet {
335+ http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
336+ return
337+ }
338+
339+ w.Header().Set("Content-Type", "text/event-stream")
340+ w.Header().Set("Cache-Control", "no-cache")
341+ w.Header().Set("Connection", "keep-alive")
342+ w.Header().Set("Access-Control-Allow-Origin", "*")
343+
344+ flusher, ok := w.(http.Flusher)
345+ if !ok {
346+ http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
347+ return
348+ }
349+
350+ sessionID := uuid.New().String()
351+ session := &sseSession{
352+ done: make(chan struct{}),
353+ eventQueue: make(chan string, 100), // Buffer for events
354+ sessionID: sessionID,
355+ notificationChannel: make(chan mcp.JSONRPCNotification, 100),
356+ }
357+
358+ s.sessions.Store(sessionID, session)
359+ defer s.sessions.Delete(sessionID)
360+
361+ if err := s.server.RegisterSession(r.Context(), session); err != nil {
362+ http.Error(
363+ w,
364+ fmt.Sprintf("Session registration failed: %v", err),
365+ http.StatusInternalServerError,
366+ )
367+ return
368+ }
369+ defer s.server.UnregisterSession(r.Context(), sessionID)
370+
371+ // Start notification handler for this session
372+ go func() {
373+ for {
374+ select {
375+ case notification := <-session.notificationChannel:
376+ eventData, err := json.Marshal(notification)
377+ if err == nil {
378+ select {
379+ case session.eventQueue <- fmt.Sprintf("event: message\ndata: %s\n\n", eventData):
380+ // Event queued successfully
381+ case <-session.done:
382+ return
383+ }
384+ }
385+ case <-session.done:
386+ return
387+ case <-r.Context().Done():
388+ return
389+ }
390+ }
391+ }()
392+
393+ // Start keep alive : ping
394+ if s.keepAlive {
395+ go func() {
396+ ticker := time.NewTicker(s.keepAliveInterval)
397+ defer ticker.Stop()
398+ for {
399+ select {
400+ case <-ticker.C:
401+ message := mcp.JSONRPCRequest{
402+ JSONRPC: "2.0",
403+ ID: mcp.NewRequestId(session.requestID.Add(1)),
404+ Request: mcp.Request{
405+ Method: "ping",
406+ },
407+ }
408+ messageBytes, _ := json.Marshal(message)
409+ pingMsg := fmt.Sprintf("event: message\ndata:%s\n\n", messageBytes)
410+ select {
411+ case session.eventQueue <- pingMsg:
412+ // Message sent successfully
413+ case <-session.done:
414+ return
415+ }
416+ case <-session.done:
417+ return
418+ case <-r.Context().Done():
419+ return
420+ }
421+ }
422+ }()
423+ }
424+
425+ // Send the initial endpoint event
426+ endpoint := s.GetMessageEndpointForClient(r, sessionID)
427+ if s.appendQueryToMessageEndpoint && len(r.URL.RawQuery) > 0 {
428+ endpoint += "&" + r.URL.RawQuery
429+ }
430+ fmt.Fprintf(w, "event: endpoint\ndata: %s\r\n\r\n", endpoint)
431+ flusher.Flush()
432+
433+ // Main event loop - this runs in the HTTP handler goroutine
434+ for {
435+ select {
436+ case event := <-session.eventQueue:
437+ // Write the event to the response
438+ fmt.Fprint(w, event)
439+ flusher.Flush()
440+ case <-r.Context().Done():
441+ close(session.done)
442+ return
443+ case <-session.done:
444+ return
445+ }
446+ }
447+}
448+
449+// GetMessageEndpointForClient returns the appropriate message endpoint URL with session ID
450+// for the given request. This is the canonical way to compute the message endpoint for a client.
451+// It handles both dynamic and static path modes, and honors the WithUseFullURLForMessageEndpoint flag.
452+func (s *SSEServer) GetMessageEndpointForClient(r *http.Request, sessionID string) string {
453+ basePath := s.basePath
454+ if s.dynamicBasePathFunc != nil {
455+ basePath = s.dynamicBasePathFunc(r, sessionID)
456+ }
457+
458+ endpointPath := normalizeURLPath(basePath, s.messageEndpoint)
459+ if s.useFullURLForMessageEndpoint && s.baseURL != "" {
460+ endpointPath = s.baseURL + endpointPath
461+ }
462+
463+ return fmt.Sprintf("%s?sessionId=%s", endpointPath, sessionID)
464+}
465+
466+// handleMessage processes incoming JSON-RPC messages from clients and sends responses
467+// back through the SSE connection and 202 code to HTTP response.
468+func (s *SSEServer) handleMessage(w http.ResponseWriter, r *http.Request) {
469+ if r.Method != http.MethodPost {
470+ s.writeJSONRPCError(w, nil, mcp.INVALID_REQUEST, "Method not allowed")
471+ return
472+ }
473+
474+ sessionID := r.URL.Query().Get("sessionId")
475+ if sessionID == "" {
476+ s.writeJSONRPCError(w, nil, mcp.INVALID_PARAMS, "Missing sessionId")
477+ return
478+ }
479+ sessionI, ok := s.sessions.Load(sessionID)
480+ if !ok {
481+ s.writeJSONRPCError(w, nil, mcp.INVALID_PARAMS, "Invalid session ID")
482+ return
483+ }
484+ session := sessionI.(*sseSession)
485+
486+ // Set the client context before handling the message
487+ ctx := s.server.WithContext(r.Context(), session)
488+ if s.contextFunc != nil {
489+ ctx = s.contextFunc(ctx, r)
490+ }
491+
492+ // Parse message as raw JSON
493+ var rawMessage json.RawMessage
494+ if err := json.NewDecoder(r.Body).Decode(&rawMessage); err != nil {
495+ s.writeJSONRPCError(w, nil, mcp.PARSE_ERROR, "Parse error")
496+ return
497+ }
498+
499+ // Create a context that preserves all values from parent ctx but won't be canceled when the parent is canceled.
500+ // this is required because the http ctx will be canceled when the client disconnects
501+ detachedCtx := context.WithoutCancel(ctx)
502+
503+ // quick return request, send 202 Accepted with no body, then deal the message and sent response via SSE
504+ w.WriteHeader(http.StatusAccepted)
505+
506+ // Create a new context for handling the message that will be canceled when the message handling is done
507+ messageCtx, cancel := context.WithCancel(detachedCtx)
508+
509+ go func(ctx context.Context) {
510+ defer cancel()
511+ // Use the context that will be canceled when session is done
512+ // Process message through MCPServer
513+ response := s.server.HandleMessage(ctx, rawMessage)
514+ // Only send response if there is one (not for notifications)
515+ if response != nil {
516+ var message string
517+ if eventData, err := json.Marshal(response); err != nil {
518+ // If there is an error marshalling the response, send a generic error response
519+ log.Printf("failed to marshal response: %v", err)
520+ message = "event: message\ndata: {\"error\": \"internal error\",\"jsonrpc\": \"2.0\", \"id\": null}\n\n"
521+ } else {
522+ message = fmt.Sprintf("event: message\ndata: %s\n\n", eventData)
523+ }
524+
525+ // Queue the event for sending via SSE
526+ select {
527+ case session.eventQueue <- message:
528+ // Event queued successfully
529+ case <-session.done:
530+ // Session is closed, don't try to queue
531+ default:
532+ // Queue is full, log this situation
533+ log.Printf("Event queue full for session %s", sessionID)
534+ }
535+ }
536+ }(messageCtx)
537+}
538+
539+// writeJSONRPCError writes a JSON-RPC error response with the given error details.
540+func (s *SSEServer) writeJSONRPCError(
541+ w http.ResponseWriter,
542+ id any,
543+ code int,
544+ message string,
545+) {
546+ response := createErrorResponse(id, code, message)
547+ w.Header().Set("Content-Type", "application/json")
548+ w.WriteHeader(http.StatusBadRequest)
549+ if err := json.NewEncoder(w).Encode(response); err != nil {
550+ http.Error(
551+ w,
552+ fmt.Sprintf("Failed to encode response: %v", err),
553+ http.StatusInternalServerError,
554+ )
555+ return
556+ }
557+}
558+
559+// SendEventToSession sends an event to a specific SSE session identified by sessionID.
560+// Returns an error if the session is not found or closed.
561+func (s *SSEServer) SendEventToSession(
562+ sessionID string,
563+ event any,
564+) error {
565+ sessionI, ok := s.sessions.Load(sessionID)
566+ if !ok {
567+ return fmt.Errorf("session not found: %s", sessionID)
568+ }
569+ session := sessionI.(*sseSession)
570+
571+ eventData, err := json.Marshal(event)
572+ if err != nil {
573+ return err
574+ }
575+
576+ // Queue the event for sending via SSE
577+ select {
578+ case session.eventQueue <- fmt.Sprintf("event: message\ndata: %s\n\n", eventData):
579+ return nil
580+ case <-session.done:
581+ return fmt.Errorf("session closed")
582+ default:
583+ return fmt.Errorf("event queue full")
584+ }
585+}
586+
587+func (s *SSEServer) GetUrlPath(input string) (string, error) {
588+ parse, err := url.Parse(input)
589+ if err != nil {
590+ return "", fmt.Errorf("failed to parse URL %s: %w", input, err)
591+ }
592+ return parse.Path, nil
593+}
594+
595+func (s *SSEServer) CompleteSseEndpoint() (string, error) {
596+ if s.dynamicBasePathFunc != nil {
597+ return "", &ErrDynamicPathConfig{Method: "CompleteSseEndpoint"}
598+ }
599+
600+ path := normalizeURLPath(s.basePath, s.sseEndpoint)
601+ return s.baseURL + path, nil
602+}
603+
604+func (s *SSEServer) CompleteSsePath() string {
605+ path, err := s.CompleteSseEndpoint()
606+ if err != nil {
607+ return normalizeURLPath(s.basePath, s.sseEndpoint)
608+ }
609+ urlPath, err := s.GetUrlPath(path)
610+ if err != nil {
611+ return normalizeURLPath(s.basePath, s.sseEndpoint)
612+ }
613+ return urlPath
614+}
615+
616+func (s *SSEServer) CompleteMessageEndpoint() (string, error) {
617+ if s.dynamicBasePathFunc != nil {
618+ return "", &ErrDynamicPathConfig{Method: "CompleteMessageEndpoint"}
619+ }
620+ path := normalizeURLPath(s.basePath, s.messageEndpoint)
621+ return s.baseURL + path, nil
622+}
623+
624+func (s *SSEServer) CompleteMessagePath() string {
625+ path, err := s.CompleteMessageEndpoint()
626+ if err != nil {
627+ return normalizeURLPath(s.basePath, s.messageEndpoint)
628+ }
629+ urlPath, err := s.GetUrlPath(path)
630+ if err != nil {
631+ return normalizeURLPath(s.basePath, s.messageEndpoint)
632+ }
633+ return urlPath
634+}
635+
636+// SSEHandler returns an http.Handler for the SSE endpoint.
637+//
638+// This method allows you to mount the SSE handler at any arbitrary path
639+// using your own router (e.g. net/http, gorilla/mux, chi, etc.). It is
640+// intended for advanced scenarios where you want to control the routing or
641+// support dynamic segments.
642+//
643+// IMPORTANT: When using this handler in advanced/dynamic mounting scenarios,
644+// you must use the WithDynamicBasePath option to ensure the correct base path
645+// is communicated to clients.
646+//
647+// Example usage:
648+//
649+// // Advanced/dynamic:
650+// sseServer := NewSSEServer(mcpServer,
651+// WithDynamicBasePath(func(r *http.Request, sessionID string) string {
652+// tenant := r.PathValue("tenant")
653+// return "/mcp/" + tenant
654+// }),
655+// WithBaseURL("http://localhost:8080")
656+// )
657+// mux.Handle("/mcp/{tenant}/sse", sseServer.SSEHandler())
658+// mux.Handle("/mcp/{tenant}/message", sseServer.MessageHandler())
659+//
660+// For non-dynamic cases, use ServeHTTP method instead.
661+func (s *SSEServer) SSEHandler() http.Handler {
662+ return http.HandlerFunc(s.handleSSE)
663+}
664+
665+// MessageHandler returns an http.Handler for the message endpoint.
666+//
667+// This method allows you to mount the message handler at any arbitrary path
668+// using your own router (e.g. net/http, gorilla/mux, chi, etc.). It is
669+// intended for advanced scenarios where you want to control the routing or
670+// support dynamic segments.
671+//
672+// IMPORTANT: When using this handler in advanced/dynamic mounting scenarios,
673+// you must use the WithDynamicBasePath option to ensure the correct base path
674+// is communicated to clients.
675+//
676+// Example usage:
677+//
678+// // Advanced/dynamic:
679+// sseServer := NewSSEServer(mcpServer,
680+// WithDynamicBasePath(func(r *http.Request, sessionID string) string {
681+// tenant := r.PathValue("tenant")
682+// return "/mcp/" + tenant
683+// }),
684+// WithBaseURL("http://localhost:8080")
685+// )
686+// mux.Handle("/mcp/{tenant}/sse", sseServer.SSEHandler())
687+// mux.Handle("/mcp/{tenant}/message", sseServer.MessageHandler())
688+//
689+// For non-dynamic cases, use ServeHTTP method instead.
690+func (s *SSEServer) MessageHandler() http.Handler {
691+ return http.HandlerFunc(s.handleMessage)
692+}
693+
694+// ServeHTTP implements the http.Handler interface.
695+func (s *SSEServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
696+ if s.dynamicBasePathFunc != nil {
697+ http.Error(
698+ w,
699+ (&ErrDynamicPathConfig{Method: "ServeHTTP"}).Error(),
700+ http.StatusInternalServerError,
701+ )
702+ return
703+ }
704+ path := r.URL.Path
705+ // Use exact path matching rather than Contains
706+ ssePath := s.CompleteSsePath()
707+ if ssePath != "" && path == ssePath {
708+ s.handleSSE(w, r)
709+ return
710+ }
711+ messagePath := s.CompleteMessagePath()
712+ if messagePath != "" && path == messagePath {
713+ s.handleMessage(w, r)
714+ return
715+ }
716+
717+ http.NotFound(w, r)
718+}
719+
720+// normalizeURLPath joins path elements like path.Join but ensures the
721+// result always starts with a leading slash and never ends with a slash
722+func normalizeURLPath(elem ...string) string {
723+ joined := path.Join(elem...)
724+
725+ // Ensure leading slash
726+ if !strings.HasPrefix(joined, "/") {
727+ joined = "/" + joined
728+ }
729+
730+ // Remove trailing slash if not just "/"
731+ if len(joined) > 1 && strings.HasSuffix(joined, "/") {
732+ joined = joined[:len(joined)-1]
733+ }
734+
735+ return joined
736+}
vendor/github.com/mark3labs/mcp-go/server/stdio.gonew file+314
@@ -0,0 +1,314 @@
1+package server
2+
3+import (
4+ "bufio"
5+ "context"
6+ "encoding/json"
7+ "fmt"
8+ "io"
9+ "log"
10+ "os"
11+ "os/signal"
12+ "sync/atomic"
13+ "syscall"
14+
15+ "github.com/mark3labs/mcp-go/mcp"
16+)
17+
18+// StdioContextFunc is a function that takes an existing context and returns
19+// a potentially modified context.
20+// This can be used to inject context values from environment variables,
21+// for example.
22+type StdioContextFunc func(ctx context.Context) context.Context
23+
24+// StdioServer wraps a MCPServer and handles stdio communication.
25+// It provides a simple way to create command-line MCP servers that
26+// communicate via standard input/output streams using JSON-RPC messages.
27+type StdioServer struct {
28+ server *MCPServer
29+ errLogger *log.Logger
30+ contextFunc StdioContextFunc
31+}
32+
33+// StdioOption defines a function type for configuring StdioServer
34+type StdioOption func(*StdioServer)
35+
36+// WithErrorLogger sets the error logger for the server
37+func WithErrorLogger(logger *log.Logger) StdioOption {
38+ return func(s *StdioServer) {
39+ s.errLogger = logger
40+ }
41+}
42+
43+// WithStdioContextFunc sets a function that will be called to customise the context
44+// to the server. Note that the stdio server uses the same context for all requests,
45+// so this function will only be called once per server instance.
46+func WithStdioContextFunc(fn StdioContextFunc) StdioOption {
47+ return func(s *StdioServer) {
48+ s.contextFunc = fn
49+ }
50+}
51+
52+// stdioSession is a static client session, since stdio has only one client.
53+type stdioSession struct {
54+ notifications chan mcp.JSONRPCNotification
55+ initialized atomic.Bool
56+ loggingLevel atomic.Value
57+ clientInfo atomic.Value // stores session-specific client info
58+}
59+
60+func (s *stdioSession) SessionID() string {
61+ return "stdio"
62+}
63+
64+func (s *stdioSession) NotificationChannel() chan<- mcp.JSONRPCNotification {
65+ return s.notifications
66+}
67+
68+func (s *stdioSession) Initialize() {
69+ // set default logging level
70+ s.loggingLevel.Store(mcp.LoggingLevelError)
71+ s.initialized.Store(true)
72+}
73+
74+func (s *stdioSession) Initialized() bool {
75+ return s.initialized.Load()
76+}
77+
78+func (s *stdioSession) GetClientInfo() mcp.Implementation {
79+ if value := s.clientInfo.Load(); value != nil {
80+ if clientInfo, ok := value.(mcp.Implementation); ok {
81+ return clientInfo
82+ }
83+ }
84+ return mcp.Implementation{}
85+}
86+
87+func (s *stdioSession) SetClientInfo(clientInfo mcp.Implementation) {
88+ s.clientInfo.Store(clientInfo)
89+}
90+
91+func (s *stdioSession) SetLogLevel(level mcp.LoggingLevel) {
92+ s.loggingLevel.Store(level)
93+}
94+
95+func (s *stdioSession) GetLogLevel() mcp.LoggingLevel {
96+ level := s.loggingLevel.Load()
97+ if level == nil {
98+ return mcp.LoggingLevelError
99+ }
100+ return level.(mcp.LoggingLevel)
101+}
102+
103+var (
104+ _ ClientSession = (*stdioSession)(nil)
105+ _ SessionWithLogging = (*stdioSession)(nil)
106+ _ SessionWithClientInfo = (*stdioSession)(nil)
107+)
108+
109+var stdioSessionInstance = stdioSession{
110+ notifications: make(chan mcp.JSONRPCNotification, 100),
111+}
112+
113+// NewStdioServer creates a new stdio server wrapper around an MCPServer.
114+// It initializes the server with a default error logger that discards all output.
115+func NewStdioServer(server *MCPServer) *StdioServer {
116+ return &StdioServer{
117+ server: server,
118+ errLogger: log.New(
119+ os.Stderr,
120+ "",
121+ log.LstdFlags,
122+ ), // Default to discarding logs
123+ }
124+}
125+
126+// SetErrorLogger configures where error messages from the StdioServer are logged.
127+// The provided logger will receive all error messages generated during server operation.
128+func (s *StdioServer) SetErrorLogger(logger *log.Logger) {
129+ s.errLogger = logger
130+}
131+
132+// SetContextFunc sets a function that will be called to customise the context
133+// to the server. Note that the stdio server uses the same context for all requests,
134+// so this function will only be called once per server instance.
135+func (s *StdioServer) SetContextFunc(fn StdioContextFunc) {
136+ s.contextFunc = fn
137+}
138+
139+// handleNotifications continuously processes notifications from the session's notification channel
140+// and writes them to the provided output. It runs until the context is cancelled.
141+// Any errors encountered while writing notifications are logged but do not stop the handler.
142+func (s *StdioServer) handleNotifications(ctx context.Context, stdout io.Writer) {
143+ for {
144+ select {
145+ case notification := <-stdioSessionInstance.notifications:
146+ if err := s.writeResponse(notification, stdout); err != nil {
147+ s.errLogger.Printf("Error writing notification: %v", err)
148+ }
149+ case <-ctx.Done():
150+ return
151+ }
152+ }
153+}
154+
155+// processInputStream continuously reads and processes messages from the input stream.
156+// It handles EOF gracefully as a normal termination condition.
157+// The function returns when either:
158+// - The context is cancelled (returns context.Err())
159+// - EOF is encountered (returns nil)
160+// - An error occurs while reading or processing messages (returns the error)
161+func (s *StdioServer) processInputStream(ctx context.Context, reader *bufio.Reader, stdout io.Writer) error {
162+ for {
163+ if err := ctx.Err(); err != nil {
164+ return err
165+ }
166+
167+ line, err := s.readNextLine(ctx, reader)
168+ if err != nil {
169+ if err == io.EOF {
170+ return nil
171+ }
172+ s.errLogger.Printf("Error reading input: %v", err)
173+ return err
174+ }
175+
176+ if err := s.processMessage(ctx, line, stdout); err != nil {
177+ if err == io.EOF {
178+ return nil
179+ }
180+ s.errLogger.Printf("Error handling message: %v", err)
181+ return err
182+ }
183+ }
184+}
185+
186+// readNextLine reads a single line from the input reader in a context-aware manner.
187+// It uses channels to make the read operation cancellable via context.
188+// Returns the read line and any error encountered. If the context is cancelled,
189+// returns an empty string and the context's error. EOF is returned when the input
190+// stream is closed.
191+func (s *StdioServer) readNextLine(ctx context.Context, reader *bufio.Reader) (string, error) {
192+ type result struct {
193+ line string
194+ err error
195+ }
196+
197+ resultCh := make(chan result, 1)
198+
199+ go func() {
200+ line, err := reader.ReadString('\n')
201+ resultCh <- result{line: line, err: err}
202+ }()
203+
204+ select {
205+ case <-ctx.Done():
206+ return "", nil
207+ case res := <-resultCh:
208+ return res.line, res.err
209+ }
210+}
211+
212+// Listen starts listening for JSON-RPC messages on the provided input and writes responses to the provided output.
213+// It runs until the context is cancelled or an error occurs.
214+// Returns an error if there are issues with reading input or writing output.
215+func (s *StdioServer) Listen(
216+ ctx context.Context,
217+ stdin io.Reader,
218+ stdout io.Writer,
219+) error {
220+ // Set a static client context since stdio only has one client
221+ if err := s.server.RegisterSession(ctx, &stdioSessionInstance); err != nil {
222+ return fmt.Errorf("register session: %w", err)
223+ }
224+ defer s.server.UnregisterSession(ctx, stdioSessionInstance.SessionID())
225+ ctx = s.server.WithContext(ctx, &stdioSessionInstance)
226+
227+ // Add in any custom context.
228+ if s.contextFunc != nil {
229+ ctx = s.contextFunc(ctx)
230+ }
231+
232+ reader := bufio.NewReader(stdin)
233+
234+ // Start notification handler
235+ go s.handleNotifications(ctx, stdout)
236+ return s.processInputStream(ctx, reader, stdout)
237+}
238+
239+// processMessage handles a single JSON-RPC message and writes the response.
240+// It parses the message, processes it through the wrapped MCPServer, and writes any response.
241+// Returns an error if there are issues with message processing or response writing.
242+func (s *StdioServer) processMessage(
243+ ctx context.Context,
244+ line string,
245+ writer io.Writer,
246+) error {
247+ // If line is empty, likely due to ctx cancellation
248+ if len(line) == 0 {
249+ return nil
250+ }
251+
252+ // Parse the message as raw JSON
253+ var rawMessage json.RawMessage
254+ if err := json.Unmarshal([]byte(line), &rawMessage); err != nil {
255+ response := createErrorResponse(nil, mcp.PARSE_ERROR, "Parse error")
256+ return s.writeResponse(response, writer)
257+ }
258+
259+ // Handle the message using the wrapped server
260+ response := s.server.HandleMessage(ctx, rawMessage)
261+
262+ // Only write response if there is one (not for notifications)
263+ if response != nil {
264+ if err := s.writeResponse(response, writer); err != nil {
265+ return fmt.Errorf("failed to write response: %w", err)
266+ }
267+ }
268+
269+ return nil
270+}
271+
272+// writeResponse marshals and writes a JSON-RPC response message followed by a newline.
273+// Returns an error if marshaling or writing fails.
274+func (s *StdioServer) writeResponse(
275+ response mcp.JSONRPCMessage,
276+ writer io.Writer,
277+) error {
278+ responseBytes, err := json.Marshal(response)
279+ if err != nil {
280+ return err
281+ }
282+
283+ // Write response followed by newline
284+ if _, err := fmt.Fprintf(writer, "%s\n", responseBytes); err != nil {
285+ return err
286+ }
287+
288+ return nil
289+}
290+
291+// ServeStdio is a convenience function that creates and starts a StdioServer with os.Stdin and os.Stdout.
292+// It sets up signal handling for graceful shutdown on SIGTERM and SIGINT.
293+// Returns an error if the server encounters any issues during operation.
294+func ServeStdio(server *MCPServer, opts ...StdioOption) error {
295+ s := NewStdioServer(server)
296+
297+ for _, opt := range opts {
298+ opt(s)
299+ }
300+
301+ ctx, cancel := context.WithCancel(context.Background())
302+ defer cancel()
303+
304+ // Set up signal handling
305+ sigChan := make(chan os.Signal, 1)
306+ signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
307+
308+ go func() {
309+ <-sigChan
310+ cancel()
311+ }()
312+
313+ return s.Listen(ctx, os.Stdin, os.Stdout)
314+}
vendor/github.com/mark3labs/mcp-go/server/streamable_http.gonew file+653
@@ -0,0 +1,653 @@
1+package server
2+
3+import (
4+ "context"
5+ "encoding/json"
6+ "fmt"
7+ "io"
8+ "net/http"
9+ "net/http/httptest"
10+ "strings"
11+ "sync"
12+ "sync/atomic"
13+ "time"
14+
15+ "github.com/google/uuid"
16+ "github.com/mark3labs/mcp-go/mcp"
17+ "github.com/mark3labs/mcp-go/util"
18+)
19+
20+// StreamableHTTPOption defines a function type for configuring StreamableHTTPServer
21+type StreamableHTTPOption func(*StreamableHTTPServer)
22+
23+// WithEndpointPath sets the endpoint path for the server.
24+// The default is "/mcp".
25+// It's only works for `Start` method. When used as a http.Handler, it has no effect.
26+func WithEndpointPath(endpointPath string) StreamableHTTPOption {
27+ return func(s *StreamableHTTPServer) {
28+ // Normalize the endpoint path to ensure it starts with a slash and doesn't end with one
29+ normalizedPath := "/" + strings.Trim(endpointPath, "/")
30+ s.endpointPath = normalizedPath
31+ }
32+}
33+
34+// WithStateLess sets the server to stateless mode.
35+// If true, the server will manage no session information. Every request will be treated
36+// as a new session. No session id returned to the client.
37+// The default is false.
38+//
39+// Notice: This is a convenience method. It's identical to set WithSessionIdManager option
40+// to StatelessSessionIdManager.
41+func WithStateLess(stateLess bool) StreamableHTTPOption {
42+ return func(s *StreamableHTTPServer) {
43+ s.sessionIdManager = &StatelessSessionIdManager{}
44+ }
45+}
46+
47+// WithSessionIdManager sets a custom session id generator for the server.
48+// By default, the server will use SimpleStatefulSessionIdGenerator, which generates
49+// session ids with uuid, and it's insecure.
50+// Notice: it will override the WithStateLess option.
51+func WithSessionIdManager(manager SessionIdManager) StreamableHTTPOption {
52+ return func(s *StreamableHTTPServer) {
53+ s.sessionIdManager = manager
54+ }
55+}
56+
57+// WithHeartbeatInterval sets the heartbeat interval. Positive interval means the
58+// server will send a heartbeat to the client through the GET connection, to keep
59+// the connection alive from being closed by the network infrastructure (e.g.
60+// gateways). If the client does not establish a GET connection, it has no
61+// effect. The default is not to send heartbeats.
62+func WithHeartbeatInterval(interval time.Duration) StreamableHTTPOption {
63+ return func(s *StreamableHTTPServer) {
64+ s.listenHeartbeatInterval = interval
65+ }
66+}
67+
68+// WithHTTPContextFunc sets a function that will be called to customise the context
69+// to the server using the incoming request.
70+// This can be used to inject context values from headers, for example.
71+func WithHTTPContextFunc(fn HTTPContextFunc) StreamableHTTPOption {
72+ return func(s *StreamableHTTPServer) {
73+ s.contextFunc = fn
74+ }
75+}
76+
77+// WithStreamableHTTPServer sets the HTTP server instance for StreamableHTTPServer.
78+// NOTE: When providing a custom HTTP server, you must handle routing yourself
79+// If routing is not set up, the server will start but won't handle any MCP requests.
80+func WithStreamableHTTPServer(srv *http.Server) StreamableHTTPOption {
81+ return func(s *StreamableHTTPServer) {
82+ s.httpServer = srv
83+ }
84+}
85+
86+// WithLogger sets the logger for the server
87+func WithLogger(logger util.Logger) StreamableHTTPOption {
88+ return func(s *StreamableHTTPServer) {
89+ s.logger = logger
90+ }
91+}
92+
93+// StreamableHTTPServer implements a Streamable-http based MCP server.
94+// It communicates with clients over HTTP protocol, supporting both direct HTTP responses, and SSE streams.
95+// https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http
96+//
97+// Usage:
98+//
99+// server := NewStreamableHTTPServer(mcpServer)
100+// server.Start(":8080") // The final url for client is http://xxxx:8080/mcp by default
101+//
102+// or the server itself can be used as a http.Handler, which is convenient to
103+// integrate with existing http servers, or advanced usage:
104+//
105+// handler := NewStreamableHTTPServer(mcpServer)
106+// http.Handle("/streamable-http", handler)
107+// http.ListenAndServe(":8080", nil)
108+//
109+// Notice:
110+// Except for the GET handlers(listening), the POST handlers(request/notification) will
111+// not trigger the session registration. So the methods like `SendNotificationToSpecificClient`
112+// or `hooks.onRegisterSession` will not be triggered for POST messages.
113+//
114+// The current implementation does not support the following features from the specification:
115+// - Batching of requests/notifications/responses in arrays.
116+// - Stream Resumability
117+type StreamableHTTPServer struct {
118+ server *MCPServer
119+ sessionTools *sessionToolsStore
120+ sessionRequestIDs sync.Map // sessionId --> last requestID(*atomic.Int64)
121+
122+ httpServer *http.Server
123+ mu sync.RWMutex
124+
125+ endpointPath string
126+ contextFunc HTTPContextFunc
127+ sessionIdManager SessionIdManager
128+ listenHeartbeatInterval time.Duration
129+ logger util.Logger
130+}
131+
132+// NewStreamableHTTPServer creates a new streamable-http server instance
133+func NewStreamableHTTPServer(server *MCPServer, opts ...StreamableHTTPOption) *StreamableHTTPServer {
134+ s := &StreamableHTTPServer{
135+ server: server,
136+ sessionTools: newSessionToolsStore(),
137+ endpointPath: "/mcp",
138+ sessionIdManager: &InsecureStatefulSessionIdManager{},
139+ logger: util.DefaultLogger(),
140+ }
141+
142+ // Apply all options
143+ for _, opt := range opts {
144+ opt(s)
145+ }
146+ return s
147+}
148+
149+// ServeHTTP implements the http.Handler interface.
150+func (s *StreamableHTTPServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
151+ switch r.Method {
152+ case http.MethodPost:
153+ s.handlePost(w, r)
154+ case http.MethodGet:
155+ s.handleGet(w, r)
156+ case http.MethodDelete:
157+ s.handleDelete(w, r)
158+ default:
159+ http.NotFound(w, r)
160+ }
161+}
162+
163+// Start begins serving the http server on the specified address and path
164+// (endpointPath). like:
165+//
166+// s.Start(":8080")
167+func (s *StreamableHTTPServer) Start(addr string) error {
168+ s.mu.Lock()
169+ if s.httpServer == nil {
170+ mux := http.NewServeMux()
171+ mux.Handle(s.endpointPath, s)
172+ s.httpServer = &http.Server{
173+ Addr: addr,
174+ Handler: mux,
175+ }
176+ } else {
177+ if s.httpServer.Addr == "" {
178+ s.httpServer.Addr = addr
179+ } else if s.httpServer.Addr != addr {
180+ return fmt.Errorf("conflicting listen address: WithStreamableHTTPServer(%q) vs Start(%q)", s.httpServer.Addr, addr)
181+ }
182+ }
183+ srv := s.httpServer
184+ s.mu.Unlock()
185+
186+ return srv.ListenAndServe()
187+}
188+
189+// Shutdown gracefully stops the server, closing all active sessions
190+// and shutting down the HTTP server.
191+func (s *StreamableHTTPServer) Shutdown(ctx context.Context) error {
192+
193+ // shutdown the server if needed (may use as a http.Handler)
194+ s.mu.RLock()
195+ srv := s.httpServer
196+ s.mu.RUnlock()
197+ if srv != nil {
198+ return srv.Shutdown(ctx)
199+ }
200+ return nil
201+}
202+
203+// --- internal methods ---
204+
205+const (
206+ headerKeySessionID = "Mcp-Session-Id"
207+)
208+
209+func (s *StreamableHTTPServer) handlePost(w http.ResponseWriter, r *http.Request) {
210+ // post request carry request/notification message
211+
212+ // Check content type
213+ contentType := r.Header.Get("Content-Type")
214+ if contentType != "application/json" {
215+ http.Error(w, "Invalid content type: must be 'application/json'", http.StatusBadRequest)
216+ return
217+ }
218+
219+ // Check the request body is valid json, meanwhile, get the request Method
220+ rawData, err := io.ReadAll(r.Body)
221+ if err != nil {
222+ s.writeJSONRPCError(w, nil, mcp.PARSE_ERROR, fmt.Sprintf("read request body error: %v", err))
223+ return
224+ }
225+ var baseMessage struct {
226+ Method mcp.MCPMethod `json:"method"`
227+ }
228+ if err := json.Unmarshal(rawData, &baseMessage); err != nil {
229+ s.writeJSONRPCError(w, nil, mcp.PARSE_ERROR, "request body is not valid json")
230+ return
231+ }
232+ isInitializeRequest := baseMessage.Method == mcp.MethodInitialize
233+
234+ // Prepare the session for the mcp server
235+ // The session is ephemeral. Its life is the same as the request. It's only created
236+ // for interaction with the mcp server.
237+ var sessionID string
238+ if isInitializeRequest {
239+ // generate a new one for initialize request
240+ sessionID = s.sessionIdManager.Generate()
241+ } else {
242+ // Get session ID from header.
243+ // Stateful servers need the client to carry the session ID.
244+ sessionID = r.Header.Get(headerKeySessionID)
245+ isTerminated, err := s.sessionIdManager.Validate(sessionID)
246+ if err != nil {
247+ http.Error(w, "Invalid session ID", http.StatusBadRequest)
248+ return
249+ }
250+ if isTerminated {
251+ http.Error(w, "Session terminated", http.StatusNotFound)
252+ return
253+ }
254+ }
255+
256+ session := newStreamableHttpSession(sessionID, s.sessionTools)
257+
258+ // Set the client context before handling the message
259+ ctx := s.server.WithContext(r.Context(), session)
260+ if s.contextFunc != nil {
261+ ctx = s.contextFunc(ctx, r)
262+ }
263+
264+ // handle potential notifications
265+ mu := sync.Mutex{}
266+ upgradedHeader := false
267+ done := make(chan struct{})
268+
269+ go func() {
270+ for {
271+ select {
272+ case nt := <-session.notificationChannel:
273+ func() {
274+ mu.Lock()
275+ defer mu.Unlock()
276+ // if the done chan is closed, as the request is terminated, just return
277+ select {
278+ case <-done:
279+ return
280+ default:
281+ }
282+ defer func() {
283+ flusher, ok := w.(http.Flusher)
284+ if ok {
285+ flusher.Flush()
286+ }
287+ }()
288+
289+ // if there's notifications, upgradedHeader to SSE response
290+ if !upgradedHeader {
291+ w.Header().Set("Content-Type", "text/event-stream")
292+ w.Header().Set("Connection", "keep-alive")
293+ w.Header().Set("Cache-Control", "no-cache")
294+ w.WriteHeader(http.StatusAccepted)
295+ upgradedHeader = true
296+ }
297+ err := writeSSEEvent(w, nt)
298+ if err != nil {
299+ s.logger.Errorf("Failed to write SSE event: %v", err)
300+ return
301+ }
302+ }()
303+ case <-done:
304+ return
305+ case <-ctx.Done():
306+ return
307+ }
308+ }
309+ }()
310+
311+ // Process message through MCPServer
312+ response := s.server.HandleMessage(ctx, rawData)
313+ if response == nil {
314+ // For notifications, just send 202 Accepted with no body
315+ w.WriteHeader(http.StatusAccepted)
316+ return
317+ }
318+
319+ // Write response
320+ mu.Lock()
321+ defer mu.Unlock()
322+ // close the done chan before unlock
323+ defer close(done)
324+ if ctx.Err() != nil {
325+ return
326+ }
327+ // If client-server communication already upgraded to SSE stream
328+ if session.upgradeToSSE.Load() {
329+ if !upgradedHeader {
330+ w.Header().Set("Content-Type", "text/event-stream")
331+ w.Header().Set("Connection", "keep-alive")
332+ w.Header().Set("Cache-Control", "no-cache")
333+ w.WriteHeader(http.StatusAccepted)
334+ upgradedHeader = true
335+ }
336+ if err := writeSSEEvent(w, response); err != nil {
337+ s.logger.Errorf("Failed to write final SSE response event: %v", err)
338+ }
339+ } else {
340+ w.Header().Set("Content-Type", "application/json")
341+ if isInitializeRequest && sessionID != "" {
342+ // send the session ID back to the client
343+ w.Header().Set(headerKeySessionID, sessionID)
344+ }
345+ w.WriteHeader(http.StatusOK)
346+ err := json.NewEncoder(w).Encode(response)
347+ if err != nil {
348+ s.logger.Errorf("Failed to write response: %v", err)
349+ }
350+ }
351+}
352+
353+func (s *StreamableHTTPServer) handleGet(w http.ResponseWriter, r *http.Request) {
354+ // get request is for listening to notifications
355+ // https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#listening-for-messages-from-the-server
356+
357+ sessionID := r.Header.Get(headerKeySessionID)
358+ // the specification didn't say we should validate the session id
359+
360+ if sessionID == "" {
361+ // It's a stateless server,
362+ // but the MCP server requires a unique ID for registering, so we use a random one
363+ sessionID = uuid.New().String()
364+ }
365+
366+ session := newStreamableHttpSession(sessionID, s.sessionTools)
367+ if err := s.server.RegisterSession(r.Context(), session); err != nil {
368+ http.Error(w, fmt.Sprintf("Session registration failed: %v", err), http.StatusBadRequest)
369+ return
370+ }
371+ defer s.server.UnregisterSession(r.Context(), sessionID)
372+
373+ // Set the client context before handling the message
374+ w.Header().Set("Content-Type", "text/event-stream")
375+ w.Header().Set("Cache-Control", "no-cache")
376+ w.Header().Set("Connection", "keep-alive")
377+ w.WriteHeader(http.StatusAccepted)
378+
379+ flusher, ok := w.(http.Flusher)
380+ if !ok {
381+ http.Error(w, "Streaming unsupported", http.StatusInternalServerError)
382+ return
383+ }
384+ flusher.Flush()
385+
386+ // Start notification handler for this session
387+ done := make(chan struct{})
388+ defer close(done)
389+ writeChan := make(chan any, 16)
390+
391+ go func() {
392+ for {
393+ select {
394+ case nt := <-session.notificationChannel:
395+ select {
396+ case writeChan <- &nt:
397+ case <-done:
398+ return
399+ }
400+ case <-done:
401+ return
402+ }
403+ }
404+ }()
405+
406+ if s.listenHeartbeatInterval > 0 {
407+ // heartbeat to keep the connection alive
408+ go func() {
409+ ticker := time.NewTicker(s.listenHeartbeatInterval)
410+ defer ticker.Stop()
411+ for {
412+ select {
413+ case <-ticker.C:
414+ message := mcp.JSONRPCRequest{
415+ JSONRPC: "2.0",
416+ ID: mcp.NewRequestId(s.nextRequestID(sessionID)),
417+ Request: mcp.Request{
418+ Method: "ping",
419+ },
420+ }
421+ select {
422+ case writeChan <- message:
423+ case <-done:
424+ return
425+ }
426+ case <-done:
427+ return
428+ }
429+ }
430+ }()
431+ }
432+
433+ // Keep the connection open until the client disconnects
434+ //
435+ // There's will a Available() check when handler ends, and it maybe race with Flush(),
436+ // so we use a separate channel to send the data, inteading of flushing directly in other goroutine.
437+ for {
438+ select {
439+ case data := <-writeChan:
440+ if data == nil {
441+ continue
442+ }
443+ if err := writeSSEEvent(w, data); err != nil {
444+ s.logger.Errorf("Failed to write SSE event: %v", err)
445+ return
446+ }
447+ flusher.Flush()
448+ case <-r.Context().Done():
449+ return
450+ }
451+ }
452+}
453+
454+func (s *StreamableHTTPServer) handleDelete(w http.ResponseWriter, r *http.Request) {
455+ // delete request terminate the session
456+ sessionID := r.Header.Get(headerKeySessionID)
457+ notAllowed, err := s.sessionIdManager.Terminate(sessionID)
458+ if err != nil {
459+ http.Error(w, fmt.Sprintf("Session termination failed: %v", err), http.StatusInternalServerError)
460+ return
461+ }
462+ if notAllowed {
463+ http.Error(w, "Session termination not allowed", http.StatusMethodNotAllowed)
464+ return
465+ }
466+
467+ // remove the session relateddata from the sessionToolsStore
468+ s.sessionTools.delete(sessionID)
469+
470+ // remove current session's requstID information
471+ s.sessionRequestIDs.Delete(sessionID)
472+
473+ w.WriteHeader(http.StatusOK)
474+}
475+
476+func writeSSEEvent(w io.Writer, data any) error {
477+ jsonData, err := json.Marshal(data)
478+ if err != nil {
479+ return fmt.Errorf("failed to marshal data: %w", err)
480+ }
481+ _, err = fmt.Fprintf(w, "event: message\ndata: %s\n\n", jsonData)
482+ if err != nil {
483+ return fmt.Errorf("failed to write SSE event: %w", err)
484+ }
485+ return nil
486+}
487+
488+// writeJSONRPCError writes a JSON-RPC error response with the given error details.
489+func (s *StreamableHTTPServer) writeJSONRPCError(
490+ w http.ResponseWriter,
491+ id any,
492+ code int,
493+ message string,
494+) {
495+ response := createErrorResponse(id, code, message)
496+ w.Header().Set("Content-Type", "application/json")
497+ w.WriteHeader(http.StatusBadRequest)
498+ err := json.NewEncoder(w).Encode(response)
499+ if err != nil {
500+ s.logger.Errorf("Failed to write JSONRPCError: %v", err)
501+ }
502+}
503+
504+// nextRequestID gets the next incrementing requestID for the current session
505+func (s *StreamableHTTPServer) nextRequestID(sessionID string) int64 {
506+ actual, _ := s.sessionRequestIDs.LoadOrStore(sessionID, new(atomic.Int64))
507+ counter := actual.(*atomic.Int64)
508+ return counter.Add(1)
509+}
510+
511+// --- session ---
512+
513+type sessionToolsStore struct {
514+ mu sync.RWMutex
515+ tools map[string]map[string]ServerTool // sessionID -> toolName -> tool
516+}
517+
518+func newSessionToolsStore() *sessionToolsStore {
519+ return &sessionToolsStore{
520+ tools: make(map[string]map[string]ServerTool),
521+ }
522+}
523+
524+func (s *sessionToolsStore) get(sessionID string) map[string]ServerTool {
525+ s.mu.RLock()
526+ defer s.mu.RUnlock()
527+ return s.tools[sessionID]
528+}
529+
530+func (s *sessionToolsStore) set(sessionID string, tools map[string]ServerTool) {
531+ s.mu.Lock()
532+ defer s.mu.Unlock()
533+ s.tools[sessionID] = tools
534+}
535+
536+func (s *sessionToolsStore) delete(sessionID string) {
537+ s.mu.Lock()
538+ defer s.mu.Unlock()
539+ delete(s.tools, sessionID)
540+}
541+
542+// streamableHttpSession is a session for streamable-http transport
543+// When in POST handlers(request/notification), it's ephemeral, and only exists in the life of the request handler.
544+// When in GET handlers(listening), it's a real session, and will be registered in the MCP server.
545+type streamableHttpSession struct {
546+ sessionID string
547+ notificationChannel chan mcp.JSONRPCNotification // server -> client notifications
548+ tools *sessionToolsStore
549+ upgradeToSSE atomic.Bool
550+}
551+
552+func newStreamableHttpSession(sessionID string, toolStore *sessionToolsStore) *streamableHttpSession {
553+ return &streamableHttpSession{
554+ sessionID: sessionID,
555+ notificationChannel: make(chan mcp.JSONRPCNotification, 100),
556+ tools: toolStore,
557+ }
558+}
559+
560+func (s *streamableHttpSession) SessionID() string {
561+ return s.sessionID
562+}
563+
564+func (s *streamableHttpSession) NotificationChannel() chan<- mcp.JSONRPCNotification {
565+ return s.notificationChannel
566+}
567+
568+func (s *streamableHttpSession) Initialize() {
569+ // do nothing
570+ // the session is ephemeral, no real initialized action needed
571+}
572+
573+func (s *streamableHttpSession) Initialized() bool {
574+ // the session is ephemeral, no real initialized action needed
575+ return true
576+}
577+
578+var _ ClientSession = (*streamableHttpSession)(nil)
579+
580+func (s *streamableHttpSession) GetSessionTools() map[string]ServerTool {
581+ return s.tools.get(s.sessionID)
582+}
583+
584+func (s *streamableHttpSession) SetSessionTools(tools map[string]ServerTool) {
585+ s.tools.set(s.sessionID, tools)
586+}
587+
588+var _ SessionWithTools = (*streamableHttpSession)(nil)
589+
590+func (s *streamableHttpSession) UpgradeToSSEWhenReceiveNotification() {
591+ s.upgradeToSSE.Store(true)
592+}
593+
594+var _ SessionWithStreamableHTTPConfig = (*streamableHttpSession)(nil)
595+
596+// --- session id manager ---
597+
598+type SessionIdManager interface {
599+ Generate() string
600+ // Validate checks if a session ID is valid and not terminated.
601+ // Returns isTerminated=true if the ID is valid but belongs to a terminated session.
602+ // Returns err!=nil if the ID format is invalid or lookup failed.
603+ Validate(sessionID string) (isTerminated bool, err error)
604+ // Terminate marks a session ID as terminated.
605+ // Returns isNotAllowed=true if the server policy prevents client termination.
606+ // Returns err!=nil if the ID is invalid or termination failed.
607+ Terminate(sessionID string) (isNotAllowed bool, err error)
608+}
609+
610+// StatelessSessionIdManager does nothing, which means it has no session management, which is stateless.
611+type StatelessSessionIdManager struct{}
612+
613+func (s *StatelessSessionIdManager) Generate() string {
614+ return ""
615+}
616+func (s *StatelessSessionIdManager) Validate(sessionID string) (isTerminated bool, err error) {
617+ // In stateless mode, ignore session IDs completely - don't validate or reject them
618+ return false, nil
619+}
620+func (s *StatelessSessionIdManager) Terminate(sessionID string) (isNotAllowed bool, err error) {
621+ return false, nil
622+}
623+
624+// InsecureStatefulSessionIdManager generate id with uuid
625+// It won't validate the id indeed, so it could be fake.
626+// For more secure session id, use a more complex generator, like a JWT.
627+type InsecureStatefulSessionIdManager struct{}
628+
629+const idPrefix = "mcp-session-"
630+
631+func (s *InsecureStatefulSessionIdManager) Generate() string {
632+ return idPrefix + uuid.New().String()
633+}
634+func (s *InsecureStatefulSessionIdManager) Validate(sessionID string) (isTerminated bool, err error) {
635+ // validate the session id is a valid uuid
636+ if !strings.HasPrefix(sessionID, idPrefix) {
637+ return false, fmt.Errorf("invalid session id: %s", sessionID)
638+ }
639+ if _, err := uuid.Parse(sessionID[len(idPrefix):]); err != nil {
640+ return false, fmt.Errorf("invalid session id: %s", sessionID)
641+ }
642+ return false, nil
643+}
644+func (s *InsecureStatefulSessionIdManager) Terminate(sessionID string) (isNotAllowed bool, err error) {
645+ return false, nil
646+}
647+
648+// NewTestStreamableHTTPServer creates a test server for testing purposes
649+func NewTestStreamableHTTPServer(server *MCPServer, opts ...StreamableHTTPOption) *httptest.Server {
650+ sseServer := NewStreamableHTTPServer(server, opts...)
651+ testServer := httptest.NewServer(sseServer)
652+ return testServer
653+}
vendor/github.com/mark3labs/mcp-go/util/logger.gonew file+33
@@ -0,0 +1,33 @@
1+package util
2+
3+import (
4+ "log"
5+)
6+
7+// Logger defines a minimal logging interface
8+type Logger interface {
9+ Infof(format string, v ...any)
10+ Errorf(format string, v ...any)
11+}
12+
13+// --- Standard Library Logger Wrapper ---
14+
15+// DefaultStdLogger implements Logger using the standard library's log.Logger.
16+func DefaultLogger() Logger {
17+ return &stdLogger{
18+ logger: log.Default(),
19+ }
20+}
21+
22+// stdLogger wraps the standard library's log.Logger.
23+type stdLogger struct {
24+ logger *log.Logger
25+}
26+
27+func (l *stdLogger) Infof(format string, v ...any) {
28+ l.logger.Printf("INFO: "+format, v...)
29+}
30+
31+func (l *stdLogger) Errorf(format string, v ...any) {
32+ l.logger.Printf("ERROR: "+format, v...)
33+}
vendor/github.com/openai/openai-go/.release-please-manifest.json+1−1
@@ -1,3 +1,3 @@
11{
2− ".": "0.1.0-beta.2"
2+ ".": "1.8.2"
33}
vendor/github.com/openai/openai-go/.stats.yml+4−2
@@ -1,2 +1,4 @@
1−configured_endpoints: 80
2−openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-5ad6884898c07591750dde560118baf7074a59aecd1f367f930c5e42b04e848a.yml
1+configured_endpoints: 97
2+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a473967d1766dc155994d932fbc4a5bcbd1c140a37c20d0a4065e1bf0640536d.yml
3+openapi_spec_hash: 67cdc62b0d6c8b1de29b7dc54b265749
4+config_hash: 05c7d4a6f4d5983fe9550457114b47dd
vendor/github.com/openai/openai-go/CHANGELOG.md+352
@@ -1,5 +1,357 @@
11# Changelog
22
3+## 1.8.2 (2025-06-27)
4+
5+Full Changelog: [v1.8.1...v1.8.2](https://github.com/openai/openai-go/compare/v1.8.1...v1.8.2)
6+
7+### Bug Fixes
8+
9+* don't try to deserialize as json when ResponseBodyInto is []byte ([74ad0f8](https://github.com/openai/openai-go/commit/74ad0f8fab0f956234503a9ba26fbd395944dcf8))
10+* **pagination:** check if page data is empty in GetNextPage ([c9becdc](https://github.com/openai/openai-go/commit/c9becdc9908f2a1961160837c6ab8cd9064e7854))
11+
12+## 1.8.1 (2025-06-26)
13+
14+Full Changelog: [v1.8.0...v1.8.1](https://github.com/openai/openai-go/compare/v1.8.0...v1.8.1)
15+
16+### Chores
17+
18+* **api:** remove unsupported property ([e22316a](https://github.com/openai/openai-go/commit/e22316adcd8f2c5aa672b12453cbd287de0e1878))
19+* **docs:** update README to include links to docs on Webhooks ([7bb8f85](https://github.com/openai/openai-go/commit/7bb8f8549fdd98997b1d145cbae98ff0146b4e43))
20+
21+## 1.8.0 (2025-06-26)
22+
23+Full Changelog: [v1.7.0...v1.8.0](https://github.com/openai/openai-go/compare/v1.7.0...v1.8.0)
24+
25+### Features
26+
27+* **api:** webhook and deep research support ([f6a7e7d](https://github.com/openai/openai-go/commit/f6a7e7dcd8801facc4f8d981f1ca43786c10de1e))
28+
29+
30+### Chores
31+
32+* **internal:** add tests for breaking change detection ([339522d](https://github.com/openai/openai-go/commit/339522d38cd31b0753a8df37b8924f7e7dfb0b1d))
33+
34+## 1.7.0 (2025-06-23)
35+
36+Full Changelog: [v1.6.0...v1.7.0](https://github.com/openai/openai-go/compare/v1.6.0...v1.7.0)
37+
38+### Features
39+
40+* **api:** make model and inputs not required to create response ([19f0b76](https://github.com/openai/openai-go/commit/19f0b76378d35b3d81c60c85bf2e64d6bf85b9c2))
41+* **api:** update api shapes for usage and code interpreter ([d24d42c](https://github.com/openai/openai-go/commit/d24d42cba60e565627e8ffb1cac63a5085ddb6da))
42+* **client:** add escape hatch for null slice & maps ([9c633d6](https://github.com/openai/openai-go/commit/9c633d6f1dbcc0b153f42f831ee7e13d6fe62296))
43+
44+
45+### Chores
46+
47+* fix documentation of null map ([8f3a134](https://github.com/openai/openai-go/commit/8f3a134e500b1b7791ab855adaef2d7b10d2d1c3))
48+
49+## 1.6.0 (2025-06-17)
50+
51+Full Changelog: [v1.5.0...v1.6.0](https://github.com/openai/openai-go/compare/v1.5.0...v1.6.0)
52+
53+### Features
54+
55+* **api:** add reusable prompt IDs ([280c698](https://github.com/openai/openai-go/commit/280c698015eba5f6bd47e2fce038eb401f6ef0f2))
56+* **api:** manual updates ([740f840](https://github.com/openai/openai-go/commit/740f84006ac283a25f5ad96aaf845a3c8a51c6ac))
57+* **client:** add debug log helper ([5715c49](https://github.com/openai/openai-go/commit/5715c491c483f8dab4ea2a900c400384f6810024))
58+
59+
60+### Chores
61+
62+* **ci:** enable for pull requests ([9ed793a](https://github.com/openai/openai-go/commit/9ed793a51010423db464a7b7bd263d2fd275967f))
63+
64+## 1.5.0 (2025-06-10)
65+
66+Full Changelog: [v1.4.0...v1.5.0](https://github.com/openai/openai-go/compare/v1.4.0...v1.5.0)
67+
68+### Features
69+
70+* **api:** Add o3-pro model IDs ([3bbd0b8](https://github.com/openai/openai-go/commit/3bbd0b8f09030a6c571900d444742c4fc2a3c211))
71+
72+## 1.4.0 (2025-06-09)
73+
74+Full Changelog: [v1.3.0...v1.4.0](https://github.com/openai/openai-go/compare/v1.3.0...v1.4.0)
75+
76+### Features
77+
78+* **client:** allow overriding unions ([27c6299](https://github.com/openai/openai-go/commit/27c6299cb4ac275c6542b5691d81b795e65eeff6))
79+
80+
81+### Bug Fixes
82+
83+* **client:** cast to raw message when converting to params ([a3282b0](https://github.com/openai/openai-go/commit/a3282b01a8d9a2c0cd04f24b298bf2ffcd160ebd))
84+
85+## 1.3.0 (2025-06-03)
86+
87+Full Changelog: [v1.2.1...v1.3.0](https://github.com/openai/openai-go/compare/v1.2.1...v1.3.0)
88+
89+### Features
90+
91+* **api:** add new realtime and audio models, realtime session options ([8b8f62b](https://github.com/openai/openai-go/commit/8b8f62b8e185f3fe4aaa99e892df5d35638931a1))
92+
93+## 1.2.1 (2025-06-02)
94+
95+Full Changelog: [v1.2.0...v1.2.1](https://github.com/openai/openai-go/compare/v1.2.0...v1.2.1)
96+
97+### Bug Fixes
98+
99+* **api:** Fix evals and code interpreter interfaces ([7e244c7](https://github.com/openai/openai-go/commit/7e244c73caad6b4768cced9a798452f03b1165c8))
100+* fix error ([a200fca](https://github.com/openai/openai-go/commit/a200fca92c3fa413cf724f424077d1537fa2ca3e))
101+
102+
103+### Chores
104+
105+* make go mod tidy continue on error ([48f41c2](https://github.com/openai/openai-go/commit/48f41c2993bf6181018da859ae759951261f9ee2))
106+
107+## 1.2.0 (2025-05-29)
108+
109+Full Changelog: [v1.1.0...v1.2.0](https://github.com/openai/openai-go/compare/v1.1.0...v1.2.0)
110+
111+### Features
112+
113+* **api:** Config update for pakrym-stream-param ([84d59d5](https://github.com/openai/openai-go/commit/84d59d5cbc7521ddcc04435317903fd4ec3d17f6))
114+
115+
116+### Bug Fixes
117+
118+* **client:** return binary content from `get /containers/{container_id}/files/{file_id}/content` ([f8c8de1](https://github.com/openai/openai-go/commit/f8c8de18b720b224267d54da53d7d919ed0fdff3))
119+
120+
121+### Chores
122+
123+* deprecate Assistants API ([027470e](https://github.com/openai/openai-go/commit/027470e066ea6bbca1aeeb4fb9a8a3430babb84c))
124+* **internal:** fix release workflows ([fd46533](https://github.com/openai/openai-go/commit/fd4653316312755ccab7435fca9fb0a2d8bf8fbb))
125+
126+## 1.1.0 (2025-05-22)
127+
128+Full Changelog: [v1.0.0...v1.1.0](https://github.com/openai/openai-go/compare/v1.0.0...v1.1.0)
129+
130+### Features
131+
132+* **api:** add container endpoint ([2bd777d](https://github.com/openai/openai-go/commit/2bd777d6813b5dfcd3a2d339047a944c478dcd64))
133+* **api:** new API tools ([e7e2123](https://github.com/openai/openai-go/commit/e7e2123de7cafef515e07adde6edd45a7035b610))
134+* **api:** new streaming helpers for background responses ([422a0db](https://github.com/openai/openai-go/commit/422a0db3c674135e23dd200f5d8d785bd0be33e6))
135+
136+
137+### Chores
138+
139+* **docs:** grammar improvements ([f4b23dd](https://github.com/openai/openai-go/commit/f4b23dd31facfc8839310854521b48060ef76be2))
140+* improve devcontainer setup ([dfdaeec](https://github.com/openai/openai-go/commit/dfdaeec2d6dd5cd679514d60c49b68c5df9e1b1e))
141+
142+## 1.0.0 (2025-05-19)
143+
144+Full Changelog: [v0.1.0-beta.11...v1.0.0](https://github.com/openai/openai-go/compare/v0.1.0-beta.11...v1.0.0)
145+
146+### ⚠ BREAKING CHANGES
147+
148+* **client:** rename file array param variant
149+* **api:** improve naming and remove assistants
150+* **accumulator:** update casing ([#401](https://github.com/openai/openai-go/issues/401))
151+
152+### Features
153+
154+* **api:** improve naming and remove assistants ([4c623b8](https://github.com/openai/openai-go/commit/4c623b88a9025db1961cc57985eb7374342f43e7))
155+
156+
157+### Bug Fixes
158+
159+* **accumulator:** update casing ([#401](https://github.com/openai/openai-go/issues/401)) ([d59453c](https://github.com/openai/openai-go/commit/d59453c95b89fdd0b51305778dec0a39ce3a9d2a))
160+* **client:** correctly set stream key for multipart ([0ec68f0](https://github.com/openai/openai-go/commit/0ec68f0d779e7726931b1115eca9ae81eab59ba8))
161+* **client:** don't panic on marshal with extra null field ([9c15332](https://github.com/openai/openai-go/commit/9c153320272d212beaa516d4c70d54ae8053a958))
162+* **client:** increase max stream buffer size ([9456455](https://github.com/openai/openai-go/commit/945645559c5d68d9e28cf445d9c3b83e5fc6bd35))
163+* **client:** rename file array param variant ([4cfcf86](https://github.com/openai/openai-go/commit/4cfcf869280e7531fbbc8c00db0dd9271d07c423))
164+* **client:** use scanner for streaming ([aa58806](https://github.com/openai/openai-go/commit/aa58806bffc3aed68425c480414ddbb4dac3fa78))
165+
166+
167+### Chores
168+
169+* **docs:** typo fix ([#400](https://github.com/openai/openai-go/issues/400)) ([bececf2](https://github.com/openai/openai-go/commit/bececf24cd0324b7c991b7d7f1d3eff6bf71f996))
170+* **examples:** migrate enum ([#447](https://github.com/openai/openai-go/issues/447)) ([814dd8b](https://github.com/openai/openai-go/commit/814dd8b6cfe4eeb535dc8ecd161a409ea2eb6698))
171+* **examples:** migrate to latest version ([#444](https://github.com/openai/openai-go/issues/444)) ([1c8754f](https://github.com/openai/openai-go/commit/1c8754ff905ed023f6381c8493910d63039407de))
172+* **examples:** remove beta assisstants examples ([#445](https://github.com/openai/openai-go/issues/445)) ([5891583](https://github.com/openai/openai-go/commit/589158372be9c0517b5508f9ccd872fdb1fe480b))
173+* **example:** update fine-tuning ([#450](https://github.com/openai/openai-go/issues/450)) ([421e3c5](https://github.com/openai/openai-go/commit/421e3c5065ace2d5ddd3d13a036477fff9123e5f))
174+
175+## 0.1.0-beta.11 (2025-05-16)
176+
177+Full Changelog: [v0.1.0-beta.10...v0.1.0-beta.11](https://github.com/openai/openai-go/compare/v0.1.0-beta.10...v0.1.0-beta.11)
178+
179+### ⚠ BREAKING CHANGES
180+
181+* **client:** clearer array variant names
182+* **client:** rename resp package
183+* **client:** improve core function names
184+* **client:** improve union variant names
185+* **client:** improve param subunions & deduplicate types
186+
187+### Features
188+
189+* **api:** add image sizes, reasoning encryption ([0852fb3](https://github.com/openai/openai-go/commit/0852fb3101dc940761f9e4f32875bfcf3669eada))
190+* **api:** add o3 and o4-mini model IDs ([3fabca6](https://github.com/openai/openai-go/commit/3fabca6b5c610edfb7bcd0cab5334a06444df0b0))
191+* **api:** Add reinforcement fine-tuning api support ([831a124](https://github.com/openai/openai-go/commit/831a12451cfce907b5ae4d294b9c2ac95f40d97a))
192+* **api:** adding gpt-4.1 family of model IDs ([1ef19d4](https://github.com/openai/openai-go/commit/1ef19d4cc94992dc435d7d5f28b30c9b1d255cd4))
193+* **api:** adding new image model support ([bf17880](https://github.com/openai/openai-go/commit/bf17880e182549c5c0fc34ec05df3184f223bc00))
194+* **api:** manual updates ([11f5716](https://github.com/openai/openai-go/commit/11f5716afa86aa100f80f3fa127e1d49203e5e21))
195+* **api:** responses x eval api ([183aaf7](https://github.com/openai/openai-go/commit/183aaf700f1d7ffad4ac847627d9ace65379c459))
196+* **api:** Updating Assistants and Evals API schemas ([47ca619](https://github.com/openai/openai-go/commit/47ca619fa1b439cf3a68c98e48e9bf1942f0568b))
197+* **client:** add dynamic streaming buffer to handle large lines ([8e6aad6](https://github.com/openai/openai-go/commit/8e6aad6d54fc73f1fcc174e1f06c9b3cf00c2689))
198+* **client:** add helper method to generate constant structs ([ff82809](https://github.com/openai/openai-go/commit/ff828094b561fc11184fed83f04424b6f68f7781))
199+* **client:** add support for endpoint-specific base URLs in python ([072dce4](https://github.com/openai/openai-go/commit/072dce46486d373fa0f0de5415f5270b01c2d972))
200+* **client:** add support for reading base URL from environment variable ([0d37268](https://github.com/openai/openai-go/commit/0d372687d673990290bad583f1906a2b121960b2))
201+* **client:** clearer array variant names ([a5d8b5d](https://github.com/openai/openai-go/commit/a5d8b5d6b161e3083184586840b2cbe0606d8de1))
202+* **client:** experimental support for unmarshalling into param structs ([5234875](https://github.com/openai/openai-go/commit/523487582e15a47e2f409f183568551258f4b8fe))
203+* **client:** improve param subunions & deduplicate types ([8a78f37](https://github.com/openai/openai-go/commit/8a78f37c25abf10498d16d210de3078f491ff23e))
204+* **client:** rename resp package ([4433516](https://github.com/openai/openai-go/commit/443351625ee290937a25425719b099ce785bd21b))
205+* **client:** support more time formats ([ec171b2](https://github.com/openai/openai-go/commit/ec171b2405c46f9cf04560760da001f7133d2fec))
206+* fix lint ([9c50a1e](https://github.com/openai/openai-go/commit/9c50a1eb9f93b578cb78085616f6bfab69f21dbc))
207+
208+
209+### Bug Fixes
210+
211+* **client:** clean up reader resources ([710b92e](https://github.com/openai/openai-go/commit/710b92eaa7e94c03aeeca7479668677b32acb154))
212+* **client:** correctly update body in WithJSONSet ([f2d7118](https://github.com/openai/openai-go/commit/f2d7118295dd3073aa449426801d02e6f60bdaa3))
213+* **client:** improve core function names ([9f312a9](https://github.com/openai/openai-go/commit/9f312a9b14f5424d44d5834f1b82f3d3fcd57db2))
214+* **client:** improve union variant names ([a2c3de9](https://github.com/openai/openai-go/commit/a2c3de9e6c9f6e406b953f6de2eb78d1e72ec1b5))
215+* **client:** include path for type names in example code ([69561c5](https://github.com/openai/openai-go/commit/69561c549e18bd16a3641d62769479b125a4e955))
216+* **client:** resolve issue with optional multipart files ([910d173](https://github.com/openai/openai-go/commit/910d1730e97a03898e5dee7c889844a2ccec3e56))
217+* **client:** time format encoding fix ([ca17553](https://github.com/openai/openai-go/commit/ca175533ac8a17d36be1f531bbaa89c770da3f58))
218+* **client:** unmarshal responses properly ([fc9fec3](https://github.com/openai/openai-go/commit/fc9fec3c466ba9f633c3f7a4eebb5ebd3b85e8ac))
219+* handle empty bodies in WithJSONSet ([8372464](https://github.com/openai/openai-go/commit/83724640c6c00dcef1547dcabace309f17d14afc))
220+* **pagination:** handle errors when applying options ([eebf84b](https://github.com/openai/openai-go/commit/eebf84bf19f0eb6d9fa21e64bb83b0258e8cb42c))
221+
222+
223+### Chores
224+
225+* **ci:** add timeout thresholds for CI jobs ([26b0dd7](https://github.com/openai/openai-go/commit/26b0dd760c142ca3aa287e8441bbe44cc8b3be0b))
226+* **ci:** only use depot for staging repos ([7682154](https://github.com/openai/openai-go/commit/7682154fdbcbe2a2ffdb2df590647a1712d52275))
227+* **ci:** run on more branches and use depot runners ([d7badbc](https://github.com/openai/openai-go/commit/d7badbc0d17bcf3cffec332f65cb68e531cb3176))
228+* **docs:** document pre-request options ([4befa5a](https://github.com/openai/openai-go/commit/4befa5a48ca61372715f36c45e72eb159d95bf2d))
229+* **docs:** update respjson package name ([9a00229](https://github.com/openai/openai-go/commit/9a002299a91e1145f053c51b1a4de10298fd2f43))
230+* **readme:** improve formatting ([a847e8d](https://github.com/openai/openai-go/commit/a847e8df45f725f9652fcea53ce57d3b9046efc7))
231+* **utils:** add internal resp to param utility ([239c4e2](https://github.com/openai/openai-go/commit/239c4e2cb32c7af71ab14668ccc2f52ea59653f9))
232+
233+
234+### Documentation
235+
236+* update documentation links to be more uniform ([f5f0bb0](https://github.com/openai/openai-go/commit/f5f0bb05ee705d84119806f8e703bf2e0becb1fa))
237+
238+## 0.1.0-beta.10 (2025-04-14)
239+
240+Full Changelog: [v0.1.0-beta.9...v0.1.0-beta.10](https://github.com/openai/openai-go/compare/v0.1.0-beta.9...v0.1.0-beta.10)
241+
242+### Chores
243+
244+* **internal:** expand CI branch coverage ([#369](https://github.com/openai/openai-go/issues/369)) ([258dda8](https://github.com/openai/openai-go/commit/258dda8007a69b9c2720b225ee6d27474d676a93))
245+* **internal:** reduce CI branch coverage ([a2f7c03](https://github.com/openai/openai-go/commit/a2f7c03eb984d98f29f908df103ea1743f2e3d9a))
246+
247+## 0.1.0-beta.9 (2025-04-09)
248+
249+Full Changelog: [v0.1.0-beta.8...v0.1.0-beta.9](https://github.com/openai/openai-go/compare/v0.1.0-beta.8...v0.1.0-beta.9)
250+
251+### Chores
252+
253+* workaround build errors ([#366](https://github.com/openai/openai-go/issues/366)) ([adeb003](https://github.com/openai/openai-go/commit/adeb003cab8efbfbf4424e03e96a0f5e728551cb))
254+
255+## 0.1.0-beta.8 (2025-04-09)
256+
257+Full Changelog: [v0.1.0-beta.7...v0.1.0-beta.8](https://github.com/openai/openai-go/compare/v0.1.0-beta.7...v0.1.0-beta.8)
258+
259+### Features
260+
261+* **api:** Add evalapi to sdk ([#360](https://github.com/openai/openai-go/issues/360)) ([88977d1](https://github.com/openai/openai-go/commit/88977d1868dbbe0060c56ba5dac8eb19773e4938))
262+* **api:** manual updates ([#363](https://github.com/openai/openai-go/issues/363)) ([5d068e0](https://github.com/openai/openai-go/commit/5d068e0053172db7f5b75038aa215eee074eeeed))
263+* **client:** add escape hatch to omit required param fields ([#354](https://github.com/openai/openai-go/issues/354)) ([9690d6b](https://github.com/openai/openai-go/commit/9690d6b49f8b00329afc038ec15116750853e620))
264+* **client:** support custom http clients ([#357](https://github.com/openai/openai-go/issues/357)) ([b5a624f](https://github.com/openai/openai-go/commit/b5a624f658cad774094427b36b05e446b41e8c52))
265+
266+
267+### Chores
268+
269+* **docs:** readme improvements ([#356](https://github.com/openai/openai-go/issues/356)) ([b2f8539](https://github.com/openai/openai-go/commit/b2f8539d6316e3443aa733be2c95926696119c13))
270+* **internal:** fix examples ([#361](https://github.com/openai/openai-go/issues/361)) ([de398b4](https://github.com/openai/openai-go/commit/de398b453d398299eb80c15f8fdb2bcbef5eeed6))
271+* **internal:** skip broken test ([#362](https://github.com/openai/openai-go/issues/362)) ([cccead9](https://github.com/openai/openai-go/commit/cccead9ba916142ac8fbe6e8926d706511e32ae3))
272+* **tests:** improve enum examples ([#359](https://github.com/openai/openai-go/issues/359)) ([e0b9739](https://github.com/openai/openai-go/commit/e0b9739920114d6e991d3947b67fdf62cfaa09c7))
273+
274+## 0.1.0-beta.7 (2025-04-07)
275+
276+Full Changelog: [v0.1.0-beta.6...v0.1.0-beta.7](https://github.com/openai/openai-go/compare/v0.1.0-beta.6...v0.1.0-beta.7)
277+
278+### Features
279+
280+* **client:** make response union's AsAny method type safe ([#352](https://github.com/openai/openai-go/issues/352)) ([1252f56](https://github.com/openai/openai-go/commit/1252f56c917e57d6d2b031501b2ff5f89f87cf87))
281+
282+
283+### Chores
284+
285+* **docs:** doc improvements ([#350](https://github.com/openai/openai-go/issues/350)) ([80debc8](https://github.com/openai/openai-go/commit/80debc824eaacb4b07c8f3e8b1d0488d860d5be5))
286+
287+## 0.1.0-beta.6 (2025-04-04)
288+
289+Full Changelog: [v0.1.0-beta.5...v0.1.0-beta.6](https://github.com/openai/openai-go/compare/v0.1.0-beta.5...v0.1.0-beta.6)
290+
291+### Features
292+
293+* **api:** manual updates ([4e39609](https://github.com/openai/openai-go/commit/4e39609d499b88039f1c90cc4b56e26f28fd58ea))
294+* **client:** support unions in query and forms ([#347](https://github.com/openai/openai-go/issues/347)) ([cf8af37](https://github.com/openai/openai-go/commit/cf8af373ab7c019c75e886855009ffaca320d0e3))
295+
296+## 0.1.0-beta.5 (2025-04-03)
297+
298+Full Changelog: [v0.1.0-beta.4...v0.1.0-beta.5](https://github.com/openai/openai-go/compare/v0.1.0-beta.4...v0.1.0-beta.5)
299+
300+### Features
301+
302+* **api:** manual updates ([563cc50](https://github.com/openai/openai-go/commit/563cc505f2ab17749bb77e937342a6614243b975))
303+* **client:** omitzero on required id parameter ([#339](https://github.com/openai/openai-go/issues/339)) ([c0b4842](https://github.com/openai/openai-go/commit/c0b484266ccd9faee66873916d8c0c92ea9f1014))
304+
305+
306+### Bug Fixes
307+
308+* **client:** return error on bad custom url instead of panic ([#341](https://github.com/openai/openai-go/issues/341)) ([a06c5e6](https://github.com/openai/openai-go/commit/a06c5e632242e53d3fdcc8964931acb533a30b7e))
309+* **client:** support multipart encoding array formats ([#342](https://github.com/openai/openai-go/issues/342)) ([5993b28](https://github.com/openai/openai-go/commit/5993b28309d02c2d748b54d98934ef401dcd193a))
310+* **client:** unmarshal stream events into fresh memory ([#340](https://github.com/openai/openai-go/issues/340)) ([52c3e08](https://github.com/openai/openai-go/commit/52c3e08f51d471d728e5acd16b3c304b51be2d03))
311+
312+## 0.1.0-beta.4 (2025-04-02)
313+
314+Full Changelog: [v0.1.0-beta.3...v0.1.0-beta.4](https://github.com/openai/openai-go/compare/v0.1.0-beta.3...v0.1.0-beta.4)
315+
316+### Features
317+
318+* **api:** manual updates ([bc4fe73](https://github.com/openai/openai-go/commit/bc4fe73eec9c4d39229e4beae8eaafb55b1d3364))
319+* **api:** manual updates ([aa7ff10](https://github.com/openai/openai-go/commit/aa7ff10b0616a6b2ece45cb10e9c83f25e35aded))
320+
321+
322+### Chores
323+
324+* **docs:** update file uploads in README ([#333](https://github.com/openai/openai-go/issues/333)) ([471c452](https://github.com/openai/openai-go/commit/471c4525c94e83cf4b78cb6c9b2f65a8a27bf3ce))
325+* **internal:** codegen related update ([#335](https://github.com/openai/openai-go/issues/335)) ([48422dc](https://github.com/openai/openai-go/commit/48422dcca333ab808ccb02506c033f1c69d2aa19))
326+* Remove deprecated/unused remote spec feature ([c5077a1](https://github.com/openai/openai-go/commit/c5077a154a6db79b73cf4978bdc08212c6da6423))
327+
328+## 0.1.0-beta.3 (2025-03-28)
329+
330+Full Changelog: [v0.1.0-beta.2...v0.1.0-beta.3](https://github.com/openai/openai-go/compare/v0.1.0-beta.2...v0.1.0-beta.3)
331+
332+### ⚠ BREAKING CHANGES
333+
334+* **client:** add enums ([#327](https://github.com/openai/openai-go/issues/327))
335+
336+### Features
337+
338+* **api:** add `get /chat/completions` endpoint ([e8ed116](https://github.com/openai/openai-go/commit/e8ed1168576c885cb26fbf819b9c8d24975749bd))
339+* **api:** add `get /responses/{response_id}/input_items` endpoint ([8870c26](https://github.com/openai/openai-go/commit/8870c26f010a596adcf37ac10dba096bdd4394e3))
340+
341+
342+### Bug Fixes
343+
344+* **client:** add enums ([#327](https://github.com/openai/openai-go/issues/327)) ([b0e3afb](https://github.com/openai/openai-go/commit/b0e3afbd6f18fd9fc2a5ea9174bd7ec0ac0614db))
345+
346+
347+### Chores
348+
349+* add hash of OpenAPI spec/config inputs to .stats.yml ([104b786](https://github.com/openai/openai-go/commit/104b7861bb025514999b143f7d1de45d2dab659f))
350+* add request options to client tests ([#321](https://github.com/openai/openai-go/issues/321)) ([f5239ce](https://github.com/openai/openai-go/commit/f5239ceecf36835341eac5121ed1770020c4806a))
351+* **api:** updates to supported Voice IDs ([#325](https://github.com/openai/openai-go/issues/325)) ([477727a](https://github.com/openai/openai-go/commit/477727a44b0fb72493c4749cc60171e0d30f98ec))
352+* **docs:** improve security documentation ([#319](https://github.com/openai/openai-go/issues/319)) ([0271053](https://github.com/openai/openai-go/commit/027105363ab30ac3e189234908169faf94e0ca49))
353+* fix typos ([#324](https://github.com/openai/openai-go/issues/324)) ([dba15f7](https://github.com/openai/openai-go/commit/dba15f74d63814ce16f778e1017a209a42f46179))
354+
3355## 0.1.0-beta.2 (2025-03-22)
4356
5357Full Changelog: [v0.1.0-beta.1...v0.1.0-beta.2](https://github.com/openai/openai-go/compare/v0.1.0-beta.1...v0.1.0-beta.2)
vendor/github.com/openai/openai-go/CONTRIBUTING.md+1−1
@@ -4,7 +4,7 @@ To set up the repository, run:
44
55```sh
66$ ./scripts/bootstrap
7−$ ./scripts/build
7+$ ./scripts/lint
88```
99
1010This will install all the required dependencies and build the SDK.
vendor/github.com/openai/openai-go/MIGRATION.md+14−14
@@ -227,15 +227,15 @@ var name *string = animal.GetName()
227227
228228The old SDK had a function `param.Null[T]()` which could set `param.Field[T]` to `null`.
229229
230−The new SDK uses `param.NullOpt[T]()` for to set a `param.Opt[T]` to `null`,
231−and `param.NullObj[T]()` to set a param struct `T` to `null`.
230+The new SDK uses `param.Null[T]()` for to set a `param.Opt[T]` to `null`,
231+but `param.NullStruct[T]()` to set a param struct `T` to `null`.
232232
233233```diff
234−- var nullObj param.Field[BarParam] = param.Null[BarParam]()
235−+ var nullObj BarParam = param.NullObj[BarParam]()
236−
237234- var nullPrimitive param.Field[int64] = param.Null[int64]()
238−+ var nullPrimitive param.Opt[int64] = param.NullOpt[int64]()
235++ var nullPrimitive param.Opt[int64] = param.Null[int64]()
236+
237+- var nullStruct param.Field[BarParam] = param.Null[BarParam]()
238++ var nullStruct BarParam = param.NullStruct[BarParam]()
239239```
240240
241241## Sending custom values
@@ -248,7 +248,7 @@ foo := FooParams{
248248 A: param.String("hello"),
249249- B: param.Raw[string](12) // sending `12` instead of a string
250250}
251−+ foo.WithExtraFields(map[string]any{
251++ foo.SetExtraFields(map[string]any{
252252+ "B": 12,
253253+ })
254254```
@@ -257,20 +257,20 @@ foo := FooParams{
257257
258258## Checking for presence of optional fields
259259
260−The `.IsNull()` method has been changed to `.IsPresent()` to better reflect its behavior.
260+The `.IsNull()` method has been changed to `.Valid()` to better reflect its behavior.
261261
262262```diff
263263- if !resp.Foo.JSON.Bar.IsNull() {
264−+ if resp.Foo.JSON.Bar.IsPresent() {
264++ if resp.Foo.JSON.Bar.Valid() {
265265 println("bar is present:", resp.Foo.Bar)
266266}
267267```
268268
269−| Previous | New | Returns true for values |
270−| -------------- | ------------------- | ----------------------- |
271−| `.IsNull()` | `!.IsPresent()` | `null` or Omitted |
272−| `.IsMissing()` | `.Raw() == ""` | Omitted |
273−| | `.IsExplicitNull()` | `null` |
269+| Previous | New | Returns true for values |
270+| -------------- | ------------------------ | ----------------------- |
271+| `.IsNull()` | `!.Valid()` | `null` or Omitted |
272+| `.IsMissing()` | `.Raw() == resp.Omitted` | Omitted |
273+| | `.Raw() == resp.Null` |
274274
275275## Checking Raw JSON of a response
276276
vendor/github.com/openai/openai-go/README.md+219−79
@@ -2,8 +2,8 @@
22
33<a href="https://pkg.go.dev/github.com/openai/openai-go"><img src="https://pkg.go.dev/badge/github.com/openai/openai-go.svg" alt="Go Reference"></a>
44
5−The OpenAI Go library provides convenient access to [the OpenAI REST
6−API](https://platform.openai.com/docs) from applications written in Go. The full API of this library can be found in [api.md](api.md).
5+The OpenAI Go library provides convenient access to the [OpenAI REST API](https://platform.openai.com/docs)
6+from applications written in Go.
77
88> [!WARNING]
99> The latest version of this package uses a new design with significant breaking changes.
@@ -26,7 +26,7 @@ Or to pin the version:
2626<!-- x-release-please-start-version -->
2727
2828```sh
29−go get -u 'github.com/openai/openai-go@v0.1.0-beta.2'
29+go get -u 'github.com/openai/openai-go@v1.8.2'
3030```
3131
3232<!-- x-release-please-end -->
@@ -295,52 +295,59 @@ func main() {
295295The openai library uses the [`omitzero`](https://tip.golang.org/doc/go1.24#encodingjsonpkgencodingjson)
296296semantics from the Go 1.24+ `encoding/json` release for request fields.
297297
298−Required primitive fields (`int64`, `string`, etc.) feature the tag <code>\`json:...,required\`</code>. These
298+Required primitive fields (`int64`, `string`, etc.) feature the tag <code>\`json:"...,required"\`</code>. These
299299fields are always serialized, even their zero values.
300300
301−Optional primitive types are wrapped in a `param.Opt[T]`. Use the provided constructors set `param.Opt[T]` fields such as `openai.String(string)`, `openai.Int(int64)`, etc.
301+Optional primitive types are wrapped in a `param.Opt[T]`. These fields can be set with the provided constructors, `openai.String(string)`, `openai.Int(int64)`, etc.
302302
303−Optional primitives, maps, slices and structs and string enums (represented as `string`) always feature the
304−tag <code>\`json:"...,omitzero"\`</code>. Their zero values are considered omitted.
303+Any `param.Opt[T]`, map, slice, struct or string enum uses the
304+tag <code>\`json:"...,omitzero"\`</code>. Its zero value is considered omitted.
305305
306−Any non-nil slice of length zero will serialize as an empty JSON array, `"[]"`. Similarly, any non-nil map with length zero with serialize as an empty JSON object, `"{}"`.
307−
308−To send `null` instead of an `param.Opt[T]`, use `param.NullOpt[T]()`.
309−To send `null` instead of a struct, use `param.NullObj[T]()`, where `T` is a struct.
310−To send a custom value instead of a struct, use `param.OverrideObj[T](value)`.
311−
312−To override request structs contain a `.WithExtraFields(map[string]any)` method which can be used to
313−send non-conforming fields in the request body. Extra fields take higher precedence than normal
314−fields.
306+The `param.IsOmitted(any)` function can confirm the presence of any `omitzero` field.
315307
316308```go
317−params := FooParams{
318− ID: "id_xxx", // required property
319− Name: openai.String("hello"), // optional property
320− Description: param.NullOpt[string](), // explicit null property
309+p := openai.ExampleParams{
310+ ID: "id_xxx", // required property
311+ Name: openai.String("..."), // optional property
321312
322313 Point: openai.Point{
323− X: 0, // required field will serialize as 0
314+ X: 0, // required field will serialize as 0
324315 Y: openai.Int(1), // optional field will serialize as 1
325− // ... omitted non-required fields will not be serialized
326− }),
316+ // ... omitted non-required fields will not be serialized
317+ },
327318
328319 Origin: openai.Origin{}, // the zero value of [Origin] is considered omitted
329320}
321+```
322+
323+To send `null` instead of a `param.Opt[T]`, use `param.Null[T]()`.
324+To send `null` instead of a struct `T`, use `param.NullStruct[T]()`.
325+
326+```go
327+p.Name = param.Null[string]() // 'null' instead of string
328+p.Point = param.NullStruct[Point]() // 'null' instead of struct
329+
330+param.IsNull(p.Name) // true
331+param.IsNull(p.Point) // true
332+```
330333
334+Request structs contain a `.SetExtraFields(map[string]any)` method which can send non-conforming
335+fields in the request body. Extra fields overwrite any struct fields with a matching
336+key. For security reasons, only use `SetExtraFields` with trusted data.
337+
338+To send a custom value instead of a struct, use `param.Override[T](value)`.
339+
340+```go
331341// In cases where the API specifies a given type,
332−// but you want to send something else, use [WithExtraFields]:
333−params.WithExtraFields(map[string]any{
342+// but you want to send something else, use [SetExtraFields]:
343+p.SetExtraFields(map[string]any{
334344 "x": 0.01, // send "x" as a float instead of int
335345})
336346
337347// Send a number instead of an object
338−custom := param.OverrideObj[openai.FooParams](12)
348+custom := param.Override[openai.FooParams](12)
339349```
340350
341−When available, use the `.IsPresent()` method to check if an optional parameter is not omitted or `null`.
342−Otherwise, the `param.IsOmitted(any)` function can confirm the presence of any `omitzero` field.
343−
344351### Request unions
345352
346353Unions are represented as a struct with fields prefixed by "Of" for each of it's variants,
@@ -352,8 +359,8 @@ These methods return a mutable pointer to the underlying data, if present.
352359```go
353360// Only one field can be non-zero, use param.IsOmitted() to check if a field is set
354361type AnimalUnionParam struct {
355− OfCat *Cat `json:",omitzero,inline`
356− OfDog *Dog `json:",omitzero,inline`
362+ OfCat *Cat `json:",omitzero,inline`
363+ OfDog *Dog `json:",omitzero,inline`
357364}
358365
359366animal := AnimalUnionParam{
@@ -373,34 +380,54 @@ if address := animal.GetOwner().GetAddress(); address != nil {
373380
374381### Response objects
375382
376−All fields in response structs are value types (not pointers or wrappers).
383+All fields in response structs are ordinary value types (not pointers or wrappers).
384+Response structs also include a special `JSON` field containing metadata about
385+each property.
386+
387+```go
388+type Animal struct {
389+ Name string `json:"name,nullable"`
390+ Owners int `json:"owners"`
391+ Age int `json:"age"`
392+ JSON struct {
393+ Name respjson.Field
394+ Owner respjson.Field
395+ Age respjson.Field
396+ ExtraFields map[string]respjson.Field
397+ } `json:"-"`
398+}
399+```
377400
378−If a given field is `null`, not present, or invalid, the corresponding field
379−will simply be its zero value.
401+To handle optional data, use the `.Valid()` method on the JSON field.
402+`.Valid()` returns true if a field is not `null`, not present, or couldn't be marshaled.
380403
381−All response structs also include a special `JSON` field, containing more detailed
382−information about each property, which you can use like so:
404+If `.Valid()` is false, the corresponding field will simply be its zero value.
383405
384406```go
385−if res.Name == "" {
386− // true if `"name"` was unmarshalled successfully
387− res.JSON.Name.IsPresent()
388−
389− res.JSON.Name.IsExplicitNull() // true if `"name"` is explicitly null
390− res.JSON.Name.Raw() == "" // true if `"name"` field does not exist
391−
392− // When the API returns data that cannot be coerced to the expected type:
393− if !res.JSON.Name.IsPresent() && res.JSON.Name.Raw() != "" {
394− raw := res.JSON.Name.Raw()
395−
396− legacyName := struct{
397− First string `json:"first"`
398− Last string `json:"last"`
399− }{}
400− json.Unmarshal([]byte(raw), &legacyName)
401− name = legacyName.First + " " + legacyName.Last
402− }
403−}
407+raw := `{"owners": 1, "name": null}`
408+
409+var res Animal
410+json.Unmarshal([]byte(raw), &res)
411+
412+// Accessing regular fields
413+
414+res.Owners // 1
415+res.Name // ""
416+res.Age // 0
417+
418+// Optional field checks
419+
420+res.JSON.Owners.Valid() // true
421+res.JSON.Name.Valid() // false
422+res.JSON.Age.Valid() // false
423+
424+// Raw JSON values
425+
426+res.JSON.Owners.Raw() // "1"
427+res.JSON.Name.Raw() == "null" // true
428+res.JSON.Name.Raw() == respjson.Null // true
429+res.JSON.Age.Raw() == "" // true
430+res.JSON.Age.Raw() == respjson.Omitted // true
404431```
405432
406433These `.JSON` structs also include an `ExtraFields` map containing
@@ -423,31 +450,27 @@ the properties but prefixed with `Of` and feature the tag `json:"...,inline"`.
423450
424451```go
425452type AnimalUnion struct {
426− OfString string `json:",inline"`
427− Name string `json:"name"`
428− Owner Person `json:"owner"`
453+ // From variants [Dog], [Cat]
454+ Owner Person `json:"owner"`
455+ // From variant [Dog]
456+ DogBreed string `json:"dog_breed"`
457+ // From variant [Cat]
458+ CatBreed string `json:"cat_breed"`
429459 // ...
460+
430461 JSON struct {
431− OfString resp.Field
432− Name resp.Field
433− Owner resp.Field
462+ Owner respjson.Field
434463 // ...
435− }
464+ } `json:"-"`
436465}
437466
438467// If animal variant
439−if animal.Owner.Address.JSON.ZipCode == "" {
468+if animal.Owner.Address.ZipCode == "" {
440469 panic("missing zip code")
441470}
442471
443−// If string variant
444−if !animal.OfString == "" {
445− panic("expected a name")
446−}
447−
448472// Switch on the variant
449−switch variant := animalOrName.AsAny().(type) {
450−case string:
473+switch variant := animal.AsAny().(type) {
451474case Dog:
452475case Cat:
453476default:
@@ -476,6 +499,8 @@ client.Chat.Completions.New(context.TODO(), ...,
476499)
477500```
478501
502+The request option `option.WithDebugLog(nil)` may be helpful while debugging.
503+
479504See the [full list of request options](https://pkg.go.dev/github.com/openai/openai-go/option).
480505
481506### Pagination
@@ -527,7 +552,7 @@ To handle errors, we recommend that you use the `errors.As` pattern:
527552
528553```go
529554_, err := client.FineTuning.Jobs.New(context.TODO(), openai.FineTuningJobNewParams{
530− Model: "babbage-002",
555+ Model: openai.FineTuningJobNewParamsModelBabbage002,
531556 TrainingFile: "file-abc123",
532557})
533558if err != nil {
@@ -564,7 +589,7 @@ client.Chat.Completions.New(
564589 },
565590 },
566591 }},
567− Model: shared.ChatModelO3Mini,
592+ Model: shared.ChatModelGPT4_1,
568593 },
569594 // This sets the per-retry timeout
570595 option.WithRequestTimeout(20*time.Second),
@@ -581,30 +606,145 @@ The file name and content-type can be customized by implementing `Name() string`
581606string` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a
582607file returned by `os.Open` will be sent with the file name on disk.
583608
584−We also provide a helper `openai.FileParam(reader io.Reader, filename string, contentType string)`
609+We also provide a helper `openai.File(reader io.Reader, filename string, contentType string)`
585610which can be used to wrap any `io.Reader` with the appropriate file name and content type.
586611
587612```go
588613// A file from the file system
589614file, err := os.Open("input.jsonl")
590615openai.FileNewParams{
591− File: openai.F[io.Reader](file),
616+ File: file,
592617 Purpose: openai.FilePurposeFineTune,
593618}
594619
595620// A file from a string
596621openai.FileNewParams{
597− File: openai.F[io.Reader](strings.NewReader("my file contents")),
622+ File: strings.NewReader("my file contents"),
598623 Purpose: openai.FilePurposeFineTune,
599624}
600625
601626// With a custom filename and contentType
602627openai.FileNewParams{
603− File: openai.FileParam(strings.NewReader(`{"hello": "foo"}`), "file.go", "application/json"),
628+ File: openai.File(strings.NewReader(`{"hello": "foo"}`), "file.go", "application/json"),
604629 Purpose: openai.FilePurposeFineTune,
605630}
606631```
607632
633+## Webhook Verification
634+
635+Verifying webhook signatures is _optional but encouraged_.
636+
637+For more information about webhooks, see [the API docs](https://platform.openai.com/docs/guides/webhooks).
638+
639+### Parsing webhook payloads
640+
641+For most use cases, you will likely want to verify the webhook and parse the payload at the same time. To achieve this, we provide the method `client.Webhooks.Unwrap()`, which parses a webhook request and verifies that it was sent by OpenAI. This method will return an error if the signature is invalid.
642+
643+Note that the `body` parameter should be the raw JSON bytes sent from the server (do not parse it first). The `Unwrap()` method will parse this JSON for you into an event object after verifying the webhook was sent from OpenAI.
644+
645+```go
646+package main
647+
648+import (
649+ "io"
650+ "log"
651+ "net/http"
652+ "os"
653+
654+ "github.com/gin-gonic/gin"
655+ "github.com/openai/openai-go"
656+ "github.com/openai/openai-go/option"
657+ "github.com/openai/openai-go/webhooks"
658+)
659+
660+func main() {
661+ client := openai.NewClient(
662+ option.WithWebhookSecret(os.Getenv("OPENAI_WEBHOOK_SECRET")), // env var used by default; explicit here.
663+ )
664+
665+ r := gin.Default()
666+
667+ r.POST("/webhook", func(c *gin.Context) {
668+ body, err := io.ReadAll(c.Request.Body)
669+ if err != nil {
670+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Error reading request body"})
671+ return
672+ }
673+ defer c.Request.Body.Close()
674+
675+ webhookEvent, err := client.Webhooks.Unwrap(body, c.Request.Header)
676+ if err != nil {
677+ log.Printf("Invalid webhook signature: %v", err)
678+ c.JSON(http.StatusBadRequest, gin.H{"error": "invalid signature"})
679+ return
680+ }
681+
682+ switch event := webhookEvent.AsAny().(type) {
683+ case webhooks.ResponseCompletedWebhookEvent:
684+ log.Printf("Response completed: %+v", event.Data)
685+ case webhooks.ResponseFailedWebhookEvent:
686+ log.Printf("Response failed: %+v", event.Data)
687+ default:
688+ log.Printf("Unhandled event type: %T", event)
689+ }
690+
691+ c.JSON(http.StatusOK, gin.H{"message": "ok"})
692+ })
693+
694+ r.Run(":8000")
695+}
696+```
697+
698+### Verifying webhook payloads directly
699+
700+In some cases, you may want to verify the webhook separately from parsing the payload. If you prefer to handle these steps separately, we provide the method `client.Webhooks.VerifySignature()` to _only verify_ the signature of a webhook request. Like `Unwrap()`, this method will return an error if the signature is invalid.
701+
702+Note that the `body` parameter should be the raw JSON bytes sent from the server (do not parse it first). You will then need to parse the body after verifying the signature.
703+
704+```go
705+package main
706+
707+import (
708+ "encoding/json"
709+ "io"
710+ "log"
711+ "net/http"
712+ "os"
713+
714+ "github.com/gin-gonic/gin"
715+ "github.com/openai/openai-go"
716+ "github.com/openai/openai-go/option"
717+)
718+
719+func main() {
720+ client := openai.NewClient(
721+ option.WithWebhookSecret(os.Getenv("OPENAI_WEBHOOK_SECRET")), // env var used by default; explicit here.
722+ )
723+
724+ r := gin.Default()
725+
726+ r.POST("/webhook", func(c *gin.Context) {
727+ body, err := io.ReadAll(c.Request.Body)
728+ if err != nil {
729+ c.JSON(http.StatusInternalServerError, gin.H{"error": "Error reading request body"})
730+ return
731+ }
732+ defer c.Request.Body.Close()
733+
734+ err = client.Webhooks.VerifySignature(body, c.Request.Header)
735+ if err != nil {
736+ log.Printf("Invalid webhook signature: %v", err)
737+ c.JSON(http.StatusBadRequest, gin.H{"error": "invalid signature"})
738+ return
739+ }
740+
741+ c.JSON(http.StatusOK, gin.H{"message": "ok"})
742+ })
743+
744+ r.Run(":8000")
745+}
746+```
747+
608748### Retries
609749
610750Certain errors will be automatically retried 2 times by default, with a short exponential backoff.
@@ -630,7 +770,7 @@ client.Chat.Completions.New(
630770 },
631771 },
632772 }},
633− Model: shared.ChatModelO3Mini,
773+ Model: shared.ChatModelGPT4_1,
634774 },
635775 option.WithMaxRetries(5),
636776)
@@ -654,7 +794,7 @@ chatCompletion, err := client.Chat.Completions.New(
654794 },
655795 },
656796 }},
657− Model: shared.ChatModelO3Mini,
797+ Model: shared.ChatModelGPT4_1,
658798 },
659799 option.WithResponseInto(&response),
660800)
@@ -681,7 +821,7 @@ To make requests to undocumented endpoints, you can use `client.Get`, `client.Po
681821var (
682822 // params can be an io.Reader, a []byte, an encoding/json serializable object,
683823 // or a "…Params" struct defined in this library.
684− params map[string]interface{}
824+ params map[string]any
685825
686826 // result can be an []byte, *http.Response, a encoding/json deserializable object,
687827 // or a model defined in this library.
vendor/github.com/openai/openai-go/SECURITY.md+2−2
@@ -16,13 +16,13 @@ before making any information public.
1616## Reporting Non-SDK Related Security Issues
1717
1818If you encounter security issues that are not directly related to SDKs but pertain to the services
19−or products provided by OpenAI please follow the respective company's security reporting guidelines.
19+or products provided by OpenAI, please follow the respective company's security reporting guidelines.
2020
2121### OpenAI Terms and Policies
2222
2323Our Security Policy can be found at [Security Policy URL](https://openai.com/policies/coordinated-vulnerability-disclosure-policy).
2424
25−Please contact disclosure@openai.com for any questions or concerns regarding security of our services.
25+Please contact disclosure@openai.com for any questions or concerns regarding the security of our services.
2626
2727---
2828
vendor/github.com/openai/openai-go/aliases.go+76−24
@@ -5,7 +5,6 @@ package openai
55import (
66 "github.com/openai/openai-go/internal/apierror"
77 "github.com/openai/openai-go/packages/param"
8− "github.com/openai/openai-go/packages/resp"
98 "github.com/openai/openai-go/shared"
109)
1110
@@ -20,6 +19,36 @@ type Error = apierror.Error
2019// This is an alias to an internal type.
2120type ChatModel = shared.ChatModel
2221
22+// Equals "gpt-4.1"
23+const ChatModelGPT4_1 = shared.ChatModelGPT4_1
24+
25+// Equals "gpt-4.1-mini"
26+const ChatModelGPT4_1Mini = shared.ChatModelGPT4_1Mini
27+
28+// Equals "gpt-4.1-nano"
29+const ChatModelGPT4_1Nano = shared.ChatModelGPT4_1Nano
30+
31+// Equals "gpt-4.1-2025-04-14"
32+const ChatModelGPT4_1_2025_04_14 = shared.ChatModelGPT4_1_2025_04_14
33+
34+// Equals "gpt-4.1-mini-2025-04-14"
35+const ChatModelGPT4_1Mini2025_04_14 = shared.ChatModelGPT4_1Mini2025_04_14
36+
37+// Equals "gpt-4.1-nano-2025-04-14"
38+const ChatModelGPT4_1Nano2025_04_14 = shared.ChatModelGPT4_1Nano2025_04_14
39+
40+// Equals "o4-mini"
41+const ChatModelO4Mini = shared.ChatModelO4Mini
42+
43+// Equals "o4-mini-2025-04-16"
44+const ChatModelO4Mini2025_04_16 = shared.ChatModelO4Mini2025_04_16
45+
46+// Equals "o3"
47+const ChatModelO3 = shared.ChatModelO3
48+
49+// Equals "o3-2025-04-16"
50+const ChatModelO3_2025_04_16 = shared.ChatModelO3_2025_04_16
51+
2352// Equals "o3-mini"
2453const ChatModelO3Mini = shared.ChatModelO3Mini
2554
@@ -65,6 +94,9 @@ const ChatModelGPT4oAudioPreview2024_10_01 = shared.ChatModelGPT4oAudioPreview20
6594// Equals "gpt-4o-audio-preview-2024-12-17"
6695const ChatModelGPT4oAudioPreview2024_12_17 = shared.ChatModelGPT4oAudioPreview2024_12_17
6796
97+// Equals "gpt-4o-audio-preview-2025-06-03"
98+const ChatModelGPT4oAudioPreview2025_06_03 = shared.ChatModelGPT4oAudioPreview2025_06_03
99+
68100// Equals "gpt-4o-mini-audio-preview"
69101const ChatModelGPT4oMiniAudioPreview = shared.ChatModelGPT4oMiniAudioPreview
70102
@@ -86,6 +118,9 @@ const ChatModelGPT4oMiniSearchPreview2025_03_11 = shared.ChatModelGPT4oMiniSearc
86118// Equals "chatgpt-4o-latest"
87119const ChatModelChatgpt4oLatest = shared.ChatModelChatgpt4oLatest
88120
121+// Equals "codex-mini-latest"
122+const ChatModelCodexMiniLatest = shared.ChatModelCodexMiniLatest
123+
89124// Equals "gpt-4o-mini"
90125const ChatModelGPT4oMini = shared.ChatModelGPT4oMini
91126
@@ -254,16 +289,6 @@ type FunctionParameters = shared.FunctionParameters
254289// This is an alias to an internal type.
255290type Metadata = shared.Metadata
256291
257−// Set of 16 key-value pairs that can be attached to an object. This can be useful
258−// for storing additional information about the object in a structured format, and
259−// querying for objects via API or the dashboard.
260−//
261−// Keys are strings with a maximum length of 64 characters. Values are strings with
262−// a maximum length of 512 characters.
263−//
264−// This is an alias to an internal type.
265−type MetadataParam = shared.MetadataParam
266−
267292// **o-series models only**
268293//
269294// Configuration options for
@@ -272,21 +297,40 @@ type MetadataParam = shared.MetadataParam
272297// This is an alias to an internal type.
273298type Reasoning = shared.Reasoning
274299
275−// **computer_use_preview only**
300+// **Deprecated:** use `summary` instead.
276301//
277302// A summary of the reasoning performed by the model. This can be useful for
278−// debugging and understanding the model's reasoning process. One of `concise` or
279−// `detailed`.
303+// debugging and understanding the model's reasoning process. One of `auto`,
304+// `concise`, or `detailed`.
280305//
281306// This is an alias to an internal type.
282307type ReasoningGenerateSummary = shared.ReasoningGenerateSummary
283308
309+// Equals "auto"
310+const ReasoningGenerateSummaryAuto = shared.ReasoningGenerateSummaryAuto
311+
284312// Equals "concise"
285313const ReasoningGenerateSummaryConcise = shared.ReasoningGenerateSummaryConcise
286314
287315// Equals "detailed"
288316const ReasoningGenerateSummaryDetailed = shared.ReasoningGenerateSummaryDetailed
289317
318+// A summary of the reasoning performed by the model. This can be useful for
319+// debugging and understanding the model's reasoning process. One of `auto`,
320+// `concise`, or `detailed`.
321+//
322+// This is an alias to an internal type.
323+type ReasoningSummary = shared.ReasoningSummary
324+
325+// Equals "auto"
326+const ReasoningSummaryAuto = shared.ReasoningSummaryAuto
327+
328+// Equals "concise"
329+const ReasoningSummaryConcise = shared.ReasoningSummaryConcise
330+
331+// Equals "detailed"
332+const ReasoningSummaryDetailed = shared.ReasoningSummaryDetailed
333+
290334// **o-series models only**
291335//
292336// Configuration options for
@@ -371,18 +415,26 @@ const ResponsesModelO1Pro = shared.ResponsesModelO1Pro
371415// Equals "o1-pro-2025-03-19"
372416const ResponsesModelO1Pro2025_03_19 = shared.ResponsesModelO1Pro2025_03_19
373417
418+// Equals "o3-pro"
419+const ResponsesModelO3Pro = shared.ResponsesModelO3Pro
420+
421+// Equals "o3-pro-2025-06-10"
422+const ResponsesModelO3Pro2025_06_10 = shared.ResponsesModelO3Pro2025_06_10
423+
424+// Equals "o3-deep-research"
425+const ResponsesModelO3DeepResearch = shared.ResponsesModelO3DeepResearch
426+
427+// Equals "o3-deep-research-2025-06-26"
428+const ResponsesModelO3DeepResearch2025_06_26 = shared.ResponsesModelO3DeepResearch2025_06_26
429+
430+// Equals "o4-mini-deep-research"
431+const ResponsesModelO4MiniDeepResearch = shared.ResponsesModelO4MiniDeepResearch
432+
433+// Equals "o4-mini-deep-research-2025-06-26"
434+const ResponsesModelO4MiniDeepResearch2025_06_26 = shared.ResponsesModelO4MiniDeepResearch2025_06_26
435+
374436// Equals "computer-use-preview"
375437const ResponsesModelComputerUsePreview = shared.ResponsesModelComputerUsePreview
376438
377439// Equals "computer-use-preview-2025-03-11"
378440const ResponsesModelComputerUsePreview2025_03_11 = shared.ResponsesModelComputerUsePreview2025_03_11
379−
380−func toParam[T comparable](value T, meta resp.Field) param.Opt[T] {
381− if meta.IsPresent() {
382− return param.NewOpt(value)
383− }
384− if meta.IsExplicitNull() {
385− return param.NullOpt[T]()
386− }
387− return param.Opt[T]{}
388−}
vendor/github.com/openai/openai-go/api.md+170−2
@@ -5,7 +5,7 @@
55- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#CompoundFilterParam">CompoundFilterParam</a>
66- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#FunctionDefinitionParam">FunctionDefinitionParam</a>
77- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#FunctionParameters">FunctionParameters</a>
8−- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#MetadataParam">MetadataParam</a>
8+- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#Metadata">Metadata</a>
99- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#ReasoningParam">ReasoningParam</a>
1010- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#ReasoningEffort">ReasoningEffort</a>
1111- <a href="https://pkg.go.dev/github.com/openai/openai-go/shared">shared</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/shared#ResponseFormatJSONObjectParam">ResponseFormatJSONObjectParam</a>
@@ -221,6 +221,26 @@ Methods:
221221
222222# FineTuning
223223
224+## Methods
225+
226+Params Types:
227+
228+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#DpoHyperparameters">DpoHyperparameters</a>
229+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#DpoMethodParam">DpoMethodParam</a>
230+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ReinforcementHyperparameters">ReinforcementHyperparameters</a>
231+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ReinforcementMethodParam">ReinforcementMethodParam</a>
232+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#SupervisedHyperparameters">SupervisedHyperparameters</a>
233+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#SupervisedMethodParam">SupervisedMethodParam</a>
234+
235+Response Types:
236+
237+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#DpoHyperparametersResp">DpoHyperparametersResp</a>
238+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#DpoMethod">DpoMethod</a>
239+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ReinforcementHyperparametersResp">ReinforcementHyperparametersResp</a>
240+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ReinforcementMethod">ReinforcementMethod</a>
241+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#SupervisedHyperparametersResp">SupervisedHyperparametersResp</a>
242+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#SupervisedMethod">SupervisedMethod</a>
243+
224244## Jobs
225245
226246Response Types:
@@ -237,6 +257,8 @@ Methods:
237257- <code title="get /fine_tuning/jobs">client.FineTuning.Jobs.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobListParams">FineTuningJobListParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#CursorPage">CursorPage</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJob">FineTuningJob</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
238258- <code title="post /fine_tuning/jobs/{fine_tuning_job_id}/cancel">client.FineTuning.Jobs.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobService.Cancel">Cancel</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTuningJobID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJob">FineTuningJob</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
239259- <code title="get /fine_tuning/jobs/{fine_tuning_job_id}/events">client.FineTuning.Jobs.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobService.ListEvents">ListEvents</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTuningJobID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobListEventsParams">FineTuningJobListEventsParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#CursorPage">CursorPage</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobEvent">FineTuningJobEvent</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
260+- <code title="post /fine_tuning/jobs/{fine_tuning_job_id}/pause">client.FineTuning.Jobs.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobService.Pause">Pause</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTuningJobID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJob">FineTuningJob</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
261+- <code title="post /fine_tuning/jobs/{fine_tuning_job_id}/resume">client.FineTuning.Jobs.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobService.Resume">Resume</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTuningJobID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJob">FineTuningJob</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
240262
241263### Checkpoints
242264
@@ -248,6 +270,58 @@ Methods:
248270
249271- <code title="get /fine_tuning/jobs/{fine_tuning_job_id}/checkpoints">client.FineTuning.Jobs.Checkpoints.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobCheckpointService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTuningJobID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobCheckpointListParams">FineTuningJobCheckpointListParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#CursorPage">CursorPage</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningJobCheckpoint">FineTuningJobCheckpoint</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
250272
273+## Checkpoints
274+
275+### Permissions
276+
277+Response Types:
278+
279+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionNewResponse">FineTuningCheckpointPermissionNewResponse</a>
280+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionGetResponse">FineTuningCheckpointPermissionGetResponse</a>
281+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionDeleteResponse">FineTuningCheckpointPermissionDeleteResponse</a>
282+
283+Methods:
284+
285+- <code title="post /fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions">client.FineTuning.Checkpoints.Permissions.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTunedModelCheckpoint <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionNewParams">FineTuningCheckpointPermissionNewParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#Page">Page</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionNewResponse">FineTuningCheckpointPermissionNewResponse</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
286+- <code title="get /fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions">client.FineTuning.Checkpoints.Permissions.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTunedModelCheckpoint <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionGetParams">FineTuningCheckpointPermissionGetParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionGetResponse">FineTuningCheckpointPermissionGetResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
287+- <code title="delete /fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}">client.FineTuning.Checkpoints.Permissions.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, fineTunedModelCheckpoint <a href="https://pkg.go.dev/builtin#string">string</a>, permissionID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningCheckpointPermissionDeleteResponse">FineTuningCheckpointPermissionDeleteResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
288+
289+## Alpha
290+
291+### Graders
292+
293+Response Types:
294+
295+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderRunResponse">FineTuningAlphaGraderRunResponse</a>
296+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderValidateResponse">FineTuningAlphaGraderValidateResponse</a>
297+
298+Methods:
299+
300+- <code title="post /fine_tuning/alpha/graders/run">client.FineTuning.Alpha.Graders.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderService.Run">Run</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderRunParams">FineTuningAlphaGraderRunParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderRunResponse">FineTuningAlphaGraderRunResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
301+- <code title="post /fine_tuning/alpha/graders/validate">client.FineTuning.Alpha.Graders.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderService.Validate">Validate</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderValidateParams">FineTuningAlphaGraderValidateParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#FineTuningAlphaGraderValidateResponse">FineTuningAlphaGraderValidateResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
302+
303+# Graders
304+
305+## GraderModels
306+
307+Params Types:
308+
309+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#LabelModelGraderParam">LabelModelGraderParam</a>
310+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#MultiGraderParam">MultiGraderParam</a>
311+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#PythonGraderParam">PythonGraderParam</a>
312+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ScoreModelGraderParam">ScoreModelGraderParam</a>
313+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#StringCheckGraderParam">StringCheckGraderParam</a>
314+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#TextSimilarityGraderParam">TextSimilarityGraderParam</a>
315+
316+Response Types:
317+
318+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#LabelModelGrader">LabelModelGrader</a>
319+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#MultiGrader">MultiGrader</a>
320+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#PythonGrader">PythonGrader</a>
321+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ScoreModelGrader">ScoreModelGrader</a>
322+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#StringCheckGrader">StringCheckGrader</a>
323+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#TextSimilarityGrader">TextSimilarityGrader</a>
324+
251325# VectorStores
252326
253327Params Types:
@@ -306,6 +380,35 @@ Methods:
306380- <code title="post /vector_stores/{vector_store_id}/file_batches/{batch_id}/cancel">client.VectorStores.FileBatches.<a href="https://pkg.go.dev/github.com/openai/openai-go#VectorStoreFileBatchService.Cancel">Cancel</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, vectorStoreID <a href="https://pkg.go.dev/builtin#string">string</a>, batchID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#VectorStoreFileBatch">VectorStoreFileBatch</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
307381- <code title="get /vector_stores/{vector_store_id}/file_batches/{batch_id}/files">client.VectorStores.FileBatches.<a href="https://pkg.go.dev/github.com/openai/openai-go#VectorStoreFileBatchService.ListFiles">ListFiles</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, vectorStoreID <a href="https://pkg.go.dev/builtin#string">string</a>, batchID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#VectorStoreFileBatchListFilesParams">VectorStoreFileBatchListFilesParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#CursorPage">CursorPage</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#VectorStoreFile">VectorStoreFile</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
308382
383+# Webhooks
384+
385+Response Types:
386+
387+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#BatchCancelledWebhookEvent">BatchCancelledWebhookEvent</a>
388+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#BatchCompletedWebhookEvent">BatchCompletedWebhookEvent</a>
389+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#BatchExpiredWebhookEvent">BatchExpiredWebhookEvent</a>
390+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#BatchFailedWebhookEvent">BatchFailedWebhookEvent</a>
391+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#EvalRunCanceledWebhookEvent">EvalRunCanceledWebhookEvent</a>
392+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#EvalRunFailedWebhookEvent">EvalRunFailedWebhookEvent</a>
393+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#EvalRunSucceededWebhookEvent">EvalRunSucceededWebhookEvent</a>
394+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#FineTuningJobCancelledWebhookEvent">FineTuningJobCancelledWebhookEvent</a>
395+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#FineTuningJobFailedWebhookEvent">FineTuningJobFailedWebhookEvent</a>
396+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#FineTuningJobSucceededWebhookEvent">FineTuningJobSucceededWebhookEvent</a>
397+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#ResponseCancelledWebhookEvent">ResponseCancelledWebhookEvent</a>
398+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#ResponseCompletedWebhookEvent">ResponseCompletedWebhookEvent</a>
399+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#ResponseFailedWebhookEvent">ResponseFailedWebhookEvent</a>
400+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#ResponseIncompleteWebhookEvent">ResponseIncompleteWebhookEvent</a>
401+- <a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#UnwrapWebhookEventUnion">UnwrapWebhookEventUnion</a>
402+
403+Methods:
404+
405+- <code>client.Webhooks.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#WebhookService.Unwrap">Unwrap</a>(body []<a href="https://pkg.go.dev/builtin#byte">byte</a>, headers <a href="https://pkg.go.dev/net/http">http</a>.<a href="https://pkg.go.dev/net/http#Header">Header</a>, opts ...<a href="https://pkg.go.dev/github.com/openai/openai-go/option">option</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/option#RequestOption">RequestOption</a>) (*<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#UnwrapWebhookEventUnion">UnwrapWebhookEventUnion</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
406+- <code>client.Webhooks.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#WebhookService.UnwrapWithTolerance">UnwrapWithTolerance</a>(body []<a href="https://pkg.go.dev/builtin#byte">byte</a>, headers <a href="https://pkg.go.dev/net/http">http</a>.<a href="https://pkg.go.dev/net/http#Header">Header</a>, tolerance <a href="https://pkg.go.dev/time">time</a>.<a href="https://pkg.go.dev/time#Duration">Duration</a>, opts ...<a href="https://pkg.go.dev/github.com/openai/openai-go/option">option</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/option#RequestOption">RequestOption</a>) (*<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#UnwrapWebhookEventUnion">UnwrapWebhookEventUnion</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
407+- <code>client.Webhooks.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#WebhookService.UnwrapWithToleranceAndTime">UnwrapWithToleranceAndTime</a>(body []<a href="https://pkg.go.dev/builtin#byte">byte</a>, headers <a href="https://pkg.go.dev/net/http">http</a>.<a href="https://pkg.go.dev/net/http#Header">Header</a>, tolerance <a href="https://pkg.go.dev/time">time</a>.<a href="https://pkg.go.dev/time#Duration">Duration</a>, now <a href="https://pkg.go.dev/time">time</a>.<a href="https://pkg.go.dev/time#Time">Time</a>, opts ...<a href="https://pkg.go.dev/github.com/openai/openai-go/option">option</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/option#RequestOption">RequestOption</a>) (*<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks">webhooks</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#UnwrapWebhookEventUnion">UnwrapWebhookEventUnion</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
408+- <code>client.Webhooks.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#WebhookService.VerifySignature">VerifySignature</a>(body []<a href="https://pkg.go.dev/builtin#byte">byte</a>, headers <a href="https://pkg.go.dev/net/http">http</a>.<a href="https://pkg.go.dev/net/http#Header">Header</a>, opts ...<a href="https://pkg.go.dev/github.com/openai/openai-go/option">option</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/option#RequestOption">RequestOption</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
409+- <code>client.Webhooks.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#WebhookService.VerifySignatureWithTolerance">VerifySignatureWithTolerance</a>(body []<a href="https://pkg.go.dev/builtin#byte">byte</a>, headers <a href="https://pkg.go.dev/net/http">http</a>.<a href="https://pkg.go.dev/net/http#Header">Header</a>, tolerance <a href="https://pkg.go.dev/time">time</a>.<a href="https://pkg.go.dev/time#Duration">Duration</a>, opts ...<a href="https://pkg.go.dev/github.com/openai/openai-go/option">option</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/option#RequestOption">RequestOption</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
410+- <code>client.Webhooks.<a href="https://pkg.go.dev/github.com/openai/openai-go/webhooks#WebhookService.VerifySignatureWithToleranceAndTime">VerifySignatureWithToleranceAndTime</a>(body []<a href="https://pkg.go.dev/builtin#byte">byte</a>, headers <a href="https://pkg.go.dev/net/http">http</a>.<a href="https://pkg.go.dev/net/http#Header">Header</a>, tolerance <a href="https://pkg.go.dev/time">time</a>.<a href="https://pkg.go.dev/time#Duration">Duration</a>, now <a href="https://pkg.go.dev/time">time</a>.<a href="https://pkg.go.dev/time#Time">Time</a>, opts ...<a href="https://pkg.go.dev/github.com/openai/openai-go/option">option</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/option#RequestOption">RequestOption</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
411+
309412# Beta
310413
311414## Assistants
@@ -502,6 +605,7 @@ Params Types:
502605- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#EasyInputMessageParam">EasyInputMessageParam</a>
503606- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#FileSearchToolParam">FileSearchToolParam</a>
504607- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#FunctionToolParam">FunctionToolParam</a>
608+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseCodeInterpreterToolCallParam">ResponseCodeInterpreterToolCallParam</a>
505609- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseComputerToolCallParam">ResponseComputerToolCallParam</a>
506610- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseComputerToolCallOutputScreenshotParam">ResponseComputerToolCallOutputScreenshotParam</a>
507611- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseFileSearchToolCallParam">ResponseFileSearchToolCallParam</a>
@@ -520,10 +624,12 @@ Params Types:
520624- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputMessageParam">ResponseOutputMessageParam</a>
521625- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputRefusalParam">ResponseOutputRefusalParam</a>
522626- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputTextParam">ResponseOutputTextParam</a>
627+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponsePromptParam">ResponsePromptParam</a>
523628- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningItemParam">ResponseReasoningItemParam</a>
524629- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseTextConfigParam">ResponseTextConfigParam</a>
525630- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolUnionParam">ToolUnionParam</a>
526631- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceFunctionParam">ToolChoiceFunctionParam</a>
632+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceMcpParam">ToolChoiceMcpParam</a>
527633- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceOptions">ToolChoiceOptions</a>
528634- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceTypesParam">ToolChoiceTypesParam</a>
529635- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#WebSearchToolParam">WebSearchToolParam</a>
@@ -531,6 +637,7 @@ Params Types:
531637Response Types:
532638
533639- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ComputerTool">ComputerTool</a>
640+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#EasyInputMessage">EasyInputMessage</a>
534641- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#FileSearchTool">FileSearchTool</a>
535642- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#FunctionTool">FunctionTool</a>
536643- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#Response">Response</a>
@@ -566,27 +673,50 @@ Response Types:
566673- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseFunctionToolCallItem">ResponseFunctionToolCallItem</a>
567674- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseFunctionToolCallOutputItem">ResponseFunctionToolCallOutputItem</a>
568675- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseFunctionWebSearch">ResponseFunctionWebSearch</a>
676+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseImageGenCallCompletedEvent">ResponseImageGenCallCompletedEvent</a>
677+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseImageGenCallGeneratingEvent">ResponseImageGenCallGeneratingEvent</a>
678+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseImageGenCallInProgressEvent">ResponseImageGenCallInProgressEvent</a>
679+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseImageGenCallPartialImageEvent">ResponseImageGenCallPartialImageEvent</a>
569680- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInProgressEvent">ResponseInProgressEvent</a>
570681- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseIncompleteEvent">ResponseIncompleteEvent</a>
571682- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInputContentUnion">ResponseInputContentUnion</a>
572683- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInputFile">ResponseInputFile</a>
573684- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInputImage">ResponseInputImage</a>
685+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInputItemUnion">ResponseInputItemUnion</a>
574686- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInputMessageContentList">ResponseInputMessageContentList</a>
575687- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInputMessageItem">ResponseInputMessageItem</a>
576688- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseInputText">ResponseInputText</a>
577689- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseItemUnion">ResponseItemUnion</a>
690+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpCallArgumentsDeltaEvent">ResponseMcpCallArgumentsDeltaEvent</a>
691+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpCallArgumentsDoneEvent">ResponseMcpCallArgumentsDoneEvent</a>
692+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpCallCompletedEvent">ResponseMcpCallCompletedEvent</a>
693+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpCallFailedEvent">ResponseMcpCallFailedEvent</a>
694+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpCallInProgressEvent">ResponseMcpCallInProgressEvent</a>
695+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpListToolsCompletedEvent">ResponseMcpListToolsCompletedEvent</a>
696+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpListToolsFailedEvent">ResponseMcpListToolsFailedEvent</a>
697+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseMcpListToolsInProgressEvent">ResponseMcpListToolsInProgressEvent</a>
578698- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputItemUnion">ResponseOutputItemUnion</a>
579699- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputItemAddedEvent">ResponseOutputItemAddedEvent</a>
580700- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputItemDoneEvent">ResponseOutputItemDoneEvent</a>
581701- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputMessage">ResponseOutputMessage</a>
582702- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputRefusal">ResponseOutputRefusal</a>
583703- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputText">ResponseOutputText</a>
704+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseOutputTextAnnotationAddedEvent">ResponseOutputTextAnnotationAddedEvent</a>
705+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponsePrompt">ResponsePrompt</a>
706+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseQueuedEvent">ResponseQueuedEvent</a>
707+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningDeltaEvent">ResponseReasoningDeltaEvent</a>
708+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningDoneEvent">ResponseReasoningDoneEvent</a>
584709- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningItem">ResponseReasoningItem</a>
710+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningSummaryDeltaEvent">ResponseReasoningSummaryDeltaEvent</a>
711+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningSummaryDoneEvent">ResponseReasoningSummaryDoneEvent</a>
712+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningSummaryPartAddedEvent">ResponseReasoningSummaryPartAddedEvent</a>
713+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningSummaryPartDoneEvent">ResponseReasoningSummaryPartDoneEvent</a>
714+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningSummaryTextDeltaEvent">ResponseReasoningSummaryTextDeltaEvent</a>
715+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseReasoningSummaryTextDoneEvent">ResponseReasoningSummaryTextDoneEvent</a>
585716- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseRefusalDeltaEvent">ResponseRefusalDeltaEvent</a>
586717- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseRefusalDoneEvent">ResponseRefusalDoneEvent</a>
587718- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseStatus">ResponseStatus</a>
588719- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseStreamEventUnion">ResponseStreamEventUnion</a>
589−- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseTextAnnotationDeltaEvent">ResponseTextAnnotationDeltaEvent</a>
590720- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseTextConfig">ResponseTextConfig</a>
591721- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseTextDeltaEvent">ResponseTextDeltaEvent</a>
592722- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseTextDoneEvent">ResponseTextDoneEvent</a>
@@ -596,6 +726,7 @@ Response Types:
596726- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseWebSearchCallSearchingEvent">ResponseWebSearchCallSearchingEvent</a>
597727- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolUnion">ToolUnion</a>
598728- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceFunction">ToolChoiceFunction</a>
729+- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceMcp">ToolChoiceMcp</a>
599730- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceOptions">ToolChoiceOptions</a>
600731- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ToolChoiceTypes">ToolChoiceTypes</a>
601732- <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#WebSearchTool">WebSearchTool</a>
@@ -605,6 +736,7 @@ Methods:
605736- <code title="post /responses">client.Responses.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseNewParams">ResponseNewParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#Response">Response</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
606737- <code title="get /responses/{response_id}">client.Responses.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, responseID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseGetParams">ResponseGetParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#Response">Response</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
607738- <code title="delete /responses/{response_id}">client.Responses.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, responseID <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
739+- <code title="post /responses/{response_id}/cancel">client.Responses.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseService.Cancel">Cancel</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, responseID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#Response">Response</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
608740
609741## InputItems
610742
@@ -615,3 +747,39 @@ Response Types:
615747Methods:
616748
617749- <code title="get /responses/{response_id}/input_items">client.Responses.InputItems.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#InputItemService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, responseID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#InputItemListParams">InputItemListParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#CursorPage">CursorPage</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go/responses">responses</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/responses#ResponseItemUnion">ResponseItemUnion</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
750+
751+# Containers
752+
753+Response Types:
754+
755+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerNewResponse">ContainerNewResponse</a>
756+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerGetResponse">ContainerGetResponse</a>
757+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerListResponse">ContainerListResponse</a>
758+
759+Methods:
760+
761+- <code title="post /containers">client.Containers.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, body <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerNewParams">ContainerNewParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerNewResponse">ContainerNewResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
762+- <code title="get /containers/{container_id}">client.Containers.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, containerID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerGetResponse">ContainerGetResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
763+- <code title="get /containers">client.Containers.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerListParams">ContainerListParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#CursorPage">CursorPage</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerListResponse">ContainerListResponse</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
764+- <code title="delete /containers/{container_id}">client.Containers.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, containerID <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
765+
766+## Files
767+
768+Response Types:
769+
770+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileNewResponse">ContainerFileNewResponse</a>
771+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileGetResponse">ContainerFileGetResponse</a>
772+- <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileListResponse">ContainerFileListResponse</a>
773+
774+Methods:
775+
776+- <code title="post /containers/{container_id}/files">client.Containers.Files.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileService.New">New</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, containerID <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileNewParams">ContainerFileNewParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileNewResponse">ContainerFileNewResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
777+- <code title="get /containers/{container_id}/files/{file_id}">client.Containers.Files.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, containerID <a href="https://pkg.go.dev/builtin#string">string</a>, fileID <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileGetResponse">ContainerFileGetResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
778+- <code title="get /containers/{container_id}/files">client.Containers.Files.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileService.List">List</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, containerID <a href="https://pkg.go.dev/builtin#string">string</a>, query <a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileListParams">ContainerFileListParams</a>) (<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination">pagination</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go/packages/pagination#CursorPage">CursorPage</a>[<a href="https://pkg.go.dev/github.com/openai/openai-go">openai</a>.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileListResponse">ContainerFileListResponse</a>], <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
779+- <code title="delete /containers/{container_id}/files/{file_id}">client.Containers.Files.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileService.Delete">Delete</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, containerID <a href="https://pkg.go.dev/builtin#string">string</a>, fileID <a href="https://pkg.go.dev/builtin#string">string</a>) <a href="https://pkg.go.dev/builtin#error">error</a></code>
780+
781+### Content
782+
783+Methods:
784+
785+- <code title="get /containers/{container_id}/files/{file_id}/content">client.Containers.Files.Content.<a href="https://pkg.go.dev/github.com/openai/openai-go#ContainerFileContentService.Get">Get</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, containerID <a href="https://pkg.go.dev/builtin#string">string</a>, fileID <a href="https://pkg.go.dev/builtin#string">string</a>) (http.Response, <a href="https://pkg.go.dev/builtin#error">error</a>)</code>
vendor/github.com/openai/openai-go/audiospeech.go+24−11
@@ -6,6 +6,7 @@ import (
66 "context"
77 "net/http"
88
9+ "github.com/openai/openai-go/internal/apijson"
910 "github.com/openai/openai-go/internal/requestconfig"
1011 "github.com/openai/openai-go/option"
1112 "github.com/openai/openai-go/packages/param"
@@ -54,12 +55,9 @@ type AudioSpeechNewParams struct {
5455 // `tts-1`, `tts-1-hd` or `gpt-4o-mini-tts`.
5556 Model SpeechModel `json:"model,omitzero,required"`
5657 // The voice to use when generating the audio. Supported voices are `alloy`, `ash`,
57− // `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the
58− // voices are available in the
58+ // `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and
59+ // `verse`. Previews of the voices are available in the
5960 // [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options).
60− //
61− // Any of "alloy", "ash", "coral", "echo", "fable", "onyx", "nova", "sage",
62− // "shimmer".
6361 Voice AudioSpeechNewParamsVoice `json:"voice,omitzero,required"`
6462 // Control the voice of your generated audio with additional instructions. Does not
6563 // work with `tts-1` or `tts-1-hd`.
@@ -72,27 +70,32 @@ type AudioSpeechNewParams struct {
7270 //
7371 // Any of "mp3", "opus", "aac", "flac", "wav", "pcm".
7472 ResponseFormat AudioSpeechNewParamsResponseFormat `json:"response_format,omitzero"`
73+ // The format to stream the audio in. Supported formats are `sse` and `audio`.
74+ // `sse` is not supported for `tts-1` or `tts-1-hd`.
75+ //
76+ // Any of "sse", "audio".
77+ StreamFormat AudioSpeechNewParamsStreamFormat `json:"stream_format,omitzero"`
7578 paramObj
7679}
7780
78−// IsPresent returns true if the field's value is not omitted and not the JSON
79−// "null". To check if this field is omitted, use [param.IsOmitted].
80−func (f AudioSpeechNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
81−
8281func (r AudioSpeechNewParams) MarshalJSON() (data []byte, err error) {
8382 type shadow AudioSpeechNewParams
8483 return param.MarshalObject(r, (*shadow)(&r))
8584}
85+func (r *AudioSpeechNewParams) UnmarshalJSON(data []byte) error {
86+ return apijson.UnmarshalRoot(data, r)
87+}
8688
8789// The voice to use when generating the audio. Supported voices are `alloy`, `ash`,
88−// `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the
89−// voices are available in the
90+// `ballad`, `coral`, `echo`, `fable`, `onyx`, `nova`, `sage`, `shimmer`, and
91+// `verse`. Previews of the voices are available in the
9092// [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options).
9193type AudioSpeechNewParamsVoice string
9294
9395const (
9496 AudioSpeechNewParamsVoiceAlloy AudioSpeechNewParamsVoice = "alloy"
9597 AudioSpeechNewParamsVoiceAsh AudioSpeechNewParamsVoice = "ash"
98+ AudioSpeechNewParamsVoiceBallad AudioSpeechNewParamsVoice = "ballad"
9699 AudioSpeechNewParamsVoiceCoral AudioSpeechNewParamsVoice = "coral"
97100 AudioSpeechNewParamsVoiceEcho AudioSpeechNewParamsVoice = "echo"
98101 AudioSpeechNewParamsVoiceFable AudioSpeechNewParamsVoice = "fable"
@@ -100,6 +103,7 @@ const (
100103 AudioSpeechNewParamsVoiceNova AudioSpeechNewParamsVoice = "nova"
101104 AudioSpeechNewParamsVoiceSage AudioSpeechNewParamsVoice = "sage"
102105 AudioSpeechNewParamsVoiceShimmer AudioSpeechNewParamsVoice = "shimmer"
106+ AudioSpeechNewParamsVoiceVerse AudioSpeechNewParamsVoice = "verse"
103107)
104108
105109// The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`,
@@ -114,3 +118,12 @@ const (
114118 AudioSpeechNewParamsResponseFormatWAV AudioSpeechNewParamsResponseFormat = "wav"
115119 AudioSpeechNewParamsResponseFormatPCM AudioSpeechNewParamsResponseFormat = "pcm"
116120)
121+
122+// The format to stream the audio in. Supported formats are `sse` and `audio`.
123+// `sse` is not supported for `tts-1` or `tts-1-hd`.
124+type AudioSpeechNewParamsStreamFormat string
125+
126+const (
127+ AudioSpeechNewParamsStreamFormatSSE AudioSpeechNewParamsStreamFormat = "sse"
128+ AudioSpeechNewParamsStreamFormatAudio AudioSpeechNewParamsStreamFormat = "audio"
129+)
vendor/github.com/openai/openai-go/audiotranscription.go+332−54
@@ -15,7 +15,7 @@ import (
1515 "github.com/openai/openai-go/internal/requestconfig"
1616 "github.com/openai/openai-go/option"
1717 "github.com/openai/openai-go/packages/param"
18− "github.com/openai/openai-go/packages/resp"
18+ "github.com/openai/openai-go/packages/respjson"
1919 "github.com/openai/openai-go/packages/ssestream"
2020 "github.com/openai/openai-go/shared/constant"
2121)
@@ -54,7 +54,9 @@ func (r *AudioTranscriptionService) NewStreaming(ctx context.Context, body Audio
5454 err error
5555 )
5656 opts = append(r.Options[:], opts...)
57− opts = append([]option.RequestOption{option.WithJSONSet("stream", true)}, opts...)
57+ body.SetExtraFields(map[string]any{
58+ "stream": "true",
59+ })
5860 path := "audio/transcriptions"
5961 err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &raw, opts...)
6062 return ssestream.NewStream[TranscriptionStreamEventUnion](ssestream.NewDecoder(raw), err)
@@ -69,12 +71,14 @@ type Transcription struct {
6971 // models `gpt-4o-transcribe` and `gpt-4o-mini-transcribe` if `logprobs` is added
7072 // to the `include` array.
7173 Logprobs []TranscriptionLogprob `json:"logprobs"`
72− // Metadata for the response, check the presence of optional fields with the
73− // [resp.Field.IsPresent] method.
74+ // Token usage statistics for the request.
75+ Usage TranscriptionUsageUnion `json:"usage"`
76+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
7477 JSON struct {
75− Text resp.Field
76− Logprobs resp.Field
77− ExtraFields map[string]resp.Field
78+ Text respjson.Field
79+ Logprobs respjson.Field
80+ Usage respjson.Field
81+ ExtraFields map[string]respjson.Field
7882 raw string
7983 } `json:"-"`
8084}
@@ -92,13 +96,12 @@ type TranscriptionLogprob struct {
9296 Bytes []float64 `json:"bytes"`
9397 // The log probability of the token.
9498 Logprob float64 `json:"logprob"`
95− // Metadata for the response, check the presence of optional fields with the
96− // [resp.Field.IsPresent] method.
99+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
97100 JSON struct {
98− Token resp.Field
99− Bytes resp.Field
100− Logprob resp.Field
101− ExtraFields map[string]resp.Field
101+ Token respjson.Field
102+ Bytes respjson.Field
103+ Logprob respjson.Field
104+ ExtraFields map[string]respjson.Field
102105 raw string
103106 } `json:"-"`
104107}
@@ -109,6 +112,153 @@ func (r *TranscriptionLogprob) UnmarshalJSON(data []byte) error {
109112 return apijson.UnmarshalRoot(data, r)
110113}
111114
115+// TranscriptionUsageUnion contains all possible properties and values from
116+// [TranscriptionUsageTokens], [TranscriptionUsageDuration].
117+//
118+// Use the [TranscriptionUsageUnion.AsAny] method to switch on the variant.
119+//
120+// Use the methods beginning with 'As' to cast the union to one of its variants.
121+type TranscriptionUsageUnion struct {
122+ // This field is from variant [TranscriptionUsageTokens].
123+ InputTokens int64 `json:"input_tokens"`
124+ // This field is from variant [TranscriptionUsageTokens].
125+ OutputTokens int64 `json:"output_tokens"`
126+ // This field is from variant [TranscriptionUsageTokens].
127+ TotalTokens int64 `json:"total_tokens"`
128+ // Any of "tokens", "duration".
129+ Type string `json:"type"`
130+ // This field is from variant [TranscriptionUsageTokens].
131+ InputTokenDetails TranscriptionUsageTokensInputTokenDetails `json:"input_token_details"`
132+ // This field is from variant [TranscriptionUsageDuration].
133+ Duration float64 `json:"duration"`
134+ JSON struct {
135+ InputTokens respjson.Field
136+ OutputTokens respjson.Field
137+ TotalTokens respjson.Field
138+ Type respjson.Field
139+ InputTokenDetails respjson.Field
140+ Duration respjson.Field
141+ raw string
142+ } `json:"-"`
143+}
144+
145+// anyTranscriptionUsage is implemented by each variant of
146+// [TranscriptionUsageUnion] to add type safety for the return type of
147+// [TranscriptionUsageUnion.AsAny]
148+type anyTranscriptionUsage interface {
149+ implTranscriptionUsageUnion()
150+}
151+
152+func (TranscriptionUsageTokens) implTranscriptionUsageUnion() {}
153+func (TranscriptionUsageDuration) implTranscriptionUsageUnion() {}
154+
155+// Use the following switch statement to find the correct variant
156+//
157+// switch variant := TranscriptionUsageUnion.AsAny().(type) {
158+// case openai.TranscriptionUsageTokens:
159+// case openai.TranscriptionUsageDuration:
160+// default:
161+// fmt.Errorf("no variant present")
162+// }
163+func (u TranscriptionUsageUnion) AsAny() anyTranscriptionUsage {
164+ switch u.Type {
165+ case "tokens":
166+ return u.AsTokens()
167+ case "duration":
168+ return u.AsDuration()
169+ }
170+ return nil
171+}
172+
173+func (u TranscriptionUsageUnion) AsTokens() (v TranscriptionUsageTokens) {
174+ apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
175+ return
176+}
177+
178+func (u TranscriptionUsageUnion) AsDuration() (v TranscriptionUsageDuration) {
179+ apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
180+ return
181+}
182+
183+// Returns the unmodified JSON received from the API
184+func (u TranscriptionUsageUnion) RawJSON() string { return u.JSON.raw }
185+
186+func (r *TranscriptionUsageUnion) UnmarshalJSON(data []byte) error {
187+ return apijson.UnmarshalRoot(data, r)
188+}
189+
190+// Usage statistics for models billed by token usage.
191+type TranscriptionUsageTokens struct {
192+ // Number of input tokens billed for this request.
193+ InputTokens int64 `json:"input_tokens,required"`
194+ // Number of output tokens generated.
195+ OutputTokens int64 `json:"output_tokens,required"`
196+ // Total number of tokens used (input + output).
197+ TotalTokens int64 `json:"total_tokens,required"`
198+ // The type of the usage object. Always `tokens` for this variant.
199+ Type constant.Tokens `json:"type,required"`
200+ // Details about the input tokens billed for this request.
201+ InputTokenDetails TranscriptionUsageTokensInputTokenDetails `json:"input_token_details"`
202+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
203+ JSON struct {
204+ InputTokens respjson.Field
205+ OutputTokens respjson.Field
206+ TotalTokens respjson.Field
207+ Type respjson.Field
208+ InputTokenDetails respjson.Field
209+ ExtraFields map[string]respjson.Field
210+ raw string
211+ } `json:"-"`
212+}
213+
214+// Returns the unmodified JSON received from the API
215+func (r TranscriptionUsageTokens) RawJSON() string { return r.JSON.raw }
216+func (r *TranscriptionUsageTokens) UnmarshalJSON(data []byte) error {
217+ return apijson.UnmarshalRoot(data, r)
218+}
219+
220+// Details about the input tokens billed for this request.
221+type TranscriptionUsageTokensInputTokenDetails struct {
222+ // Number of audio tokens billed for this request.
223+ AudioTokens int64 `json:"audio_tokens"`
224+ // Number of text tokens billed for this request.
225+ TextTokens int64 `json:"text_tokens"`
226+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
227+ JSON struct {
228+ AudioTokens respjson.Field
229+ TextTokens respjson.Field
230+ ExtraFields map[string]respjson.Field
231+ raw string
232+ } `json:"-"`
233+}
234+
235+// Returns the unmodified JSON received from the API
236+func (r TranscriptionUsageTokensInputTokenDetails) RawJSON() string { return r.JSON.raw }
237+func (r *TranscriptionUsageTokensInputTokenDetails) UnmarshalJSON(data []byte) error {
238+ return apijson.UnmarshalRoot(data, r)
239+}
240+
241+// Usage statistics for models billed by audio input duration.
242+type TranscriptionUsageDuration struct {
243+ // Duration of the input audio in seconds.
244+ Duration float64 `json:"duration,required"`
245+ // The type of the usage object. Always `duration` for this variant.
246+ Type constant.Duration `json:"type,required"`
247+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
248+ JSON struct {
249+ Duration respjson.Field
250+ Type respjson.Field
251+ ExtraFields map[string]respjson.Field
252+ raw string
253+ } `json:"-"`
254+}
255+
256+// Returns the unmodified JSON received from the API
257+func (r TranscriptionUsageDuration) RawJSON() string { return r.JSON.raw }
258+func (r *TranscriptionUsageDuration) UnmarshalJSON(data []byte) error {
259+ return apijson.UnmarshalRoot(data, r)
260+}
261+
112262type TranscriptionInclude string
113263
114264const (
@@ -131,24 +281,37 @@ type TranscriptionStreamEventUnion struct {
131281 Logprobs TranscriptionStreamEventUnionLogprobs `json:"logprobs"`
132282 // This field is from variant [TranscriptionTextDoneEvent].
133283 Text string `json:"text"`
134− JSON struct {
135− Delta resp.Field
136− Type resp.Field
137− Logprobs resp.Field
138− Text resp.Field
284+ // This field is from variant [TranscriptionTextDoneEvent].
285+ Usage TranscriptionTextDoneEventUsage `json:"usage"`
286+ JSON struct {
287+ Delta respjson.Field
288+ Type respjson.Field
289+ Logprobs respjson.Field
290+ Text respjson.Field
291+ Usage respjson.Field
139292 raw string
140293 } `json:"-"`
141294}
142295
296+// anyTranscriptionStreamEvent is implemented by each variant of
297+// [TranscriptionStreamEventUnion] to add type safety for the return type of
298+// [TranscriptionStreamEventUnion.AsAny]
299+type anyTranscriptionStreamEvent interface {
300+ implTranscriptionStreamEventUnion()
301+}
302+
303+func (TranscriptionTextDeltaEvent) implTranscriptionStreamEventUnion() {}
304+func (TranscriptionTextDoneEvent) implTranscriptionStreamEventUnion() {}
305+
143306// Use the following switch statement to find the correct variant
144307//
145308// switch variant := TranscriptionStreamEventUnion.AsAny().(type) {
146−// case TranscriptionTextDeltaEvent:
147−// case TranscriptionTextDoneEvent:
309+// case openai.TranscriptionTextDeltaEvent:
310+// case openai.TranscriptionTextDoneEvent:
148311// default:
149312// fmt.Errorf("no variant present")
150313// }
151−func (u TranscriptionStreamEventUnion) AsAny() any {
314+func (u TranscriptionStreamEventUnion) AsAny() anyTranscriptionStreamEvent {
152315 switch u.Type {
153316 case "transcript.text.delta":
154317 return u.AsTranscriptTextDelta()
@@ -193,8 +356,8 @@ type TranscriptionStreamEventUnionLogprobs struct {
193356 // [[]TranscriptionTextDoneEventLogprob] instead of an object.
194357 OfTranscriptionTextDoneEventLogprobs []TranscriptionTextDoneEventLogprob `json:",inline"`
195358 JSON struct {
196− OfTranscriptionTextDeltaEventLogprobs resp.Field
197− OfTranscriptionTextDoneEventLogprobs resp.Field
359+ OfTranscriptionTextDeltaEventLogprobs respjson.Field
360+ OfTranscriptionTextDoneEventLogprobs respjson.Field
198361 raw string
199362 } `json:"-"`
200363}
@@ -216,13 +379,12 @@ type TranscriptionTextDeltaEvent struct {
216379 // [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription)
217380 // with the `include[]` parameter set to `logprobs`.
218381 Logprobs []TranscriptionTextDeltaEventLogprob `json:"logprobs"`
219− // Metadata for the response, check the presence of optional fields with the
220− // [resp.Field.IsPresent] method.
382+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
221383 JSON struct {
222− Delta resp.Field
223− Type resp.Field
224− Logprobs resp.Field
225− ExtraFields map[string]resp.Field
384+ Delta respjson.Field
385+ Type respjson.Field
386+ Logprobs respjson.Field
387+ ExtraFields map[string]respjson.Field
226388 raw string
227389 } `json:"-"`
228390}
@@ -237,16 +399,15 @@ type TranscriptionTextDeltaEventLogprob struct {
237399 // The token that was used to generate the log probability.
238400 Token string `json:"token"`
239401 // The bytes that were used to generate the log probability.
240− Bytes []interface{} `json:"bytes"`
402+ Bytes []int64 `json:"bytes"`
241403 // The log probability of the token.
242404 Logprob float64 `json:"logprob"`
243− // Metadata for the response, check the presence of optional fields with the
244− // [resp.Field.IsPresent] method.
405+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
245406 JSON struct {
246− Token resp.Field
247− Bytes resp.Field
248− Logprob resp.Field
249− ExtraFields map[string]resp.Field
407+ Token respjson.Field
408+ Bytes respjson.Field
409+ Logprob respjson.Field
410+ ExtraFields map[string]respjson.Field
250411 raw string
251412 } `json:"-"`
252413}
@@ -271,13 +432,15 @@ type TranscriptionTextDoneEvent struct {
271432 // [create a transcription](https://platform.openai.com/docs/api-reference/audio/create-transcription)
272433 // with the `include[]` parameter set to `logprobs`.
273434 Logprobs []TranscriptionTextDoneEventLogprob `json:"logprobs"`
274− // Metadata for the response, check the presence of optional fields with the
275− // [resp.Field.IsPresent] method.
435+ // Usage statistics for models billed by token usage.
436+ Usage TranscriptionTextDoneEventUsage `json:"usage"`
437+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
276438 JSON struct {
277− Text resp.Field
278− Type resp.Field
279− Logprobs resp.Field
280− ExtraFields map[string]resp.Field
439+ Text respjson.Field
440+ Type respjson.Field
441+ Logprobs respjson.Field
442+ Usage respjson.Field
443+ ExtraFields map[string]respjson.Field
281444 raw string
282445 } `json:"-"`
283446}
@@ -292,16 +455,15 @@ type TranscriptionTextDoneEventLogprob struct {
292455 // The token that was used to generate the log probability.
293456 Token string `json:"token"`
294457 // The bytes that were used to generate the log probability.
295− Bytes []interface{} `json:"bytes"`
458+ Bytes []int64 `json:"bytes"`
296459 // The log probability of the token.
297460 Logprob float64 `json:"logprob"`
298− // Metadata for the response, check the presence of optional fields with the
299− // [resp.Field.IsPresent] method.
461+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
300462 JSON struct {
301− Token resp.Field
302− Bytes resp.Field
303− Logprob resp.Field
304− ExtraFields map[string]resp.Field
463+ Token respjson.Field
464+ Bytes respjson.Field
465+ Logprob respjson.Field
466+ ExtraFields map[string]respjson.Field
305467 raw string
306468 } `json:"-"`
307469}
@@ -312,10 +474,61 @@ func (r *TranscriptionTextDoneEventLogprob) UnmarshalJSON(data []byte) error {
312474 return apijson.UnmarshalRoot(data, r)
313475}
314476
477+// Usage statistics for models billed by token usage.
478+type TranscriptionTextDoneEventUsage struct {
479+ // Number of input tokens billed for this request.
480+ InputTokens int64 `json:"input_tokens,required"`
481+ // Number of output tokens generated.
482+ OutputTokens int64 `json:"output_tokens,required"`
483+ // Total number of tokens used (input + output).
484+ TotalTokens int64 `json:"total_tokens,required"`
485+ // The type of the usage object. Always `tokens` for this variant.
486+ Type constant.Tokens `json:"type,required"`
487+ // Details about the input tokens billed for this request.
488+ InputTokenDetails TranscriptionTextDoneEventUsageInputTokenDetails `json:"input_token_details"`
489+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
490+ JSON struct {
491+ InputTokens respjson.Field
492+ OutputTokens respjson.Field
493+ TotalTokens respjson.Field
494+ Type respjson.Field
495+ InputTokenDetails respjson.Field
496+ ExtraFields map[string]respjson.Field
497+ raw string
498+ } `json:"-"`
499+}
500+
501+// Returns the unmodified JSON received from the API
502+func (r TranscriptionTextDoneEventUsage) RawJSON() string { return r.JSON.raw }
503+func (r *TranscriptionTextDoneEventUsage) UnmarshalJSON(data []byte) error {
504+ return apijson.UnmarshalRoot(data, r)
505+}
506+
507+// Details about the input tokens billed for this request.
508+type TranscriptionTextDoneEventUsageInputTokenDetails struct {
509+ // Number of audio tokens billed for this request.
510+ AudioTokens int64 `json:"audio_tokens"`
511+ // Number of text tokens billed for this request.
512+ TextTokens int64 `json:"text_tokens"`
513+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
514+ JSON struct {
515+ AudioTokens respjson.Field
516+ TextTokens respjson.Field
517+ ExtraFields map[string]respjson.Field
518+ raw string
519+ } `json:"-"`
520+}
521+
522+// Returns the unmodified JSON received from the API
523+func (r TranscriptionTextDoneEventUsageInputTokenDetails) RawJSON() string { return r.JSON.raw }
524+func (r *TranscriptionTextDoneEventUsageInputTokenDetails) UnmarshalJSON(data []byte) error {
525+ return apijson.UnmarshalRoot(data, r)
526+}
527+
315528type AudioTranscriptionNewParams struct {
316529 // The audio file object (not file name) to transcribe, in one of these formats:
317530 // flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm.
318− File io.Reader `json:"file,required" format:"binary"`
531+ File io.Reader `json:"file,omitzero,required" format:"binary"`
319532 // ID of the model to use. The options are `gpt-4o-transcribe`,
320533 // `gpt-4o-mini-transcribe`, and `whisper-1` (which is powered by our open source
321534 // Whisper V2 model).
@@ -335,6 +548,11 @@ type AudioTranscriptionNewParams struct {
335548 // [log probability](https://en.wikipedia.org/wiki/Log_probability) to
336549 // automatically increase the temperature until certain thresholds are hit.
337550 Temperature param.Opt[float64] `json:"temperature,omitzero"`
551+ // Controls how the audio is cut into chunks. When set to `"auto"`, the server
552+ // first normalizes loudness and then uses voice activity detection (VAD) to choose
553+ // boundaries. `server_vad` object can be provided to tweak VAD detection
554+ // parameters manually. If unset, the audio is transcribed as a single block.
555+ ChunkingStrategy AudioTranscriptionNewParamsChunkingStrategyUnion `json:"chunking_strategy,omitzero"`
338556 // Additional information to include in the transcription response. `logprobs` will
339557 // return the log probabilities of the tokens in the response to understand the
340558 // model's confidence in the transcription. `logprobs` only works with
@@ -352,18 +570,19 @@ type AudioTranscriptionNewParams struct {
352570 // Either or both of these options are supported: `word`, or `segment`. Note: There
353571 // is no additional latency for segment timestamps, but generating word timestamps
354572 // incurs additional latency.
573+ //
574+ // Any of "word", "segment".
355575 TimestampGranularities []string `json:"timestamp_granularities,omitzero"`
356576 paramObj
357577}
358578
359−// IsPresent returns true if the field's value is not omitted and not the JSON
360−// "null". To check if this field is omitted, use [param.IsOmitted].
361−func (f AudioTranscriptionNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
362−
363579func (r AudioTranscriptionNewParams) MarshalMultipart() (data []byte, contentType string, err error) {
364580 buf := bytes.NewBuffer(nil)
365581 writer := multipart.NewWriter(buf)
366582 err = apiform.MarshalRoot(r, writer)
583+ if err == nil {
584+ err = apiform.WriteExtras(writer, r.ExtraFields())
585+ }
367586 if err != nil {
368587 writer.Close()
369588 return nil, "", err
@@ -374,3 +593,62 @@ func (r AudioTranscriptionNewParams) MarshalMultipart() (data []byte, contentTyp
374593 }
375594 return buf.Bytes(), writer.FormDataContentType(), nil
376595}
596+
597+// Only one field can be non-zero.
598+//
599+// Use [param.IsOmitted] to confirm if a field is set.
600+type AudioTranscriptionNewParamsChunkingStrategyUnion struct {
601+ // Construct this variant with constant.ValueOf[constant.Auto]()
602+ OfAuto constant.Auto `json:",omitzero,inline"`
603+ OfAudioTranscriptionNewsChunkingStrategyVadConfig *AudioTranscriptionNewParamsChunkingStrategyVadConfig `json:",omitzero,inline"`
604+ paramUnion
605+}
606+
607+func (u AudioTranscriptionNewParamsChunkingStrategyUnion) MarshalJSON() ([]byte, error) {
608+ return param.MarshalUnion(u, u.OfAuto, u.OfAudioTranscriptionNewsChunkingStrategyVadConfig)
609+}
610+func (u *AudioTranscriptionNewParamsChunkingStrategyUnion) UnmarshalJSON(data []byte) error {
611+ return apijson.UnmarshalRoot(data, u)
612+}
613+
614+func (u *AudioTranscriptionNewParamsChunkingStrategyUnion) asAny() any {
615+ if !param.IsOmitted(u.OfAuto) {
616+ return &u.OfAuto
617+ } else if !param.IsOmitted(u.OfAudioTranscriptionNewsChunkingStrategyVadConfig) {
618+ return u.OfAudioTranscriptionNewsChunkingStrategyVadConfig
619+ }
620+ return nil
621+}
622+
623+// The property Type is required.
624+type AudioTranscriptionNewParamsChunkingStrategyVadConfig struct {
625+ // Must be set to `server_vad` to enable manual chunking using server side VAD.
626+ //
627+ // Any of "server_vad".
628+ Type string `json:"type,omitzero,required"`
629+ // Amount of audio to include before the VAD detected speech (in milliseconds).
630+ PrefixPaddingMs param.Opt[int64] `json:"prefix_padding_ms,omitzero"`
631+ // Duration of silence to detect speech stop (in milliseconds). With shorter values
632+ // the model will respond more quickly, but may jump in on short pauses from the
633+ // user.
634+ SilenceDurationMs param.Opt[int64] `json:"silence_duration_ms,omitzero"`
635+ // Sensitivity threshold (0.0 to 1.0) for voice activity detection. A higher
636+ // threshold will require louder audio to activate the model, and thus might
637+ // perform better in noisy environments.
638+ Threshold param.Opt[float64] `json:"threshold,omitzero"`
639+ paramObj
640+}
641+
642+func (r AudioTranscriptionNewParamsChunkingStrategyVadConfig) MarshalJSON() (data []byte, err error) {
643+ type shadow AudioTranscriptionNewParamsChunkingStrategyVadConfig
644+ return param.MarshalObject(r, (*shadow)(&r))
645+}
646+func (r *AudioTranscriptionNewParamsChunkingStrategyVadConfig) UnmarshalJSON(data []byte) error {
647+ return apijson.UnmarshalRoot(data, r)
648+}
649+
650+func init() {
651+ apijson.RegisterFieldValidator[AudioTranscriptionNewParamsChunkingStrategyVadConfig](
652+ "type", "server_vad",
653+ )
654+}
vendor/github.com/openai/openai-go/audiotranslation.go+8−10
@@ -14,7 +14,7 @@ import (
1414 "github.com/openai/openai-go/internal/requestconfig"
1515 "github.com/openai/openai-go/option"
1616 "github.com/openai/openai-go/packages/param"
17− "github.com/openai/openai-go/packages/resp"
17+ "github.com/openai/openai-go/packages/respjson"
1818)
1919
2020// AudioTranslationService contains methods and other services that help with
@@ -46,11 +46,10 @@ func (r *AudioTranslationService) New(ctx context.Context, body AudioTranslation
4646
4747type Translation struct {
4848 Text string `json:"text,required"`
49− // Metadata for the response, check the presence of optional fields with the
50− // [resp.Field.IsPresent] method.
49+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
5150 JSON struct {
52− Text resp.Field
53− ExtraFields map[string]resp.Field
51+ Text respjson.Field
52+ ExtraFields map[string]respjson.Field
5453 raw string
5554 } `json:"-"`
5655}
@@ -64,7 +63,7 @@ func (r *Translation) UnmarshalJSON(data []byte) error {
6463type AudioTranslationNewParams struct {
6564 // The audio file object (not file name) translate, in one of these formats: flac,
6665 // mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm.
67− File io.Reader `json:"file,required" format:"binary"`
66+ File io.Reader `json:"file,omitzero,required" format:"binary"`
6867 // ID of the model to use. Only `whisper-1` (which is powered by our open source
6968 // Whisper V2 model) is currently available.
7069 Model AudioModel `json:"model,omitzero,required"`
@@ -87,14 +86,13 @@ type AudioTranslationNewParams struct {
8786 paramObj
8887}
8988
90−// IsPresent returns true if the field's value is not omitted and not the JSON
91−// "null". To check if this field is omitted, use [param.IsOmitted].
92−func (f AudioTranslationNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
93−
9489func (r AudioTranslationNewParams) MarshalMultipart() (data []byte, contentType string, err error) {
9590 buf := bytes.NewBuffer(nil)
9691 writer := multipart.NewWriter(buf)
9792 err = apiform.MarshalRoot(r, writer)
93+ if err == nil {
94+ err = apiform.WriteExtras(writer, r.ExtraFields())
95+ }
9896 if err != nil {
9997 writer.Close()
10098 return nil, "", err
vendor/github.com/openai/openai-go/batch.go+43−52
@@ -15,7 +15,7 @@ import (
1515 "github.com/openai/openai-go/option"
1616 "github.com/openai/openai-go/packages/pagination"
1717 "github.com/openai/openai-go/packages/param"
18− "github.com/openai/openai-go/packages/resp"
18+ "github.com/openai/openai-go/packages/respjson"
1919 "github.com/openai/openai-go/shared"
2020 "github.com/openai/openai-go/shared/constant"
2121)
@@ -143,30 +143,29 @@ type Batch struct {
143143 OutputFileID string `json:"output_file_id"`
144144 // The request counts for different statuses within the batch.
145145 RequestCounts BatchRequestCounts `json:"request_counts"`
146− // Metadata for the response, check the presence of optional fields with the
147− // [resp.Field.IsPresent] method.
146+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
148147 JSON struct {
149− ID resp.Field
150− CompletionWindow resp.Field
151− CreatedAt resp.Field
152− Endpoint resp.Field
153− InputFileID resp.Field
154− Object resp.Field
155− Status resp.Field
156− CancelledAt resp.Field
157− CancellingAt resp.Field
158− CompletedAt resp.Field
159− ErrorFileID resp.Field
160− Errors resp.Field
161− ExpiredAt resp.Field
162− ExpiresAt resp.Field
163− FailedAt resp.Field
164− FinalizingAt resp.Field
165− InProgressAt resp.Field
166− Metadata resp.Field
167− OutputFileID resp.Field
168− RequestCounts resp.Field
169− ExtraFields map[string]resp.Field
148+ ID respjson.Field
149+ CompletionWindow respjson.Field
150+ CreatedAt respjson.Field
151+ Endpoint respjson.Field
152+ InputFileID respjson.Field
153+ Object respjson.Field
154+ Status respjson.Field
155+ CancelledAt respjson.Field
156+ CancellingAt respjson.Field
157+ CompletedAt respjson.Field
158+ ErrorFileID respjson.Field
159+ Errors respjson.Field
160+ ExpiredAt respjson.Field
161+ ExpiresAt respjson.Field
162+ FailedAt respjson.Field
163+ FinalizingAt respjson.Field
164+ InProgressAt respjson.Field
165+ Metadata respjson.Field
166+ OutputFileID respjson.Field
167+ RequestCounts respjson.Field
168+ ExtraFields map[string]respjson.Field
170169 raw string
171170 } `json:"-"`
172171}
@@ -195,12 +194,11 @@ type BatchErrors struct {
195194 Data []BatchError `json:"data"`
196195 // The object type, which is always `list`.
197196 Object string `json:"object"`
198− // Metadata for the response, check the presence of optional fields with the
199− // [resp.Field.IsPresent] method.
197+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
200198 JSON struct {
201− Data resp.Field
202− Object resp.Field
203− ExtraFields map[string]resp.Field
199+ Data respjson.Field
200+ Object respjson.Field
201+ ExtraFields map[string]respjson.Field
204202 raw string
205203 } `json:"-"`
206204}
@@ -220,14 +218,13 @@ type BatchError struct {
220218 Message string `json:"message"`
221219 // The name of the parameter that caused the error, if applicable.
222220 Param string `json:"param,nullable"`
223− // Metadata for the response, check the presence of optional fields with the
224− // [resp.Field.IsPresent] method.
221+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
225222 JSON struct {
226− Code resp.Field
227− Line resp.Field
228− Message resp.Field
229− Param resp.Field
230− ExtraFields map[string]resp.Field
223+ Code respjson.Field
224+ Line respjson.Field
225+ Message respjson.Field
226+ Param respjson.Field
227+ ExtraFields map[string]respjson.Field
231228 raw string
232229 } `json:"-"`
233230}
@@ -246,13 +243,12 @@ type BatchRequestCounts struct {
246243 Failed int64 `json:"failed,required"`
247244 // Total number of requests in the batch.
248245 Total int64 `json:"total,required"`
249− // Metadata for the response, check the presence of optional fields with the
250− // [resp.Field.IsPresent] method.
246+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
251247 JSON struct {
252− Completed resp.Field
253− Failed resp.Field
254− Total resp.Field
255− ExtraFields map[string]resp.Field
248+ Completed respjson.Field
249+ Failed respjson.Field
250+ Total respjson.Field
251+ ExtraFields map[string]respjson.Field
256252 raw string
257253 } `json:"-"`
258254}
@@ -293,18 +289,17 @@ type BatchNewParams struct {
293289 //
294290 // Keys are strings with a maximum length of 64 characters. Values are strings with
295291 // a maximum length of 512 characters.
296− Metadata shared.MetadataParam `json:"metadata,omitzero"`
292+ Metadata shared.Metadata `json:"metadata,omitzero"`
297293 paramObj
298294}
299295
300−// IsPresent returns true if the field's value is not omitted and not the JSON
301−// "null". To check if this field is omitted, use [param.IsOmitted].
302−func (f BatchNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
303−
304296func (r BatchNewParams) MarshalJSON() (data []byte, err error) {
305297 type shadow BatchNewParams
306298 return param.MarshalObject(r, (*shadow)(&r))
307299}
300+func (r *BatchNewParams) UnmarshalJSON(data []byte) error {
301+ return apijson.UnmarshalRoot(data, r)
302+}
308303
309304// The time frame within which the batch should be processed. Currently only `24h`
310305// is supported.
@@ -339,12 +334,8 @@ type BatchListParams struct {
339334 paramObj
340335}
341336
342−// IsPresent returns true if the field's value is not omitted and not the JSON
343−// "null". To check if this field is omitted, use [param.IsOmitted].
344−func (f BatchListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
345−
346337// URLQuery serializes [BatchListParams]'s query parameters as `url.Values`.
347−func (r BatchListParams) URLQuery() (v url.Values) {
338+func (r BatchListParams) URLQuery() (v url.Values, err error) {
348339 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
349340 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
350341 NestedFormat: apiquery.NestedQueryFormatBrackets,
vendor/github.com/openai/openai-go/beta.go+2−1
@@ -15,7 +15,8 @@ import (
1515type BetaService struct {
1616 Options []option.RequestOption
1717 Assistants BetaAssistantService
18− Threads BetaThreadService
18+ // Deprecated: The Assistants API is deprecated in favor of the Responses API
19+ Threads BetaThreadService
1920}
2021
2122// NewBetaService generates a new service that applies the given options to each
vendor/github.com/openai/openai-go/betaassistant.go+413−401
@@ -9,7 +9,6 @@ import (
99 "fmt"
1010 "net/http"
1111 "net/url"
12− "reflect"
1312
1413 "github.com/openai/openai-go/internal/apijson"
1514 "github.com/openai/openai-go/internal/apiquery"
@@ -17,10 +16,9 @@ import (
1716 "github.com/openai/openai-go/option"
1817 "github.com/openai/openai-go/packages/pagination"
1918 "github.com/openai/openai-go/packages/param"
20− "github.com/openai/openai-go/packages/resp"
19+ "github.com/openai/openai-go/packages/respjson"
2120 "github.com/openai/openai-go/shared"
2221 "github.com/openai/openai-go/shared/constant"
23− "github.com/tidwall/gjson"
2422)
2523
2624// BetaAssistantService contains methods and other services that help with
@@ -181,23 +179,22 @@ type Assistant struct {
181179 //
182180 // We generally recommend altering this or temperature but not both.
183181 TopP float64 `json:"top_p,nullable"`
184− // Metadata for the response, check the presence of optional fields with the
185− // [resp.Field.IsPresent] method.
182+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
186183 JSON struct {
187− ID resp.Field
188− CreatedAt resp.Field
189− Description resp.Field
190− Instructions resp.Field
191− Metadata resp.Field
192− Model resp.Field
193− Name resp.Field
194− Object resp.Field
195− Tools resp.Field
196− ResponseFormat resp.Field
197− Temperature resp.Field
198− ToolResources resp.Field
199− TopP resp.Field
200− ExtraFields map[string]resp.Field
184+ ID respjson.Field
185+ CreatedAt respjson.Field
186+ Description respjson.Field
187+ Instructions respjson.Field
188+ Metadata respjson.Field
189+ Model respjson.Field
190+ Name respjson.Field
191+ Object respjson.Field
192+ Tools respjson.Field
193+ ResponseFormat respjson.Field
194+ Temperature respjson.Field
195+ ToolResources respjson.Field
196+ TopP respjson.Field
197+ ExtraFields map[string]respjson.Field
201198 raw string
202199 } `json:"-"`
203200}
@@ -215,12 +212,11 @@ func (r *Assistant) UnmarshalJSON(data []byte) error {
215212type AssistantToolResources struct {
216213 CodeInterpreter AssistantToolResourcesCodeInterpreter `json:"code_interpreter"`
217214 FileSearch AssistantToolResourcesFileSearch `json:"file_search"`
218− // Metadata for the response, check the presence of optional fields with the
219− // [resp.Field.IsPresent] method.
215+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
220216 JSON struct {
221− CodeInterpreter resp.Field
222− FileSearch resp.Field
223− ExtraFields map[string]resp.Field
217+ CodeInterpreter respjson.Field
218+ FileSearch respjson.Field
219+ ExtraFields map[string]respjson.Field
224220 raw string
225221 } `json:"-"`
226222}
@@ -236,11 +232,10 @@ type AssistantToolResourcesCodeInterpreter struct {
236232 // available to the `code_interpreter“ tool. There can be a maximum of 20 files
237233 // associated with the tool.
238234 FileIDs []string `json:"file_ids"`
239− // Metadata for the response, check the presence of optional fields with the
240− // [resp.Field.IsPresent] method.
235+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
241236 JSON struct {
242− FileIDs resp.Field
243− ExtraFields map[string]resp.Field
237+ FileIDs respjson.Field
238+ ExtraFields map[string]respjson.Field
244239 raw string
245240 } `json:"-"`
246241}
@@ -257,11 +252,10 @@ type AssistantToolResourcesFileSearch struct {
257252 // attached to this assistant. There can be a maximum of 1 vector store attached to
258253 // the assistant.
259254 VectorStoreIDs []string `json:"vector_store_ids"`
260− // Metadata for the response, check the presence of optional fields with the
261− // [resp.Field.IsPresent] method.
255+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
262256 JSON struct {
263− VectorStoreIDs resp.Field
264− ExtraFields map[string]resp.Field
257+ VectorStoreIDs respjson.Field
258+ ExtraFields map[string]respjson.Field
265259 raw string
266260 } `json:"-"`
267261}
@@ -276,13 +270,12 @@ type AssistantDeleted struct {
276270 ID string `json:"id,required"`
277271 Deleted bool `json:"deleted,required"`
278272 Object constant.AssistantDeleted `json:"object,required"`
279− // Metadata for the response, check the presence of optional fields with the
280− // [resp.Field.IsPresent] method.
273+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
281274 JSON struct {
282− ID resp.Field
283− Deleted resp.Field
284− Object resp.Field
285− ExtraFields map[string]resp.Field
275+ ID respjson.Field
276+ Deleted respjson.Field
277+ Object respjson.Field
278+ ExtraFields map[string]respjson.Field
286279 raw string
287280 } `json:"-"`
288281}
@@ -337,44 +330,76 @@ type AssistantStreamEventUnion struct {
337330 // This field is from variant [AssistantStreamEventThreadCreated].
338331 Enabled bool `json:"enabled"`
339332 JSON struct {
340− Data resp.Field
341− Event resp.Field
342− Enabled resp.Field
333+ Data respjson.Field
334+ Event respjson.Field
335+ Enabled respjson.Field
343336 raw string
344337 } `json:"-"`
345338}
346339
340+// anyAssistantStreamEvent is implemented by each variant of
341+// [AssistantStreamEventUnion] to add type safety for the return type of
342+// [AssistantStreamEventUnion.AsAny]
343+type anyAssistantStreamEvent interface {
344+ implAssistantStreamEventUnion()
345+}
346+
347+func (AssistantStreamEventThreadCreated) implAssistantStreamEventUnion() {}
348+func (AssistantStreamEventThreadRunCreated) implAssistantStreamEventUnion() {}
349+func (AssistantStreamEventThreadRunQueued) implAssistantStreamEventUnion() {}
350+func (AssistantStreamEventThreadRunInProgress) implAssistantStreamEventUnion() {}
351+func (AssistantStreamEventThreadRunRequiresAction) implAssistantStreamEventUnion() {}
352+func (AssistantStreamEventThreadRunCompleted) implAssistantStreamEventUnion() {}
353+func (AssistantStreamEventThreadRunIncomplete) implAssistantStreamEventUnion() {}
354+func (AssistantStreamEventThreadRunFailed) implAssistantStreamEventUnion() {}
355+func (AssistantStreamEventThreadRunCancelling) implAssistantStreamEventUnion() {}
356+func (AssistantStreamEventThreadRunCancelled) implAssistantStreamEventUnion() {}
357+func (AssistantStreamEventThreadRunExpired) implAssistantStreamEventUnion() {}
358+func (AssistantStreamEventThreadRunStepCreated) implAssistantStreamEventUnion() {}
359+func (AssistantStreamEventThreadRunStepInProgress) implAssistantStreamEventUnion() {}
360+func (AssistantStreamEventThreadRunStepDelta) implAssistantStreamEventUnion() {}
361+func (AssistantStreamEventThreadRunStepCompleted) implAssistantStreamEventUnion() {}
362+func (AssistantStreamEventThreadRunStepFailed) implAssistantStreamEventUnion() {}
363+func (AssistantStreamEventThreadRunStepCancelled) implAssistantStreamEventUnion() {}
364+func (AssistantStreamEventThreadRunStepExpired) implAssistantStreamEventUnion() {}
365+func (AssistantStreamEventThreadMessageCreated) implAssistantStreamEventUnion() {}
366+func (AssistantStreamEventThreadMessageInProgress) implAssistantStreamEventUnion() {}
367+func (AssistantStreamEventThreadMessageDelta) implAssistantStreamEventUnion() {}
368+func (AssistantStreamEventThreadMessageCompleted) implAssistantStreamEventUnion() {}
369+func (AssistantStreamEventThreadMessageIncomplete) implAssistantStreamEventUnion() {}
370+func (AssistantStreamEventErrorEvent) implAssistantStreamEventUnion() {}
371+
347372// Use the following switch statement to find the correct variant
348373//
349374// switch variant := AssistantStreamEventUnion.AsAny().(type) {
350−// case AssistantStreamEventThreadCreated:
351−// case AssistantStreamEventThreadRunCreated:
352−// case AssistantStreamEventThreadRunQueued:
353−// case AssistantStreamEventThreadRunInProgress:
354−// case AssistantStreamEventThreadRunRequiresAction:
355−// case AssistantStreamEventThreadRunCompleted:
356−// case AssistantStreamEventThreadRunIncomplete:
357−// case AssistantStreamEventThreadRunFailed:
358−// case AssistantStreamEventThreadRunCancelling:
359−// case AssistantStreamEventThreadRunCancelled:
360−// case AssistantStreamEventThreadRunExpired:
361−// case AssistantStreamEventThreadRunStepCreated:
362−// case AssistantStreamEventThreadRunStepInProgress:
363−// case AssistantStreamEventThreadRunStepDelta:
364−// case AssistantStreamEventThreadRunStepCompleted:
365−// case AssistantStreamEventThreadRunStepFailed:
366−// case AssistantStreamEventThreadRunStepCancelled:
367−// case AssistantStreamEventThreadRunStepExpired:
368−// case AssistantStreamEventThreadMessageCreated:
369−// case AssistantStreamEventThreadMessageInProgress:
370−// case AssistantStreamEventThreadMessageDelta:
371−// case AssistantStreamEventThreadMessageCompleted:
372−// case AssistantStreamEventThreadMessageIncomplete:
373−// case AssistantStreamEventErrorEvent:
375+// case openai.AssistantStreamEventThreadCreated:
376+// case openai.AssistantStreamEventThreadRunCreated:
377+// case openai.AssistantStreamEventThreadRunQueued:
378+// case openai.AssistantStreamEventThreadRunInProgress:
379+// case openai.AssistantStreamEventThreadRunRequiresAction:
380+// case openai.AssistantStreamEventThreadRunCompleted:
381+// case openai.AssistantStreamEventThreadRunIncomplete:
382+// case openai.AssistantStreamEventThreadRunFailed:
383+// case openai.AssistantStreamEventThreadRunCancelling:
384+// case openai.AssistantStreamEventThreadRunCancelled:
385+// case openai.AssistantStreamEventThreadRunExpired:
386+// case openai.AssistantStreamEventThreadRunStepCreated:
387+// case openai.AssistantStreamEventThreadRunStepInProgress:
388+// case openai.AssistantStreamEventThreadRunStepDelta:
389+// case openai.AssistantStreamEventThreadRunStepCompleted:
390+// case openai.AssistantStreamEventThreadRunStepFailed:
391+// case openai.AssistantStreamEventThreadRunStepCancelled:
392+// case openai.AssistantStreamEventThreadRunStepExpired:
393+// case openai.AssistantStreamEventThreadMessageCreated:
394+// case openai.AssistantStreamEventThreadMessageInProgress:
395+// case openai.AssistantStreamEventThreadMessageDelta:
396+// case openai.AssistantStreamEventThreadMessageCompleted:
397+// case openai.AssistantStreamEventThreadMessageIncomplete:
398+// case openai.AssistantStreamEventErrorEvent:
374399// default:
375400// fmt.Errorf("no variant present")
376401// }
377−func (u AssistantStreamEventUnion) AsAny() any {
402+func (u AssistantStreamEventUnion) AsAny() anyAssistantStreamEvent {
378403 switch u.Event {
379404 case "thread.created":
380405 return u.AsThreadCreated()
@@ -632,46 +657,46 @@ type AssistantStreamEventUnionData struct {
632657 // This field is from variant [shared.ErrorObject].
633658 Param string `json:"param"`
634659 JSON struct {
635− ID resp.Field
636− CreatedAt resp.Field
637− Metadata resp.Field
638− Object resp.Field
639− ToolResources resp.Field
640− AssistantID resp.Field
641− CancelledAt resp.Field
642− CompletedAt resp.Field
643− ExpiresAt resp.Field
644− FailedAt resp.Field
645− IncompleteDetails resp.Field
646− Instructions resp.Field
647− LastError resp.Field
648− MaxCompletionTokens resp.Field
649− MaxPromptTokens resp.Field
650− Model resp.Field
651− ParallelToolCalls resp.Field
652− RequiredAction resp.Field
653− ResponseFormat resp.Field
654− StartedAt resp.Field
655− Status resp.Field
656− ThreadID resp.Field
657− ToolChoice resp.Field
658− Tools resp.Field
659− TruncationStrategy resp.Field
660− Usage resp.Field
661− Temperature resp.Field
662− TopP resp.Field
663− ExpiredAt resp.Field
664− RunID resp.Field
665− StepDetails resp.Field
666− Type resp.Field
667− Delta resp.Field
668− Attachments resp.Field
669− Content resp.Field
670− IncompleteAt resp.Field
671− Role resp.Field
672− Code resp.Field
673− Message resp.Field
674− Param resp.Field
660+ ID respjson.Field
661+ CreatedAt respjson.Field
662+ Metadata respjson.Field
663+ Object respjson.Field
664+ ToolResources respjson.Field
665+ AssistantID respjson.Field
666+ CancelledAt respjson.Field
667+ CompletedAt respjson.Field
668+ ExpiresAt respjson.Field
669+ FailedAt respjson.Field
670+ IncompleteDetails respjson.Field
671+ Instructions respjson.Field
672+ LastError respjson.Field
673+ MaxCompletionTokens respjson.Field
674+ MaxPromptTokens respjson.Field
675+ Model respjson.Field
676+ ParallelToolCalls respjson.Field
677+ RequiredAction respjson.Field
678+ ResponseFormat respjson.Field
679+ StartedAt respjson.Field
680+ Status respjson.Field
681+ ThreadID respjson.Field
682+ ToolChoice respjson.Field
683+ Tools respjson.Field
684+ TruncationStrategy respjson.Field
685+ Usage respjson.Field
686+ Temperature respjson.Field
687+ TopP respjson.Field
688+ ExpiredAt respjson.Field
689+ RunID respjson.Field
690+ StepDetails respjson.Field
691+ Type respjson.Field
692+ Delta respjson.Field
693+ Attachments respjson.Field
694+ Content respjson.Field
695+ IncompleteAt respjson.Field
696+ Role respjson.Field
697+ Code respjson.Field
698+ Message respjson.Field
699+ Param respjson.Field
675700 raw string
676701 } `json:"-"`
677702}
@@ -689,7 +714,7 @@ func (r *AssistantStreamEventUnionData) UnmarshalJSON(data []byte) error {
689714type AssistantStreamEventUnionDataIncompleteDetails struct {
690715 Reason string `json:"reason"`
691716 JSON struct {
692− Reason resp.Field
717+ Reason respjson.Field
693718 raw string
694719 } `json:"-"`
695720}
@@ -708,8 +733,8 @@ type AssistantStreamEventUnionDataLastError struct {
708733 Code string `json:"code"`
709734 Message string `json:"message"`
710735 JSON struct {
711− Code resp.Field
712− Message resp.Field
736+ Code respjson.Field
737+ Message respjson.Field
713738 raw string
714739 } `json:"-"`
715740}
@@ -729,9 +754,9 @@ type AssistantStreamEventUnionDataUsage struct {
729754 PromptTokens int64 `json:"prompt_tokens"`
730755 TotalTokens int64 `json:"total_tokens"`
731756 JSON struct {
732− CompletionTokens resp.Field
733− PromptTokens resp.Field
734− TotalTokens resp.Field
757+ CompletionTokens respjson.Field
758+ PromptTokens respjson.Field
759+ TotalTokens respjson.Field
735760 raw string
736761 } `json:"-"`
737762}
@@ -754,9 +779,9 @@ type AssistantStreamEventUnionDataDelta struct {
754779 // This field is from variant [MessageDelta].
755780 Role MessageDeltaRole `json:"role"`
756781 JSON struct {
757− StepDetails resp.Field
758− Content resp.Field
759− Role resp.Field
782+ StepDetails respjson.Field
783+ Content respjson.Field
784+ Role respjson.Field
760785 raw string
761786 } `json:"-"`
762787}
@@ -775,13 +800,12 @@ type AssistantStreamEventThreadCreated struct {
775800 Event constant.ThreadCreated `json:"event,required"`
776801 // Whether to enable input audio transcription.
777802 Enabled bool `json:"enabled"`
778− // Metadata for the response, check the presence of optional fields with the
779− // [resp.Field.IsPresent] method.
803+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
780804 JSON struct {
781− Data resp.Field
782− Event resp.Field
783− Enabled resp.Field
784− ExtraFields map[string]resp.Field
805+ Data respjson.Field
806+ Event respjson.Field
807+ Enabled respjson.Field
808+ ExtraFields map[string]respjson.Field
785809 raw string
786810 } `json:"-"`
787811}
@@ -799,12 +823,11 @@ type AssistantStreamEventThreadRunCreated struct {
799823 // [thread](https://platform.openai.com/docs/api-reference/threads).
800824 Data Run `json:"data,required"`
801825 Event constant.ThreadRunCreated `json:"event,required"`
802− // Metadata for the response, check the presence of optional fields with the
803− // [resp.Field.IsPresent] method.
826+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
804827 JSON struct {
805− Data resp.Field
806− Event resp.Field
807− ExtraFields map[string]resp.Field
828+ Data respjson.Field
829+ Event respjson.Field
830+ ExtraFields map[string]respjson.Field
808831 raw string
809832 } `json:"-"`
810833}
@@ -822,12 +845,11 @@ type AssistantStreamEventThreadRunQueued struct {
822845 // [thread](https://platform.openai.com/docs/api-reference/threads).
823846 Data Run `json:"data,required"`
824847 Event constant.ThreadRunQueued `json:"event,required"`
825− // Metadata for the response, check the presence of optional fields with the
826− // [resp.Field.IsPresent] method.
848+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
827849 JSON struct {
828− Data resp.Field
829− Event resp.Field
830− ExtraFields map[string]resp.Field
850+ Data respjson.Field
851+ Event respjson.Field
852+ ExtraFields map[string]respjson.Field
831853 raw string
832854 } `json:"-"`
833855}
@@ -845,12 +867,11 @@ type AssistantStreamEventThreadRunInProgress struct {
845867 // [thread](https://platform.openai.com/docs/api-reference/threads).
846868 Data Run `json:"data,required"`
847869 Event constant.ThreadRunInProgress `json:"event,required"`
848− // Metadata for the response, check the presence of optional fields with the
849− // [resp.Field.IsPresent] method.
870+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
850871 JSON struct {
851− Data resp.Field
852− Event resp.Field
853− ExtraFields map[string]resp.Field
872+ Data respjson.Field
873+ Event respjson.Field
874+ ExtraFields map[string]respjson.Field
854875 raw string
855876 } `json:"-"`
856877}
@@ -868,12 +889,11 @@ type AssistantStreamEventThreadRunRequiresAction struct {
868889 // [thread](https://platform.openai.com/docs/api-reference/threads).
869890 Data Run `json:"data,required"`
870891 Event constant.ThreadRunRequiresAction `json:"event,required"`
871− // Metadata for the response, check the presence of optional fields with the
872− // [resp.Field.IsPresent] method.
892+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
873893 JSON struct {
874− Data resp.Field
875− Event resp.Field
876− ExtraFields map[string]resp.Field
894+ Data respjson.Field
895+ Event respjson.Field
896+ ExtraFields map[string]respjson.Field
877897 raw string
878898 } `json:"-"`
879899}
@@ -891,12 +911,11 @@ type AssistantStreamEventThreadRunCompleted struct {
891911 // [thread](https://platform.openai.com/docs/api-reference/threads).
892912 Data Run `json:"data,required"`
893913 Event constant.ThreadRunCompleted `json:"event,required"`
894− // Metadata for the response, check the presence of optional fields with the
895− // [resp.Field.IsPresent] method.
914+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
896915 JSON struct {
897− Data resp.Field
898− Event resp.Field
899− ExtraFields map[string]resp.Field
916+ Data respjson.Field
917+ Event respjson.Field
918+ ExtraFields map[string]respjson.Field
900919 raw string
901920 } `json:"-"`
902921}
@@ -914,12 +933,11 @@ type AssistantStreamEventThreadRunIncomplete struct {
914933 // [thread](https://platform.openai.com/docs/api-reference/threads).
915934 Data Run `json:"data,required"`
916935 Event constant.ThreadRunIncomplete `json:"event,required"`
917− // Metadata for the response, check the presence of optional fields with the
918− // [resp.Field.IsPresent] method.
936+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
919937 JSON struct {
920− Data resp.Field
921− Event resp.Field
922− ExtraFields map[string]resp.Field
938+ Data respjson.Field
939+ Event respjson.Field
940+ ExtraFields map[string]respjson.Field
923941 raw string
924942 } `json:"-"`
925943}
@@ -937,12 +955,11 @@ type AssistantStreamEventThreadRunFailed struct {
937955 // [thread](https://platform.openai.com/docs/api-reference/threads).
938956 Data Run `json:"data,required"`
939957 Event constant.ThreadRunFailed `json:"event,required"`
940− // Metadata for the response, check the presence of optional fields with the
941− // [resp.Field.IsPresent] method.
958+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
942959 JSON struct {
943− Data resp.Field
944− Event resp.Field
945− ExtraFields map[string]resp.Field
960+ Data respjson.Field
961+ Event respjson.Field
962+ ExtraFields map[string]respjson.Field
946963 raw string
947964 } `json:"-"`
948965}
@@ -960,12 +977,11 @@ type AssistantStreamEventThreadRunCancelling struct {
960977 // [thread](https://platform.openai.com/docs/api-reference/threads).
961978 Data Run `json:"data,required"`
962979 Event constant.ThreadRunCancelling `json:"event,required"`
963− // Metadata for the response, check the presence of optional fields with the
964− // [resp.Field.IsPresent] method.
980+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
965981 JSON struct {
966− Data resp.Field
967− Event resp.Field
968− ExtraFields map[string]resp.Field
982+ Data respjson.Field
983+ Event respjson.Field
984+ ExtraFields map[string]respjson.Field
969985 raw string
970986 } `json:"-"`
971987}
@@ -983,12 +999,11 @@ type AssistantStreamEventThreadRunCancelled struct {
983999 // [thread](https://platform.openai.com/docs/api-reference/threads).
9841000 Data Run `json:"data,required"`
9851001 Event constant.ThreadRunCancelled `json:"event,required"`
986− // Metadata for the response, check the presence of optional fields with the
987− // [resp.Field.IsPresent] method.
1002+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
9881003 JSON struct {
989− Data resp.Field
990− Event resp.Field
991− ExtraFields map[string]resp.Field
1004+ Data respjson.Field
1005+ Event respjson.Field
1006+ ExtraFields map[string]respjson.Field
9921007 raw string
9931008 } `json:"-"`
9941009}
@@ -1006,12 +1021,11 @@ type AssistantStreamEventThreadRunExpired struct {
10061021 // [thread](https://platform.openai.com/docs/api-reference/threads).
10071022 Data Run `json:"data,required"`
10081023 Event constant.ThreadRunExpired `json:"event,required"`
1009− // Metadata for the response, check the presence of optional fields with the
1010− // [resp.Field.IsPresent] method.
1024+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
10111025 JSON struct {
1012− Data resp.Field
1013− Event resp.Field
1014− ExtraFields map[string]resp.Field
1026+ Data respjson.Field
1027+ Event respjson.Field
1028+ ExtraFields map[string]respjson.Field
10151029 raw string
10161030 } `json:"-"`
10171031}
@@ -1029,12 +1043,11 @@ type AssistantStreamEventThreadRunStepCreated struct {
10291043 // Represents a step in execution of a run.
10301044 Data RunStep `json:"data,required"`
10311045 Event constant.ThreadRunStepCreated `json:"event,required"`
1032− // Metadata for the response, check the presence of optional fields with the
1033− // [resp.Field.IsPresent] method.
1046+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
10341047 JSON struct {
1035− Data resp.Field
1036− Event resp.Field
1037− ExtraFields map[string]resp.Field
1048+ Data respjson.Field
1049+ Event respjson.Field
1050+ ExtraFields map[string]respjson.Field
10381051 raw string
10391052 } `json:"-"`
10401053}
@@ -1052,12 +1065,11 @@ type AssistantStreamEventThreadRunStepInProgress struct {
10521065 // Represents a step in execution of a run.
10531066 Data RunStep `json:"data,required"`
10541067 Event constant.ThreadRunStepInProgress `json:"event,required"`
1055− // Metadata for the response, check the presence of optional fields with the
1056− // [resp.Field.IsPresent] method.
1068+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
10571069 JSON struct {
1058− Data resp.Field
1059− Event resp.Field
1060− ExtraFields map[string]resp.Field
1070+ Data respjson.Field
1071+ Event respjson.Field
1072+ ExtraFields map[string]respjson.Field
10611073 raw string
10621074 } `json:"-"`
10631075}
@@ -1076,12 +1088,11 @@ type AssistantStreamEventThreadRunStepDelta struct {
10761088 // streaming.
10771089 Data RunStepDeltaEvent `json:"data,required"`
10781090 Event constant.ThreadRunStepDelta `json:"event,required"`
1079− // Metadata for the response, check the presence of optional fields with the
1080− // [resp.Field.IsPresent] method.
1091+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
10811092 JSON struct {
1082− Data resp.Field
1083− Event resp.Field
1084− ExtraFields map[string]resp.Field
1093+ Data respjson.Field
1094+ Event respjson.Field
1095+ ExtraFields map[string]respjson.Field
10851096 raw string
10861097 } `json:"-"`
10871098}
@@ -1099,12 +1110,11 @@ type AssistantStreamEventThreadRunStepCompleted struct {
10991110 // Represents a step in execution of a run.
11001111 Data RunStep `json:"data,required"`
11011112 Event constant.ThreadRunStepCompleted `json:"event,required"`
1102− // Metadata for the response, check the presence of optional fields with the
1103− // [resp.Field.IsPresent] method.
1113+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
11041114 JSON struct {
1105− Data resp.Field
1106− Event resp.Field
1107− ExtraFields map[string]resp.Field
1115+ Data respjson.Field
1116+ Event respjson.Field
1117+ ExtraFields map[string]respjson.Field
11081118 raw string
11091119 } `json:"-"`
11101120}
@@ -1122,12 +1132,11 @@ type AssistantStreamEventThreadRunStepFailed struct {
11221132 // Represents a step in execution of a run.
11231133 Data RunStep `json:"data,required"`
11241134 Event constant.ThreadRunStepFailed `json:"event,required"`
1125− // Metadata for the response, check the presence of optional fields with the
1126− // [resp.Field.IsPresent] method.
1135+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
11271136 JSON struct {
1128− Data resp.Field
1129− Event resp.Field
1130− ExtraFields map[string]resp.Field
1137+ Data respjson.Field
1138+ Event respjson.Field
1139+ ExtraFields map[string]respjson.Field
11311140 raw string
11321141 } `json:"-"`
11331142}
@@ -1145,12 +1154,11 @@ type AssistantStreamEventThreadRunStepCancelled struct {
11451154 // Represents a step in execution of a run.
11461155 Data RunStep `json:"data,required"`
11471156 Event constant.ThreadRunStepCancelled `json:"event,required"`
1148− // Metadata for the response, check the presence of optional fields with the
1149− // [resp.Field.IsPresent] method.
1157+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
11501158 JSON struct {
1151− Data resp.Field
1152− Event resp.Field
1153− ExtraFields map[string]resp.Field
1159+ Data respjson.Field
1160+ Event respjson.Field
1161+ ExtraFields map[string]respjson.Field
11541162 raw string
11551163 } `json:"-"`
11561164}
@@ -1168,12 +1176,11 @@ type AssistantStreamEventThreadRunStepExpired struct {
11681176 // Represents a step in execution of a run.
11691177 Data RunStep `json:"data,required"`
11701178 Event constant.ThreadRunStepExpired `json:"event,required"`
1171− // Metadata for the response, check the presence of optional fields with the
1172− // [resp.Field.IsPresent] method.
1179+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
11731180 JSON struct {
1174− Data resp.Field
1175− Event resp.Field
1176− ExtraFields map[string]resp.Field
1181+ Data respjson.Field
1182+ Event respjson.Field
1183+ ExtraFields map[string]respjson.Field
11771184 raw string
11781185 } `json:"-"`
11791186}
@@ -1192,12 +1199,11 @@ type AssistantStreamEventThreadMessageCreated struct {
11921199 // [thread](https://platform.openai.com/docs/api-reference/threads).
11931200 Data Message `json:"data,required"`
11941201 Event constant.ThreadMessageCreated `json:"event,required"`
1195− // Metadata for the response, check the presence of optional fields with the
1196− // [resp.Field.IsPresent] method.
1202+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
11971203 JSON struct {
1198− Data resp.Field
1199− Event resp.Field
1200− ExtraFields map[string]resp.Field
1204+ Data respjson.Field
1205+ Event respjson.Field
1206+ ExtraFields map[string]respjson.Field
12011207 raw string
12021208 } `json:"-"`
12031209}
@@ -1216,12 +1222,11 @@ type AssistantStreamEventThreadMessageInProgress struct {
12161222 // [thread](https://platform.openai.com/docs/api-reference/threads).
12171223 Data Message `json:"data,required"`
12181224 Event constant.ThreadMessageInProgress `json:"event,required"`
1219− // Metadata for the response, check the presence of optional fields with the
1220− // [resp.Field.IsPresent] method.
1225+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12211226 JSON struct {
1222− Data resp.Field
1223− Event resp.Field
1224− ExtraFields map[string]resp.Field
1227+ Data respjson.Field
1228+ Event respjson.Field
1229+ ExtraFields map[string]respjson.Field
12251230 raw string
12261231 } `json:"-"`
12271232}
@@ -1240,12 +1245,11 @@ type AssistantStreamEventThreadMessageDelta struct {
12401245 // streaming.
12411246 Data MessageDeltaEvent `json:"data,required"`
12421247 Event constant.ThreadMessageDelta `json:"event,required"`
1243− // Metadata for the response, check the presence of optional fields with the
1244− // [resp.Field.IsPresent] method.
1248+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12451249 JSON struct {
1246− Data resp.Field
1247− Event resp.Field
1248− ExtraFields map[string]resp.Field
1250+ Data respjson.Field
1251+ Event respjson.Field
1252+ ExtraFields map[string]respjson.Field
12491253 raw string
12501254 } `json:"-"`
12511255}
@@ -1264,12 +1268,11 @@ type AssistantStreamEventThreadMessageCompleted struct {
12641268 // [thread](https://platform.openai.com/docs/api-reference/threads).
12651269 Data Message `json:"data,required"`
12661270 Event constant.ThreadMessageCompleted `json:"event,required"`
1267− // Metadata for the response, check the presence of optional fields with the
1268− // [resp.Field.IsPresent] method.
1271+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12691272 JSON struct {
1270− Data resp.Field
1271− Event resp.Field
1272− ExtraFields map[string]resp.Field
1273+ Data respjson.Field
1274+ Event respjson.Field
1275+ ExtraFields map[string]respjson.Field
12731276 raw string
12741277 } `json:"-"`
12751278}
@@ -1288,12 +1291,11 @@ type AssistantStreamEventThreadMessageIncomplete struct {
12881291 // [thread](https://platform.openai.com/docs/api-reference/threads).
12891292 Data Message `json:"data,required"`
12901293 Event constant.ThreadMessageIncomplete `json:"event,required"`
1291− // Metadata for the response, check the presence of optional fields with the
1292− // [resp.Field.IsPresent] method.
1294+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12931295 JSON struct {
1294− Data resp.Field
1295− Event resp.Field
1296− ExtraFields map[string]resp.Field
1296+ Data respjson.Field
1297+ Event respjson.Field
1298+ ExtraFields map[string]respjson.Field
12971299 raw string
12981300 } `json:"-"`
12991301}
@@ -1310,12 +1312,11 @@ func (r *AssistantStreamEventThreadMessageIncomplete) UnmarshalJSON(data []byte)
13101312type AssistantStreamEventErrorEvent struct {
13111313 Data shared.ErrorObject `json:"data,required"`
13121314 Event constant.Error `json:"event,required"`
1313− // Metadata for the response, check the presence of optional fields with the
1314− // [resp.Field.IsPresent] method.
1315+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13151316 JSON struct {
1316− Data resp.Field
1317− Event resp.Field
1318− ExtraFields map[string]resp.Field
1317+ Data respjson.Field
1318+ Event respjson.Field
1319+ ExtraFields map[string]respjson.Field
13191320 raw string
13201321 } `json:"-"`
13211322}
@@ -1340,23 +1341,33 @@ type AssistantToolUnion struct {
13401341 // This field is from variant [FunctionTool].
13411342 Function shared.FunctionDefinition `json:"function"`
13421343 JSON struct {
1343− Type resp.Field
1344− FileSearch resp.Field
1345− Function resp.Field
1344+ Type respjson.Field
1345+ FileSearch respjson.Field
1346+ Function respjson.Field
13461347 raw string
13471348 } `json:"-"`
13481349}
13491350
1351+// anyAssistantTool is implemented by each variant of [AssistantToolUnion] to add
1352+// type safety for the return type of [AssistantToolUnion.AsAny]
1353+type anyAssistantTool interface {
1354+ implAssistantToolUnion()
1355+}
1356+
1357+func (CodeInterpreterTool) implAssistantToolUnion() {}
1358+func (FileSearchTool) implAssistantToolUnion() {}
1359+func (FunctionTool) implAssistantToolUnion() {}
1360+
13501361// Use the following switch statement to find the correct variant
13511362//
13521363// switch variant := AssistantToolUnion.AsAny().(type) {
1353−// case CodeInterpreterTool:
1354−// case FileSearchTool:
1355−// case FunctionTool:
1364+// case openai.CodeInterpreterTool:
1365+// case openai.FileSearchTool:
1366+// case openai.FunctionTool:
13561367// default:
13571368// fmt.Errorf("no variant present")
13581369// }
1359−func (u AssistantToolUnion) AsAny() any {
1370+func (u AssistantToolUnion) AsAny() anyAssistantTool {
13601371 switch u.Type {
13611372 case "code_interpreter":
13621373 return u.AsCodeInterpreter()
@@ -1394,9 +1405,9 @@ func (r *AssistantToolUnion) UnmarshalJSON(data []byte) error {
13941405//
13951406// Warning: the fields of the param type will not be present. ToParam should only
13961407// be used at the last possible moment before sending a request. Test for this with
1397−// AssistantToolUnionParam.IsOverridden()
1408+// AssistantToolUnionParam.Overrides()
13981409func (r AssistantToolUnion) ToParam() AssistantToolUnionParam {
1399− return param.OverrideObj[AssistantToolUnionParam](r.RawJSON())
1410+ return param.Override[AssistantToolUnionParam](json.RawMessage(r.RawJSON()))
14001411}
14011412
14021413func AssistantToolParamOfFunction(function shared.FunctionDefinitionParam) AssistantToolUnionParam {
@@ -1415,11 +1426,11 @@ type AssistantToolUnionParam struct {
14151426 paramUnion
14161427}
14171428
1418−// IsPresent returns true if the field's value is not omitted and not the JSON
1419−// "null". To check if this field is omitted, use [param.IsOmitted].
1420−func (u AssistantToolUnionParam) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() }
14211429func (u AssistantToolUnionParam) MarshalJSON() ([]byte, error) {
1422− return param.MarshalUnion[AssistantToolUnionParam](u.OfCodeInterpreter, u.OfFileSearch, u.OfFunction)
1430+ return param.MarshalUnion(u, u.OfCodeInterpreter, u.OfFileSearch, u.OfFunction)
1431+}
1432+func (u *AssistantToolUnionParam) UnmarshalJSON(data []byte) error {
1433+ return apijson.UnmarshalRoot(data, u)
14231434}
14241435
14251436func (u *AssistantToolUnionParam) asAny() any {
@@ -1464,32 +1475,19 @@ func (u AssistantToolUnionParam) GetType() *string {
14641475func init() {
14651476 apijson.RegisterUnion[AssistantToolUnionParam](
14661477 "type",
1467− apijson.UnionVariant{
1468− TypeFilter: gjson.JSON,
1469− Type: reflect.TypeOf(CodeInterpreterToolParam{}),
1470− DiscriminatorValue: "code_interpreter",
1471− },
1472− apijson.UnionVariant{
1473− TypeFilter: gjson.JSON,
1474− Type: reflect.TypeOf(FileSearchToolParam{}),
1475− DiscriminatorValue: "file_search",
1476− },
1477− apijson.UnionVariant{
1478− TypeFilter: gjson.JSON,
1479− Type: reflect.TypeOf(FunctionToolParam{}),
1480− DiscriminatorValue: "function",
1481− },
1478+ apijson.Discriminator[CodeInterpreterToolParam]("code_interpreter"),
1479+ apijson.Discriminator[FileSearchToolParam]("file_search"),
1480+ apijson.Discriminator[FunctionToolParam]("function"),
14821481 )
14831482}
14841483
14851484type CodeInterpreterTool struct {
14861485 // The type of tool being defined: `code_interpreter`
14871486 Type constant.CodeInterpreter `json:"type,required"`
1488− // Metadata for the response, check the presence of optional fields with the
1489− // [resp.Field.IsPresent] method.
1487+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
14901488 JSON struct {
1491− Type resp.Field
1492− ExtraFields map[string]resp.Field
1489+ Type respjson.Field
1490+ ExtraFields map[string]respjson.Field
14931491 raw string
14941492 } `json:"-"`
14951493}
@@ -1504,39 +1502,43 @@ func (r *CodeInterpreterTool) UnmarshalJSON(data []byte) error {
15041502//
15051503// Warning: the fields of the param type will not be present. ToParam should only
15061504// be used at the last possible moment before sending a request. Test for this with
1507−// CodeInterpreterToolParam.IsOverridden()
1505+// CodeInterpreterToolParam.Overrides()
15081506func (r CodeInterpreterTool) ToParam() CodeInterpreterToolParam {
1509− return param.OverrideObj[CodeInterpreterToolParam](r.RawJSON())
1507+ return param.Override[CodeInterpreterToolParam](json.RawMessage(r.RawJSON()))
15101508}
15111509
1512−// The property Type is required.
1510+func NewCodeInterpreterToolParam() CodeInterpreterToolParam {
1511+ return CodeInterpreterToolParam{
1512+ Type: "code_interpreter",
1513+ }
1514+}
1515+
1516+// This struct has a constant value, construct it with
1517+// [NewCodeInterpreterToolParam].
15131518type CodeInterpreterToolParam struct {
15141519 // The type of tool being defined: `code_interpreter`
1515− //
1516− // This field can be elided, and will marshal its zero value as "code_interpreter".
15171520 Type constant.CodeInterpreter `json:"type,required"`
15181521 paramObj
15191522}
15201523
1521−// IsPresent returns true if the field's value is not omitted and not the JSON
1522−// "null". To check if this field is omitted, use [param.IsOmitted].
1523−func (f CodeInterpreterToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
15241524func (r CodeInterpreterToolParam) MarshalJSON() (data []byte, err error) {
15251525 type shadow CodeInterpreterToolParam
15261526 return param.MarshalObject(r, (*shadow)(&r))
15271527}
1528+func (r *CodeInterpreterToolParam) UnmarshalJSON(data []byte) error {
1529+ return apijson.UnmarshalRoot(data, r)
1530+}
15281531
15291532type FileSearchTool struct {
15301533 // The type of tool being defined: `file_search`
15311534 Type constant.FileSearch `json:"type,required"`
15321535 // Overrides for the file search tool.
15331536 FileSearch FileSearchToolFileSearch `json:"file_search"`
1534− // Metadata for the response, check the presence of optional fields with the
1535− // [resp.Field.IsPresent] method.
1537+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
15361538 JSON struct {
1537− Type resp.Field
1538− FileSearch resp.Field
1539− ExtraFields map[string]resp.Field
1539+ Type respjson.Field
1540+ FileSearch respjson.Field
1541+ ExtraFields map[string]respjson.Field
15401542 raw string
15411543 } `json:"-"`
15421544}
@@ -1551,9 +1553,9 @@ func (r *FileSearchTool) UnmarshalJSON(data []byte) error {
15511553//
15521554// Warning: the fields of the param type will not be present. ToParam should only
15531555// be used at the last possible moment before sending a request. Test for this with
1554−// FileSearchToolParam.IsOverridden()
1556+// FileSearchToolParam.Overrides()
15551557func (r FileSearchTool) ToParam() FileSearchToolParam {
1556− return param.OverrideObj[FileSearchToolParam](r.RawJSON())
1558+ return param.Override[FileSearchToolParam](json.RawMessage(r.RawJSON()))
15571559}
15581560
15591561// Overrides for the file search tool.
@@ -1574,12 +1576,11 @@ type FileSearchToolFileSearch struct {
15741576 // [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings)
15751577 // for more information.
15761578 RankingOptions FileSearchToolFileSearchRankingOptions `json:"ranking_options"`
1577− // Metadata for the response, check the presence of optional fields with the
1578− // [resp.Field.IsPresent] method.
1579+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
15791580 JSON struct {
1580− MaxNumResults resp.Field
1581− RankingOptions resp.Field
1582− ExtraFields map[string]resp.Field
1581+ MaxNumResults respjson.Field
1582+ RankingOptions respjson.Field
1583+ ExtraFields map[string]respjson.Field
15831584 raw string
15841585 } `json:"-"`
15851586}
@@ -1605,12 +1606,11 @@ type FileSearchToolFileSearchRankingOptions struct {
16051606 //
16061607 // Any of "auto", "default_2024_08_21".
16071608 Ranker string `json:"ranker"`
1608− // Metadata for the response, check the presence of optional fields with the
1609− // [resp.Field.IsPresent] method.
1609+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
16101610 JSON struct {
1611− ScoreThreshold resp.Field
1612− Ranker resp.Field
1613− ExtraFields map[string]resp.Field
1611+ ScoreThreshold respjson.Field
1612+ Ranker respjson.Field
1613+ ExtraFields map[string]respjson.Field
16141614 raw string
16151615 } `json:"-"`
16161616}
@@ -1632,13 +1632,13 @@ type FileSearchToolParam struct {
16321632 paramObj
16331633}
16341634
1635−// IsPresent returns true if the field's value is not omitted and not the JSON
1636−// "null". To check if this field is omitted, use [param.IsOmitted].
1637−func (f FileSearchToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
16381635func (r FileSearchToolParam) MarshalJSON() (data []byte, err error) {
16391636 type shadow FileSearchToolParam
16401637 return param.MarshalObject(r, (*shadow)(&r))
16411638}
1639+func (r *FileSearchToolParam) UnmarshalJSON(data []byte) error {
1640+ return apijson.UnmarshalRoot(data, r)
1641+}
16421642
16431643// Overrides for the file search tool.
16441644type FileSearchToolFileSearchParam struct {
@@ -1661,13 +1661,13 @@ type FileSearchToolFileSearchParam struct {
16611661 paramObj
16621662}
16631663
1664−// IsPresent returns true if the field's value is not omitted and not the JSON
1665−// "null". To check if this field is omitted, use [param.IsOmitted].
1666−func (f FileSearchToolFileSearchParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
16671664func (r FileSearchToolFileSearchParam) MarshalJSON() (data []byte, err error) {
16681665 type shadow FileSearchToolFileSearchParam
16691666 return param.MarshalObject(r, (*shadow)(&r))
16701667}
1668+func (r *FileSearchToolFileSearchParam) UnmarshalJSON(data []byte) error {
1669+ return apijson.UnmarshalRoot(data, r)
1670+}
16711671
16721672// The ranking options for the file search. If not specified, the file search tool
16731673// will use the `auto` ranker and a score_threshold of 0.
@@ -1689,19 +1689,17 @@ type FileSearchToolFileSearchRankingOptionsParam struct {
16891689 paramObj
16901690}
16911691
1692−// IsPresent returns true if the field's value is not omitted and not the JSON
1693−// "null". To check if this field is omitted, use [param.IsOmitted].
1694−func (f FileSearchToolFileSearchRankingOptionsParam) IsPresent() bool {
1695− return !param.IsOmitted(f) && !f.IsNull()
1696−}
16971692func (r FileSearchToolFileSearchRankingOptionsParam) MarshalJSON() (data []byte, err error) {
16981693 type shadow FileSearchToolFileSearchRankingOptionsParam
16991694 return param.MarshalObject(r, (*shadow)(&r))
17001695}
1696+func (r *FileSearchToolFileSearchRankingOptionsParam) UnmarshalJSON(data []byte) error {
1697+ return apijson.UnmarshalRoot(data, r)
1698+}
17011699
17021700func init() {
17031701 apijson.RegisterFieldValidator[FileSearchToolFileSearchRankingOptionsParam](
1704− "Ranker", false, "auto", "default_2024_08_21",
1702+ "ranker", "auto", "default_2024_08_21",
17051703 )
17061704}
17071705
@@ -1709,12 +1707,11 @@ type FunctionTool struct {
17091707 Function shared.FunctionDefinition `json:"function,required"`
17101708 // The type of tool being defined: `function`
17111709 Type constant.Function `json:"type,required"`
1712− // Metadata for the response, check the presence of optional fields with the
1713− // [resp.Field.IsPresent] method.
1710+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
17141711 JSON struct {
1715− Function resp.Field
1716− Type resp.Field
1717− ExtraFields map[string]resp.Field
1712+ Function respjson.Field
1713+ Type respjson.Field
1714+ ExtraFields map[string]respjson.Field
17181715 raw string
17191716 } `json:"-"`
17201717}
@@ -1729,9 +1726,9 @@ func (r *FunctionTool) UnmarshalJSON(data []byte) error {
17291726//
17301727// Warning: the fields of the param type will not be present. ToParam should only
17311728// be used at the last possible moment before sending a request. Test for this with
1732−// FunctionToolParam.IsOverridden()
1729+// FunctionToolParam.Overrides()
17331730func (r FunctionTool) ToParam() FunctionToolParam {
1734− return param.OverrideObj[FunctionToolParam](r.RawJSON())
1731+ return param.Override[FunctionToolParam](json.RawMessage(r.RawJSON()))
17351732}
17361733
17371734// The properties Function, Type are required.
@@ -1744,13 +1741,13 @@ type FunctionToolParam struct {
17441741 paramObj
17451742}
17461743
1747−// IsPresent returns true if the field's value is not omitted and not the JSON
1748−// "null". To check if this field is omitted, use [param.IsOmitted].
1749−func (f FunctionToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
17501744func (r FunctionToolParam) MarshalJSON() (data []byte, err error) {
17511745 type shadow FunctionToolParam
17521746 return param.MarshalObject(r, (*shadow)(&r))
17531747}
1748+func (r *FunctionToolParam) UnmarshalJSON(data []byte) error {
1749+ return apijson.UnmarshalRoot(data, r)
1750+}
17541751
17551752type BetaAssistantNewParams struct {
17561753 // ID of the model to use. You can use the
@@ -1782,7 +1779,7 @@ type BetaAssistantNewParams struct {
17821779 //
17831780 // Keys are strings with a maximum length of 64 characters. Values are strings with
17841781 // a maximum length of 512 characters.
1785− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1782+ Metadata shared.Metadata `json:"metadata,omitzero"`
17861783 // **o-series models only**
17871784 //
17881785 // Constrains effort on reasoning for
@@ -1825,14 +1822,13 @@ type BetaAssistantNewParams struct {
18251822 paramObj
18261823}
18271824
1828−// IsPresent returns true if the field's value is not omitted and not the JSON
1829−// "null". To check if this field is omitted, use [param.IsOmitted].
1830−func (f BetaAssistantNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
1831−
18321825func (r BetaAssistantNewParams) MarshalJSON() (data []byte, err error) {
18331826 type shadow BetaAssistantNewParams
18341827 return param.MarshalObject(r, (*shadow)(&r))
18351828}
1829+func (r *BetaAssistantNewParams) UnmarshalJSON(data []byte) error {
1830+ return apijson.UnmarshalRoot(data, r)
1831+}
18361832
18371833// A set of resources that are used by the assistant's tools. The resources are
18381834// specific to the type of tool. For example, the `code_interpreter` tool requires
@@ -1844,15 +1840,13 @@ type BetaAssistantNewParamsToolResources struct {
18441840 paramObj
18451841}
18461842
1847−// IsPresent returns true if the field's value is not omitted and not the JSON
1848−// "null". To check if this field is omitted, use [param.IsOmitted].
1849−func (f BetaAssistantNewParamsToolResources) IsPresent() bool {
1850− return !param.IsOmitted(f) && !f.IsNull()
1851−}
18521843func (r BetaAssistantNewParamsToolResources) MarshalJSON() (data []byte, err error) {
18531844 type shadow BetaAssistantNewParamsToolResources
18541845 return param.MarshalObject(r, (*shadow)(&r))
18551846}
1847+func (r *BetaAssistantNewParamsToolResources) UnmarshalJSON(data []byte) error {
1848+ return apijson.UnmarshalRoot(data, r)
1849+}
18561850
18571851type BetaAssistantNewParamsToolResourcesCodeInterpreter struct {
18581852 // A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made
@@ -1862,15 +1856,13 @@ type BetaAssistantNewParamsToolResourcesCodeInterpreter struct {
18621856 paramObj
18631857}
18641858
1865−// IsPresent returns true if the field's value is not omitted and not the JSON
1866−// "null". To check if this field is omitted, use [param.IsOmitted].
1867−func (f BetaAssistantNewParamsToolResourcesCodeInterpreter) IsPresent() bool {
1868− return !param.IsOmitted(f) && !f.IsNull()
1869−}
18701859func (r BetaAssistantNewParamsToolResourcesCodeInterpreter) MarshalJSON() (data []byte, err error) {
18711860 type shadow BetaAssistantNewParamsToolResourcesCodeInterpreter
18721861 return param.MarshalObject(r, (*shadow)(&r))
18731862}
1863+func (r *BetaAssistantNewParamsToolResourcesCodeInterpreter) UnmarshalJSON(data []byte) error {
1864+ return apijson.UnmarshalRoot(data, r)
1865+}
18741866
18751867type BetaAssistantNewParamsToolResourcesFileSearch struct {
18761868 // The
@@ -1886,15 +1878,13 @@ type BetaAssistantNewParamsToolResourcesFileSearch struct {
18861878 paramObj
18871879}
18881880
1889−// IsPresent returns true if the field's value is not omitted and not the JSON
1890−// "null". To check if this field is omitted, use [param.IsOmitted].
1891−func (f BetaAssistantNewParamsToolResourcesFileSearch) IsPresent() bool {
1892− return !param.IsOmitted(f) && !f.IsNull()
1893−}
18941881func (r BetaAssistantNewParamsToolResourcesFileSearch) MarshalJSON() (data []byte, err error) {
18951882 type shadow BetaAssistantNewParamsToolResourcesFileSearch
18961883 return param.MarshalObject(r, (*shadow)(&r))
18971884}
1885+func (r *BetaAssistantNewParamsToolResourcesFileSearch) UnmarshalJSON(data []byte) error {
1886+ return apijson.UnmarshalRoot(data, r)
1887+}
18981888
18991889type BetaAssistantNewParamsToolResourcesFileSearchVectorStore struct {
19001890 // Set of 16 key-value pairs that can be attached to an object. This can be useful
@@ -1903,7 +1893,7 @@ type BetaAssistantNewParamsToolResourcesFileSearchVectorStore struct {
19031893 //
19041894 // Keys are strings with a maximum length of 64 characters. Values are strings with
19051895 // a maximum length of 512 characters.
1906− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1896+ Metadata shared.Metadata `json:"metadata,omitzero"`
19071897 // The chunking strategy used to chunk the file(s). If not set, will use the `auto`
19081898 // strategy.
19091899 ChunkingStrategy BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion `json:"chunking_strategy,omitzero"`
@@ -1914,15 +1904,13 @@ type BetaAssistantNewParamsToolResourcesFileSearchVectorStore struct {
19141904 paramObj
19151905}
19161906
1917−// IsPresent returns true if the field's value is not omitted and not the JSON
1918−// "null". To check if this field is omitted, use [param.IsOmitted].
1919−func (f BetaAssistantNewParamsToolResourcesFileSearchVectorStore) IsPresent() bool {
1920− return !param.IsOmitted(f) && !f.IsNull()
1921−}
19221907func (r BetaAssistantNewParamsToolResourcesFileSearchVectorStore) MarshalJSON() (data []byte, err error) {
19231908 type shadow BetaAssistantNewParamsToolResourcesFileSearchVectorStore
19241909 return param.MarshalObject(r, (*shadow)(&r))
19251910}
1911+func (r *BetaAssistantNewParamsToolResourcesFileSearchVectorStore) UnmarshalJSON(data []byte) error {
1912+ return apijson.UnmarshalRoot(data, r)
1913+}
19261914
19271915// Only one field can be non-zero.
19281916//
@@ -1933,13 +1921,11 @@ type BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUni
19331921 paramUnion
19341922}
19351923
1936−// IsPresent returns true if the field's value is not omitted and not the JSON
1937−// "null". To check if this field is omitted, use [param.IsOmitted].
1938−func (u BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) IsPresent() bool {
1939− return !param.IsOmitted(u) && !u.IsNull()
1940−}
19411924func (u BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) MarshalJSON() ([]byte, error) {
1942− return param.MarshalUnion[BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion](u.OfAuto, u.OfStatic)
1925+ return param.MarshalUnion(u, u.OfAuto, u.OfStatic)
1926+}
1927+func (u *BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) UnmarshalJSON(data []byte) error {
1928+ return apijson.UnmarshalRoot(data, u)
19431929}
19441930
19451931func (u *BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) asAny() any {
@@ -1972,40 +1958,35 @@ func (u BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategy
19721958func init() {
19731959 apijson.RegisterUnion[BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion](
19741960 "type",
1975− apijson.UnionVariant{
1976− TypeFilter: gjson.JSON,
1977− Type: reflect.TypeOf(BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto{}),
1978− DiscriminatorValue: "auto",
1979− },
1980− apijson.UnionVariant{
1981− TypeFilter: gjson.JSON,
1982− Type: reflect.TypeOf(BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic{}),
1983− DiscriminatorValue: "static",
1984− },
1961+ apijson.Discriminator[BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto]("auto"),
1962+ apijson.Discriminator[BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic]("static"),
19851963 )
19861964}
19871965
1966+func NewBetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto() BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto {
1967+ return BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto{
1968+ Type: "auto",
1969+ }
1970+}
1971+
19881972// The default strategy. This strategy currently uses a `max_chunk_size_tokens` of
19891973// `800` and `chunk_overlap_tokens` of `400`.
19901974//
1991−// The property Type is required.
1975+// This struct has a constant value, construct it with
1976+// [NewBetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto].
19921977type BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto struct {
19931978 // Always `auto`.
1994− //
1995− // This field can be elided, and will marshal its zero value as "auto".
19961979 Type constant.Auto `json:"type,required"`
19971980 paramObj
19981981}
19991982
2000−// IsPresent returns true if the field's value is not omitted and not the JSON
2001−// "null". To check if this field is omitted, use [param.IsOmitted].
2002−func (f BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto) IsPresent() bool {
2003− return !param.IsOmitted(f) && !f.IsNull()
2004−}
20051983func (r BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto) MarshalJSON() (data []byte, err error) {
20061984 type shadow BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto
20071985 return param.MarshalObject(r, (*shadow)(&r))
20081986}
1987+func (r *BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto) UnmarshalJSON(data []byte) error {
1988+ return apijson.UnmarshalRoot(data, r)
1989+}
20091990
20101991// The properties Static, Type are required.
20111992type BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic struct {
@@ -2017,15 +1998,13 @@ type BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategySta
20171998 paramObj
20181999}
20192000
2020−// IsPresent returns true if the field's value is not omitted and not the JSON
2021−// "null". To check if this field is omitted, use [param.IsOmitted].
2022−func (f BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic) IsPresent() bool {
2023− return !param.IsOmitted(f) && !f.IsNull()
2024−}
20252001func (r BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic) MarshalJSON() (data []byte, err error) {
20262002 type shadow BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic
20272003 return param.MarshalObject(r, (*shadow)(&r))
20282004}
2005+func (r *BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic) UnmarshalJSON(data []byte) error {
2006+ return apijson.UnmarshalRoot(data, r)
2007+}
20292008
20302009// The properties ChunkOverlapTokens, MaxChunkSizeTokens are required.
20312010type BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic struct {
@@ -2039,15 +2018,13 @@ type BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategySta
20392018 paramObj
20402019}
20412020
2042−// IsPresent returns true if the field's value is not omitted and not the JSON
2043−// "null". To check if this field is omitted, use [param.IsOmitted].
2044−func (f BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) IsPresent() bool {
2045− return !param.IsOmitted(f) && !f.IsNull()
2046−}
20472021func (r BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) MarshalJSON() (data []byte, err error) {
20482022 type shadow BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic
20492023 return param.MarshalObject(r, (*shadow)(&r))
20502024}
2025+func (r *BetaAssistantNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) UnmarshalJSON(data []byte) error {
2026+ return apijson.UnmarshalRoot(data, r)
2027+}
20512028
20522029type BetaAssistantUpdateParams struct {
20532030 // The description of the assistant. The maximum length is 512 characters.
@@ -2073,7 +2050,7 @@ type BetaAssistantUpdateParams struct {
20732050 //
20742051 // Keys are strings with a maximum length of 64 characters. Values are strings with
20752052 // a maximum length of 512 characters.
2076− Metadata shared.MetadataParam `json:"metadata,omitzero"`
2053+ Metadata shared.Metadata `json:"metadata,omitzero"`
20772054 // **o-series models only**
20782055 //
20792056 // Constrains effort on reasoning for
@@ -2093,7 +2070,7 @@ type BetaAssistantUpdateParams struct {
20932070 // see all of your available models, or see our
20942071 // [Model overview](https://platform.openai.com/docs/models) for descriptions of
20952072 // them.
2096− Model string `json:"model,omitzero"`
2073+ Model BetaAssistantUpdateParamsModel `json:"model,omitzero"`
20972074 // Specifies the format that the model must output. Compatible with
20982075 // [GPT-4o](https://platform.openai.com/docs/models#gpt-4o),
20992076 // [GPT-4 Turbo](https://platform.openai.com/docs/models#gpt-4-turbo-and-gpt-4),
@@ -2122,14 +2099,59 @@ type BetaAssistantUpdateParams struct {
21222099 paramObj
21232100}
21242101
2125−// IsPresent returns true if the field's value is not omitted and not the JSON
2126−// "null". To check if this field is omitted, use [param.IsOmitted].
2127−func (f BetaAssistantUpdateParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
2128−
21292102func (r BetaAssistantUpdateParams) MarshalJSON() (data []byte, err error) {
21302103 type shadow BetaAssistantUpdateParams
21312104 return param.MarshalObject(r, (*shadow)(&r))
21322105}
2106+func (r *BetaAssistantUpdateParams) UnmarshalJSON(data []byte) error {
2107+ return apijson.UnmarshalRoot(data, r)
2108+}
2109+
2110+// ID of the model to use. You can use the
2111+// [List models](https://platform.openai.com/docs/api-reference/models/list) API to
2112+// see all of your available models, or see our
2113+// [Model overview](https://platform.openai.com/docs/models) for descriptions of
2114+// them.
2115+type BetaAssistantUpdateParamsModel string
2116+
2117+const (
2118+ BetaAssistantUpdateParamsModelGPT4_1 BetaAssistantUpdateParamsModel = "gpt-4.1"
2119+ BetaAssistantUpdateParamsModelGPT4_1Mini BetaAssistantUpdateParamsModel = "gpt-4.1-mini"
2120+ BetaAssistantUpdateParamsModelGPT4_1Nano BetaAssistantUpdateParamsModel = "gpt-4.1-nano"
2121+ BetaAssistantUpdateParamsModelGPT4_1_2025_04_14 BetaAssistantUpdateParamsModel = "gpt-4.1-2025-04-14"
2122+ BetaAssistantUpdateParamsModelGPT4_1Mini2025_04_14 BetaAssistantUpdateParamsModel = "gpt-4.1-mini-2025-04-14"
2123+ BetaAssistantUpdateParamsModelGPT4_1Nano2025_04_14 BetaAssistantUpdateParamsModel = "gpt-4.1-nano-2025-04-14"
2124+ BetaAssistantUpdateParamsModelO3Mini BetaAssistantUpdateParamsModel = "o3-mini"
2125+ BetaAssistantUpdateParamsModelO3Mini2025_01_31 BetaAssistantUpdateParamsModel = "o3-mini-2025-01-31"
2126+ BetaAssistantUpdateParamsModelO1 BetaAssistantUpdateParamsModel = "o1"
2127+ BetaAssistantUpdateParamsModelO1_2024_12_17 BetaAssistantUpdateParamsModel = "o1-2024-12-17"
2128+ BetaAssistantUpdateParamsModelGPT4o BetaAssistantUpdateParamsModel = "gpt-4o"
2129+ BetaAssistantUpdateParamsModelGPT4o2024_11_20 BetaAssistantUpdateParamsModel = "gpt-4o-2024-11-20"
2130+ BetaAssistantUpdateParamsModelGPT4o2024_08_06 BetaAssistantUpdateParamsModel = "gpt-4o-2024-08-06"
2131+ BetaAssistantUpdateParamsModelGPT4o2024_05_13 BetaAssistantUpdateParamsModel = "gpt-4o-2024-05-13"
2132+ BetaAssistantUpdateParamsModelGPT4oMini BetaAssistantUpdateParamsModel = "gpt-4o-mini"
2133+ BetaAssistantUpdateParamsModelGPT4oMini2024_07_18 BetaAssistantUpdateParamsModel = "gpt-4o-mini-2024-07-18"
2134+ BetaAssistantUpdateParamsModelGPT4_5Preview BetaAssistantUpdateParamsModel = "gpt-4.5-preview"
2135+ BetaAssistantUpdateParamsModelGPT4_5Preview2025_02_27 BetaAssistantUpdateParamsModel = "gpt-4.5-preview-2025-02-27"
2136+ BetaAssistantUpdateParamsModelGPT4Turbo BetaAssistantUpdateParamsModel = "gpt-4-turbo"
2137+ BetaAssistantUpdateParamsModelGPT4Turbo2024_04_09 BetaAssistantUpdateParamsModel = "gpt-4-turbo-2024-04-09"
2138+ BetaAssistantUpdateParamsModelGPT4_0125Preview BetaAssistantUpdateParamsModel = "gpt-4-0125-preview"
2139+ BetaAssistantUpdateParamsModelGPT4TurboPreview BetaAssistantUpdateParamsModel = "gpt-4-turbo-preview"
2140+ BetaAssistantUpdateParamsModelGPT4_1106Preview BetaAssistantUpdateParamsModel = "gpt-4-1106-preview"
2141+ BetaAssistantUpdateParamsModelGPT4VisionPreview BetaAssistantUpdateParamsModel = "gpt-4-vision-preview"
2142+ BetaAssistantUpdateParamsModelGPT4 BetaAssistantUpdateParamsModel = "gpt-4"
2143+ BetaAssistantUpdateParamsModelGPT4_0314 BetaAssistantUpdateParamsModel = "gpt-4-0314"
2144+ BetaAssistantUpdateParamsModelGPT4_0613 BetaAssistantUpdateParamsModel = "gpt-4-0613"
2145+ BetaAssistantUpdateParamsModelGPT4_32k BetaAssistantUpdateParamsModel = "gpt-4-32k"
2146+ BetaAssistantUpdateParamsModelGPT4_32k0314 BetaAssistantUpdateParamsModel = "gpt-4-32k-0314"
2147+ BetaAssistantUpdateParamsModelGPT4_32k0613 BetaAssistantUpdateParamsModel = "gpt-4-32k-0613"
2148+ BetaAssistantUpdateParamsModelGPT3_5Turbo BetaAssistantUpdateParamsModel = "gpt-3.5-turbo"
2149+ BetaAssistantUpdateParamsModelGPT3_5Turbo16k BetaAssistantUpdateParamsModel = "gpt-3.5-turbo-16k"
2150+ BetaAssistantUpdateParamsModelGPT3_5Turbo0613 BetaAssistantUpdateParamsModel = "gpt-3.5-turbo-0613"
2151+ BetaAssistantUpdateParamsModelGPT3_5Turbo1106 BetaAssistantUpdateParamsModel = "gpt-3.5-turbo-1106"
2152+ BetaAssistantUpdateParamsModelGPT3_5Turbo0125 BetaAssistantUpdateParamsModel = "gpt-3.5-turbo-0125"
2153+ BetaAssistantUpdateParamsModelGPT3_5Turbo16k0613 BetaAssistantUpdateParamsModel = "gpt-3.5-turbo-16k-0613"
2154+)
21332155
21342156// A set of resources that are used by the assistant's tools. The resources are
21352157// specific to the type of tool. For example, the `code_interpreter` tool requires
@@ -2141,15 +2163,13 @@ type BetaAssistantUpdateParamsToolResources struct {
21412163 paramObj
21422164}
21432165
2144−// IsPresent returns true if the field's value is not omitted and not the JSON
2145−// "null". To check if this field is omitted, use [param.IsOmitted].
2146−func (f BetaAssistantUpdateParamsToolResources) IsPresent() bool {
2147− return !param.IsOmitted(f) && !f.IsNull()
2148−}
21492166func (r BetaAssistantUpdateParamsToolResources) MarshalJSON() (data []byte, err error) {
21502167 type shadow BetaAssistantUpdateParamsToolResources
21512168 return param.MarshalObject(r, (*shadow)(&r))
21522169}
2170+func (r *BetaAssistantUpdateParamsToolResources) UnmarshalJSON(data []byte) error {
2171+ return apijson.UnmarshalRoot(data, r)
2172+}
21532173
21542174type BetaAssistantUpdateParamsToolResourcesCodeInterpreter struct {
21552175 // Overrides the list of
@@ -2160,15 +2180,13 @@ type BetaAssistantUpdateParamsToolResourcesCodeInterpreter struct {
21602180 paramObj
21612181}
21622182
2163−// IsPresent returns true if the field's value is not omitted and not the JSON
2164−// "null". To check if this field is omitted, use [param.IsOmitted].
2165−func (f BetaAssistantUpdateParamsToolResourcesCodeInterpreter) IsPresent() bool {
2166− return !param.IsOmitted(f) && !f.IsNull()
2167−}
21682183func (r BetaAssistantUpdateParamsToolResourcesCodeInterpreter) MarshalJSON() (data []byte, err error) {
21692184 type shadow BetaAssistantUpdateParamsToolResourcesCodeInterpreter
21702185 return param.MarshalObject(r, (*shadow)(&r))
21712186}
2187+func (r *BetaAssistantUpdateParamsToolResourcesCodeInterpreter) UnmarshalJSON(data []byte) error {
2188+ return apijson.UnmarshalRoot(data, r)
2189+}
21722190
21732191type BetaAssistantUpdateParamsToolResourcesFileSearch struct {
21742192 // Overrides the
@@ -2179,15 +2197,13 @@ type BetaAssistantUpdateParamsToolResourcesFileSearch struct {
21792197 paramObj
21802198}
21812199
2182−// IsPresent returns true if the field's value is not omitted and not the JSON
2183−// "null". To check if this field is omitted, use [param.IsOmitted].
2184−func (f BetaAssistantUpdateParamsToolResourcesFileSearch) IsPresent() bool {
2185− return !param.IsOmitted(f) && !f.IsNull()
2186−}
21872200func (r BetaAssistantUpdateParamsToolResourcesFileSearch) MarshalJSON() (data []byte, err error) {
21882201 type shadow BetaAssistantUpdateParamsToolResourcesFileSearch
21892202 return param.MarshalObject(r, (*shadow)(&r))
21902203}
2204+func (r *BetaAssistantUpdateParamsToolResourcesFileSearch) UnmarshalJSON(data []byte) error {
2205+ return apijson.UnmarshalRoot(data, r)
2206+}
21912207
21922208type BetaAssistantListParams struct {
21932209 // A cursor for use in pagination. `after` is an object ID that defines your place
@@ -2211,13 +2227,9 @@ type BetaAssistantListParams struct {
22112227 paramObj
22122228}
22132229
2214−// IsPresent returns true if the field's value is not omitted and not the JSON
2215−// "null". To check if this field is omitted, use [param.IsOmitted].
2216−func (f BetaAssistantListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
2217−
22182230// URLQuery serializes [BetaAssistantListParams]'s query parameters as
22192231// `url.Values`.
2220−func (r BetaAssistantListParams) URLQuery() (v url.Values) {
2232+func (r BetaAssistantListParams) URLQuery() (v url.Values, err error) {
22212233 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
22222234 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
22232235 NestedFormat: apiquery.NestedQueryFormatBrackets,
vendor/github.com/openai/openai-go/betathread.go+257−403
@@ -8,17 +8,15 @@ import (
88 "errors"
99 "fmt"
1010 "net/http"
11− "reflect"
1211
1312 "github.com/openai/openai-go/internal/apijson"
1413 "github.com/openai/openai-go/internal/requestconfig"
1514 "github.com/openai/openai-go/option"
1615 "github.com/openai/openai-go/packages/param"
17− "github.com/openai/openai-go/packages/resp"
16+ "github.com/openai/openai-go/packages/respjson"
1817 "github.com/openai/openai-go/packages/ssestream"
1918 "github.com/openai/openai-go/shared"
2019 "github.com/openai/openai-go/shared/constant"
21− "github.com/tidwall/gjson"
2220)
2321
2422// BetaThreadService contains methods and other services that help with interacting
@@ -27,9 +25,13 @@ import (
2725// Note, unlike clients, this service does not read variables from the environment
2826// automatically. You should not instantiate this service directly, and instead use
2927// the [NewBetaThreadService] method instead.
28+//
29+// Deprecated: The Assistants API is deprecated in favor of the Responses API
3030type BetaThreadService struct {
31− Options []option.RequestOption
32− Runs BetaThreadRunService
31+ Options []option.RequestOption
32+ // Deprecated: The Assistants API is deprecated in favor of the Responses API
33+ Runs BetaThreadRunService
34+ // Deprecated: The Assistants API is deprecated in favor of the Responses API
3335 Messages BetaThreadMessageService
3436}
3537
@@ -45,6 +47,8 @@ func NewBetaThreadService(opts ...option.RequestOption) (r BetaThreadService) {
4547}
4648
4749// Create a thread.
50+//
51+// Deprecated: The Assistants API is deprecated in favor of the Responses API
4852func (r *BetaThreadService) New(ctx context.Context, body BetaThreadNewParams, opts ...option.RequestOption) (res *Thread, err error) {
4953 opts = append(r.Options[:], opts...)
5054 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -53,16 +57,9 @@ func (r *BetaThreadService) New(ctx context.Context, body BetaThreadNewParams, o
5357 return
5458}
5559
56−// Create a thread and run it in one request. Poll the API until the run is complete.
57−func (r *BetaThreadService) NewAndRunPoll(ctx context.Context, body BetaThreadNewAndRunParams, pollIntervalMs int, opts ...option.RequestOption) (res *Run, err error) {
58− run, err := r.NewAndRun(ctx, body, opts...)
59− if err != nil {
60− return nil, err
61− }
62− return r.Runs.PollStatus(ctx, run.ThreadID, run.ID, pollIntervalMs, opts...)
63−}
64−
6560// Retrieves a thread.
61+//
62+// Deprecated: The Assistants API is deprecated in favor of the Responses API
6663func (r *BetaThreadService) Get(ctx context.Context, threadID string, opts ...option.RequestOption) (res *Thread, err error) {
6764 opts = append(r.Options[:], opts...)
6865 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -76,6 +73,8 @@ func (r *BetaThreadService) Get(ctx context.Context, threadID string, opts ...op
7673}
7774
7875// Modifies a thread.
76+//
77+// Deprecated: The Assistants API is deprecated in favor of the Responses API
7978func (r *BetaThreadService) Update(ctx context.Context, threadID string, body BetaThreadUpdateParams, opts ...option.RequestOption) (res *Thread, err error) {
8079 opts = append(r.Options[:], opts...)
8180 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -89,6 +88,8 @@ func (r *BetaThreadService) Update(ctx context.Context, threadID string, body Be
8988}
9089
9190// Delete a thread.
91+//
92+// Deprecated: The Assistants API is deprecated in favor of the Responses API
9293func (r *BetaThreadService) Delete(ctx context.Context, threadID string, opts ...option.RequestOption) (res *ThreadDeleted, err error) {
9394 opts = append(r.Options[:], opts...)
9495 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -102,6 +103,8 @@ func (r *BetaThreadService) Delete(ctx context.Context, threadID string, opts ..
102103}
103104
104105// Create a thread and run it in one request.
106+//
107+// Deprecated: The Assistants API is deprecated in favor of the Responses API
105108func (r *BetaThreadService) NewAndRun(ctx context.Context, body BetaThreadNewAndRunParams, opts ...option.RequestOption) (res *Run, err error) {
106109 opts = append(r.Options[:], opts...)
107110 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -111,6 +114,8 @@ func (r *BetaThreadService) NewAndRun(ctx context.Context, body BetaThreadNewAnd
111114}
112115
113116// Create a thread and run it in one request.
117+//
118+// Deprecated: The Assistants API is deprecated in favor of the Responses API
114119func (r *BetaThreadService) NewAndRunStreaming(ctx context.Context, body BetaThreadNewAndRunParams, opts ...option.RequestOption) (stream *ssestream.Stream[AssistantStreamEventUnion]) {
115120 var (
116121 raw *http.Response
@@ -139,9 +144,9 @@ type AssistantResponseFormatOptionUnion struct {
139144 // This field is from variant [shared.ResponseFormatJSONSchema].
140145 JSONSchema shared.ResponseFormatJSONSchemaJSONSchema `json:"json_schema"`
141146 JSON struct {
142− OfAuto resp.Field
143− Type resp.Field
144− JSONSchema resp.Field
147+ OfAuto respjson.Field
148+ Type respjson.Field
149+ JSONSchema respjson.Field
145150 raw string
146151 } `json:"-"`
147152}
@@ -178,9 +183,9 @@ func (r *AssistantResponseFormatOptionUnion) UnmarshalJSON(data []byte) error {
178183//
179184// Warning: the fields of the param type will not be present. ToParam should only
180185// be used at the last possible moment before sending a request. Test for this with
181−// AssistantResponseFormatOptionUnionParam.IsOverridden()
186+// AssistantResponseFormatOptionUnionParam.Overrides()
182187func (r AssistantResponseFormatOptionUnion) ToParam() AssistantResponseFormatOptionUnionParam {
183− return param.OverrideObj[AssistantResponseFormatOptionUnionParam](r.RawJSON())
188+ return param.Override[AssistantResponseFormatOptionUnionParam](json.RawMessage(r.RawJSON()))
184189}
185190
186191func AssistantResponseFormatOptionParamOfAuto() AssistantResponseFormatOptionUnionParam {
@@ -197,8 +202,7 @@ func AssistantResponseFormatOptionParamOfJSONSchema(jsonSchema shared.ResponseFo
197202//
198203// Use [param.IsOmitted] to confirm if a field is set.
199204type AssistantResponseFormatOptionUnionParam struct {
200− // Construct this variant with constant.New[constant.Auto]() Check if union is this
201− // variant with !param.IsOmitted(union.OfAuto)
205+ // Construct this variant with constant.ValueOf[constant.Auto]()
202206 OfAuto constant.Auto `json:",omitzero,inline"`
203207 OfText *shared.ResponseFormatTextParam `json:",omitzero,inline"`
204208 OfJSONObject *shared.ResponseFormatJSONObjectParam `json:",omitzero,inline"`
@@ -206,13 +210,11 @@ type AssistantResponseFormatOptionUnionParam struct {
206210 paramUnion
207211}
208212
209−// IsPresent returns true if the field's value is not omitted and not the JSON
210−// "null". To check if this field is omitted, use [param.IsOmitted].
211−func (u AssistantResponseFormatOptionUnionParam) IsPresent() bool {
212− return !param.IsOmitted(u) && !u.IsNull()
213−}
214213func (u AssistantResponseFormatOptionUnionParam) MarshalJSON() ([]byte, error) {
215− return param.MarshalUnion[AssistantResponseFormatOptionUnionParam](u.OfAuto, u.OfText, u.OfJSONObject, u.OfJSONSchema)
214+ return param.MarshalUnion(u, u.OfAuto, u.OfText, u.OfJSONObject, u.OfJSONSchema)
215+}
216+func (u *AssistantResponseFormatOptionUnionParam) UnmarshalJSON(data []byte) error {
217+ return apijson.UnmarshalRoot(data, u)
216218}
217219
218220func (u *AssistantResponseFormatOptionUnionParam) asAny() any {
@@ -256,12 +258,11 @@ type AssistantToolChoice struct {
256258 // Any of "function", "code_interpreter", "file_search".
257259 Type AssistantToolChoiceType `json:"type,required"`
258260 Function AssistantToolChoiceFunction `json:"function"`
259− // Metadata for the response, check the presence of optional fields with the
260− // [resp.Field.IsPresent] method.
261+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
261262 JSON struct {
262− Type resp.Field
263− Function resp.Field
264− ExtraFields map[string]resp.Field
263+ Type respjson.Field
264+ Function respjson.Field
265+ ExtraFields map[string]respjson.Field
265266 raw string
266267 } `json:"-"`
267268}
@@ -276,9 +277,9 @@ func (r *AssistantToolChoice) UnmarshalJSON(data []byte) error {
276277//
277278// Warning: the fields of the param type will not be present. ToParam should only
278279// be used at the last possible moment before sending a request. Test for this with
279−// AssistantToolChoiceParam.IsOverridden()
280+// AssistantToolChoiceParam.Overrides()
280281func (r AssistantToolChoice) ToParam() AssistantToolChoiceParam {
281− return param.OverrideObj[AssistantToolChoiceParam](r.RawJSON())
282+ return param.Override[AssistantToolChoiceParam](json.RawMessage(r.RawJSON()))
282283}
283284
284285// The type of the tool. If type is `function`, the function name must be set
@@ -303,22 +304,21 @@ type AssistantToolChoiceParam struct {
303304 paramObj
304305}
305306
306−// IsPresent returns true if the field's value is not omitted and not the JSON
307−// "null". To check if this field is omitted, use [param.IsOmitted].
308−func (f AssistantToolChoiceParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
309307func (r AssistantToolChoiceParam) MarshalJSON() (data []byte, err error) {
310308 type shadow AssistantToolChoiceParam
311309 return param.MarshalObject(r, (*shadow)(&r))
312310}
311+func (r *AssistantToolChoiceParam) UnmarshalJSON(data []byte) error {
312+ return apijson.UnmarshalRoot(data, r)
313+}
313314
314315type AssistantToolChoiceFunction struct {
315316 // The name of the function to call.
316317 Name string `json:"name,required"`
317− // Metadata for the response, check the presence of optional fields with the
318− // [resp.Field.IsPresent] method.
318+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
319319 JSON struct {
320− Name resp.Field
321− ExtraFields map[string]resp.Field
320+ Name respjson.Field
321+ ExtraFields map[string]respjson.Field
322322 raw string
323323 } `json:"-"`
324324}
@@ -334,9 +334,9 @@ func (r *AssistantToolChoiceFunction) UnmarshalJSON(data []byte) error {
334334//
335335// Warning: the fields of the param type will not be present. ToParam should only
336336// be used at the last possible moment before sending a request. Test for this with
337−// AssistantToolChoiceFunctionParam.IsOverridden()
337+// AssistantToolChoiceFunctionParam.Overrides()
338338func (r AssistantToolChoiceFunction) ToParam() AssistantToolChoiceFunctionParam {
339− return param.OverrideObj[AssistantToolChoiceFunctionParam](r.RawJSON())
339+ return param.Override[AssistantToolChoiceFunctionParam](json.RawMessage(r.RawJSON()))
340340}
341341
342342// The property Name is required.
@@ -346,13 +346,13 @@ type AssistantToolChoiceFunctionParam struct {
346346 paramObj
347347}
348348
349−// IsPresent returns true if the field's value is not omitted and not the JSON
350−// "null". To check if this field is omitted, use [param.IsOmitted].
351−func (f AssistantToolChoiceFunctionParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
352349func (r AssistantToolChoiceFunctionParam) MarshalJSON() (data []byte, err error) {
353350 type shadow AssistantToolChoiceFunctionParam
354351 return param.MarshalObject(r, (*shadow)(&r))
355352}
353+func (r *AssistantToolChoiceFunctionParam) UnmarshalJSON(data []byte) error {
354+ return apijson.UnmarshalRoot(data, r)
355+}
356356
357357// AssistantToolChoiceOptionUnion contains all possible properties and values from
358358// [string], [AssistantToolChoice].
@@ -369,9 +369,9 @@ type AssistantToolChoiceOptionUnion struct {
369369 // This field is from variant [AssistantToolChoice].
370370 Function AssistantToolChoiceFunction `json:"function"`
371371 JSON struct {
372− OfAuto resp.Field
373− Type resp.Field
374− Function resp.Field
372+ OfAuto respjson.Field
373+ Type respjson.Field
374+ Function respjson.Field
375375 raw string
376376 } `json:"-"`
377377}
@@ -398,11 +398,23 @@ func (r *AssistantToolChoiceOptionUnion) UnmarshalJSON(data []byte) error {
398398//
399399// Warning: the fields of the param type will not be present. ToParam should only
400400// be used at the last possible moment before sending a request. Test for this with
401−// AssistantToolChoiceOptionUnionParam.IsOverridden()
401+// AssistantToolChoiceOptionUnionParam.Overrides()
402402func (r AssistantToolChoiceOptionUnion) ToParam() AssistantToolChoiceOptionUnionParam {
403− return param.OverrideObj[AssistantToolChoiceOptionUnionParam](r.RawJSON())
403+ return param.Override[AssistantToolChoiceOptionUnionParam](json.RawMessage(r.RawJSON()))
404404}
405405
406+// `none` means the model will not call any tools and instead generates a message.
407+// `auto` means the model can pick between generating a message or calling one or
408+// more tools. `required` means the model must call one or more tools before
409+// responding to the user.
410+type AssistantToolChoiceOptionAuto string
411+
412+const (
413+ AssistantToolChoiceOptionAutoNone AssistantToolChoiceOptionAuto = "none"
414+ AssistantToolChoiceOptionAutoAuto AssistantToolChoiceOptionAuto = "auto"
415+ AssistantToolChoiceOptionAutoRequired AssistantToolChoiceOptionAuto = "required"
416+)
417+
406418func AssistantToolChoiceOptionParamOfAssistantToolChoice(type_ AssistantToolChoiceType) AssistantToolChoiceOptionUnionParam {
407419 var variant AssistantToolChoiceParam
408420 variant.Type = type_
@@ -419,13 +431,11 @@ type AssistantToolChoiceOptionUnionParam struct {
419431 paramUnion
420432}
421433
422−// IsPresent returns true if the field's value is not omitted and not the JSON
423−// "null". To check if this field is omitted, use [param.IsOmitted].
424−func (u AssistantToolChoiceOptionUnionParam) IsPresent() bool {
425− return !param.IsOmitted(u) && !u.IsNull()
426−}
427434func (u AssistantToolChoiceOptionUnionParam) MarshalJSON() ([]byte, error) {
428− return param.MarshalUnion[AssistantToolChoiceOptionUnionParam](u.OfAuto, u.OfAssistantToolChoice)
435+ return param.MarshalUnion(u, u.OfAuto, u.OfAssistantToolChoice)
436+}
437+func (u *AssistantToolChoiceOptionUnionParam) UnmarshalJSON(data []byte) error {
438+ return apijson.UnmarshalRoot(data, u)
429439}
430440
431441func (u *AssistantToolChoiceOptionUnionParam) asAny() any {
@@ -437,22 +447,6 @@ func (u *AssistantToolChoiceOptionUnionParam) asAny() any {
437447 return nil
438448}
439449
440−// Returns a pointer to the underlying variant's property, if present.
441−func (u AssistantToolChoiceOptionUnionParam) GetType() *string {
442− if vt := u.OfAssistantToolChoice; vt != nil {
443− return (*string)(&vt.Type)
444− }
445− return nil
446−}
447−
448−// Returns a pointer to the underlying variant's property, if present.
449−func (u AssistantToolChoiceOptionUnionParam) GetFunction() *AssistantToolChoiceFunctionParam {
450− if vt := u.OfAssistantToolChoice; vt != nil {
451− return &vt.Function
452− }
453− return nil
454−}
455−
456450// Represents a thread that contains
457451// [messages](https://platform.openai.com/docs/api-reference/messages).
458452type Thread struct {
@@ -474,15 +468,14 @@ type Thread struct {
474468 // `code_interpreter` tool requires a list of file IDs, while the `file_search`
475469 // tool requires a list of vector store IDs.
476470 ToolResources ThreadToolResources `json:"tool_resources,required"`
477− // Metadata for the response, check the presence of optional fields with the
478− // [resp.Field.IsPresent] method.
471+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
479472 JSON struct {
480− ID resp.Field
481− CreatedAt resp.Field
482− Metadata resp.Field
483− Object resp.Field
484− ToolResources resp.Field
485− ExtraFields map[string]resp.Field
473+ ID respjson.Field
474+ CreatedAt respjson.Field
475+ Metadata respjson.Field
476+ Object respjson.Field
477+ ToolResources respjson.Field
478+ ExtraFields map[string]respjson.Field
486479 raw string
487480 } `json:"-"`
488481}
@@ -500,12 +493,11 @@ func (r *Thread) UnmarshalJSON(data []byte) error {
500493type ThreadToolResources struct {
501494 CodeInterpreter ThreadToolResourcesCodeInterpreter `json:"code_interpreter"`
502495 FileSearch ThreadToolResourcesFileSearch `json:"file_search"`
503− // Metadata for the response, check the presence of optional fields with the
504− // [resp.Field.IsPresent] method.
496+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
505497 JSON struct {
506− CodeInterpreter resp.Field
507− FileSearch resp.Field
508− ExtraFields map[string]resp.Field
498+ CodeInterpreter respjson.Field
499+ FileSearch respjson.Field
500+ ExtraFields map[string]respjson.Field
509501 raw string
510502 } `json:"-"`
511503}
@@ -521,11 +513,10 @@ type ThreadToolResourcesCodeInterpreter struct {
521513 // available to the `code_interpreter` tool. There can be a maximum of 20 files
522514 // associated with the tool.
523515 FileIDs []string `json:"file_ids"`
524− // Metadata for the response, check the presence of optional fields with the
525− // [resp.Field.IsPresent] method.
516+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
526517 JSON struct {
527− FileIDs resp.Field
528− ExtraFields map[string]resp.Field
518+ FileIDs respjson.Field
519+ ExtraFields map[string]respjson.Field
529520 raw string
530521 } `json:"-"`
531522}
@@ -542,11 +533,10 @@ type ThreadToolResourcesFileSearch struct {
542533 // attached to this thread. There can be a maximum of 1 vector store attached to
543534 // the thread.
544535 VectorStoreIDs []string `json:"vector_store_ids"`
545− // Metadata for the response, check the presence of optional fields with the
546− // [resp.Field.IsPresent] method.
536+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
547537 JSON struct {
548− VectorStoreIDs resp.Field
549− ExtraFields map[string]resp.Field
538+ VectorStoreIDs respjson.Field
539+ ExtraFields map[string]respjson.Field
550540 raw string
551541 } `json:"-"`
552542}
@@ -561,13 +551,12 @@ type ThreadDeleted struct {
561551 ID string `json:"id,required"`
562552 Deleted bool `json:"deleted,required"`
563553 Object constant.ThreadDeleted `json:"object,required"`
564− // Metadata for the response, check the presence of optional fields with the
565− // [resp.Field.IsPresent] method.
554+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
566555 JSON struct {
567− ID resp.Field
568− Deleted resp.Field
569− Object resp.Field
570− ExtraFields map[string]resp.Field
556+ ID respjson.Field
557+ Deleted respjson.Field
558+ Object respjson.Field
559+ ExtraFields map[string]respjson.Field
571560 raw string
572561 } `json:"-"`
573562}
@@ -585,7 +574,7 @@ type BetaThreadNewParams struct {
585574 //
586575 // Keys are strings with a maximum length of 64 characters. Values are strings with
587576 // a maximum length of 512 characters.
588− Metadata shared.MetadataParam `json:"metadata,omitzero"`
577+ Metadata shared.Metadata `json:"metadata,omitzero"`
589578 // A set of resources that are made available to the assistant's tools in this
590579 // thread. The resources are specific to the type of tool. For example, the
591580 // `code_interpreter` tool requires a list of file IDs, while the `file_search`
@@ -597,14 +586,13 @@ type BetaThreadNewParams struct {
597586 paramObj
598587}
599588
600−// IsPresent returns true if the field's value is not omitted and not the JSON
601−// "null". To check if this field is omitted, use [param.IsOmitted].
602−func (f BetaThreadNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
603−
604589func (r BetaThreadNewParams) MarshalJSON() (data []byte, err error) {
605590 type shadow BetaThreadNewParams
606591 return param.MarshalObject(r, (*shadow)(&r))
607592}
593+func (r *BetaThreadNewParams) UnmarshalJSON(data []byte) error {
594+ return apijson.UnmarshalRoot(data, r)
595+}
608596
609597// The properties Content, Role are required.
610598type BetaThreadNewParamsMessage struct {
@@ -627,21 +615,21 @@ type BetaThreadNewParamsMessage struct {
627615 //
628616 // Keys are strings with a maximum length of 64 characters. Values are strings with
629617 // a maximum length of 512 characters.
630− Metadata shared.MetadataParam `json:"metadata,omitzero"`
618+ Metadata shared.Metadata `json:"metadata,omitzero"`
631619 paramObj
632620}
633621
634−// IsPresent returns true if the field's value is not omitted and not the JSON
635−// "null". To check if this field is omitted, use [param.IsOmitted].
636−func (f BetaThreadNewParamsMessage) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
637622func (r BetaThreadNewParamsMessage) MarshalJSON() (data []byte, err error) {
638623 type shadow BetaThreadNewParamsMessage
639624 return param.MarshalObject(r, (*shadow)(&r))
640625}
626+func (r *BetaThreadNewParamsMessage) UnmarshalJSON(data []byte) error {
627+ return apijson.UnmarshalRoot(data, r)
628+}
641629
642630func init() {
643631 apijson.RegisterFieldValidator[BetaThreadNewParamsMessage](
644− "Role", false, "user", "assistant",
632+ "role", "user", "assistant",
645633 )
646634}
647635
@@ -654,13 +642,11 @@ type BetaThreadNewParamsMessageContentUnion struct {
654642 paramUnion
655643}
656644
657−// IsPresent returns true if the field's value is not omitted and not the JSON
658−// "null". To check if this field is omitted, use [param.IsOmitted].
659−func (u BetaThreadNewParamsMessageContentUnion) IsPresent() bool {
660− return !param.IsOmitted(u) && !u.IsNull()
661−}
662645func (u BetaThreadNewParamsMessageContentUnion) MarshalJSON() ([]byte, error) {
663− return param.MarshalUnion[BetaThreadNewParamsMessageContentUnion](u.OfString, u.OfArrayOfContentParts)
646+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
647+}
648+func (u *BetaThreadNewParamsMessageContentUnion) UnmarshalJSON(data []byte) error {
649+ return apijson.UnmarshalRoot(data, u)
664650}
665651
666652func (u *BetaThreadNewParamsMessageContentUnion) asAny() any {
@@ -680,15 +666,13 @@ type BetaThreadNewParamsMessageAttachment struct {
680666 paramObj
681667}
682668
683−// IsPresent returns true if the field's value is not omitted and not the JSON
684−// "null". To check if this field is omitted, use [param.IsOmitted].
685−func (f BetaThreadNewParamsMessageAttachment) IsPresent() bool {
686− return !param.IsOmitted(f) && !f.IsNull()
687−}
688669func (r BetaThreadNewParamsMessageAttachment) MarshalJSON() (data []byte, err error) {
689670 type shadow BetaThreadNewParamsMessageAttachment
690671 return param.MarshalObject(r, (*shadow)(&r))
691672}
673+func (r *BetaThreadNewParamsMessageAttachment) UnmarshalJSON(data []byte) error {
674+ return apijson.UnmarshalRoot(data, r)
675+}
692676
693677// Only one field can be non-zero.
694678//
@@ -699,13 +683,11 @@ type BetaThreadNewParamsMessageAttachmentToolUnion struct {
699683 paramUnion
700684}
701685
702−// IsPresent returns true if the field's value is not omitted and not the JSON
703−// "null". To check if this field is omitted, use [param.IsOmitted].
704−func (u BetaThreadNewParamsMessageAttachmentToolUnion) IsPresent() bool {
705− return !param.IsOmitted(u) && !u.IsNull()
706−}
707686func (u BetaThreadNewParamsMessageAttachmentToolUnion) MarshalJSON() ([]byte, error) {
708− return param.MarshalUnion[BetaThreadNewParamsMessageAttachmentToolUnion](u.OfCodeInterpreter, u.OfFileSearch)
687+ return param.MarshalUnion(u, u.OfCodeInterpreter, u.OfFileSearch)
688+}
689+func (u *BetaThreadNewParamsMessageAttachmentToolUnion) UnmarshalJSON(data []byte) error {
690+ return apijson.UnmarshalRoot(data, u)
709691}
710692
711693func (u *BetaThreadNewParamsMessageAttachmentToolUnion) asAny() any {
@@ -730,37 +712,32 @@ func (u BetaThreadNewParamsMessageAttachmentToolUnion) GetType() *string {
730712func init() {
731713 apijson.RegisterUnion[BetaThreadNewParamsMessageAttachmentToolUnion](
732714 "type",
733− apijson.UnionVariant{
734− TypeFilter: gjson.JSON,
735− Type: reflect.TypeOf(CodeInterpreterToolParam{}),
736− DiscriminatorValue: "code_interpreter",
737− },
738− apijson.UnionVariant{
739− TypeFilter: gjson.JSON,
740− Type: reflect.TypeOf(BetaThreadNewParamsMessageAttachmentToolFileSearch{}),
741− DiscriminatorValue: "file_search",
742− },
715+ apijson.Discriminator[CodeInterpreterToolParam]("code_interpreter"),
716+ apijson.Discriminator[BetaThreadNewParamsMessageAttachmentToolFileSearch]("file_search"),
743717 )
744718}
745719
746−// The property Type is required.
720+func NewBetaThreadNewParamsMessageAttachmentToolFileSearch() BetaThreadNewParamsMessageAttachmentToolFileSearch {
721+ return BetaThreadNewParamsMessageAttachmentToolFileSearch{
722+ Type: "file_search",
723+ }
724+}
725+
726+// This struct has a constant value, construct it with
727+// [NewBetaThreadNewParamsMessageAttachmentToolFileSearch].
747728type BetaThreadNewParamsMessageAttachmentToolFileSearch struct {
748729 // The type of tool being defined: `file_search`
749− //
750− // This field can be elided, and will marshal its zero value as "file_search".
751730 Type constant.FileSearch `json:"type,required"`
752731 paramObj
753732}
754733
755−// IsPresent returns true if the field's value is not omitted and not the JSON
756−// "null". To check if this field is omitted, use [param.IsOmitted].
757−func (f BetaThreadNewParamsMessageAttachmentToolFileSearch) IsPresent() bool {
758− return !param.IsOmitted(f) && !f.IsNull()
759−}
760734func (r BetaThreadNewParamsMessageAttachmentToolFileSearch) MarshalJSON() (data []byte, err error) {
761735 type shadow BetaThreadNewParamsMessageAttachmentToolFileSearch
762736 return param.MarshalObject(r, (*shadow)(&r))
763737}
738+func (r *BetaThreadNewParamsMessageAttachmentToolFileSearch) UnmarshalJSON(data []byte) error {
739+ return apijson.UnmarshalRoot(data, r)
740+}
764741
765742// A set of resources that are made available to the assistant's tools in this
766743// thread. The resources are specific to the type of tool. For example, the
@@ -772,13 +749,13 @@ type BetaThreadNewParamsToolResources struct {
772749 paramObj
773750}
774751
775−// IsPresent returns true if the field's value is not omitted and not the JSON
776−// "null". To check if this field is omitted, use [param.IsOmitted].
777−func (f BetaThreadNewParamsToolResources) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
778752func (r BetaThreadNewParamsToolResources) MarshalJSON() (data []byte, err error) {
779753 type shadow BetaThreadNewParamsToolResources
780754 return param.MarshalObject(r, (*shadow)(&r))
781755}
756+func (r *BetaThreadNewParamsToolResources) UnmarshalJSON(data []byte) error {
757+ return apijson.UnmarshalRoot(data, r)
758+}
782759
783760type BetaThreadNewParamsToolResourcesCodeInterpreter struct {
784761 // A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made
@@ -788,15 +765,13 @@ type BetaThreadNewParamsToolResourcesCodeInterpreter struct {
788765 paramObj
789766}
790767
791−// IsPresent returns true if the field's value is not omitted and not the JSON
792−// "null". To check if this field is omitted, use [param.IsOmitted].
793−func (f BetaThreadNewParamsToolResourcesCodeInterpreter) IsPresent() bool {
794− return !param.IsOmitted(f) && !f.IsNull()
795−}
796768func (r BetaThreadNewParamsToolResourcesCodeInterpreter) MarshalJSON() (data []byte, err error) {
797769 type shadow BetaThreadNewParamsToolResourcesCodeInterpreter
798770 return param.MarshalObject(r, (*shadow)(&r))
799771}
772+func (r *BetaThreadNewParamsToolResourcesCodeInterpreter) UnmarshalJSON(data []byte) error {
773+ return apijson.UnmarshalRoot(data, r)
774+}
800775
801776type BetaThreadNewParamsToolResourcesFileSearch struct {
802777 // The
@@ -812,15 +787,13 @@ type BetaThreadNewParamsToolResourcesFileSearch struct {
812787 paramObj
813788}
814789
815−// IsPresent returns true if the field's value is not omitted and not the JSON
816−// "null". To check if this field is omitted, use [param.IsOmitted].
817−func (f BetaThreadNewParamsToolResourcesFileSearch) IsPresent() bool {
818− return !param.IsOmitted(f) && !f.IsNull()
819−}
820790func (r BetaThreadNewParamsToolResourcesFileSearch) MarshalJSON() (data []byte, err error) {
821791 type shadow BetaThreadNewParamsToolResourcesFileSearch
822792 return param.MarshalObject(r, (*shadow)(&r))
823793}
794+func (r *BetaThreadNewParamsToolResourcesFileSearch) UnmarshalJSON(data []byte) error {
795+ return apijson.UnmarshalRoot(data, r)
796+}
824797
825798type BetaThreadNewParamsToolResourcesFileSearchVectorStore struct {
826799 // Set of 16 key-value pairs that can be attached to an object. This can be useful
@@ -829,7 +802,7 @@ type BetaThreadNewParamsToolResourcesFileSearchVectorStore struct {
829802 //
830803 // Keys are strings with a maximum length of 64 characters. Values are strings with
831804 // a maximum length of 512 characters.
832− Metadata shared.MetadataParam `json:"metadata,omitzero"`
805+ Metadata shared.Metadata `json:"metadata,omitzero"`
833806 // The chunking strategy used to chunk the file(s). If not set, will use the `auto`
834807 // strategy.
835808 ChunkingStrategy BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion `json:"chunking_strategy,omitzero"`
@@ -840,15 +813,13 @@ type BetaThreadNewParamsToolResourcesFileSearchVectorStore struct {
840813 paramObj
841814}
842815
843−// IsPresent returns true if the field's value is not omitted and not the JSON
844−// "null". To check if this field is omitted, use [param.IsOmitted].
845−func (f BetaThreadNewParamsToolResourcesFileSearchVectorStore) IsPresent() bool {
846− return !param.IsOmitted(f) && !f.IsNull()
847−}
848816func (r BetaThreadNewParamsToolResourcesFileSearchVectorStore) MarshalJSON() (data []byte, err error) {
849817 type shadow BetaThreadNewParamsToolResourcesFileSearchVectorStore
850818 return param.MarshalObject(r, (*shadow)(&r))
851819}
820+func (r *BetaThreadNewParamsToolResourcesFileSearchVectorStore) UnmarshalJSON(data []byte) error {
821+ return apijson.UnmarshalRoot(data, r)
822+}
852823
853824// Only one field can be non-zero.
854825//
@@ -859,13 +830,11 @@ type BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion
859830 paramUnion
860831}
861832
862−// IsPresent returns true if the field's value is not omitted and not the JSON
863−// "null". To check if this field is omitted, use [param.IsOmitted].
864−func (u BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) IsPresent() bool {
865− return !param.IsOmitted(u) && !u.IsNull()
866−}
867833func (u BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) MarshalJSON() ([]byte, error) {
868− return param.MarshalUnion[BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion](u.OfAuto, u.OfStatic)
834+ return param.MarshalUnion(u, u.OfAuto, u.OfStatic)
835+}
836+func (u *BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) UnmarshalJSON(data []byte) error {
837+ return apijson.UnmarshalRoot(data, u)
869838}
870839
871840func (u *BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion) asAny() any {
@@ -898,40 +867,35 @@ func (u BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUni
898867func init() {
899868 apijson.RegisterUnion[BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyUnion](
900869 "type",
901− apijson.UnionVariant{
902− TypeFilter: gjson.JSON,
903− Type: reflect.TypeOf(BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto{}),
904− DiscriminatorValue: "auto",
905− },
906− apijson.UnionVariant{
907− TypeFilter: gjson.JSON,
908− Type: reflect.TypeOf(BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic{}),
909− DiscriminatorValue: "static",
910− },
870+ apijson.Discriminator[BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto]("auto"),
871+ apijson.Discriminator[BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic]("static"),
911872 )
912873}
913874
875+func NewBetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto() BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto {
876+ return BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto{
877+ Type: "auto",
878+ }
879+}
880+
914881// The default strategy. This strategy currently uses a `max_chunk_size_tokens` of
915882// `800` and `chunk_overlap_tokens` of `400`.
916883//
917−// The property Type is required.
884+// This struct has a constant value, construct it with
885+// [NewBetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto].
918886type BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto struct {
919887 // Always `auto`.
920− //
921− // This field can be elided, and will marshal its zero value as "auto".
922888 Type constant.Auto `json:"type,required"`
923889 paramObj
924890}
925891
926−// IsPresent returns true if the field's value is not omitted and not the JSON
927−// "null". To check if this field is omitted, use [param.IsOmitted].
928−func (f BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto) IsPresent() bool {
929− return !param.IsOmitted(f) && !f.IsNull()
930−}
931892func (r BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto) MarshalJSON() (data []byte, err error) {
932893 type shadow BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto
933894 return param.MarshalObject(r, (*shadow)(&r))
934895}
896+func (r *BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyAuto) UnmarshalJSON(data []byte) error {
897+ return apijson.UnmarshalRoot(data, r)
898+}
935899
936900// The properties Static, Type are required.
937901type BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic struct {
@@ -943,15 +907,13 @@ type BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic
943907 paramObj
944908}
945909
946−// IsPresent returns true if the field's value is not omitted and not the JSON
947−// "null". To check if this field is omitted, use [param.IsOmitted].
948−func (f BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic) IsPresent() bool {
949− return !param.IsOmitted(f) && !f.IsNull()
950−}
951910func (r BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic) MarshalJSON() (data []byte, err error) {
952911 type shadow BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic
953912 return param.MarshalObject(r, (*shadow)(&r))
954913}
914+func (r *BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic) UnmarshalJSON(data []byte) error {
915+ return apijson.UnmarshalRoot(data, r)
916+}
955917
956918// The properties ChunkOverlapTokens, MaxChunkSizeTokens are required.
957919type BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic struct {
@@ -965,15 +927,13 @@ type BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStatic
965927 paramObj
966928}
967929
968−// IsPresent returns true if the field's value is not omitted and not the JSON
969−// "null". To check if this field is omitted, use [param.IsOmitted].
970−func (f BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) IsPresent() bool {
971− return !param.IsOmitted(f) && !f.IsNull()
972−}
973930func (r BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) MarshalJSON() (data []byte, err error) {
974931 type shadow BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic
975932 return param.MarshalObject(r, (*shadow)(&r))
976933}
934+func (r *BetaThreadNewParamsToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) UnmarshalJSON(data []byte) error {
935+ return apijson.UnmarshalRoot(data, r)
936+}
977937
978938type BetaThreadUpdateParams struct {
979939 // Set of 16 key-value pairs that can be attached to an object. This can be useful
@@ -982,7 +942,7 @@ type BetaThreadUpdateParams struct {
982942 //
983943 // Keys are strings with a maximum length of 64 characters. Values are strings with
984944 // a maximum length of 512 characters.
985− Metadata shared.MetadataParam `json:"metadata,omitzero"`
945+ Metadata shared.Metadata `json:"metadata,omitzero"`
986946 // A set of resources that are made available to the assistant's tools in this
987947 // thread. The resources are specific to the type of tool. For example, the
988948 // `code_interpreter` tool requires a list of file IDs, while the `file_search`
@@ -991,14 +951,13 @@ type BetaThreadUpdateParams struct {
991951 paramObj
992952}
993953
994−// IsPresent returns true if the field's value is not omitted and not the JSON
995−// "null". To check if this field is omitted, use [param.IsOmitted].
996−func (f BetaThreadUpdateParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
997−
998954func (r BetaThreadUpdateParams) MarshalJSON() (data []byte, err error) {
999955 type shadow BetaThreadUpdateParams
1000956 return param.MarshalObject(r, (*shadow)(&r))
1001957}
958+func (r *BetaThreadUpdateParams) UnmarshalJSON(data []byte) error {
959+ return apijson.UnmarshalRoot(data, r)
960+}
1002961
1003962// A set of resources that are made available to the assistant's tools in this
1004963// thread. The resources are specific to the type of tool. For example, the
@@ -1010,15 +969,13 @@ type BetaThreadUpdateParamsToolResources struct {
1010969 paramObj
1011970}
1012971
1013−// IsPresent returns true if the field's value is not omitted and not the JSON
1014−// "null". To check if this field is omitted, use [param.IsOmitted].
1015−func (f BetaThreadUpdateParamsToolResources) IsPresent() bool {
1016− return !param.IsOmitted(f) && !f.IsNull()
1017−}
1018972func (r BetaThreadUpdateParamsToolResources) MarshalJSON() (data []byte, err error) {
1019973 type shadow BetaThreadUpdateParamsToolResources
1020974 return param.MarshalObject(r, (*shadow)(&r))
1021975}
976+func (r *BetaThreadUpdateParamsToolResources) UnmarshalJSON(data []byte) error {
977+ return apijson.UnmarshalRoot(data, r)
978+}
1022979
1023980type BetaThreadUpdateParamsToolResourcesCodeInterpreter struct {
1024981 // A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made
@@ -1028,15 +985,13 @@ type BetaThreadUpdateParamsToolResourcesCodeInterpreter struct {
1028985 paramObj
1029986}
1030987
1031−// IsPresent returns true if the field's value is not omitted and not the JSON
1032−// "null". To check if this field is omitted, use [param.IsOmitted].
1033−func (f BetaThreadUpdateParamsToolResourcesCodeInterpreter) IsPresent() bool {
1034− return !param.IsOmitted(f) && !f.IsNull()
1035−}
1036988func (r BetaThreadUpdateParamsToolResourcesCodeInterpreter) MarshalJSON() (data []byte, err error) {
1037989 type shadow BetaThreadUpdateParamsToolResourcesCodeInterpreter
1038990 return param.MarshalObject(r, (*shadow)(&r))
1039991}
992+func (r *BetaThreadUpdateParamsToolResourcesCodeInterpreter) UnmarshalJSON(data []byte) error {
993+ return apijson.UnmarshalRoot(data, r)
994+}
1040995
1041996type BetaThreadUpdateParamsToolResourcesFileSearch struct {
1042997 // The
@@ -1047,15 +1002,13 @@ type BetaThreadUpdateParamsToolResourcesFileSearch struct {
10471002 paramObj
10481003}
10491004
1050−// IsPresent returns true if the field's value is not omitted and not the JSON
1051−// "null". To check if this field is omitted, use [param.IsOmitted].
1052−func (f BetaThreadUpdateParamsToolResourcesFileSearch) IsPresent() bool {
1053− return !param.IsOmitted(f) && !f.IsNull()
1054−}
10551005func (r BetaThreadUpdateParamsToolResourcesFileSearch) MarshalJSON() (data []byte, err error) {
10561006 type shadow BetaThreadUpdateParamsToolResourcesFileSearch
10571007 return param.MarshalObject(r, (*shadow)(&r))
10581008}
1009+func (r *BetaThreadUpdateParamsToolResourcesFileSearch) UnmarshalJSON(data []byte) error {
1010+ return apijson.UnmarshalRoot(data, r)
1011+}
10591012
10601013type BetaThreadNewAndRunParams struct {
10611014 // The ID of the
@@ -1097,7 +1050,7 @@ type BetaThreadNewAndRunParams struct {
10971050 //
10981051 // Keys are strings with a maximum length of 64 characters. Values are strings with
10991052 // a maximum length of 512 characters.
1100− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1053+ Metadata shared.Metadata `json:"metadata,omitzero"`
11011054 // The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to
11021055 // be used to execute this run. If a value is provided here, it will override the
11031056 // model associated with the assistant. If not, the model associated with the
@@ -1110,7 +1063,7 @@ type BetaThreadNewAndRunParams struct {
11101063 ToolResources BetaThreadNewAndRunParamsToolResources `json:"tool_resources,omitzero"`
11111064 // Override the tools the assistant can use for this run. This is useful for
11121065 // modifying the behavior on a per-run basis.
1113− Tools []BetaThreadNewAndRunParamsToolUnion `json:"tools,omitzero"`
1066+ Tools []AssistantToolUnionParam `json:"tools,omitzero"`
11141067 // Controls for how a thread will be truncated prior to the run. Use this to
11151068 // control the intial context window of the run.
11161069 TruncationStrategy BetaThreadNewAndRunParamsTruncationStrategy `json:"truncation_strategy,omitzero"`
@@ -1149,14 +1102,13 @@ type BetaThreadNewAndRunParams struct {
11491102 paramObj
11501103}
11511104
1152−// IsPresent returns true if the field's value is not omitted and not the JSON
1153−// "null". To check if this field is omitted, use [param.IsOmitted].
1154−func (f BetaThreadNewAndRunParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
1155−
11561105func (r BetaThreadNewAndRunParams) MarshalJSON() (data []byte, err error) {
11571106 type shadow BetaThreadNewAndRunParams
11581107 return param.MarshalObject(r, (*shadow)(&r))
11591108}
1109+func (r *BetaThreadNewAndRunParams) UnmarshalJSON(data []byte) error {
1110+ return apijson.UnmarshalRoot(data, r)
1111+}
11601112
11611113// Options to create a new thread. If no thread is provided when running a request,
11621114// an empty thread will be created.
@@ -1167,7 +1119,7 @@ type BetaThreadNewAndRunParamsThread struct {
11671119 //
11681120 // Keys are strings with a maximum length of 64 characters. Values are strings with
11691121 // a maximum length of 512 characters.
1170− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1122+ Metadata shared.Metadata `json:"metadata,omitzero"`
11711123 // A set of resources that are made available to the assistant's tools in this
11721124 // thread. The resources are specific to the type of tool. For example, the
11731125 // `code_interpreter` tool requires a list of file IDs, while the `file_search`
@@ -1179,13 +1131,13 @@ type BetaThreadNewAndRunParamsThread struct {
11791131 paramObj
11801132}
11811133
1182−// IsPresent returns true if the field's value is not omitted and not the JSON
1183−// "null". To check if this field is omitted, use [param.IsOmitted].
1184−func (f BetaThreadNewAndRunParamsThread) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
11851134func (r BetaThreadNewAndRunParamsThread) MarshalJSON() (data []byte, err error) {
11861135 type shadow BetaThreadNewAndRunParamsThread
11871136 return param.MarshalObject(r, (*shadow)(&r))
11881137}
1138+func (r *BetaThreadNewAndRunParamsThread) UnmarshalJSON(data []byte) error {
1139+ return apijson.UnmarshalRoot(data, r)
1140+}
11891141
11901142// The properties Content, Role are required.
11911143type BetaThreadNewAndRunParamsThreadMessage struct {
@@ -1208,23 +1160,21 @@ type BetaThreadNewAndRunParamsThreadMessage struct {
12081160 //
12091161 // Keys are strings with a maximum length of 64 characters. Values are strings with
12101162 // a maximum length of 512 characters.
1211− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1163+ Metadata shared.Metadata `json:"metadata,omitzero"`
12121164 paramObj
12131165}
12141166
1215−// IsPresent returns true if the field's value is not omitted and not the JSON
1216−// "null". To check if this field is omitted, use [param.IsOmitted].
1217−func (f BetaThreadNewAndRunParamsThreadMessage) IsPresent() bool {
1218− return !param.IsOmitted(f) && !f.IsNull()
1219−}
12201167func (r BetaThreadNewAndRunParamsThreadMessage) MarshalJSON() (data []byte, err error) {
12211168 type shadow BetaThreadNewAndRunParamsThreadMessage
12221169 return param.MarshalObject(r, (*shadow)(&r))
12231170}
1171+func (r *BetaThreadNewAndRunParamsThreadMessage) UnmarshalJSON(data []byte) error {
1172+ return apijson.UnmarshalRoot(data, r)
1173+}
12241174
12251175func init() {
12261176 apijson.RegisterFieldValidator[BetaThreadNewAndRunParamsThreadMessage](
1227− "Role", false, "user", "assistant",
1177+ "role", "user", "assistant",
12281178 )
12291179}
12301180
@@ -1237,13 +1187,11 @@ type BetaThreadNewAndRunParamsThreadMessageContentUnion struct {
12371187 paramUnion
12381188}
12391189
1240−// IsPresent returns true if the field's value is not omitted and not the JSON
1241−// "null". To check if this field is omitted, use [param.IsOmitted].
1242−func (u BetaThreadNewAndRunParamsThreadMessageContentUnion) IsPresent() bool {
1243− return !param.IsOmitted(u) && !u.IsNull()
1244−}
12451190func (u BetaThreadNewAndRunParamsThreadMessageContentUnion) MarshalJSON() ([]byte, error) {
1246− return param.MarshalUnion[BetaThreadNewAndRunParamsThreadMessageContentUnion](u.OfString, u.OfArrayOfContentParts)
1191+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
1192+}
1193+func (u *BetaThreadNewAndRunParamsThreadMessageContentUnion) UnmarshalJSON(data []byte) error {
1194+ return apijson.UnmarshalRoot(data, u)
12471195}
12481196
12491197func (u *BetaThreadNewAndRunParamsThreadMessageContentUnion) asAny() any {
@@ -1263,15 +1211,13 @@ type BetaThreadNewAndRunParamsThreadMessageAttachment struct {
12631211 paramObj
12641212}
12651213
1266−// IsPresent returns true if the field's value is not omitted and not the JSON
1267−// "null". To check if this field is omitted, use [param.IsOmitted].
1268−func (f BetaThreadNewAndRunParamsThreadMessageAttachment) IsPresent() bool {
1269− return !param.IsOmitted(f) && !f.IsNull()
1270−}
12711214func (r BetaThreadNewAndRunParamsThreadMessageAttachment) MarshalJSON() (data []byte, err error) {
12721215 type shadow BetaThreadNewAndRunParamsThreadMessageAttachment
12731216 return param.MarshalObject(r, (*shadow)(&r))
12741217}
1218+func (r *BetaThreadNewAndRunParamsThreadMessageAttachment) UnmarshalJSON(data []byte) error {
1219+ return apijson.UnmarshalRoot(data, r)
1220+}
12751221
12761222// Only one field can be non-zero.
12771223//
@@ -1282,13 +1228,11 @@ type BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion struct {
12821228 paramUnion
12831229}
12841230
1285−// IsPresent returns true if the field's value is not omitted and not the JSON
1286−// "null". To check if this field is omitted, use [param.IsOmitted].
1287−func (u BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion) IsPresent() bool {
1288− return !param.IsOmitted(u) && !u.IsNull()
1289−}
12901231func (u BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion) MarshalJSON() ([]byte, error) {
1291− return param.MarshalUnion[BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion](u.OfCodeInterpreter, u.OfFileSearch)
1232+ return param.MarshalUnion(u, u.OfCodeInterpreter, u.OfFileSearch)
1233+}
1234+func (u *BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion) UnmarshalJSON(data []byte) error {
1235+ return apijson.UnmarshalRoot(data, u)
12921236}
12931237
12941238func (u *BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion) asAny() any {
@@ -1313,37 +1257,32 @@ func (u BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion) GetType() *st
13131257func init() {
13141258 apijson.RegisterUnion[BetaThreadNewAndRunParamsThreadMessageAttachmentToolUnion](
13151259 "type",
1316− apijson.UnionVariant{
1317− TypeFilter: gjson.JSON,
1318− Type: reflect.TypeOf(CodeInterpreterToolParam{}),
1319− DiscriminatorValue: "code_interpreter",
1320− },
1321− apijson.UnionVariant{
1322− TypeFilter: gjson.JSON,
1323− Type: reflect.TypeOf(BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch{}),
1324− DiscriminatorValue: "file_search",
1325− },
1260+ apijson.Discriminator[CodeInterpreterToolParam]("code_interpreter"),
1261+ apijson.Discriminator[BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch]("file_search"),
13261262 )
13271263}
13281264
1329−// The property Type is required.
1265+func NewBetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch() BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch {
1266+ return BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch{
1267+ Type: "file_search",
1268+ }
1269+}
1270+
1271+// This struct has a constant value, construct it with
1272+// [NewBetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch].
13301273type BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch struct {
13311274 // The type of tool being defined: `file_search`
1332− //
1333− // This field can be elided, and will marshal its zero value as "file_search".
13341275 Type constant.FileSearch `json:"type,required"`
13351276 paramObj
13361277}
13371278
1338−// IsPresent returns true if the field's value is not omitted and not the JSON
1339−// "null". To check if this field is omitted, use [param.IsOmitted].
1340−func (f BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch) IsPresent() bool {
1341− return !param.IsOmitted(f) && !f.IsNull()
1342−}
13431279func (r BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch) MarshalJSON() (data []byte, err error) {
13441280 type shadow BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch
13451281 return param.MarshalObject(r, (*shadow)(&r))
13461282}
1283+func (r *BetaThreadNewAndRunParamsThreadMessageAttachmentToolFileSearch) UnmarshalJSON(data []byte) error {
1284+ return apijson.UnmarshalRoot(data, r)
1285+}
13471286
13481287// A set of resources that are made available to the assistant's tools in this
13491288// thread. The resources are specific to the type of tool. For example, the
@@ -1355,15 +1294,13 @@ type BetaThreadNewAndRunParamsThreadToolResources struct {
13551294 paramObj
13561295}
13571296
1358−// IsPresent returns true if the field's value is not omitted and not the JSON
1359−// "null". To check if this field is omitted, use [param.IsOmitted].
1360−func (f BetaThreadNewAndRunParamsThreadToolResources) IsPresent() bool {
1361− return !param.IsOmitted(f) && !f.IsNull()
1362−}
13631297func (r BetaThreadNewAndRunParamsThreadToolResources) MarshalJSON() (data []byte, err error) {
13641298 type shadow BetaThreadNewAndRunParamsThreadToolResources
13651299 return param.MarshalObject(r, (*shadow)(&r))
13661300}
1301+func (r *BetaThreadNewAndRunParamsThreadToolResources) UnmarshalJSON(data []byte) error {
1302+ return apijson.UnmarshalRoot(data, r)
1303+}
13671304
13681305type BetaThreadNewAndRunParamsThreadToolResourcesCodeInterpreter struct {
13691306 // A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made
@@ -1373,15 +1310,13 @@ type BetaThreadNewAndRunParamsThreadToolResourcesCodeInterpreter struct {
13731310 paramObj
13741311}
13751312
1376−// IsPresent returns true if the field's value is not omitted and not the JSON
1377−// "null". To check if this field is omitted, use [param.IsOmitted].
1378−func (f BetaThreadNewAndRunParamsThreadToolResourcesCodeInterpreter) IsPresent() bool {
1379− return !param.IsOmitted(f) && !f.IsNull()
1380−}
13811313func (r BetaThreadNewAndRunParamsThreadToolResourcesCodeInterpreter) MarshalJSON() (data []byte, err error) {
13821314 type shadow BetaThreadNewAndRunParamsThreadToolResourcesCodeInterpreter
13831315 return param.MarshalObject(r, (*shadow)(&r))
13841316}
1317+func (r *BetaThreadNewAndRunParamsThreadToolResourcesCodeInterpreter) UnmarshalJSON(data []byte) error {
1318+ return apijson.UnmarshalRoot(data, r)
1319+}
13851320
13861321type BetaThreadNewAndRunParamsThreadToolResourcesFileSearch struct {
13871322 // The
@@ -1397,15 +1332,13 @@ type BetaThreadNewAndRunParamsThreadToolResourcesFileSearch struct {
13971332 paramObj
13981333}
13991334
1400−// IsPresent returns true if the field's value is not omitted and not the JSON
1401−// "null". To check if this field is omitted, use [param.IsOmitted].
1402−func (f BetaThreadNewAndRunParamsThreadToolResourcesFileSearch) IsPresent() bool {
1403− return !param.IsOmitted(f) && !f.IsNull()
1404−}
14051335func (r BetaThreadNewAndRunParamsThreadToolResourcesFileSearch) MarshalJSON() (data []byte, err error) {
14061336 type shadow BetaThreadNewAndRunParamsThreadToolResourcesFileSearch
14071337 return param.MarshalObject(r, (*shadow)(&r))
14081338}
1339+func (r *BetaThreadNewAndRunParamsThreadToolResourcesFileSearch) UnmarshalJSON(data []byte) error {
1340+ return apijson.UnmarshalRoot(data, r)
1341+}
14091342
14101343type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStore struct {
14111344 // Set of 16 key-value pairs that can be attached to an object. This can be useful
@@ -1414,7 +1347,7 @@ type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStore struct {
14141347 //
14151348 // Keys are strings with a maximum length of 64 characters. Values are strings with
14161349 // a maximum length of 512 characters.
1417− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1350+ Metadata shared.Metadata `json:"metadata,omitzero"`
14181351 // The chunking strategy used to chunk the file(s). If not set, will use the `auto`
14191352 // strategy.
14201353 ChunkingStrategy BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyUnion `json:"chunking_strategy,omitzero"`
@@ -1425,15 +1358,13 @@ type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStore struct {
14251358 paramObj
14261359}
14271360
1428−// IsPresent returns true if the field's value is not omitted and not the JSON
1429−// "null". To check if this field is omitted, use [param.IsOmitted].
1430−func (f BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStore) IsPresent() bool {
1431− return !param.IsOmitted(f) && !f.IsNull()
1432−}
14331361func (r BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStore) MarshalJSON() (data []byte, err error) {
14341362 type shadow BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStore
14351363 return param.MarshalObject(r, (*shadow)(&r))
14361364}
1365+func (r *BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStore) UnmarshalJSON(data []byte) error {
1366+ return apijson.UnmarshalRoot(data, r)
1367+}
14371368
14381369// Only one field can be non-zero.
14391370//
@@ -1444,13 +1375,11 @@ type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingSt
14441375 paramUnion
14451376}
14461377
1447−// IsPresent returns true if the field's value is not omitted and not the JSON
1448−// "null". To check if this field is omitted, use [param.IsOmitted].
1449−func (u BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyUnion) IsPresent() bool {
1450− return !param.IsOmitted(u) && !u.IsNull()
1451−}
14521378func (u BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyUnion) MarshalJSON() ([]byte, error) {
1453− return param.MarshalUnion[BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyUnion](u.OfAuto, u.OfStatic)
1379+ return param.MarshalUnion(u, u.OfAuto, u.OfStatic)
1380+}
1381+func (u *BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyUnion) UnmarshalJSON(data []byte) error {
1382+ return apijson.UnmarshalRoot(data, u)
14541383}
14551384
14561385func (u *BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyUnion) asAny() any {
@@ -1483,40 +1412,35 @@ func (u BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkin
14831412func init() {
14841413 apijson.RegisterUnion[BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyUnion](
14851414 "type",
1486− apijson.UnionVariant{
1487− TypeFilter: gjson.JSON,
1488− Type: reflect.TypeOf(BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto{}),
1489− DiscriminatorValue: "auto",
1490− },
1491− apijson.UnionVariant{
1492− TypeFilter: gjson.JSON,
1493− Type: reflect.TypeOf(BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic{}),
1494− DiscriminatorValue: "static",
1495− },
1415+ apijson.Discriminator[BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto]("auto"),
1416+ apijson.Discriminator[BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic]("static"),
14961417 )
14971418}
14981419
1420+func NewBetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto() BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto {
1421+ return BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto{
1422+ Type: "auto",
1423+ }
1424+}
1425+
14991426// The default strategy. This strategy currently uses a `max_chunk_size_tokens` of
15001427// `800` and `chunk_overlap_tokens` of `400`.
15011428//
1502−// The property Type is required.
1429+// This struct has a constant value, construct it with
1430+// [NewBetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto].
15031431type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto struct {
15041432 // Always `auto`.
1505− //
1506− // This field can be elided, and will marshal its zero value as "auto".
15071433 Type constant.Auto `json:"type,required"`
15081434 paramObj
15091435}
15101436
1511−// IsPresent returns true if the field's value is not omitted and not the JSON
1512−// "null". To check if this field is omitted, use [param.IsOmitted].
1513−func (f BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto) IsPresent() bool {
1514− return !param.IsOmitted(f) && !f.IsNull()
1515−}
15161437func (r BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto) MarshalJSON() (data []byte, err error) {
15171438 type shadow BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto
15181439 return param.MarshalObject(r, (*shadow)(&r))
15191440}
1441+func (r *BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyAuto) UnmarshalJSON(data []byte) error {
1442+ return apijson.UnmarshalRoot(data, r)
1443+}
15201444
15211445// The properties Static, Type are required.
15221446type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic struct {
@@ -1528,15 +1452,13 @@ type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingSt
15281452 paramObj
15291453}
15301454
1531−// IsPresent returns true if the field's value is not omitted and not the JSON
1532−// "null". To check if this field is omitted, use [param.IsOmitted].
1533−func (f BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic) IsPresent() bool {
1534− return !param.IsOmitted(f) && !f.IsNull()
1535−}
15361455func (r BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic) MarshalJSON() (data []byte, err error) {
15371456 type shadow BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic
15381457 return param.MarshalObject(r, (*shadow)(&r))
15391458}
1459+func (r *BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStatic) UnmarshalJSON(data []byte) error {
1460+ return apijson.UnmarshalRoot(data, r)
1461+}
15401462
15411463// The properties ChunkOverlapTokens, MaxChunkSizeTokens are required.
15421464type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic struct {
@@ -1550,15 +1472,13 @@ type BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingSt
15501472 paramObj
15511473}
15521474
1553−// IsPresent returns true if the field's value is not omitted and not the JSON
1554−// "null". To check if this field is omitted, use [param.IsOmitted].
1555−func (f BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) IsPresent() bool {
1556− return !param.IsOmitted(f) && !f.IsNull()
1557−}
15581475func (r BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) MarshalJSON() (data []byte, err error) {
15591476 type shadow BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic
15601477 return param.MarshalObject(r, (*shadow)(&r))
15611478}
1479+func (r *BetaThreadNewAndRunParamsThreadToolResourcesFileSearchVectorStoreChunkingStrategyStaticStatic) UnmarshalJSON(data []byte) error {
1480+ return apijson.UnmarshalRoot(data, r)
1481+}
15621482
15631483// A set of resources that are used by the assistant's tools. The resources are
15641484// specific to the type of tool. For example, the `code_interpreter` tool requires
@@ -1570,15 +1490,13 @@ type BetaThreadNewAndRunParamsToolResources struct {
15701490 paramObj
15711491}
15721492
1573−// IsPresent returns true if the field's value is not omitted and not the JSON
1574−// "null". To check if this field is omitted, use [param.IsOmitted].
1575−func (f BetaThreadNewAndRunParamsToolResources) IsPresent() bool {
1576− return !param.IsOmitted(f) && !f.IsNull()
1577−}
15781493func (r BetaThreadNewAndRunParamsToolResources) MarshalJSON() (data []byte, err error) {
15791494 type shadow BetaThreadNewAndRunParamsToolResources
15801495 return param.MarshalObject(r, (*shadow)(&r))
15811496}
1497+func (r *BetaThreadNewAndRunParamsToolResources) UnmarshalJSON(data []byte) error {
1498+ return apijson.UnmarshalRoot(data, r)
1499+}
15821500
15831501type BetaThreadNewAndRunParamsToolResourcesCodeInterpreter struct {
15841502 // A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made
@@ -1588,15 +1506,13 @@ type BetaThreadNewAndRunParamsToolResourcesCodeInterpreter struct {
15881506 paramObj
15891507}
15901508
1591−// IsPresent returns true if the field's value is not omitted and not the JSON
1592−// "null". To check if this field is omitted, use [param.IsOmitted].
1593−func (f BetaThreadNewAndRunParamsToolResourcesCodeInterpreter) IsPresent() bool {
1594− return !param.IsOmitted(f) && !f.IsNull()
1595−}
15961509func (r BetaThreadNewAndRunParamsToolResourcesCodeInterpreter) MarshalJSON() (data []byte, err error) {
15971510 type shadow BetaThreadNewAndRunParamsToolResourcesCodeInterpreter
15981511 return param.MarshalObject(r, (*shadow)(&r))
15991512}
1513+func (r *BetaThreadNewAndRunParamsToolResourcesCodeInterpreter) UnmarshalJSON(data []byte) error {
1514+ return apijson.UnmarshalRoot(data, r)
1515+}
16001516
16011517type BetaThreadNewAndRunParamsToolResourcesFileSearch struct {
16021518 // The ID of the
@@ -1607,72 +1523,12 @@ type BetaThreadNewAndRunParamsToolResourcesFileSearch struct {
16071523 paramObj
16081524}
16091525
1610−// IsPresent returns true if the field's value is not omitted and not the JSON
1611−// "null". To check if this field is omitted, use [param.IsOmitted].
1612−func (f BetaThreadNewAndRunParamsToolResourcesFileSearch) IsPresent() bool {
1613− return !param.IsOmitted(f) && !f.IsNull()
1614−}
16151526func (r BetaThreadNewAndRunParamsToolResourcesFileSearch) MarshalJSON() (data []byte, err error) {
16161527 type shadow BetaThreadNewAndRunParamsToolResourcesFileSearch
16171528 return param.MarshalObject(r, (*shadow)(&r))
16181529}
1619−
1620−// Only one field can be non-zero.
1621−//
1622−// Use [param.IsOmitted] to confirm if a field is set.
1623−type BetaThreadNewAndRunParamsToolUnion struct {
1624− OfCodeInterpreterTool *CodeInterpreterToolParam `json:",omitzero,inline"`
1625− OfFileSearchTool *FileSearchToolParam `json:",omitzero,inline"`
1626− OfFunctionTool *FunctionToolParam `json:",omitzero,inline"`
1627− paramUnion
1628−}
1629−
1630−// IsPresent returns true if the field's value is not omitted and not the JSON
1631−// "null". To check if this field is omitted, use [param.IsOmitted].
1632−func (u BetaThreadNewAndRunParamsToolUnion) IsPresent() bool {
1633− return !param.IsOmitted(u) && !u.IsNull()
1634−}
1635−func (u BetaThreadNewAndRunParamsToolUnion) MarshalJSON() ([]byte, error) {
1636− return param.MarshalUnion[BetaThreadNewAndRunParamsToolUnion](u.OfCodeInterpreterTool, u.OfFileSearchTool, u.OfFunctionTool)
1637−}
1638−
1639−func (u *BetaThreadNewAndRunParamsToolUnion) asAny() any {
1640− if !param.IsOmitted(u.OfCodeInterpreterTool) {
1641− return u.OfCodeInterpreterTool
1642− } else if !param.IsOmitted(u.OfFileSearchTool) {
1643− return u.OfFileSearchTool
1644− } else if !param.IsOmitted(u.OfFunctionTool) {
1645− return u.OfFunctionTool
1646− }
1647− return nil
1648−}
1649−
1650−// Returns a pointer to the underlying variant's property, if present.
1651−func (u BetaThreadNewAndRunParamsToolUnion) GetFileSearch() *FileSearchToolFileSearchParam {
1652− if vt := u.OfFileSearchTool; vt != nil {
1653− return &vt.FileSearch
1654− }
1655− return nil
1656−}
1657−
1658−// Returns a pointer to the underlying variant's property, if present.
1659−func (u BetaThreadNewAndRunParamsToolUnion) GetFunction() *shared.FunctionDefinitionParam {
1660− if vt := u.OfFunctionTool; vt != nil {
1661− return &vt.Function
1662− }
1663− return nil
1664−}
1665−
1666−// Returns a pointer to the underlying variant's property, if present.
1667−func (u BetaThreadNewAndRunParamsToolUnion) GetType() *string {
1668− if vt := u.OfCodeInterpreterTool; vt != nil {
1669− return (*string)(&vt.Type)
1670− } else if vt := u.OfFileSearchTool; vt != nil {
1671− return (*string)(&vt.Type)
1672− } else if vt := u.OfFunctionTool; vt != nil {
1673− return (*string)(&vt.Type)
1674− }
1675− return nil
1530+func (r *BetaThreadNewAndRunParamsToolResourcesFileSearch) UnmarshalJSON(data []byte) error {
1531+ return apijson.UnmarshalRoot(data, r)
16761532}
16771533
16781534// Controls for how a thread will be truncated prior to the run. Use this to
@@ -1693,18 +1549,16 @@ type BetaThreadNewAndRunParamsTruncationStrategy struct {
16931549 paramObj
16941550}
16951551
1696−// IsPresent returns true if the field's value is not omitted and not the JSON
1697−// "null". To check if this field is omitted, use [param.IsOmitted].
1698−func (f BetaThreadNewAndRunParamsTruncationStrategy) IsPresent() bool {
1699− return !param.IsOmitted(f) && !f.IsNull()
1700−}
17011552func (r BetaThreadNewAndRunParamsTruncationStrategy) MarshalJSON() (data []byte, err error) {
17021553 type shadow BetaThreadNewAndRunParamsTruncationStrategy
17031554 return param.MarshalObject(r, (*shadow)(&r))
17041555}
1556+func (r *BetaThreadNewAndRunParamsTruncationStrategy) UnmarshalJSON(data []byte) error {
1557+ return apijson.UnmarshalRoot(data, r)
1558+}
17051559
17061560func init() {
17071561 apijson.RegisterFieldValidator[BetaThreadNewAndRunParamsTruncationStrategy](
1708− "Type", false, "auto", "last_messages",
1562+ "type", "auto", "last_messages",
17091563 )
17101564}
vendor/github.com/openai/openai-go/betathreadmessage.go+308−313
@@ -9,7 +9,6 @@ import (
99 "fmt"
1010 "net/http"
1111 "net/url"
12− "reflect"
1312
1413 "github.com/openai/openai-go/internal/apijson"
1514 "github.com/openai/openai-go/internal/apiquery"
@@ -17,10 +16,9 @@ import (
1716 "github.com/openai/openai-go/option"
1817 "github.com/openai/openai-go/packages/pagination"
1918 "github.com/openai/openai-go/packages/param"
20− "github.com/openai/openai-go/packages/resp"
19+ "github.com/openai/openai-go/packages/respjson"
2120 "github.com/openai/openai-go/shared"
2221 "github.com/openai/openai-go/shared/constant"
23− "github.com/tidwall/gjson"
2422)
2523
2624// BetaThreadMessageService contains methods and other services that help with
@@ -29,6 +27,8 @@ import (
2927// Note, unlike clients, this service does not read variables from the environment
3028// automatically. You should not instantiate this service directly, and instead use
3129// the [NewBetaThreadMessageService] method instead.
30+//
31+// Deprecated: The Assistants API is deprecated in favor of the Responses API
3232type BetaThreadMessageService struct {
3333 Options []option.RequestOption
3434}
@@ -43,6 +43,8 @@ func NewBetaThreadMessageService(opts ...option.RequestOption) (r BetaThreadMess
4343}
4444
4545// Create a message.
46+//
47+// Deprecated: The Assistants API is deprecated in favor of the Responses API
4648func (r *BetaThreadMessageService) New(ctx context.Context, threadID string, body BetaThreadMessageNewParams, opts ...option.RequestOption) (res *Message, err error) {
4749 opts = append(r.Options[:], opts...)
4850 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -56,6 +58,8 @@ func (r *BetaThreadMessageService) New(ctx context.Context, threadID string, bod
5658}
5759
5860// Retrieve a message.
61+//
62+// Deprecated: The Assistants API is deprecated in favor of the Responses API
5963func (r *BetaThreadMessageService) Get(ctx context.Context, threadID string, messageID string, opts ...option.RequestOption) (res *Message, err error) {
6064 opts = append(r.Options[:], opts...)
6165 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -73,6 +77,8 @@ func (r *BetaThreadMessageService) Get(ctx context.Context, threadID string, mes
7377}
7478
7579// Modifies a message.
80+//
81+// Deprecated: The Assistants API is deprecated in favor of the Responses API
7682func (r *BetaThreadMessageService) Update(ctx context.Context, threadID string, messageID string, body BetaThreadMessageUpdateParams, opts ...option.RequestOption) (res *Message, err error) {
7783 opts = append(r.Options[:], opts...)
7884 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -90,6 +96,8 @@ func (r *BetaThreadMessageService) Update(ctx context.Context, threadID string,
9096}
9197
9298// Returns a list of messages for a given thread.
99+//
100+// Deprecated: The Assistants API is deprecated in favor of the Responses API
93101func (r *BetaThreadMessageService) List(ctx context.Context, threadID string, query BetaThreadMessageListParams, opts ...option.RequestOption) (res *pagination.CursorPage[Message], err error) {
94102 var raw *http.Response
95103 opts = append(r.Options[:], opts...)
@@ -112,11 +120,15 @@ func (r *BetaThreadMessageService) List(ctx context.Context, threadID string, qu
112120}
113121
114122// Returns a list of messages for a given thread.
123+//
124+// Deprecated: The Assistants API is deprecated in favor of the Responses API
115125func (r *BetaThreadMessageService) ListAutoPaging(ctx context.Context, threadID string, query BetaThreadMessageListParams, opts ...option.RequestOption) *pagination.CursorPageAutoPager[Message] {
116126 return pagination.NewCursorPageAutoPager(r.List(ctx, threadID, query, opts...))
117127}
118128
119129// Deletes a message.
130+//
131+// Deprecated: The Assistants API is deprecated in favor of the Responses API
120132func (r *BetaThreadMessageService) Delete(ctx context.Context, threadID string, messageID string, opts ...option.RequestOption) (res *MessageDeleted, err error) {
121133 opts = append(r.Options[:], opts...)
122134 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -150,25 +162,34 @@ type AnnotationUnion struct {
150162 // This field is from variant [FilePathAnnotation].
151163 FilePath FilePathAnnotationFilePath `json:"file_path"`
152164 JSON struct {
153− EndIndex resp.Field
154− FileCitation resp.Field
155− StartIndex resp.Field
156− Text resp.Field
157− Type resp.Field
158− FilePath resp.Field
165+ EndIndex respjson.Field
166+ FileCitation respjson.Field
167+ StartIndex respjson.Field
168+ Text respjson.Field
169+ Type respjson.Field
170+ FilePath respjson.Field
159171 raw string
160172 } `json:"-"`
161173}
162174
175+// anyAnnotation is implemented by each variant of [AnnotationUnion] to add type
176+// safety for the return type of [AnnotationUnion.AsAny]
177+type anyAnnotation interface {
178+ implAnnotationUnion()
179+}
180+
181+func (FileCitationAnnotation) implAnnotationUnion() {}
182+func (FilePathAnnotation) implAnnotationUnion() {}
183+
163184// Use the following switch statement to find the correct variant
164185//
165186// switch variant := AnnotationUnion.AsAny().(type) {
166−// case FileCitationAnnotation:
167−// case FilePathAnnotation:
187+// case openai.FileCitationAnnotation:
188+// case openai.FilePathAnnotation:
168189// default:
169190// fmt.Errorf("no variant present")
170191// }
171−func (u AnnotationUnion) AsAny() any {
192+func (u AnnotationUnion) AsAny() anyAnnotation {
172193 switch u.Type {
173194 case "file_citation":
174195 return u.AsFileCitation()
@@ -213,26 +234,35 @@ type AnnotationDeltaUnion struct {
213234 // This field is from variant [FilePathDeltaAnnotation].
214235 FilePath FilePathDeltaAnnotationFilePath `json:"file_path"`
215236 JSON struct {
216− Index resp.Field
217− Type resp.Field
218− EndIndex resp.Field
219− FileCitation resp.Field
220− StartIndex resp.Field
221− Text resp.Field
222− FilePath resp.Field
237+ Index respjson.Field
238+ Type respjson.Field
239+ EndIndex respjson.Field
240+ FileCitation respjson.Field
241+ StartIndex respjson.Field
242+ Text respjson.Field
243+ FilePath respjson.Field
223244 raw string
224245 } `json:"-"`
225246}
226247
248+// anyAnnotationDelta is implemented by each variant of [AnnotationDeltaUnion] to
249+// add type safety for the return type of [AnnotationDeltaUnion.AsAny]
250+type anyAnnotationDelta interface {
251+ implAnnotationDeltaUnion()
252+}
253+
254+func (FileCitationDeltaAnnotation) implAnnotationDeltaUnion() {}
255+func (FilePathDeltaAnnotation) implAnnotationDeltaUnion() {}
256+
227257// Use the following switch statement to find the correct variant
228258//
229259// switch variant := AnnotationDeltaUnion.AsAny().(type) {
230−// case FileCitationDeltaAnnotation:
231−// case FilePathDeltaAnnotation:
260+// case openai.FileCitationDeltaAnnotation:
261+// case openai.FilePathDeltaAnnotation:
232262// default:
233263// fmt.Errorf("no variant present")
234264// }
235−func (u AnnotationDeltaUnion) AsAny() any {
265+func (u AnnotationDeltaUnion) AsAny() anyAnnotationDelta {
236266 switch u.Type {
237267 case "file_citation":
238268 return u.AsFileCitation()
@@ -270,15 +300,14 @@ type FileCitationAnnotation struct {
270300 Text string `json:"text,required"`
271301 // Always `file_citation`.
272302 Type constant.FileCitation `json:"type,required"`
273− // Metadata for the response, check the presence of optional fields with the
274− // [resp.Field.IsPresent] method.
303+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
275304 JSON struct {
276− EndIndex resp.Field
277− FileCitation resp.Field
278− StartIndex resp.Field
279− Text resp.Field
280− Type resp.Field
281− ExtraFields map[string]resp.Field
305+ EndIndex respjson.Field
306+ FileCitation respjson.Field
307+ StartIndex respjson.Field
308+ Text respjson.Field
309+ Type respjson.Field
310+ ExtraFields map[string]respjson.Field
282311 raw string
283312 } `json:"-"`
284313}
@@ -292,11 +321,10 @@ func (r *FileCitationAnnotation) UnmarshalJSON(data []byte) error {
292321type FileCitationAnnotationFileCitation struct {
293322 // The ID of the specific File the citation is from.
294323 FileID string `json:"file_id,required"`
295− // Metadata for the response, check the presence of optional fields with the
296− // [resp.Field.IsPresent] method.
324+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
297325 JSON struct {
298− FileID resp.Field
299− ExtraFields map[string]resp.Field
326+ FileID respjson.Field
327+ ExtraFields map[string]respjson.Field
300328 raw string
301329 } `json:"-"`
302330}
@@ -320,16 +348,15 @@ type FileCitationDeltaAnnotation struct {
320348 StartIndex int64 `json:"start_index"`
321349 // The text in the message content that needs to be replaced.
322350 Text string `json:"text"`
323− // Metadata for the response, check the presence of optional fields with the
324− // [resp.Field.IsPresent] method.
351+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
325352 JSON struct {
326− Index resp.Field
327− Type resp.Field
328− EndIndex resp.Field
329− FileCitation resp.Field
330− StartIndex resp.Field
331− Text resp.Field
332− ExtraFields map[string]resp.Field
353+ Index respjson.Field
354+ Type respjson.Field
355+ EndIndex respjson.Field
356+ FileCitation respjson.Field
357+ StartIndex respjson.Field
358+ Text respjson.Field
359+ ExtraFields map[string]respjson.Field
333360 raw string
334361 } `json:"-"`
335362}
@@ -345,12 +372,11 @@ type FileCitationDeltaAnnotationFileCitation struct {
345372 FileID string `json:"file_id"`
346373 // The specific quote in the file.
347374 Quote string `json:"quote"`
348− // Metadata for the response, check the presence of optional fields with the
349− // [resp.Field.IsPresent] method.
375+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
350376 JSON struct {
351− FileID resp.Field
352− Quote resp.Field
353− ExtraFields map[string]resp.Field
377+ FileID respjson.Field
378+ Quote respjson.Field
379+ ExtraFields map[string]respjson.Field
354380 raw string
355381 } `json:"-"`
356382}
@@ -371,15 +397,14 @@ type FilePathAnnotation struct {
371397 Text string `json:"text,required"`
372398 // Always `file_path`.
373399 Type constant.FilePath `json:"type,required"`
374− // Metadata for the response, check the presence of optional fields with the
375− // [resp.Field.IsPresent] method.
400+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
376401 JSON struct {
377− EndIndex resp.Field
378− FilePath resp.Field
379− StartIndex resp.Field
380− Text resp.Field
381− Type resp.Field
382− ExtraFields map[string]resp.Field
402+ EndIndex respjson.Field
403+ FilePath respjson.Field
404+ StartIndex respjson.Field
405+ Text respjson.Field
406+ Type respjson.Field
407+ ExtraFields map[string]respjson.Field
383408 raw string
384409 } `json:"-"`
385410}
@@ -393,11 +418,10 @@ func (r *FilePathAnnotation) UnmarshalJSON(data []byte) error {
393418type FilePathAnnotationFilePath struct {
394419 // The ID of the file that was generated.
395420 FileID string `json:"file_id,required"`
396− // Metadata for the response, check the presence of optional fields with the
397− // [resp.Field.IsPresent] method.
421+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
398422 JSON struct {
399− FileID resp.Field
400− ExtraFields map[string]resp.Field
423+ FileID respjson.Field
424+ ExtraFields map[string]respjson.Field
401425 raw string
402426 } `json:"-"`
403427}
@@ -420,16 +444,15 @@ type FilePathDeltaAnnotation struct {
420444 StartIndex int64 `json:"start_index"`
421445 // The text in the message content that needs to be replaced.
422446 Text string `json:"text"`
423− // Metadata for the response, check the presence of optional fields with the
424− // [resp.Field.IsPresent] method.
447+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
425448 JSON struct {
426− Index resp.Field
427− Type resp.Field
428− EndIndex resp.Field
429− FilePath resp.Field
430− StartIndex resp.Field
431− Text resp.Field
432− ExtraFields map[string]resp.Field
449+ Index respjson.Field
450+ Type respjson.Field
451+ EndIndex respjson.Field
452+ FilePath respjson.Field
453+ StartIndex respjson.Field
454+ Text respjson.Field
455+ ExtraFields map[string]respjson.Field
433456 raw string
434457 } `json:"-"`
435458}
@@ -443,11 +466,10 @@ func (r *FilePathDeltaAnnotation) UnmarshalJSON(data []byte) error {
443466type FilePathDeltaAnnotationFilePath struct {
444467 // The ID of the file that was generated.
445468 FileID string `json:"file_id"`
446− // Metadata for the response, check the presence of optional fields with the
447− // [resp.Field.IsPresent] method.
469+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
448470 JSON struct {
449− FileID resp.Field
450− ExtraFields map[string]resp.Field
471+ FileID respjson.Field
472+ ExtraFields map[string]respjson.Field
451473 raw string
452474 } `json:"-"`
453475}
@@ -468,12 +490,11 @@ type ImageFile struct {
468490 //
469491 // Any of "auto", "low", "high".
470492 Detail ImageFileDetail `json:"detail"`
471− // Metadata for the response, check the presence of optional fields with the
472− // [resp.Field.IsPresent] method.
493+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
473494 JSON struct {
474− FileID resp.Field
475− Detail resp.Field
476− ExtraFields map[string]resp.Field
495+ FileID respjson.Field
496+ Detail respjson.Field
497+ ExtraFields map[string]respjson.Field
477498 raw string
478499 } `json:"-"`
479500}
@@ -488,9 +509,9 @@ func (r *ImageFile) UnmarshalJSON(data []byte) error {
488509//
489510// Warning: the fields of the param type will not be present. ToParam should only
490511// be used at the last possible moment before sending a request. Test for this with
491−// ImageFileParam.IsOverridden()
512+// ImageFileParam.Overrides()
492513func (r ImageFile) ToParam() ImageFileParam {
493− return param.OverrideObj[ImageFileParam](r.RawJSON())
514+ return param.Override[ImageFileParam](json.RawMessage(r.RawJSON()))
494515}
495516
496517// Specifies the detail level of the image if specified by the user. `low` uses
@@ -517,13 +538,13 @@ type ImageFileParam struct {
517538 paramObj
518539}
519540
520−// IsPresent returns true if the field's value is not omitted and not the JSON
521−// "null". To check if this field is omitted, use [param.IsOmitted].
522−func (f ImageFileParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
523541func (r ImageFileParam) MarshalJSON() (data []byte, err error) {
524542 type shadow ImageFileParam
525543 return param.MarshalObject(r, (*shadow)(&r))
526544}
545+func (r *ImageFileParam) UnmarshalJSON(data []byte) error {
546+ return apijson.UnmarshalRoot(data, r)
547+}
527548
528549// References an image [File](https://platform.openai.com/docs/api-reference/files)
529550// in the content of a message.
@@ -531,12 +552,11 @@ type ImageFileContentBlock struct {
531552 ImageFile ImageFile `json:"image_file,required"`
532553 // Always `image_file`.
533554 Type constant.ImageFile `json:"type,required"`
534− // Metadata for the response, check the presence of optional fields with the
535− // [resp.Field.IsPresent] method.
555+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
536556 JSON struct {
537− ImageFile resp.Field
538− Type resp.Field
539− ExtraFields map[string]resp.Field
557+ ImageFile respjson.Field
558+ Type respjson.Field
559+ ExtraFields map[string]respjson.Field
540560 raw string
541561 } `json:"-"`
542562}
@@ -551,9 +571,9 @@ func (r *ImageFileContentBlock) UnmarshalJSON(data []byte) error {
551571//
552572// Warning: the fields of the param type will not be present. ToParam should only
553573// be used at the last possible moment before sending a request. Test for this with
554−// ImageFileContentBlockParam.IsOverridden()
574+// ImageFileContentBlockParam.Overrides()
555575func (r ImageFileContentBlock) ToParam() ImageFileContentBlockParam {
556− return param.OverrideObj[ImageFileContentBlockParam](r.RawJSON())
576+ return param.Override[ImageFileContentBlockParam](json.RawMessage(r.RawJSON()))
557577}
558578
559579// References an image [File](https://platform.openai.com/docs/api-reference/files)
@@ -569,13 +589,13 @@ type ImageFileContentBlockParam struct {
569589 paramObj
570590}
571591
572−// IsPresent returns true if the field's value is not omitted and not the JSON
573−// "null". To check if this field is omitted, use [param.IsOmitted].
574−func (f ImageFileContentBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
575592func (r ImageFileContentBlockParam) MarshalJSON() (data []byte, err error) {
576593 type shadow ImageFileContentBlockParam
577594 return param.MarshalObject(r, (*shadow)(&r))
578595}
596+func (r *ImageFileContentBlockParam) UnmarshalJSON(data []byte) error {
597+ return apijson.UnmarshalRoot(data, r)
598+}
579599
580600type ImageFileDelta struct {
581601 // Specifies the detail level of the image if specified by the user. `low` uses
@@ -587,12 +607,11 @@ type ImageFileDelta struct {
587607 // in the message content. Set `purpose="vision"` when uploading the File if you
588608 // need to later display the file content.
589609 FileID string `json:"file_id"`
590− // Metadata for the response, check the presence of optional fields with the
591− // [resp.Field.IsPresent] method.
610+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
592611 JSON struct {
593− Detail resp.Field
594− FileID resp.Field
595− ExtraFields map[string]resp.Field
612+ Detail respjson.Field
613+ FileID respjson.Field
614+ ExtraFields map[string]respjson.Field
596615 raw string
597616 } `json:"-"`
598617}
@@ -621,13 +640,12 @@ type ImageFileDeltaBlock struct {
621640 // Always `image_file`.
622641 Type constant.ImageFile `json:"type,required"`
623642 ImageFile ImageFileDelta `json:"image_file"`
624− // Metadata for the response, check the presence of optional fields with the
625− // [resp.Field.IsPresent] method.
643+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
626644 JSON struct {
627− Index resp.Field
628− Type resp.Field
629− ImageFile resp.Field
630− ExtraFields map[string]resp.Field
645+ Index respjson.Field
646+ Type respjson.Field
647+ ImageFile respjson.Field
648+ ExtraFields map[string]respjson.Field
631649 raw string
632650 } `json:"-"`
633651}
@@ -647,12 +665,11 @@ type ImageURL struct {
647665 //
648666 // Any of "auto", "low", "high".
649667 Detail ImageURLDetail `json:"detail"`
650− // Metadata for the response, check the presence of optional fields with the
651− // [resp.Field.IsPresent] method.
668+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
652669 JSON struct {
653− URL resp.Field
654− Detail resp.Field
655− ExtraFields map[string]resp.Field
670+ URL respjson.Field
671+ Detail respjson.Field
672+ ExtraFields map[string]respjson.Field
656673 raw string
657674 } `json:"-"`
658675}
@@ -667,9 +684,9 @@ func (r *ImageURL) UnmarshalJSON(data []byte) error {
667684//
668685// Warning: the fields of the param type will not be present. ToParam should only
669686// be used at the last possible moment before sending a request. Test for this with
670−// ImageURLParam.IsOverridden()
687+// ImageURLParam.Overrides()
671688func (r ImageURL) ToParam() ImageURLParam {
672− return param.OverrideObj[ImageURLParam](r.RawJSON())
689+ return param.Override[ImageURLParam](json.RawMessage(r.RawJSON()))
673690}
674691
675692// Specifies the detail level of the image. `low` uses fewer tokens, you can opt in
@@ -695,25 +712,24 @@ type ImageURLParam struct {
695712 paramObj
696713}
697714
698−// IsPresent returns true if the field's value is not omitted and not the JSON
699−// "null". To check if this field is omitted, use [param.IsOmitted].
700−func (f ImageURLParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
701715func (r ImageURLParam) MarshalJSON() (data []byte, err error) {
702716 type shadow ImageURLParam
703717 return param.MarshalObject(r, (*shadow)(&r))
704718}
719+func (r *ImageURLParam) UnmarshalJSON(data []byte) error {
720+ return apijson.UnmarshalRoot(data, r)
721+}
705722
706723// References an image URL in the content of a message.
707724type ImageURLContentBlock struct {
708725 ImageURL ImageURL `json:"image_url,required"`
709726 // The type of the content part.
710727 Type constant.ImageURL `json:"type,required"`
711− // Metadata for the response, check the presence of optional fields with the
712− // [resp.Field.IsPresent] method.
728+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
713729 JSON struct {
714− ImageURL resp.Field
715− Type resp.Field
716− ExtraFields map[string]resp.Field
730+ ImageURL respjson.Field
731+ Type respjson.Field
732+ ExtraFields map[string]respjson.Field
717733 raw string
718734 } `json:"-"`
719735}
@@ -728,9 +744,9 @@ func (r *ImageURLContentBlock) UnmarshalJSON(data []byte) error {
728744//
729745// Warning: the fields of the param type will not be present. ToParam should only
730746// be used at the last possible moment before sending a request. Test for this with
731−// ImageURLContentBlockParam.IsOverridden()
747+// ImageURLContentBlockParam.Overrides()
732748func (r ImageURLContentBlock) ToParam() ImageURLContentBlockParam {
733− return param.OverrideObj[ImageURLContentBlockParam](r.RawJSON())
749+ return param.Override[ImageURLContentBlockParam](json.RawMessage(r.RawJSON()))
734750}
735751
736752// References an image URL in the content of a message.
@@ -745,13 +761,13 @@ type ImageURLContentBlockParam struct {
745761 paramObj
746762}
747763
748−// IsPresent returns true if the field's value is not omitted and not the JSON
749−// "null". To check if this field is omitted, use [param.IsOmitted].
750−func (f ImageURLContentBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
751764func (r ImageURLContentBlockParam) MarshalJSON() (data []byte, err error) {
752765 type shadow ImageURLContentBlockParam
753766 return param.MarshalObject(r, (*shadow)(&r))
754767}
768+func (r *ImageURLContentBlockParam) UnmarshalJSON(data []byte) error {
769+ return apijson.UnmarshalRoot(data, r)
770+}
755771
756772type ImageURLDelta struct {
757773 // Specifies the detail level of the image. `low` uses fewer tokens, you can opt in
@@ -762,12 +778,11 @@ type ImageURLDelta struct {
762778 // The URL of the image, must be a supported image types: jpeg, jpg, png, gif,
763779 // webp.
764780 URL string `json:"url"`
765− // Metadata for the response, check the presence of optional fields with the
766− // [resp.Field.IsPresent] method.
781+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
767782 JSON struct {
768− Detail resp.Field
769− URL resp.Field
770− ExtraFields map[string]resp.Field
783+ Detail respjson.Field
784+ URL respjson.Field
785+ ExtraFields map[string]respjson.Field
771786 raw string
772787 } `json:"-"`
773788}
@@ -795,13 +810,12 @@ type ImageURLDeltaBlock struct {
795810 // Always `image_url`.
796811 Type constant.ImageURL `json:"type,required"`
797812 ImageURL ImageURLDelta `json:"image_url"`
798− // Metadata for the response, check the presence of optional fields with the
799− // [resp.Field.IsPresent] method.
813+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
800814 JSON struct {
801− Index resp.Field
802− Type resp.Field
803− ImageURL resp.Field
804− ExtraFields map[string]resp.Field
815+ Index respjson.Field
816+ Type respjson.Field
817+ ImageURL respjson.Field
818+ ExtraFields map[string]respjson.Field
805819 raw string
806820 } `json:"-"`
807821}
@@ -858,24 +872,23 @@ type Message struct {
858872 // The [thread](https://platform.openai.com/docs/api-reference/threads) ID that
859873 // this message belongs to.
860874 ThreadID string `json:"thread_id,required"`
861− // Metadata for the response, check the presence of optional fields with the
862− // [resp.Field.IsPresent] method.
875+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
863876 JSON struct {
864− ID resp.Field
865− AssistantID resp.Field
866− Attachments resp.Field
867− CompletedAt resp.Field
868− Content resp.Field
869− CreatedAt resp.Field
870− IncompleteAt resp.Field
871− IncompleteDetails resp.Field
872− Metadata resp.Field
873− Object resp.Field
874− Role resp.Field
875− RunID resp.Field
876− Status resp.Field
877− ThreadID resp.Field
878− ExtraFields map[string]resp.Field
877+ ID respjson.Field
878+ AssistantID respjson.Field
879+ Attachments respjson.Field
880+ CompletedAt respjson.Field
881+ Content respjson.Field
882+ CreatedAt respjson.Field
883+ IncompleteAt respjson.Field
884+ IncompleteDetails respjson.Field
885+ Metadata respjson.Field
886+ Object respjson.Field
887+ Role respjson.Field
888+ RunID respjson.Field
889+ Status respjson.Field
890+ ThreadID respjson.Field
891+ ExtraFields map[string]respjson.Field
879892 raw string
880893 } `json:"-"`
881894}
@@ -891,12 +904,11 @@ type MessageAttachment struct {
891904 FileID string `json:"file_id"`
892905 // The tools to add this file to.
893906 Tools []MessageAttachmentToolUnion `json:"tools"`
894− // Metadata for the response, check the presence of optional fields with the
895− // [resp.Field.IsPresent] method.
907+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
896908 JSON struct {
897− FileID resp.Field
898− Tools resp.Field
899− ExtraFields map[string]resp.Field
909+ FileID respjson.Field
910+ Tools respjson.Field
911+ ExtraFields map[string]respjson.Field
900912 raw string
901913 } `json:"-"`
902914}
@@ -908,13 +920,13 @@ func (r *MessageAttachment) UnmarshalJSON(data []byte) error {
908920}
909921
910922// MessageAttachmentToolUnion contains all possible properties and values from
911−// [CodeInterpreterTool], [MessageAttachmentToolAssistantToolsFileSearchTypeOnly].
923+// [CodeInterpreterTool], [MessageAttachmentToolFileSearchTool].
912924//
913925// Use the methods beginning with 'As' to cast the union to one of its variants.
914926type MessageAttachmentToolUnion struct {
915927 Type string `json:"type"`
916928 JSON struct {
917− Type resp.Field
929+ Type respjson.Field
918930 raw string
919931 } `json:"-"`
920932}
@@ -924,7 +936,7 @@ func (u MessageAttachmentToolUnion) AsCodeInterpreterTool() (v CodeInterpreterTo
924936 return
925937}
926938
927−func (u MessageAttachmentToolUnion) AsFileSearchTool() (v MessageAttachmentToolAssistantToolsFileSearchTypeOnly) {
939+func (u MessageAttachmentToolUnion) AsFileSearchTool() (v MessageAttachmentToolFileSearchTool) {
928940 apijson.UnmarshalRoot(json.RawMessage(u.JSON.raw), &v)
929941 return
930942}
@@ -936,21 +948,20 @@ func (r *MessageAttachmentToolUnion) UnmarshalJSON(data []byte) error {
936948 return apijson.UnmarshalRoot(data, r)
937949}
938950
939−type MessageAttachmentToolAssistantToolsFileSearchTypeOnly struct {
951+type MessageAttachmentToolFileSearchTool struct {
940952 // The type of tool being defined: `file_search`
941953 Type constant.FileSearch `json:"type,required"`
942− // Metadata for the response, check the presence of optional fields with the
943− // [resp.Field.IsPresent] method.
954+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
944955 JSON struct {
945− Type resp.Field
946− ExtraFields map[string]resp.Field
956+ Type respjson.Field
957+ ExtraFields map[string]respjson.Field
947958 raw string
948959 } `json:"-"`
949960}
950961
951962// Returns the unmodified JSON received from the API
952−func (r MessageAttachmentToolAssistantToolsFileSearchTypeOnly) RawJSON() string { return r.JSON.raw }
953−func (r *MessageAttachmentToolAssistantToolsFileSearchTypeOnly) UnmarshalJSON(data []byte) error {
963+func (r MessageAttachmentToolFileSearchTool) RawJSON() string { return r.JSON.raw }
964+func (r *MessageAttachmentToolFileSearchTool) UnmarshalJSON(data []byte) error {
954965 return apijson.UnmarshalRoot(data, r)
955966}
956967
@@ -961,11 +972,10 @@ type MessageIncompleteDetails struct {
961972 // Any of "content_filter", "max_tokens", "run_cancelled", "run_expired",
962973 // "run_failed".
963974 Reason string `json:"reason,required"`
964− // Metadata for the response, check the presence of optional fields with the
965− // [resp.Field.IsPresent] method.
975+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
966976 JSON struct {
967− Reason resp.Field
968− ExtraFields map[string]resp.Field
977+ Reason respjson.Field
978+ ExtraFields map[string]respjson.Field
969979 raw string
970980 } `json:"-"`
971981}
@@ -1013,26 +1023,37 @@ type MessageContentUnion struct {
10131023 // This field is from variant [RefusalContentBlock].
10141024 Refusal string `json:"refusal"`
10151025 JSON struct {
1016− ImageFile resp.Field
1017− Type resp.Field
1018− ImageURL resp.Field
1019− Text resp.Field
1020− Refusal resp.Field
1026+ ImageFile respjson.Field
1027+ Type respjson.Field
1028+ ImageURL respjson.Field
1029+ Text respjson.Field
1030+ Refusal respjson.Field
10211031 raw string
10221032 } `json:"-"`
10231033}
10241034
1035+// anyMessageContent is implemented by each variant of [MessageContentUnion] to add
1036+// type safety for the return type of [MessageContentUnion.AsAny]
1037+type anyMessageContent interface {
1038+ implMessageContentUnion()
1039+}
1040+
1041+func (ImageFileContentBlock) implMessageContentUnion() {}
1042+func (ImageURLContentBlock) implMessageContentUnion() {}
1043+func (TextContentBlock) implMessageContentUnion() {}
1044+func (RefusalContentBlock) implMessageContentUnion() {}
1045+
10251046// Use the following switch statement to find the correct variant
10261047//
10271048// switch variant := MessageContentUnion.AsAny().(type) {
1028−// case ImageFileContentBlock:
1029−// case ImageURLContentBlock:
1030−// case TextContentBlock:
1031−// case RefusalContentBlock:
1049+// case openai.ImageFileContentBlock:
1050+// case openai.ImageURLContentBlock:
1051+// case openai.TextContentBlock:
1052+// case openai.RefusalContentBlock:
10321053// default:
10331054// fmt.Errorf("no variant present")
10341055// }
1035−func (u MessageContentUnion) AsAny() any {
1056+func (u MessageContentUnion) AsAny() anyMessageContent {
10361057 switch u.Type {
10371058 case "image_file":
10381059 return u.AsImageFile()
@@ -1093,27 +1114,39 @@ type MessageContentDeltaUnion struct {
10931114 // This field is from variant [ImageURLDeltaBlock].
10941115 ImageURL ImageURLDelta `json:"image_url"`
10951116 JSON struct {
1096− Index resp.Field
1097− Type resp.Field
1098− ImageFile resp.Field
1099− Text resp.Field
1100− Refusal resp.Field
1101− ImageURL resp.Field
1117+ Index respjson.Field
1118+ Type respjson.Field
1119+ ImageFile respjson.Field
1120+ Text respjson.Field
1121+ Refusal respjson.Field
1122+ ImageURL respjson.Field
11021123 raw string
11031124 } `json:"-"`
11041125}
11051126
1127+// anyMessageContentDelta is implemented by each variant of
1128+// [MessageContentDeltaUnion] to add type safety for the return type of
1129+// [MessageContentDeltaUnion.AsAny]
1130+type anyMessageContentDelta interface {
1131+ implMessageContentDeltaUnion()
1132+}
1133+
1134+func (ImageFileDeltaBlock) implMessageContentDeltaUnion() {}
1135+func (TextDeltaBlock) implMessageContentDeltaUnion() {}
1136+func (RefusalDeltaBlock) implMessageContentDeltaUnion() {}
1137+func (ImageURLDeltaBlock) implMessageContentDeltaUnion() {}
1138+
11061139// Use the following switch statement to find the correct variant
11071140//
11081141// switch variant := MessageContentDeltaUnion.AsAny().(type) {
1109−// case ImageFileDeltaBlock:
1110−// case TextDeltaBlock:
1111−// case RefusalDeltaBlock:
1112−// case ImageURLDeltaBlock:
1142+// case openai.ImageFileDeltaBlock:
1143+// case openai.TextDeltaBlock:
1144+// case openai.RefusalDeltaBlock:
1145+// case openai.ImageURLDeltaBlock:
11131146// default:
11141147// fmt.Errorf("no variant present")
11151148// }
1116−func (u MessageContentDeltaUnion) AsAny() any {
1149+func (u MessageContentDeltaUnion) AsAny() anyMessageContentDelta {
11171150 switch u.Type {
11181151 case "image_file":
11191152 return u.AsImageFile()
@@ -1182,11 +1215,11 @@ type MessageContentPartParamUnion struct {
11821215 paramUnion
11831216}
11841217
1185−// IsPresent returns true if the field's value is not omitted and not the JSON
1186−// "null". To check if this field is omitted, use [param.IsOmitted].
1187−func (u MessageContentPartParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() }
11881218func (u MessageContentPartParamUnion) MarshalJSON() ([]byte, error) {
1189− return param.MarshalUnion[MessageContentPartParamUnion](u.OfImageFile, u.OfImageURL, u.OfText)
1219+ return param.MarshalUnion(u, u.OfImageFile, u.OfImageURL, u.OfText)
1220+}
1221+func (u *MessageContentPartParamUnion) UnmarshalJSON(data []byte) error {
1222+ return apijson.UnmarshalRoot(data, u)
11901223}
11911224
11921225func (u *MessageContentPartParamUnion) asAny() any {
@@ -1239,21 +1272,9 @@ func (u MessageContentPartParamUnion) GetType() *string {
12391272func init() {
12401273 apijson.RegisterUnion[MessageContentPartParamUnion](
12411274 "type",
1242− apijson.UnionVariant{
1243− TypeFilter: gjson.JSON,
1244− Type: reflect.TypeOf(ImageFileContentBlockParam{}),
1245− DiscriminatorValue: "image_file",
1246− },
1247− apijson.UnionVariant{
1248− TypeFilter: gjson.JSON,
1249− Type: reflect.TypeOf(ImageURLContentBlockParam{}),
1250− DiscriminatorValue: "image_url",
1251− },
1252− apijson.UnionVariant{
1253− TypeFilter: gjson.JSON,
1254− Type: reflect.TypeOf(TextContentBlockParam{}),
1255− DiscriminatorValue: "text",
1256− },
1275+ apijson.Discriminator[ImageFileContentBlockParam]("image_file"),
1276+ apijson.Discriminator[ImageURLContentBlockParam]("image_url"),
1277+ apijson.Discriminator[TextContentBlockParam]("text"),
12571278 )
12581279}
12591280
@@ -1261,13 +1282,12 @@ type MessageDeleted struct {
12611282 ID string `json:"id,required"`
12621283 Deleted bool `json:"deleted,required"`
12631284 Object constant.ThreadMessageDeleted `json:"object,required"`
1264− // Metadata for the response, check the presence of optional fields with the
1265− // [resp.Field.IsPresent] method.
1285+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12661286 JSON struct {
1267− ID resp.Field
1268− Deleted resp.Field
1269− Object resp.Field
1270− ExtraFields map[string]resp.Field
1287+ ID respjson.Field
1288+ Deleted respjson.Field
1289+ Object respjson.Field
1290+ ExtraFields map[string]respjson.Field
12711291 raw string
12721292 } `json:"-"`
12731293}
@@ -1286,12 +1306,11 @@ type MessageDelta struct {
12861306 //
12871307 // Any of "user", "assistant".
12881308 Role MessageDeltaRole `json:"role"`
1289− // Metadata for the response, check the presence of optional fields with the
1290− // [resp.Field.IsPresent] method.
1309+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12911310 JSON struct {
1292− Content resp.Field
1293− Role resp.Field
1294− ExtraFields map[string]resp.Field
1311+ Content respjson.Field
1312+ Role respjson.Field
1313+ ExtraFields map[string]respjson.Field
12951314 raw string
12961315 } `json:"-"`
12971316}
@@ -1319,13 +1338,12 @@ type MessageDeltaEvent struct {
13191338 Delta MessageDelta `json:"delta,required"`
13201339 // The object type, which is always `thread.message.delta`.
13211340 Object constant.ThreadMessageDelta `json:"object,required"`
1322− // Metadata for the response, check the presence of optional fields with the
1323− // [resp.Field.IsPresent] method.
1341+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13241342 JSON struct {
1325− ID resp.Field
1326− Delta resp.Field
1327− Object resp.Field
1328− ExtraFields map[string]resp.Field
1343+ ID respjson.Field
1344+ Delta respjson.Field
1345+ Object respjson.Field
1346+ ExtraFields map[string]respjson.Field
13291347 raw string
13301348 } `json:"-"`
13311349}
@@ -1341,12 +1359,11 @@ type RefusalContentBlock struct {
13411359 Refusal string `json:"refusal,required"`
13421360 // Always `refusal`.
13431361 Type constant.Refusal `json:"type,required"`
1344− // Metadata for the response, check the presence of optional fields with the
1345− // [resp.Field.IsPresent] method.
1362+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13461363 JSON struct {
1347− Refusal resp.Field
1348− Type resp.Field
1349− ExtraFields map[string]resp.Field
1364+ Refusal respjson.Field
1365+ Type respjson.Field
1366+ ExtraFields map[string]respjson.Field
13501367 raw string
13511368 } `json:"-"`
13521369}
@@ -1364,13 +1381,12 @@ type RefusalDeltaBlock struct {
13641381 // Always `refusal`.
13651382 Type constant.Refusal `json:"type,required"`
13661383 Refusal string `json:"refusal"`
1367− // Metadata for the response, check the presence of optional fields with the
1368− // [resp.Field.IsPresent] method.
1384+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13691385 JSON struct {
1370− Index resp.Field
1371− Type resp.Field
1372− Refusal resp.Field
1373− ExtraFields map[string]resp.Field
1386+ Index respjson.Field
1387+ Type respjson.Field
1388+ Refusal respjson.Field
1389+ ExtraFields map[string]respjson.Field
13741390 raw string
13751391 } `json:"-"`
13761392}
@@ -1385,12 +1401,11 @@ type Text struct {
13851401 Annotations []AnnotationUnion `json:"annotations,required"`
13861402 // The data that makes up the text.
13871403 Value string `json:"value,required"`
1388− // Metadata for the response, check the presence of optional fields with the
1389− // [resp.Field.IsPresent] method.
1404+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13901405 JSON struct {
1391− Annotations resp.Field
1392− Value resp.Field
1393− ExtraFields map[string]resp.Field
1406+ Annotations respjson.Field
1407+ Value respjson.Field
1408+ ExtraFields map[string]respjson.Field
13941409 raw string
13951410 } `json:"-"`
13961411}
@@ -1406,12 +1421,11 @@ type TextContentBlock struct {
14061421 Text Text `json:"text,required"`
14071422 // Always `text`.
14081423 Type constant.Text `json:"type,required"`
1409− // Metadata for the response, check the presence of optional fields with the
1410− // [resp.Field.IsPresent] method.
1424+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
14111425 JSON struct {
1412− Text resp.Field
1413− Type resp.Field
1414− ExtraFields map[string]resp.Field
1426+ Text respjson.Field
1427+ Type respjson.Field
1428+ ExtraFields map[string]respjson.Field
14151429 raw string
14161430 } `json:"-"`
14171431}
@@ -1435,24 +1449,23 @@ type TextContentBlockParam struct {
14351449 paramObj
14361450}
14371451
1438−// IsPresent returns true if the field's value is not omitted and not the JSON
1439−// "null". To check if this field is omitted, use [param.IsOmitted].
1440−func (f TextContentBlockParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
14411452func (r TextContentBlockParam) MarshalJSON() (data []byte, err error) {
14421453 type shadow TextContentBlockParam
14431454 return param.MarshalObject(r, (*shadow)(&r))
14441455}
1456+func (r *TextContentBlockParam) UnmarshalJSON(data []byte) error {
1457+ return apijson.UnmarshalRoot(data, r)
1458+}
14451459
14461460type TextDelta struct {
14471461 Annotations []AnnotationDeltaUnion `json:"annotations"`
14481462 // The data that makes up the text.
14491463 Value string `json:"value"`
1450− // Metadata for the response, check the presence of optional fields with the
1451− // [resp.Field.IsPresent] method.
1464+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
14521465 JSON struct {
1453− Annotations resp.Field
1454− Value resp.Field
1455− ExtraFields map[string]resp.Field
1466+ Annotations respjson.Field
1467+ Value respjson.Field
1468+ ExtraFields map[string]respjson.Field
14561469 raw string
14571470 } `json:"-"`
14581471}
@@ -1470,13 +1483,12 @@ type TextDeltaBlock struct {
14701483 // Always `text`.
14711484 Type constant.Text `json:"type,required"`
14721485 Text TextDelta `json:"text"`
1473− // Metadata for the response, check the presence of optional fields with the
1474− // [resp.Field.IsPresent] method.
1486+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
14751487 JSON struct {
1476− Index resp.Field
1477− Type resp.Field
1478− Text resp.Field
1479− ExtraFields map[string]resp.Field
1488+ Index respjson.Field
1489+ Type respjson.Field
1490+ Text respjson.Field
1491+ ExtraFields map[string]respjson.Field
14801492 raw string
14811493 } `json:"-"`
14821494}
@@ -1507,18 +1519,17 @@ type BetaThreadMessageNewParams struct {
15071519 //
15081520 // Keys are strings with a maximum length of 64 characters. Values are strings with
15091521 // a maximum length of 512 characters.
1510− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1522+ Metadata shared.Metadata `json:"metadata,omitzero"`
15111523 paramObj
15121524}
15131525
1514−// IsPresent returns true if the field's value is not omitted and not the JSON
1515−// "null". To check if this field is omitted, use [param.IsOmitted].
1516−func (f BetaThreadMessageNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
1517−
15181526func (r BetaThreadMessageNewParams) MarshalJSON() (data []byte, err error) {
15191527 type shadow BetaThreadMessageNewParams
15201528 return param.MarshalObject(r, (*shadow)(&r))
15211529}
1530+func (r *BetaThreadMessageNewParams) UnmarshalJSON(data []byte) error {
1531+ return apijson.UnmarshalRoot(data, r)
1532+}
15221533
15231534// Only one field can be non-zero.
15241535//
@@ -1529,13 +1540,11 @@ type BetaThreadMessageNewParamsContentUnion struct {
15291540 paramUnion
15301541}
15311542
1532−// IsPresent returns true if the field's value is not omitted and not the JSON
1533−// "null". To check if this field is omitted, use [param.IsOmitted].
1534−func (u BetaThreadMessageNewParamsContentUnion) IsPresent() bool {
1535− return !param.IsOmitted(u) && !u.IsNull()
1536−}
15371543func (u BetaThreadMessageNewParamsContentUnion) MarshalJSON() ([]byte, error) {
1538− return param.MarshalUnion[BetaThreadMessageNewParamsContentUnion](u.OfString, u.OfArrayOfContentParts)
1544+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
1545+}
1546+func (u *BetaThreadMessageNewParamsContentUnion) UnmarshalJSON(data []byte) error {
1547+ return apijson.UnmarshalRoot(data, u)
15391548}
15401549
15411550func (u *BetaThreadMessageNewParamsContentUnion) asAny() any {
@@ -1568,15 +1577,13 @@ type BetaThreadMessageNewParamsAttachment struct {
15681577 paramObj
15691578}
15701579
1571−// IsPresent returns true if the field's value is not omitted and not the JSON
1572−// "null". To check if this field is omitted, use [param.IsOmitted].
1573−func (f BetaThreadMessageNewParamsAttachment) IsPresent() bool {
1574− return !param.IsOmitted(f) && !f.IsNull()
1575−}
15761580func (r BetaThreadMessageNewParamsAttachment) MarshalJSON() (data []byte, err error) {
15771581 type shadow BetaThreadMessageNewParamsAttachment
15781582 return param.MarshalObject(r, (*shadow)(&r))
15791583}
1584+func (r *BetaThreadMessageNewParamsAttachment) UnmarshalJSON(data []byte) error {
1585+ return apijson.UnmarshalRoot(data, r)
1586+}
15801587
15811588// Only one field can be non-zero.
15821589//
@@ -1587,13 +1594,11 @@ type BetaThreadMessageNewParamsAttachmentToolUnion struct {
15871594 paramUnion
15881595}
15891596
1590−// IsPresent returns true if the field's value is not omitted and not the JSON
1591−// "null". To check if this field is omitted, use [param.IsOmitted].
1592−func (u BetaThreadMessageNewParamsAttachmentToolUnion) IsPresent() bool {
1593− return !param.IsOmitted(u) && !u.IsNull()
1594−}
15951597func (u BetaThreadMessageNewParamsAttachmentToolUnion) MarshalJSON() ([]byte, error) {
1596− return param.MarshalUnion[BetaThreadMessageNewParamsAttachmentToolUnion](u.OfCodeInterpreter, u.OfFileSearch)
1598+ return param.MarshalUnion(u, u.OfCodeInterpreter, u.OfFileSearch)
1599+}
1600+func (u *BetaThreadMessageNewParamsAttachmentToolUnion) UnmarshalJSON(data []byte) error {
1601+ return apijson.UnmarshalRoot(data, u)
15971602}
15981603
15991604func (u *BetaThreadMessageNewParamsAttachmentToolUnion) asAny() any {
@@ -1618,37 +1623,32 @@ func (u BetaThreadMessageNewParamsAttachmentToolUnion) GetType() *string {
16181623func init() {
16191624 apijson.RegisterUnion[BetaThreadMessageNewParamsAttachmentToolUnion](
16201625 "type",
1621− apijson.UnionVariant{
1622− TypeFilter: gjson.JSON,
1623− Type: reflect.TypeOf(CodeInterpreterToolParam{}),
1624− DiscriminatorValue: "code_interpreter",
1625− },
1626− apijson.UnionVariant{
1627− TypeFilter: gjson.JSON,
1628− Type: reflect.TypeOf(BetaThreadMessageNewParamsAttachmentToolFileSearch{}),
1629− DiscriminatorValue: "file_search",
1630− },
1626+ apijson.Discriminator[CodeInterpreterToolParam]("code_interpreter"),
1627+ apijson.Discriminator[BetaThreadMessageNewParamsAttachmentToolFileSearch]("file_search"),
16311628 )
16321629}
16331630
1634−// The property Type is required.
1631+func NewBetaThreadMessageNewParamsAttachmentToolFileSearch() BetaThreadMessageNewParamsAttachmentToolFileSearch {
1632+ return BetaThreadMessageNewParamsAttachmentToolFileSearch{
1633+ Type: "file_search",
1634+ }
1635+}
1636+
1637+// This struct has a constant value, construct it with
1638+// [NewBetaThreadMessageNewParamsAttachmentToolFileSearch].
16351639type BetaThreadMessageNewParamsAttachmentToolFileSearch struct {
16361640 // The type of tool being defined: `file_search`
1637− //
1638− // This field can be elided, and will marshal its zero value as "file_search".
16391641 Type constant.FileSearch `json:"type,required"`
16401642 paramObj
16411643}
16421644
1643−// IsPresent returns true if the field's value is not omitted and not the JSON
1644−// "null". To check if this field is omitted, use [param.IsOmitted].
1645−func (f BetaThreadMessageNewParamsAttachmentToolFileSearch) IsPresent() bool {
1646− return !param.IsOmitted(f) && !f.IsNull()
1647−}
16481645func (r BetaThreadMessageNewParamsAttachmentToolFileSearch) MarshalJSON() (data []byte, err error) {
16491646 type shadow BetaThreadMessageNewParamsAttachmentToolFileSearch
16501647 return param.MarshalObject(r, (*shadow)(&r))
16511648}
1649+func (r *BetaThreadMessageNewParamsAttachmentToolFileSearch) UnmarshalJSON(data []byte) error {
1650+ return apijson.UnmarshalRoot(data, r)
1651+}
16521652
16531653type BetaThreadMessageUpdateParams struct {
16541654 // Set of 16 key-value pairs that can be attached to an object. This can be useful
@@ -1657,18 +1657,17 @@ type BetaThreadMessageUpdateParams struct {
16571657 //
16581658 // Keys are strings with a maximum length of 64 characters. Values are strings with
16591659 // a maximum length of 512 characters.
1660− Metadata shared.MetadataParam `json:"metadata,omitzero"`
1660+ Metadata shared.Metadata `json:"metadata,omitzero"`
16611661 paramObj
16621662}
16631663
1664−// IsPresent returns true if the field's value is not omitted and not the JSON
1665−// "null". To check if this field is omitted, use [param.IsOmitted].
1666−func (f BetaThreadMessageUpdateParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
1667−
16681664func (r BetaThreadMessageUpdateParams) MarshalJSON() (data []byte, err error) {
16691665 type shadow BetaThreadMessageUpdateParams
16701666 return param.MarshalObject(r, (*shadow)(&r))
16711667}
1668+func (r *BetaThreadMessageUpdateParams) UnmarshalJSON(data []byte) error {
1669+ return apijson.UnmarshalRoot(data, r)
1670+}
16721671
16731672type BetaThreadMessageListParams struct {
16741673 // A cursor for use in pagination. `after` is an object ID that defines your place
@@ -1694,13 +1693,9 @@ type BetaThreadMessageListParams struct {
16941693 paramObj
16951694}
16961695
1697−// IsPresent returns true if the field's value is not omitted and not the JSON
1698−// "null". To check if this field is omitted, use [param.IsOmitted].
1699−func (f BetaThreadMessageListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
1700−
17011696// URLQuery serializes [BetaThreadMessageListParams]'s query parameters as
17021697// `url.Values`.
1703−func (r BetaThreadMessageListParams) URLQuery() (v url.Values) {
1698+func (r BetaThreadMessageListParams) URLQuery() (v url.Values, err error) {
17041699 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
17051700 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
17061701 NestedFormat: apiquery.NestedQueryFormatBrackets,
vendor/github.com/openai/openai-go/betathreadrun.go+133−171
@@ -8,7 +8,6 @@ import (
88 "fmt"
99 "net/http"
1010 "net/url"
11− "reflect"
1211
1312 "github.com/openai/openai-go/internal/apijson"
1413 "github.com/openai/openai-go/internal/apiquery"
@@ -16,11 +15,10 @@ import (
1615 "github.com/openai/openai-go/option"
1716 "github.com/openai/openai-go/packages/pagination"
1817 "github.com/openai/openai-go/packages/param"
19− "github.com/openai/openai-go/packages/resp"
18+ "github.com/openai/openai-go/packages/respjson"
2019 "github.com/openai/openai-go/packages/ssestream"
2120 "github.com/openai/openai-go/shared"
2221 "github.com/openai/openai-go/shared/constant"
23− "github.com/tidwall/gjson"
2422)
2523
2624// BetaThreadRunService contains methods and other services that help with
@@ -29,9 +27,12 @@ import (
2927// Note, unlike clients, this service does not read variables from the environment
3028// automatically. You should not instantiate this service directly, and instead use
3129// the [NewBetaThreadRunService] method instead.
30+//
31+// Deprecated: The Assistants API is deprecated in favor of the Responses API
3232type BetaThreadRunService struct {
3333 Options []option.RequestOption
34− Steps BetaThreadRunStepService
34+ // Deprecated: The Assistants API is deprecated in favor of the Responses API
35+ Steps BetaThreadRunStepService
3536}
3637
3738// NewBetaThreadRunService generates a new service that applies the given options
@@ -45,6 +46,8 @@ func NewBetaThreadRunService(opts ...option.RequestOption) (r BetaThreadRunServi
4546}
4647
4748// Create a run.
49+//
50+// Deprecated: The Assistants API is deprecated in favor of the Responses API
4851func (r *BetaThreadRunService) New(ctx context.Context, threadID string, params BetaThreadRunNewParams, opts ...option.RequestOption) (res *Run, err error) {
4952 opts = append(r.Options[:], opts...)
5053 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -57,17 +60,9 @@ func (r *BetaThreadRunService) New(ctx context.Context, threadID string, params
5760 return
5861}
5962
60−// Create a run and poll until task is completed.
61−// Pass 0 to pollIntervalMs to use the default polling interval.
62−func (r *BetaThreadRunService) NewAndPoll(ctx context.Context, threadID string, params BetaThreadRunNewParams, pollIntervalMs int, opts ...option.RequestOption) (res *Run, err error) {
63− run, err := r.New(ctx, threadID, params, opts...)
64− if err != nil {
65− return nil, err
66− }
67− return r.PollStatus(ctx, threadID, run.ID, pollIntervalMs, opts...)
68−}
69−
7063// Create a run.
64+//
65+// Deprecated: The Assistants API is deprecated in favor of the Responses API
7166func (r *BetaThreadRunService) NewStreaming(ctx context.Context, threadID string, params BetaThreadRunNewParams, opts ...option.RequestOption) (stream *ssestream.Stream[AssistantStreamEventUnion]) {
7267 var (
7368 raw *http.Response
@@ -85,6 +80,8 @@ func (r *BetaThreadRunService) NewStreaming(ctx context.Context, threadID string
8580}
8681
8782// Retrieves a run.
83+//
84+// Deprecated: The Assistants API is deprecated in favor of the Responses API
8885func (r *BetaThreadRunService) Get(ctx context.Context, threadID string, runID string, opts ...option.RequestOption) (res *Run, err error) {
8986 opts = append(r.Options[:], opts...)
9087 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -102,6 +99,8 @@ func (r *BetaThreadRunService) Get(ctx context.Context, threadID string, runID s
10299}
103100
104101// Modifies a run.
102+//
103+// Deprecated: The Assistants API is deprecated in favor of the Responses API
105104func (r *BetaThreadRunService) Update(ctx context.Context, threadID string, runID string, body BetaThreadRunUpdateParams, opts ...option.RequestOption) (res *Run, err error) {
106105 opts = append(r.Options[:], opts...)
107106 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -119,6 +118,8 @@ func (r *BetaThreadRunService) Update(ctx context.Context, threadID string, runI
119118}
120119
121120// Returns a list of runs belonging to a thread.
121+//
122+// Deprecated: The Assistants API is deprecated in favor of the Responses API
122123func (r *BetaThreadRunService) List(ctx context.Context, threadID string, query BetaThreadRunListParams, opts ...option.RequestOption) (res *pagination.CursorPage[Run], err error) {
123124 var raw *http.Response
124125 opts = append(r.Options[:], opts...)
@@ -141,11 +142,15 @@ func (r *BetaThreadRunService) List(ctx context.Context, threadID string, query
141142}
142143
143144// Returns a list of runs belonging to a thread.
145+//
146+// Deprecated: The Assistants API is deprecated in favor of the Responses API
144147func (r *BetaThreadRunService) ListAutoPaging(ctx context.Context, threadID string, query BetaThreadRunListParams, opts ...option.RequestOption) *pagination.CursorPageAutoPager[Run] {
145148 return pagination.NewCursorPageAutoPager(r.List(ctx, threadID, query, opts...))
146149}
147150
148151// Cancels a run that is `in_progress`.
152+//
153+// Deprecated: The Assistants API is deprecated in favor of the Responses API
149154func (r *BetaThreadRunService) Cancel(ctx context.Context, threadID string, runID string, opts ...option.RequestOption) (res *Run, err error) {
150155 opts = append(r.Options[:], opts...)
151156 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -166,6 +171,8 @@ func (r *BetaThreadRunService) Cancel(ctx context.Context, threadID string, runI
166171// `submit_tool_outputs`, this endpoint can be used to submit the outputs from the
167172// tool calls once they're all completed. All outputs must be submitted in a single
168173// request.
174+//
175+// Deprecated: The Assistants API is deprecated in favor of the Responses API
169176func (r *BetaThreadRunService) SubmitToolOutputs(ctx context.Context, threadID string, runID string, body BetaThreadRunSubmitToolOutputsParams, opts ...option.RequestOption) (res *Run, err error) {
170177 opts = append(r.Options[:], opts...)
171178 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -182,22 +189,12 @@ func (r *BetaThreadRunService) SubmitToolOutputs(ctx context.Context, threadID s
182189 return
183190}
184191
185−// A helper to submit a tool output to a run and poll for a terminal run state.
186−// Pass 0 to pollIntervalMs to use the default polling interval.
187−// More information on Run lifecycles can be found here:
188−// https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps
189−func (r *BetaThreadRunService) SubmitToolOutputsAndPoll(ctx context.Context, threadID string, runID string, body BetaThreadRunSubmitToolOutputsParams, pollIntervalMs int, opts ...option.RequestOption) (*Run, error) {
190− run, err := r.SubmitToolOutputs(ctx, threadID, runID, body, opts...)
191− if err != nil {
192− return nil, err
193− }
194− return r.PollStatus(ctx, threadID, run.ID, pollIntervalMs, opts...)
195−}
196−
197192// When a run has the `status: "requires_action"` and `required_action.type` is
198193// `submit_tool_outputs`, this endpoint can be used to submit the outputs from the
199194// tool calls once they're all completed. All outputs must be submitted in a single
200195// request.
196+//
197+// Deprecated: The Assistants API is deprecated in favor of the Responses API
201198func (r *BetaThreadRunService) SubmitToolOutputsStreaming(ctx context.Context, threadID string, runID string, body BetaThreadRunSubmitToolOutputsParams, opts ...option.RequestOption) (stream *ssestream.Stream[AssistantStreamEventUnion]) {
202199 var (
203200 raw *http.Response
@@ -230,13 +227,12 @@ type RequiredActionFunctionToolCall struct {
230227 // The type of tool call the output is required for. For now, this is always
231228 // `function`.
232229 Type constant.Function `json:"type,required"`
233− // Metadata for the response, check the presence of optional fields with the
234− // [resp.Field.IsPresent] method.
230+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
235231 JSON struct {
236− ID resp.Field
237− Function resp.Field
238− Type resp.Field
239− ExtraFields map[string]resp.Field
232+ ID respjson.Field
233+ Function respjson.Field
234+ Type respjson.Field
235+ ExtraFields map[string]respjson.Field
240236 raw string
241237 } `json:"-"`
242238}
@@ -253,12 +249,11 @@ type RequiredActionFunctionToolCallFunction struct {
253249 Arguments string `json:"arguments,required"`
254250 // The name of the function.
255251 Name string `json:"name,required"`
256− // Metadata for the response, check the presence of optional fields with the
257− // [resp.Field.IsPresent] method.
252+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
258253 JSON struct {
259− Arguments resp.Field
260− Name resp.Field
261− ExtraFields map[string]resp.Field
254+ Arguments respjson.Field
255+ Name respjson.Field
256+ ExtraFields map[string]respjson.Field
262257 raw string
263258 } `json:"-"`
264259}
@@ -378,37 +373,36 @@ type Run struct {
378373 Temperature float64 `json:"temperature,nullable"`
379374 // The nucleus sampling value used for this run. If not set, defaults to 1.
380375 TopP float64 `json:"top_p,nullable"`
381− // Metadata for the response, check the presence of optional fields with the
382− // [resp.Field.IsPresent] method.
376+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
383377 JSON struct {
384− ID resp.Field
385− AssistantID resp.Field
386− CancelledAt resp.Field
387− CompletedAt resp.Field
388− CreatedAt resp.Field
389− ExpiresAt resp.Field
390− FailedAt resp.Field
391− IncompleteDetails resp.Field
392− Instructions resp.Field
393− LastError resp.Field
394− MaxCompletionTokens resp.Field
395− MaxPromptTokens resp.Field
396− Metadata resp.Field
397− Model resp.Field
398− Object resp.Field
399− ParallelToolCalls resp.Field
400− RequiredAction resp.Field
401− ResponseFormat resp.Field
402− StartedAt resp.Field
403− Status resp.Field
404− ThreadID resp.Field
405− ToolChoice resp.Field
406− Tools resp.Field
407− TruncationStrategy resp.Field
408− Usage resp.Field
409− Temperature resp.Field
410− TopP resp.Field
411− ExtraFields map[string]resp.Field
378+ ID respjson.Field
379+ AssistantID respjson.Field
380+ CancelledAt respjson.Field
381+ CompletedAt respjson.Field
382+ CreatedAt respjson.Field
383+ ExpiresAt respjson.Field
384+ FailedAt respjson.Field
385+ IncompleteDetails respjson.Field
386+ Instructions respjson.Field
387+ LastError respjson.Field
388+ MaxCompletionTokens respjson.Field
389+ MaxPromptTokens respjson.Field
390+ Metadata respjson.Field
391+ Model respjson.Field
392+ Object respjson.Field
393+ ParallelToolCalls respjson.Field
394+ RequiredAction respjson.Field
395+ ResponseFormat respjson.Field
396+ StartedAt respjson.Field
397+ Status respjson.Field
398+ ThreadID respjson.Field
399+ ToolChoice respjson.Field
400+ Tools respjson.Field
401+ TruncationStrategy respjson.Field
402+ Usage respjson.Field
403+ Temperature respjson.Field
404+ TopP respjson.Field
405+ ExtraFields map[string]respjson.Field
412406 raw string
413407 } `json:"-"`
414408}
@@ -427,11 +421,10 @@ type RunIncompleteDetails struct {
427421 //
428422 // Any of "max_completion_tokens", "max_prompt_tokens".
429423 Reason string `json:"reason"`
430− // Metadata for the response, check the presence of optional fields with the
431− // [resp.Field.IsPresent] method.
424+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
432425 JSON struct {
433− Reason resp.Field
434− ExtraFields map[string]resp.Field
426+ Reason respjson.Field
427+ ExtraFields map[string]respjson.Field
435428 raw string
436429 } `json:"-"`
437430}
@@ -450,12 +443,11 @@ type RunLastError struct {
450443 Code string `json:"code,required"`
451444 // A human-readable description of the error.
452445 Message string `json:"message,required"`
453− // Metadata for the response, check the presence of optional fields with the
454− // [resp.Field.IsPresent] method.
446+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
455447 JSON struct {
456− Code resp.Field
457− Message resp.Field
458− ExtraFields map[string]resp.Field
448+ Code respjson.Field
449+ Message respjson.Field
450+ ExtraFields map[string]respjson.Field
459451 raw string
460452 } `json:"-"`
461453}
@@ -473,12 +465,11 @@ type RunRequiredAction struct {
473465 SubmitToolOutputs RunRequiredActionSubmitToolOutputs `json:"submit_tool_outputs,required"`
474466 // For now, this is always `submit_tool_outputs`.
475467 Type constant.SubmitToolOutputs `json:"type,required"`
476− // Metadata for the response, check the presence of optional fields with the
477− // [resp.Field.IsPresent] method.
468+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
478469 JSON struct {
479− SubmitToolOutputs resp.Field
480− Type resp.Field
481− ExtraFields map[string]resp.Field
470+ SubmitToolOutputs respjson.Field
471+ Type respjson.Field
472+ ExtraFields map[string]respjson.Field
482473 raw string
483474 } `json:"-"`
484475}
@@ -493,11 +484,10 @@ func (r *RunRequiredAction) UnmarshalJSON(data []byte) error {
493484type RunRequiredActionSubmitToolOutputs struct {
494485 // A list of the relevant tool calls.
495486 ToolCalls []RequiredActionFunctionToolCall `json:"tool_calls,required"`
496− // Metadata for the response, check the presence of optional fields with the
497− // [resp.Field.IsPresent] method.
487+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
498488 JSON struct {
499− ToolCalls resp.Field
500− ExtraFields map[string]resp.Field
489+ ToolCalls respjson.Field
490+ ExtraFields map[string]respjson.Field
501491 raw string
502492 } `json:"-"`
503493}
@@ -521,12 +511,11 @@ type RunTruncationStrategy struct {
521511 // The number of most recent messages from the thread when constructing the context
522512 // for the run.
523513 LastMessages int64 `json:"last_messages,nullable"`
524− // Metadata for the response, check the presence of optional fields with the
525− // [resp.Field.IsPresent] method.
514+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
526515 JSON struct {
527− Type resp.Field
528− LastMessages resp.Field
529− ExtraFields map[string]resp.Field
516+ Type respjson.Field
517+ LastMessages respjson.Field
518+ ExtraFields map[string]respjson.Field
530519 raw string
531520 } `json:"-"`
532521}
@@ -546,13 +535,12 @@ type RunUsage struct {
546535 PromptTokens int64 `json:"prompt_tokens,required"`
547536 // Total number of tokens used (prompt + completion).
548537 TotalTokens int64 `json:"total_tokens,required"`
549− // Metadata for the response, check the presence of optional fields with the
550− // [resp.Field.IsPresent] method.
538+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
551539 JSON struct {
552− CompletionTokens resp.Field
553− PromptTokens resp.Field
554− TotalTokens resp.Field
555− ExtraFields map[string]resp.Field
540+ CompletionTokens respjson.Field
541+ PromptTokens respjson.Field
542+ TotalTokens respjson.Field
543+ ExtraFields map[string]respjson.Field
556544 raw string
557545 } `json:"-"`
558546}
@@ -627,7 +615,7 @@ type BetaThreadRunNewParams struct {
627615 //
628616 // Keys are strings with a maximum length of 64 characters. Values are strings with
629617 // a maximum length of 512 characters.
630− Metadata shared.MetadataParam `json:"metadata,omitzero"`
618+ Metadata shared.Metadata `json:"metadata,omitzero"`
631619 // The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to
632620 // be used to execute this run. If a value is provided here, it will override the
633621 // model associated with the assistant. If not, the model associated with the
@@ -688,17 +676,16 @@ type BetaThreadRunNewParams struct {
688676 paramObj
689677}
690678
691−// IsPresent returns true if the field's value is not omitted and not the JSON
692−// "null". To check if this field is omitted, use [param.IsOmitted].
693−func (f BetaThreadRunNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
694−
695679func (r BetaThreadRunNewParams) MarshalJSON() (data []byte, err error) {
696680 type shadow BetaThreadRunNewParams
697681 return param.MarshalObject(r, (*shadow)(&r))
698682}
683+func (r *BetaThreadRunNewParams) UnmarshalJSON(data []byte) error {
684+ return apijson.UnmarshalRoot(data, r)
685+}
699686
700687// URLQuery serializes [BetaThreadRunNewParams]'s query parameters as `url.Values`.
701−func (r BetaThreadRunNewParams) URLQuery() (v url.Values) {
688+func (r BetaThreadRunNewParams) URLQuery() (v url.Values, err error) {
702689 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
703690 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
704691 NestedFormat: apiquery.NestedQueryFormatBrackets,
@@ -726,23 +713,21 @@ type BetaThreadRunNewParamsAdditionalMessage struct {
726713 //
727714 // Keys are strings with a maximum length of 64 characters. Values are strings with
728715 // a maximum length of 512 characters.
729− Metadata shared.MetadataParam `json:"metadata,omitzero"`
716+ Metadata shared.Metadata `json:"metadata,omitzero"`
730717 paramObj
731718}
732719
733−// IsPresent returns true if the field's value is not omitted and not the JSON
734−// "null". To check if this field is omitted, use [param.IsOmitted].
735−func (f BetaThreadRunNewParamsAdditionalMessage) IsPresent() bool {
736− return !param.IsOmitted(f) && !f.IsNull()
737−}
738720func (r BetaThreadRunNewParamsAdditionalMessage) MarshalJSON() (data []byte, err error) {
739721 type shadow BetaThreadRunNewParamsAdditionalMessage
740722 return param.MarshalObject(r, (*shadow)(&r))
741723}
724+func (r *BetaThreadRunNewParamsAdditionalMessage) UnmarshalJSON(data []byte) error {
725+ return apijson.UnmarshalRoot(data, r)
726+}
742727
743728func init() {
744729 apijson.RegisterFieldValidator[BetaThreadRunNewParamsAdditionalMessage](
745− "Role", false, "user", "assistant",
730+ "role", "user", "assistant",
746731 )
747732}
748733
@@ -755,13 +740,11 @@ type BetaThreadRunNewParamsAdditionalMessageContentUnion struct {
755740 paramUnion
756741}
757742
758−// IsPresent returns true if the field's value is not omitted and not the JSON
759−// "null". To check if this field is omitted, use [param.IsOmitted].
760−func (u BetaThreadRunNewParamsAdditionalMessageContentUnion) IsPresent() bool {
761− return !param.IsOmitted(u) && !u.IsNull()
762−}
763743func (u BetaThreadRunNewParamsAdditionalMessageContentUnion) MarshalJSON() ([]byte, error) {
764− return param.MarshalUnion[BetaThreadRunNewParamsAdditionalMessageContentUnion](u.OfString, u.OfArrayOfContentParts)
744+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
745+}
746+func (u *BetaThreadRunNewParamsAdditionalMessageContentUnion) UnmarshalJSON(data []byte) error {
747+ return apijson.UnmarshalRoot(data, u)
765748}
766749
767750func (u *BetaThreadRunNewParamsAdditionalMessageContentUnion) asAny() any {
@@ -781,15 +764,13 @@ type BetaThreadRunNewParamsAdditionalMessageAttachment struct {
781764 paramObj
782765}
783766
784−// IsPresent returns true if the field's value is not omitted and not the JSON
785−// "null". To check if this field is omitted, use [param.IsOmitted].
786−func (f BetaThreadRunNewParamsAdditionalMessageAttachment) IsPresent() bool {
787− return !param.IsOmitted(f) && !f.IsNull()
788−}
789767func (r BetaThreadRunNewParamsAdditionalMessageAttachment) MarshalJSON() (data []byte, err error) {
790768 type shadow BetaThreadRunNewParamsAdditionalMessageAttachment
791769 return param.MarshalObject(r, (*shadow)(&r))
792770}
771+func (r *BetaThreadRunNewParamsAdditionalMessageAttachment) UnmarshalJSON(data []byte) error {
772+ return apijson.UnmarshalRoot(data, r)
773+}
793774
794775// Only one field can be non-zero.
795776//
@@ -800,13 +781,11 @@ type BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion struct {
800781 paramUnion
801782}
802783
803−// IsPresent returns true if the field's value is not omitted and not the JSON
804−// "null". To check if this field is omitted, use [param.IsOmitted].
805−func (u BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion) IsPresent() bool {
806− return !param.IsOmitted(u) && !u.IsNull()
807−}
808784func (u BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion) MarshalJSON() ([]byte, error) {
809− return param.MarshalUnion[BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion](u.OfCodeInterpreter, u.OfFileSearch)
785+ return param.MarshalUnion(u, u.OfCodeInterpreter, u.OfFileSearch)
786+}
787+func (u *BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion) UnmarshalJSON(data []byte) error {
788+ return apijson.UnmarshalRoot(data, u)
810789}
811790
812791func (u *BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion) asAny() any {
@@ -831,37 +810,32 @@ func (u BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion) GetType() *s
831810func init() {
832811 apijson.RegisterUnion[BetaThreadRunNewParamsAdditionalMessageAttachmentToolUnion](
833812 "type",
834− apijson.UnionVariant{
835− TypeFilter: gjson.JSON,
836− Type: reflect.TypeOf(CodeInterpreterToolParam{}),
837− DiscriminatorValue: "code_interpreter",
838− },
839− apijson.UnionVariant{
840− TypeFilter: gjson.JSON,
841− Type: reflect.TypeOf(BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch{}),
842− DiscriminatorValue: "file_search",
843− },
813+ apijson.Discriminator[CodeInterpreterToolParam]("code_interpreter"),
814+ apijson.Discriminator[BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch]("file_search"),
844815 )
845816}
846817
847−// The property Type is required.
818+func NewBetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch() BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch {
819+ return BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch{
820+ Type: "file_search",
821+ }
822+}
823+
824+// This struct has a constant value, construct it with
825+// [NewBetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch].
848826type BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch struct {
849827 // The type of tool being defined: `file_search`
850− //
851− // This field can be elided, and will marshal its zero value as "file_search".
852828 Type constant.FileSearch `json:"type,required"`
853829 paramObj
854830}
855831
856−// IsPresent returns true if the field's value is not omitted and not the JSON
857−// "null". To check if this field is omitted, use [param.IsOmitted].
858−func (f BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch) IsPresent() bool {
859− return !param.IsOmitted(f) && !f.IsNull()
860−}
861832func (r BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch) MarshalJSON() (data []byte, err error) {
862833 type shadow BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch
863834 return param.MarshalObject(r, (*shadow)(&r))
864835}
836+func (r *BetaThreadRunNewParamsAdditionalMessageAttachmentToolFileSearch) UnmarshalJSON(data []byte) error {
837+ return apijson.UnmarshalRoot(data, r)
838+}
865839
866840// Controls for how a thread will be truncated prior to the run. Use this to
867841// control the intial context window of the run.
@@ -881,19 +855,17 @@ type BetaThreadRunNewParamsTruncationStrategy struct {
881855 paramObj
882856}
883857
884−// IsPresent returns true if the field's value is not omitted and not the JSON
885−// "null". To check if this field is omitted, use [param.IsOmitted].
886−func (f BetaThreadRunNewParamsTruncationStrategy) IsPresent() bool {
887− return !param.IsOmitted(f) && !f.IsNull()
888−}
889858func (r BetaThreadRunNewParamsTruncationStrategy) MarshalJSON() (data []byte, err error) {
890859 type shadow BetaThreadRunNewParamsTruncationStrategy
891860 return param.MarshalObject(r, (*shadow)(&r))
892861}
862+func (r *BetaThreadRunNewParamsTruncationStrategy) UnmarshalJSON(data []byte) error {
863+ return apijson.UnmarshalRoot(data, r)
864+}
893865
894866func init() {
895867 apijson.RegisterFieldValidator[BetaThreadRunNewParamsTruncationStrategy](
896− "Type", false, "auto", "last_messages",
868+ "type", "auto", "last_messages",
897869 )
898870}
899871
@@ -904,18 +876,17 @@ type BetaThreadRunUpdateParams struct {
904876 //
905877 // Keys are strings with a maximum length of 64 characters. Values are strings with
906878 // a maximum length of 512 characters.
907− Metadata shared.MetadataParam `json:"metadata,omitzero"`
879+ Metadata shared.Metadata `json:"metadata,omitzero"`
908880 paramObj
909881}
910882
911−// IsPresent returns true if the field's value is not omitted and not the JSON
912−// "null". To check if this field is omitted, use [param.IsOmitted].
913−func (f BetaThreadRunUpdateParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
914−
915883func (r BetaThreadRunUpdateParams) MarshalJSON() (data []byte, err error) {
916884 type shadow BetaThreadRunUpdateParams
917885 return param.MarshalObject(r, (*shadow)(&r))
918886}
887+func (r *BetaThreadRunUpdateParams) UnmarshalJSON(data []byte) error {
888+ return apijson.UnmarshalRoot(data, r)
889+}
919890
920891type BetaThreadRunListParams struct {
921892 // A cursor for use in pagination. `after` is an object ID that defines your place
@@ -939,13 +910,9 @@ type BetaThreadRunListParams struct {
939910 paramObj
940911}
941912
942−// IsPresent returns true if the field's value is not omitted and not the JSON
943−// "null". To check if this field is omitted, use [param.IsOmitted].
944−func (f BetaThreadRunListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
945−
946913// URLQuery serializes [BetaThreadRunListParams]'s query parameters as
947914// `url.Values`.
948−func (r BetaThreadRunListParams) URLQuery() (v url.Values) {
915+func (r BetaThreadRunListParams) URLQuery() (v url.Values, err error) {
949916 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
950917 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
951918 NestedFormat: apiquery.NestedQueryFormatBrackets,
@@ -967,16 +934,13 @@ type BetaThreadRunSubmitToolOutputsParams struct {
967934 paramObj
968935}
969936
970−// IsPresent returns true if the field's value is not omitted and not the JSON
971−// "null". To check if this field is omitted, use [param.IsOmitted].
972−func (f BetaThreadRunSubmitToolOutputsParams) IsPresent() bool {
973− return !param.IsOmitted(f) && !f.IsNull()
974−}
975−
976937func (r BetaThreadRunSubmitToolOutputsParams) MarshalJSON() (data []byte, err error) {
977938 type shadow BetaThreadRunSubmitToolOutputsParams
978939 return param.MarshalObject(r, (*shadow)(&r))
979940}
941+func (r *BetaThreadRunSubmitToolOutputsParams) UnmarshalJSON(data []byte) error {
942+ return apijson.UnmarshalRoot(data, r)
943+}
980944
981945type BetaThreadRunSubmitToolOutputsParamsToolOutput struct {
982946 // The output of the tool call to be submitted to continue the run.
@@ -987,12 +951,10 @@ type BetaThreadRunSubmitToolOutputsParamsToolOutput struct {
987951 paramObj
988952}
989953
990−// IsPresent returns true if the field's value is not omitted and not the JSON
991−// "null". To check if this field is omitted, use [param.IsOmitted].
992−func (f BetaThreadRunSubmitToolOutputsParamsToolOutput) IsPresent() bool {
993− return !param.IsOmitted(f) && !f.IsNull()
994−}
995954func (r BetaThreadRunSubmitToolOutputsParamsToolOutput) MarshalJSON() (data []byte, err error) {
996955 type shadow BetaThreadRunSubmitToolOutputsParamsToolOutput
997956 return param.MarshalObject(r, (*shadow)(&r))
998957}
958+func (r *BetaThreadRunSubmitToolOutputsParamsToolOutput) UnmarshalJSON(data []byte) error {
959+ return apijson.UnmarshalRoot(data, r)
960+}
vendor/github.com/openai/openai-go/betathreadrunstep.go+270−238
@@ -16,7 +16,7 @@ import (
1616 "github.com/openai/openai-go/option"
1717 "github.com/openai/openai-go/packages/pagination"
1818 "github.com/openai/openai-go/packages/param"
19− "github.com/openai/openai-go/packages/resp"
19+ "github.com/openai/openai-go/packages/respjson"
2020 "github.com/openai/openai-go/shared"
2121 "github.com/openai/openai-go/shared/constant"
2222)
@@ -27,6 +27,8 @@ import (
2727// Note, unlike clients, this service does not read variables from the environment
2828// automatically. You should not instantiate this service directly, and instead use
2929// the [NewBetaThreadRunStepService] method instead.
30+//
31+// Deprecated: The Assistants API is deprecated in favor of the Responses API
3032type BetaThreadRunStepService struct {
3133 Options []option.RequestOption
3234}
@@ -41,6 +43,8 @@ func NewBetaThreadRunStepService(opts ...option.RequestOption) (r BetaThreadRunS
4143}
4244
4345// Retrieves a run step.
46+//
47+// Deprecated: The Assistants API is deprecated in favor of the Responses API
4448func (r *BetaThreadRunStepService) Get(ctx context.Context, threadID string, runID string, stepID string, query BetaThreadRunStepGetParams, opts ...option.RequestOption) (res *RunStep, err error) {
4549 opts = append(r.Options[:], opts...)
4650 opts = append([]option.RequestOption{option.WithHeader("OpenAI-Beta", "assistants=v2")}, opts...)
@@ -62,6 +66,8 @@ func (r *BetaThreadRunStepService) Get(ctx context.Context, threadID string, run
6266}
6367
6468// Returns a list of run steps belonging to a run.
69+//
70+// Deprecated: The Assistants API is deprecated in favor of the Responses API
6571func (r *BetaThreadRunStepService) List(ctx context.Context, threadID string, runID string, query BetaThreadRunStepListParams, opts ...option.RequestOption) (res *pagination.CursorPage[RunStep], err error) {
6672 var raw *http.Response
6773 opts = append(r.Options[:], opts...)
@@ -88,6 +94,8 @@ func (r *BetaThreadRunStepService) List(ctx context.Context, threadID string, ru
8894}
8995
9096// Returns a list of run steps belonging to a run.
97+//
98+// Deprecated: The Assistants API is deprecated in favor of the Responses API
9199func (r *BetaThreadRunStepService) ListAutoPaging(ctx context.Context, threadID string, runID string, query BetaThreadRunStepListParams, opts ...option.RequestOption) *pagination.CursorPageAutoPager[RunStep] {
92100 return pagination.NewCursorPageAutoPager(r.List(ctx, threadID, runID, query, opts...))
93101}
@@ -100,13 +108,12 @@ type CodeInterpreterLogs struct {
100108 Type constant.Logs `json:"type,required"`
101109 // The text output from the Code Interpreter tool call.
102110 Logs string `json:"logs"`
103− // Metadata for the response, check the presence of optional fields with the
104− // [resp.Field.IsPresent] method.
111+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
105112 JSON struct {
106− Index resp.Field
107− Type resp.Field
108− Logs resp.Field
109− ExtraFields map[string]resp.Field
113+ Index respjson.Field
114+ Type respjson.Field
115+ Logs respjson.Field
116+ ExtraFields map[string]respjson.Field
110117 raw string
111118 } `json:"-"`
112119}
@@ -123,13 +130,12 @@ type CodeInterpreterOutputImage struct {
123130 // Always `image`.
124131 Type constant.Image `json:"type,required"`
125132 Image CodeInterpreterOutputImageImage `json:"image"`
126− // Metadata for the response, check the presence of optional fields with the
127− // [resp.Field.IsPresent] method.
133+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
128134 JSON struct {
129− Index resp.Field
130− Type resp.Field
131− Image resp.Field
132− ExtraFields map[string]resp.Field
135+ Index respjson.Field
136+ Type respjson.Field
137+ Image respjson.Field
138+ ExtraFields map[string]respjson.Field
133139 raw string
134140 } `json:"-"`
135141}
@@ -144,11 +150,10 @@ type CodeInterpreterOutputImageImage struct {
144150 // The [file](https://platform.openai.com/docs/api-reference/files) ID of the
145151 // image.
146152 FileID string `json:"file_id"`
147− // Metadata for the response, check the presence of optional fields with the
148− // [resp.Field.IsPresent] method.
153+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
149154 JSON struct {
150− FileID resp.Field
151− ExtraFields map[string]resp.Field
155+ FileID respjson.Field
156+ ExtraFields map[string]respjson.Field
152157 raw string
153158 } `json:"-"`
154159}
@@ -168,13 +173,12 @@ type CodeInterpreterToolCall struct {
168173 // The type of tool call. This is always going to be `code_interpreter` for this
169174 // type of tool call.
170175 Type constant.CodeInterpreter `json:"type,required"`
171− // Metadata for the response, check the presence of optional fields with the
172− // [resp.Field.IsPresent] method.
176+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
173177 JSON struct {
174− ID resp.Field
175− CodeInterpreter resp.Field
176− Type resp.Field
177− ExtraFields map[string]resp.Field
178+ ID respjson.Field
179+ CodeInterpreter respjson.Field
180+ Type respjson.Field
181+ ExtraFields map[string]respjson.Field
178182 raw string
179183 } `json:"-"`
180184}
@@ -193,12 +197,11 @@ type CodeInterpreterToolCallCodeInterpreter struct {
193197 // or more items, including text (`logs`) or images (`image`). Each of these are
194198 // represented by a different object type.
195199 Outputs []CodeInterpreterToolCallCodeInterpreterOutputUnion `json:"outputs,required"`
196− // Metadata for the response, check the presence of optional fields with the
197− // [resp.Field.IsPresent] method.
200+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
198201 JSON struct {
199− Input resp.Field
200− Outputs resp.Field
201− ExtraFields map[string]resp.Field
202+ Input respjson.Field
203+ Outputs respjson.Field
204+ ExtraFields map[string]respjson.Field
202205 raw string
203206 } `json:"-"`
204207}
@@ -225,22 +228,34 @@ type CodeInterpreterToolCallCodeInterpreterOutputUnion struct {
225228 // This field is from variant [CodeInterpreterToolCallCodeInterpreterOutputImage].
226229 Image CodeInterpreterToolCallCodeInterpreterOutputImageImage `json:"image"`
227230 JSON struct {
228− Logs resp.Field
229− Type resp.Field
230− Image resp.Field
231+ Logs respjson.Field
232+ Type respjson.Field
233+ Image respjson.Field
231234 raw string
232235 } `json:"-"`
233236}
234237
238+// anyCodeInterpreterToolCallCodeInterpreterOutput is implemented by each variant
239+// of [CodeInterpreterToolCallCodeInterpreterOutputUnion] to add type safety for
240+// the return type of [CodeInterpreterToolCallCodeInterpreterOutputUnion.AsAny]
241+type anyCodeInterpreterToolCallCodeInterpreterOutput interface {
242+ implCodeInterpreterToolCallCodeInterpreterOutputUnion()
243+}
244+
245+func (CodeInterpreterToolCallCodeInterpreterOutputLogs) implCodeInterpreterToolCallCodeInterpreterOutputUnion() {
246+}
247+func (CodeInterpreterToolCallCodeInterpreterOutputImage) implCodeInterpreterToolCallCodeInterpreterOutputUnion() {
248+}
249+
235250// Use the following switch statement to find the correct variant
236251//
237252// switch variant := CodeInterpreterToolCallCodeInterpreterOutputUnion.AsAny().(type) {
238−// case CodeInterpreterToolCallCodeInterpreterOutputLogs:
239−// case CodeInterpreterToolCallCodeInterpreterOutputImage:
253+// case openai.CodeInterpreterToolCallCodeInterpreterOutputLogs:
254+// case openai.CodeInterpreterToolCallCodeInterpreterOutputImage:
240255// default:
241256// fmt.Errorf("no variant present")
242257// }
243−func (u CodeInterpreterToolCallCodeInterpreterOutputUnion) AsAny() any {
258+func (u CodeInterpreterToolCallCodeInterpreterOutputUnion) AsAny() anyCodeInterpreterToolCallCodeInterpreterOutput {
244259 switch u.Type {
245260 case "logs":
246261 return u.AsLogs()
@@ -273,12 +288,11 @@ type CodeInterpreterToolCallCodeInterpreterOutputLogs struct {
273288 Logs string `json:"logs,required"`
274289 // Always `logs`.
275290 Type constant.Logs `json:"type,required"`
276− // Metadata for the response, check the presence of optional fields with the
277− // [resp.Field.IsPresent] method.
291+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
278292 JSON struct {
279− Logs resp.Field
280− Type resp.Field
281− ExtraFields map[string]resp.Field
293+ Logs respjson.Field
294+ Type respjson.Field
295+ ExtraFields map[string]respjson.Field
282296 raw string
283297 } `json:"-"`
284298}
@@ -293,12 +307,11 @@ type CodeInterpreterToolCallCodeInterpreterOutputImage struct {
293307 Image CodeInterpreterToolCallCodeInterpreterOutputImageImage `json:"image,required"`
294308 // Always `image`.
295309 Type constant.Image `json:"type,required"`
296− // Metadata for the response, check the presence of optional fields with the
297− // [resp.Field.IsPresent] method.
310+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
298311 JSON struct {
299− Image resp.Field
300− Type resp.Field
301− ExtraFields map[string]resp.Field
312+ Image respjson.Field
313+ Type respjson.Field
314+ ExtraFields map[string]respjson.Field
302315 raw string
303316 } `json:"-"`
304317}
@@ -313,11 +326,10 @@ type CodeInterpreterToolCallCodeInterpreterOutputImageImage struct {
313326 // The [file](https://platform.openai.com/docs/api-reference/files) ID of the
314327 // image.
315328 FileID string `json:"file_id,required"`
316− // Metadata for the response, check the presence of optional fields with the
317− // [resp.Field.IsPresent] method.
329+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
318330 JSON struct {
319− FileID resp.Field
320− ExtraFields map[string]resp.Field
331+ FileID respjson.Field
332+ ExtraFields map[string]respjson.Field
321333 raw string
322334 } `json:"-"`
323335}
@@ -339,14 +351,13 @@ type CodeInterpreterToolCallDelta struct {
339351 ID string `json:"id"`
340352 // The Code Interpreter tool call definition.
341353 CodeInterpreter CodeInterpreterToolCallDeltaCodeInterpreter `json:"code_interpreter"`
342− // Metadata for the response, check the presence of optional fields with the
343− // [resp.Field.IsPresent] method.
354+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
344355 JSON struct {
345− Index resp.Field
346− Type resp.Field
347− ID resp.Field
348− CodeInterpreter resp.Field
349− ExtraFields map[string]resp.Field
356+ Index respjson.Field
357+ Type respjson.Field
358+ ID respjson.Field
359+ CodeInterpreter respjson.Field
360+ ExtraFields map[string]respjson.Field
350361 raw string
351362 } `json:"-"`
352363}
@@ -365,12 +376,11 @@ type CodeInterpreterToolCallDeltaCodeInterpreter struct {
365376 // or more items, including text (`logs`) or images (`image`). Each of these are
366377 // represented by a different object type.
367378 Outputs []CodeInterpreterToolCallDeltaCodeInterpreterOutputUnion `json:"outputs"`
368− // Metadata for the response, check the presence of optional fields with the
369− // [resp.Field.IsPresent] method.
379+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
370380 JSON struct {
371− Input resp.Field
372− Outputs resp.Field
373− ExtraFields map[string]resp.Field
381+ Input respjson.Field
382+ Outputs respjson.Field
383+ ExtraFields map[string]respjson.Field
374384 raw string
375385 } `json:"-"`
376386}
@@ -397,23 +407,34 @@ type CodeInterpreterToolCallDeltaCodeInterpreterOutputUnion struct {
397407 // This field is from variant [CodeInterpreterOutputImage].
398408 Image CodeInterpreterOutputImageImage `json:"image"`
399409 JSON struct {
400− Index resp.Field
401− Type resp.Field
402− Logs resp.Field
403− Image resp.Field
410+ Index respjson.Field
411+ Type respjson.Field
412+ Logs respjson.Field
413+ Image respjson.Field
404414 raw string
405415 } `json:"-"`
406416}
407417
418+// anyCodeInterpreterToolCallDeltaCodeInterpreterOutput is implemented by each
419+// variant of [CodeInterpreterToolCallDeltaCodeInterpreterOutputUnion] to add type
420+// safety for the return type of
421+// [CodeInterpreterToolCallDeltaCodeInterpreterOutputUnion.AsAny]
422+type anyCodeInterpreterToolCallDeltaCodeInterpreterOutput interface {
423+ implCodeInterpreterToolCallDeltaCodeInterpreterOutputUnion()
424+}
425+
426+func (CodeInterpreterLogs) implCodeInterpreterToolCallDeltaCodeInterpreterOutputUnion() {}
427+func (CodeInterpreterOutputImage) implCodeInterpreterToolCallDeltaCodeInterpreterOutputUnion() {}
428+
408429// Use the following switch statement to find the correct variant
409430//
410431// switch variant := CodeInterpreterToolCallDeltaCodeInterpreterOutputUnion.AsAny().(type) {
411−// case CodeInterpreterLogs:
412−// case CodeInterpreterOutputImage:
432+// case openai.CodeInterpreterLogs:
433+// case openai.CodeInterpreterOutputImage:
413434// default:
414435// fmt.Errorf("no variant present")
415436// }
416−func (u CodeInterpreterToolCallDeltaCodeInterpreterOutputUnion) AsAny() any {
437+func (u CodeInterpreterToolCallDeltaCodeInterpreterOutputUnion) AsAny() anyCodeInterpreterToolCallDeltaCodeInterpreterOutput {
417438 switch u.Type {
418439 case "logs":
419440 return u.AsLogs()
@@ -448,13 +469,12 @@ type FileSearchToolCall struct {
448469 // The type of tool call. This is always going to be `file_search` for this type of
449470 // tool call.
450471 Type constant.FileSearch `json:"type,required"`
451− // Metadata for the response, check the presence of optional fields with the
452− // [resp.Field.IsPresent] method.
472+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
453473 JSON struct {
454− ID resp.Field
455− FileSearch resp.Field
456− Type resp.Field
457− ExtraFields map[string]resp.Field
474+ ID respjson.Field
475+ FileSearch respjson.Field
476+ Type respjson.Field
477+ ExtraFields map[string]respjson.Field
458478 raw string
459479 } `json:"-"`
460480}
@@ -471,12 +491,11 @@ type FileSearchToolCallFileSearch struct {
471491 RankingOptions FileSearchToolCallFileSearchRankingOptions `json:"ranking_options"`
472492 // The results of the file search.
473493 Results []FileSearchToolCallFileSearchResult `json:"results"`
474− // Metadata for the response, check the presence of optional fields with the
475− // [resp.Field.IsPresent] method.
494+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
476495 JSON struct {
477− RankingOptions resp.Field
478− Results resp.Field
479− ExtraFields map[string]resp.Field
496+ RankingOptions respjson.Field
497+ Results respjson.Field
498+ ExtraFields map[string]respjson.Field
480499 raw string
481500 } `json:"-"`
482501}
@@ -497,12 +516,11 @@ type FileSearchToolCallFileSearchRankingOptions struct {
497516 // The score threshold for the file search. All values must be a floating point
498517 // number between 0 and 1.
499518 ScoreThreshold float64 `json:"score_threshold,required"`
500− // Metadata for the response, check the presence of optional fields with the
501− // [resp.Field.IsPresent] method.
519+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
502520 JSON struct {
503− Ranker resp.Field
504− ScoreThreshold resp.Field
505− ExtraFields map[string]resp.Field
521+ Ranker respjson.Field
522+ ScoreThreshold respjson.Field
523+ ExtraFields map[string]respjson.Field
506524 raw string
507525 } `json:"-"`
508526}
@@ -525,14 +543,13 @@ type FileSearchToolCallFileSearchResult struct {
525543 // The content of the result that was found. The content is only included if
526544 // requested via the include query parameter.
527545 Content []FileSearchToolCallFileSearchResultContent `json:"content"`
528− // Metadata for the response, check the presence of optional fields with the
529− // [resp.Field.IsPresent] method.
546+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
530547 JSON struct {
531− FileID resp.Field
532− FileName resp.Field
533− Score resp.Field
534− Content resp.Field
535− ExtraFields map[string]resp.Field
548+ FileID respjson.Field
549+ FileName respjson.Field
550+ Score respjson.Field
551+ Content respjson.Field
552+ ExtraFields map[string]respjson.Field
536553 raw string
537554 } `json:"-"`
538555}
@@ -550,12 +567,11 @@ type FileSearchToolCallFileSearchResultContent struct {
550567 //
551568 // Any of "text".
552569 Type string `json:"type"`
553− // Metadata for the response, check the presence of optional fields with the
554− // [resp.Field.IsPresent] method.
570+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
555571 JSON struct {
556− Text resp.Field
557− Type resp.Field
558− ExtraFields map[string]resp.Field
572+ Text respjson.Field
573+ Type respjson.Field
574+ ExtraFields map[string]respjson.Field
559575 raw string
560576 } `json:"-"`
561577}
@@ -568,7 +584,7 @@ func (r *FileSearchToolCallFileSearchResultContent) UnmarshalJSON(data []byte) e
568584
569585type FileSearchToolCallDelta struct {
570586 // For now, this is always going to be an empty object.
571− FileSearch interface{} `json:"file_search,required"`
587+ FileSearch any `json:"file_search,required"`
572588 // The index of the tool call in the tool calls array.
573589 Index int64 `json:"index,required"`
574590 // The type of tool call. This is always going to be `file_search` for this type of
@@ -576,14 +592,13 @@ type FileSearchToolCallDelta struct {
576592 Type constant.FileSearch `json:"type,required"`
577593 // The ID of the tool call object.
578594 ID string `json:"id"`
579− // Metadata for the response, check the presence of optional fields with the
580− // [resp.Field.IsPresent] method.
595+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
581596 JSON struct {
582− FileSearch resp.Field
583− Index resp.Field
584− Type resp.Field
585− ID resp.Field
586− ExtraFields map[string]resp.Field
597+ FileSearch respjson.Field
598+ Index respjson.Field
599+ Type respjson.Field
600+ ID respjson.Field
601+ ExtraFields map[string]respjson.Field
587602 raw string
588603 } `json:"-"`
589604}
@@ -602,13 +617,12 @@ type FunctionToolCall struct {
602617 // The type of tool call. This is always going to be `function` for this type of
603618 // tool call.
604619 Type constant.Function `json:"type,required"`
605− // Metadata for the response, check the presence of optional fields with the
606− // [resp.Field.IsPresent] method.
620+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
607621 JSON struct {
608− ID resp.Field
609− Function resp.Field
610− Type resp.Field
611− ExtraFields map[string]resp.Field
622+ ID respjson.Field
623+ Function respjson.Field
624+ Type respjson.Field
625+ ExtraFields map[string]respjson.Field
612626 raw string
613627 } `json:"-"`
614628}
@@ -629,13 +643,12 @@ type FunctionToolCallFunction struct {
629643 // [submitted](https://platform.openai.com/docs/api-reference/runs/submitToolOutputs)
630644 // yet.
631645 Output string `json:"output,required"`
632− // Metadata for the response, check the presence of optional fields with the
633− // [resp.Field.IsPresent] method.
646+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
634647 JSON struct {
635− Arguments resp.Field
636− Name resp.Field
637− Output resp.Field
638− ExtraFields map[string]resp.Field
648+ Arguments respjson.Field
649+ Name respjson.Field
650+ Output respjson.Field
651+ ExtraFields map[string]respjson.Field
639652 raw string
640653 } `json:"-"`
641654}
@@ -656,14 +669,13 @@ type FunctionToolCallDelta struct {
656669 ID string `json:"id"`
657670 // The definition of the function that was called.
658671 Function FunctionToolCallDeltaFunction `json:"function"`
659− // Metadata for the response, check the presence of optional fields with the
660− // [resp.Field.IsPresent] method.
672+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
661673 JSON struct {
662− Index resp.Field
663− Type resp.Field
664− ID resp.Field
665− Function resp.Field
666− ExtraFields map[string]resp.Field
674+ Index respjson.Field
675+ Type respjson.Field
676+ ID respjson.Field
677+ Function respjson.Field
678+ ExtraFields map[string]respjson.Field
667679 raw string
668680 } `json:"-"`
669681}
@@ -684,13 +696,12 @@ type FunctionToolCallDeltaFunction struct {
684696 // [submitted](https://platform.openai.com/docs/api-reference/runs/submitToolOutputs)
685697 // yet.
686698 Output string `json:"output,nullable"`
687− // Metadata for the response, check the presence of optional fields with the
688− // [resp.Field.IsPresent] method.
699+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
689700 JSON struct {
690− Arguments resp.Field
691− Name resp.Field
692− Output resp.Field
693− ExtraFields map[string]resp.Field
701+ Arguments respjson.Field
702+ Name respjson.Field
703+ Output respjson.Field
704+ ExtraFields map[string]respjson.Field
694705 raw string
695706 } `json:"-"`
696707}
@@ -706,12 +717,11 @@ type MessageCreationStepDetails struct {
706717 MessageCreation MessageCreationStepDetailsMessageCreation `json:"message_creation,required"`
707718 // Always `message_creation`.
708719 Type constant.MessageCreation `json:"type,required"`
709− // Metadata for the response, check the presence of optional fields with the
710− // [resp.Field.IsPresent] method.
720+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
711721 JSON struct {
712− MessageCreation resp.Field
713− Type resp.Field
714− ExtraFields map[string]resp.Field
722+ MessageCreation respjson.Field
723+ Type respjson.Field
724+ ExtraFields map[string]respjson.Field
715725 raw string
716726 } `json:"-"`
717727}
@@ -725,11 +735,10 @@ func (r *MessageCreationStepDetails) UnmarshalJSON(data []byte) error {
725735type MessageCreationStepDetailsMessageCreation struct {
726736 // The ID of the message that was created by this run step.
727737 MessageID string `json:"message_id,required"`
728− // Metadata for the response, check the presence of optional fields with the
729− // [resp.Field.IsPresent] method.
738+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
730739 JSON struct {
731− MessageID resp.Field
732− ExtraFields map[string]resp.Field
740+ MessageID respjson.Field
741+ ExtraFields map[string]respjson.Field
733742 raw string
734743 } `json:"-"`
735744}
@@ -791,26 +800,25 @@ type RunStep struct {
791800 // Usage statistics related to the run step. This value will be `null` while the
792801 // run step's status is `in_progress`.
793802 Usage RunStepUsage `json:"usage,required"`
794− // Metadata for the response, check the presence of optional fields with the
795− // [resp.Field.IsPresent] method.
803+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
796804 JSON struct {
797− ID resp.Field
798− AssistantID resp.Field
799− CancelledAt resp.Field
800− CompletedAt resp.Field
801− CreatedAt resp.Field
802− ExpiredAt resp.Field
803− FailedAt resp.Field
804− LastError resp.Field
805− Metadata resp.Field
806− Object resp.Field
807− RunID resp.Field
808− Status resp.Field
809− StepDetails resp.Field
810− ThreadID resp.Field
811− Type resp.Field
812− Usage resp.Field
813− ExtraFields map[string]resp.Field
805+ ID respjson.Field
806+ AssistantID respjson.Field
807+ CancelledAt respjson.Field
808+ CompletedAt respjson.Field
809+ CreatedAt respjson.Field
810+ ExpiredAt respjson.Field
811+ FailedAt respjson.Field
812+ LastError respjson.Field
813+ Metadata respjson.Field
814+ Object respjson.Field
815+ RunID respjson.Field
816+ Status respjson.Field
817+ StepDetails respjson.Field
818+ ThreadID respjson.Field
819+ Type respjson.Field
820+ Usage respjson.Field
821+ ExtraFields map[string]respjson.Field
814822 raw string
815823 } `json:"-"`
816824}
@@ -830,12 +838,11 @@ type RunStepLastError struct {
830838 Code string `json:"code,required"`
831839 // A human-readable description of the error.
832840 Message string `json:"message,required"`
833− // Metadata for the response, check the presence of optional fields with the
834− // [resp.Field.IsPresent] method.
841+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
835842 JSON struct {
836− Code resp.Field
837− Message resp.Field
838− ExtraFields map[string]resp.Field
843+ Code respjson.Field
844+ Message respjson.Field
845+ ExtraFields map[string]respjson.Field
839846 raw string
840847 } `json:"-"`
841848}
@@ -872,22 +879,32 @@ type RunStepStepDetailsUnion struct {
872879 // This field is from variant [ToolCallsStepDetails].
873880 ToolCalls []ToolCallUnion `json:"tool_calls"`
874881 JSON struct {
875− MessageCreation resp.Field
876− Type resp.Field
877− ToolCalls resp.Field
882+ MessageCreation respjson.Field
883+ Type respjson.Field
884+ ToolCalls respjson.Field
878885 raw string
879886 } `json:"-"`
880887}
881888
889+// anyRunStepStepDetails is implemented by each variant of
890+// [RunStepStepDetailsUnion] to add type safety for the return type of
891+// [RunStepStepDetailsUnion.AsAny]
892+type anyRunStepStepDetails interface {
893+ implRunStepStepDetailsUnion()
894+}
895+
896+func (MessageCreationStepDetails) implRunStepStepDetailsUnion() {}
897+func (ToolCallsStepDetails) implRunStepStepDetailsUnion() {}
898+
882899// Use the following switch statement to find the correct variant
883900//
884901// switch variant := RunStepStepDetailsUnion.AsAny().(type) {
885−// case MessageCreationStepDetails:
886−// case ToolCallsStepDetails:
902+// case openai.MessageCreationStepDetails:
903+// case openai.ToolCallsStepDetails:
887904// default:
888905// fmt.Errorf("no variant present")
889906// }
890−func (u RunStepStepDetailsUnion) AsAny() any {
907+func (u RunStepStepDetailsUnion) AsAny() anyRunStepStepDetails {
891908 switch u.Type {
892909 case "message_creation":
893910 return u.AsMessageCreation()
@@ -931,13 +948,12 @@ type RunStepUsage struct {
931948 PromptTokens int64 `json:"prompt_tokens,required"`
932949 // Total number of tokens used (prompt + completion).
933950 TotalTokens int64 `json:"total_tokens,required"`
934− // Metadata for the response, check the presence of optional fields with the
935− // [resp.Field.IsPresent] method.
951+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
936952 JSON struct {
937− CompletionTokens resp.Field
938− PromptTokens resp.Field
939− TotalTokens resp.Field
940− ExtraFields map[string]resp.Field
953+ CompletionTokens respjson.Field
954+ PromptTokens respjson.Field
955+ TotalTokens respjson.Field
956+ ExtraFields map[string]respjson.Field
941957 raw string
942958 } `json:"-"`
943959}
@@ -952,11 +968,10 @@ func (r *RunStepUsage) UnmarshalJSON(data []byte) error {
952968type RunStepDelta struct {
953969 // The details of the run step.
954970 StepDetails RunStepDeltaStepDetailsUnion `json:"step_details"`
955− // Metadata for the response, check the presence of optional fields with the
956− // [resp.Field.IsPresent] method.
971+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
957972 JSON struct {
958− StepDetails resp.Field
959− ExtraFields map[string]resp.Field
973+ StepDetails respjson.Field
974+ ExtraFields map[string]respjson.Field
960975 raw string
961976 } `json:"-"`
962977}
@@ -981,22 +996,32 @@ type RunStepDeltaStepDetailsUnion struct {
981996 // This field is from variant [ToolCallDeltaObject].
982997 ToolCalls []ToolCallDeltaUnion `json:"tool_calls"`
983998 JSON struct {
984− Type resp.Field
985− MessageCreation resp.Field
986− ToolCalls resp.Field
999+ Type respjson.Field
1000+ MessageCreation respjson.Field
1001+ ToolCalls respjson.Field
9871002 raw string
9881003 } `json:"-"`
9891004}
9901005
1006+// anyRunStepDeltaStepDetails is implemented by each variant of
1007+// [RunStepDeltaStepDetailsUnion] to add type safety for the return type of
1008+// [RunStepDeltaStepDetailsUnion.AsAny]
1009+type anyRunStepDeltaStepDetails interface {
1010+ implRunStepDeltaStepDetailsUnion()
1011+}
1012+
1013+func (RunStepDeltaMessageDelta) implRunStepDeltaStepDetailsUnion() {}
1014+func (ToolCallDeltaObject) implRunStepDeltaStepDetailsUnion() {}
1015+
9911016// Use the following switch statement to find the correct variant
9921017//
9931018// switch variant := RunStepDeltaStepDetailsUnion.AsAny().(type) {
994−// case RunStepDeltaMessageDelta:
995−// case ToolCallDeltaObject:
1019+// case openai.RunStepDeltaMessageDelta:
1020+// case openai.ToolCallDeltaObject:
9961021// default:
9971022// fmt.Errorf("no variant present")
9981023// }
999−func (u RunStepDeltaStepDetailsUnion) AsAny() any {
1024+func (u RunStepDeltaStepDetailsUnion) AsAny() anyRunStepDeltaStepDetails {
10001025 switch u.Type {
10011026 case "message_creation":
10021027 return u.AsMessageCreation()
@@ -1032,13 +1057,12 @@ type RunStepDeltaEvent struct {
10321057 Delta RunStepDelta `json:"delta,required"`
10331058 // The object type, which is always `thread.run.step.delta`.
10341059 Object constant.ThreadRunStepDelta `json:"object,required"`
1035− // Metadata for the response, check the presence of optional fields with the
1036− // [resp.Field.IsPresent] method.
1060+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
10371061 JSON struct {
1038− ID resp.Field
1039− Delta resp.Field
1040− Object resp.Field
1041− ExtraFields map[string]resp.Field
1062+ ID respjson.Field
1063+ Delta respjson.Field
1064+ Object respjson.Field
1065+ ExtraFields map[string]respjson.Field
10421066 raw string
10431067 } `json:"-"`
10441068}
@@ -1054,12 +1078,11 @@ type RunStepDeltaMessageDelta struct {
10541078 // Always `message_creation`.
10551079 Type constant.MessageCreation `json:"type,required"`
10561080 MessageCreation RunStepDeltaMessageDeltaMessageCreation `json:"message_creation"`
1057− // Metadata for the response, check the presence of optional fields with the
1058− // [resp.Field.IsPresent] method.
1081+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
10591082 JSON struct {
1060− Type resp.Field
1061− MessageCreation resp.Field
1062− ExtraFields map[string]resp.Field
1083+ Type respjson.Field
1084+ MessageCreation respjson.Field
1085+ ExtraFields map[string]respjson.Field
10631086 raw string
10641087 } `json:"-"`
10651088}
@@ -1073,11 +1096,10 @@ func (r *RunStepDeltaMessageDelta) UnmarshalJSON(data []byte) error {
10731096type RunStepDeltaMessageDeltaMessageCreation struct {
10741097 // The ID of the message that was created by this run step.
10751098 MessageID string `json:"message_id"`
1076− // Metadata for the response, check the presence of optional fields with the
1077− // [resp.Field.IsPresent] method.
1099+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
10781100 JSON struct {
1079− MessageID resp.Field
1080− ExtraFields map[string]resp.Field
1101+ MessageID respjson.Field
1102+ ExtraFields map[string]respjson.Field
10811103 raw string
10821104 } `json:"-"`
10831105}
@@ -1111,25 +1133,35 @@ type ToolCallUnion struct {
11111133 // This field is from variant [FunctionToolCall].
11121134 Function FunctionToolCallFunction `json:"function"`
11131135 JSON struct {
1114− ID resp.Field
1115− CodeInterpreter resp.Field
1116− Type resp.Field
1117− FileSearch resp.Field
1118− Function resp.Field
1136+ ID respjson.Field
1137+ CodeInterpreter respjson.Field
1138+ Type respjson.Field
1139+ FileSearch respjson.Field
1140+ Function respjson.Field
11191141 raw string
11201142 } `json:"-"`
11211143}
11221144
1145+// anyToolCall is implemented by each variant of [ToolCallUnion] to add type safety
1146+// for the return type of [ToolCallUnion.AsAny]
1147+type anyToolCall interface {
1148+ implToolCallUnion()
1149+}
1150+
1151+func (CodeInterpreterToolCall) implToolCallUnion() {}
1152+func (FileSearchToolCall) implToolCallUnion() {}
1153+func (FunctionToolCall) implToolCallUnion() {}
1154+
11231155// Use the following switch statement to find the correct variant
11241156//
11251157// switch variant := ToolCallUnion.AsAny().(type) {
1126−// case CodeInterpreterToolCall:
1127−// case FileSearchToolCall:
1128−// case FunctionToolCall:
1158+// case openai.CodeInterpreterToolCall:
1159+// case openai.FileSearchToolCall:
1160+// case openai.FunctionToolCall:
11291161// default:
11301162// fmt.Errorf("no variant present")
11311163// }
1132−func (u ToolCallUnion) AsAny() any {
1164+func (u ToolCallUnion) AsAny() anyToolCall {
11331165 switch u.Type {
11341166 case "code_interpreter":
11351167 return u.AsCodeInterpreter()
@@ -1178,30 +1210,40 @@ type ToolCallDeltaUnion struct {
11781210 // This field is from variant [CodeInterpreterToolCallDelta].
11791211 CodeInterpreter CodeInterpreterToolCallDeltaCodeInterpreter `json:"code_interpreter"`
11801212 // This field is from variant [FileSearchToolCallDelta].
1181− FileSearch interface{} `json:"file_search"`
1213+ FileSearch any `json:"file_search"`
11821214 // This field is from variant [FunctionToolCallDelta].
11831215 Function FunctionToolCallDeltaFunction `json:"function"`
11841216 JSON struct {
1185− Index resp.Field
1186− Type resp.Field
1187− ID resp.Field
1188− CodeInterpreter resp.Field
1189− FileSearch resp.Field
1190− Function resp.Field
1217+ Index respjson.Field
1218+ Type respjson.Field
1219+ ID respjson.Field
1220+ CodeInterpreter respjson.Field
1221+ FileSearch respjson.Field
1222+ Function respjson.Field
11911223 raw string
11921224 } `json:"-"`
11931225}
11941226
1227+// anyToolCallDelta is implemented by each variant of [ToolCallDeltaUnion] to add
1228+// type safety for the return type of [ToolCallDeltaUnion.AsAny]
1229+type anyToolCallDelta interface {
1230+ implToolCallDeltaUnion()
1231+}
1232+
1233+func (CodeInterpreterToolCallDelta) implToolCallDeltaUnion() {}
1234+func (FileSearchToolCallDelta) implToolCallDeltaUnion() {}
1235+func (FunctionToolCallDelta) implToolCallDeltaUnion() {}
1236+
11951237// Use the following switch statement to find the correct variant
11961238//
11971239// switch variant := ToolCallDeltaUnion.AsAny().(type) {
1198−// case CodeInterpreterToolCallDelta:
1199−// case FileSearchToolCallDelta:
1200−// case FunctionToolCallDelta:
1240+// case openai.CodeInterpreterToolCallDelta:
1241+// case openai.FileSearchToolCallDelta:
1242+// case openai.FunctionToolCallDelta:
12011243// default:
12021244// fmt.Errorf("no variant present")
12031245// }
1204−func (u ToolCallDeltaUnion) AsAny() any {
1246+func (u ToolCallDeltaUnion) AsAny() anyToolCallDelta {
12051247 switch u.Type {
12061248 case "code_interpreter":
12071249 return u.AsCodeInterpreter()
@@ -1243,12 +1285,11 @@ type ToolCallDeltaObject struct {
12431285 // with one of three types of tools: `code_interpreter`, `file_search`, or
12441286 // `function`.
12451287 ToolCalls []ToolCallDeltaUnion `json:"tool_calls"`
1246− // Metadata for the response, check the presence of optional fields with the
1247− // [resp.Field.IsPresent] method.
1288+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12481289 JSON struct {
1249− Type resp.Field
1250− ToolCalls resp.Field
1251− ExtraFields map[string]resp.Field
1290+ Type respjson.Field
1291+ ToolCalls respjson.Field
1292+ ExtraFields map[string]respjson.Field
12521293 raw string
12531294 } `json:"-"`
12541295}
@@ -1267,12 +1308,11 @@ type ToolCallsStepDetails struct {
12671308 ToolCalls []ToolCallUnion `json:"tool_calls,required"`
12681309 // Always `tool_calls`.
12691310 Type constant.ToolCalls `json:"type,required"`
1270− // Metadata for the response, check the presence of optional fields with the
1271− // [resp.Field.IsPresent] method.
1311+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12721312 JSON struct {
1273− ToolCalls resp.Field
1274− Type resp.Field
1275− ExtraFields map[string]resp.Field
1313+ ToolCalls respjson.Field
1314+ Type respjson.Field
1315+ ExtraFields map[string]respjson.Field
12761316 raw string
12771317 } `json:"-"`
12781318}
@@ -1295,13 +1335,9 @@ type BetaThreadRunStepGetParams struct {
12951335 paramObj
12961336}
12971337
1298−// IsPresent returns true if the field's value is not omitted and not the JSON
1299−// "null". To check if this field is omitted, use [param.IsOmitted].
1300−func (f BetaThreadRunStepGetParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
1301−
13021338// URLQuery serializes [BetaThreadRunStepGetParams]'s query parameters as
13031339// `url.Values`.
1304−func (r BetaThreadRunStepGetParams) URLQuery() (v url.Values) {
1340+func (r BetaThreadRunStepGetParams) URLQuery() (v url.Values, err error) {
13051341 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
13061342 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
13071343 NestedFormat: apiquery.NestedQueryFormatBrackets,
@@ -1338,13 +1374,9 @@ type BetaThreadRunStepListParams struct {
13381374 paramObj
13391375}
13401376
1341−// IsPresent returns true if the field's value is not omitted and not the JSON
1342−// "null". To check if this field is omitted, use [param.IsOmitted].
1343−func (f BetaThreadRunStepListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
1344−
13451377// URLQuery serializes [BetaThreadRunStepListParams]'s query parameters as
13461378// `url.Values`.
1347−func (r BetaThreadRunStepListParams) URLQuery() (v url.Values) {
1379+func (r BetaThreadRunStepListParams) URLQuery() (v url.Values, err error) {
13481380 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
13491381 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
13501382 NestedFormat: apiquery.NestedQueryFormatBrackets,
vendor/github.com/openai/openai-go/chatcompletion.go+457−537
@@ -4,11 +4,11 @@ package openai
44
55import (
66 "context"
7+ "encoding/json"
78 "errors"
89 "fmt"
910 "net/http"
1011 "net/url"
11− "reflect"
1212
1313 "github.com/openai/openai-go/internal/apijson"
1414 "github.com/openai/openai-go/internal/apiquery"
@@ -16,11 +16,10 @@ import (
1616 "github.com/openai/openai-go/option"
1717 "github.com/openai/openai-go/packages/pagination"
1818 "github.com/openai/openai-go/packages/param"
19− "github.com/openai/openai-go/packages/resp"
19+ "github.com/openai/openai-go/packages/respjson"
2020 "github.com/openai/openai-go/packages/ssestream"
2121 "github.com/openai/openai-go/shared"
2222 "github.com/openai/openai-go/shared/constant"
23− "github.com/tidwall/gjson"
2423)
2524
2625// ChatCompletionService contains methods and other services that help with
@@ -176,9 +175,25 @@ type ChatCompletion struct {
176175 Model string `json:"model,required"`
177176 // The object type, which is always `chat.completion`.
178177 Object constant.ChatCompletion `json:"object,required"`
179− // The service tier used for processing the request.
178+ // Specifies the processing type used for serving the request.
180179 //
181− // Any of "scale", "default".
180+ // - If set to 'auto', then the request will be processed with the service tier
181+ // configured in the Project settings. Unless otherwise configured, the Project
182+ // will use 'default'.
183+ // - If set to 'default', then the requset will be processed with the standard
184+ // pricing and performance for the selected model.
185+ // - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or
186+ // 'priority', then the request will be processed with the corresponding service
187+ // tier. [Contact sales](https://openai.com/contact-sales) to learn more about
188+ // Priority processing.
189+ // - When not set, the default behavior is 'auto'.
190+ //
191+ // When the `service_tier` parameter is set, the response body will include the
192+ // `service_tier` value based on the processing mode actually used to serve the
193+ // request. This response value may be different from the value set in the
194+ // parameter.
195+ //
196+ // Any of "auto", "default", "flex", "scale", "priority".
182197 ServiceTier ChatCompletionServiceTier `json:"service_tier,nullable"`
183198 // This fingerprint represents the backend configuration that the model runs with.
184199 //
@@ -187,18 +202,17 @@ type ChatCompletion struct {
187202 SystemFingerprint string `json:"system_fingerprint"`
188203 // Usage statistics for the completion request.
189204 Usage CompletionUsage `json:"usage"`
190− // Metadata for the response, check the presence of optional fields with the
191− // [resp.Field.IsPresent] method.
205+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
192206 JSON struct {
193− ID resp.Field
194− Choices resp.Field
195− Created resp.Field
196− Model resp.Field
197− Object resp.Field
198− ServiceTier resp.Field
199− SystemFingerprint resp.Field
200− Usage resp.Field
201− ExtraFields map[string]resp.Field
207+ ID respjson.Field
208+ Choices respjson.Field
209+ Created respjson.Field
210+ Model respjson.Field
211+ Object respjson.Field
212+ ServiceTier respjson.Field
213+ SystemFingerprint respjson.Field
214+ Usage respjson.Field
215+ ExtraFields map[string]respjson.Field
202216 raw string
203217 } `json:"-"`
204218}
@@ -225,14 +239,13 @@ type ChatCompletionChoice struct {
225239 Logprobs ChatCompletionChoiceLogprobs `json:"logprobs,required"`
226240 // A chat completion message generated by the model.
227241 Message ChatCompletionMessage `json:"message,required"`
228− // Metadata for the response, check the presence of optional fields with the
229− // [resp.Field.IsPresent] method.
242+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
230243 JSON struct {
231− FinishReason resp.Field
232− Index resp.Field
233− Logprobs resp.Field
234− Message resp.Field
235− ExtraFields map[string]resp.Field
244+ FinishReason respjson.Field
245+ Index respjson.Field
246+ Logprobs respjson.Field
247+ Message respjson.Field
248+ ExtraFields map[string]respjson.Field
236249 raw string
237250 } `json:"-"`
238251}
@@ -249,12 +262,11 @@ type ChatCompletionChoiceLogprobs struct {
249262 Content []ChatCompletionTokenLogprob `json:"content,required"`
250263 // A list of message refusal tokens with log probability information.
251264 Refusal []ChatCompletionTokenLogprob `json:"refusal,required"`
252− // Metadata for the response, check the presence of optional fields with the
253− // [resp.Field.IsPresent] method.
265+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
254266 JSON struct {
255− Content resp.Field
256− Refusal resp.Field
257− ExtraFields map[string]resp.Field
267+ Content respjson.Field
268+ Refusal respjson.Field
269+ ExtraFields map[string]respjson.Field
258270 raw string
259271 } `json:"-"`
260272}
@@ -265,12 +277,31 @@ func (r *ChatCompletionChoiceLogprobs) UnmarshalJSON(data []byte) error {
265277 return apijson.UnmarshalRoot(data, r)
266278}
267279
268−// The service tier used for processing the request.
280+// Specifies the processing type used for serving the request.
281+//
282+// - If set to 'auto', then the request will be processed with the service tier
283+// configured in the Project settings. Unless otherwise configured, the Project
284+// will use 'default'.
285+// - If set to 'default', then the requset will be processed with the standard
286+// pricing and performance for the selected model.
287+// - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or
288+// 'priority', then the request will be processed with the corresponding service
289+// tier. [Contact sales](https://openai.com/contact-sales) to learn more about
290+// Priority processing.
291+// - When not set, the default behavior is 'auto'.
292+//
293+// When the `service_tier` parameter is set, the response body will include the
294+// `service_tier` value based on the processing mode actually used to serve the
295+// request. This response value may be different from the value set in the
296+// parameter.
269297type ChatCompletionServiceTier string
270298
271299const (
272− ChatCompletionServiceTierScale ChatCompletionServiceTier = "scale"
273− ChatCompletionServiceTierDefault ChatCompletionServiceTier = "default"
300+ ChatCompletionServiceTierAuto ChatCompletionServiceTier = "auto"
301+ ChatCompletionServiceTierDefault ChatCompletionServiceTier = "default"
302+ ChatCompletionServiceTierFlex ChatCompletionServiceTier = "flex"
303+ ChatCompletionServiceTierScale ChatCompletionServiceTier = "scale"
304+ ChatCompletionServiceTierPriority ChatCompletionServiceTier = "priority"
274305)
275306
276307// Messages sent by the model in response to user messages.
@@ -302,15 +333,13 @@ type ChatCompletionAssistantMessageParam struct {
302333 paramObj
303334}
304335
305−// IsPresent returns true if the field's value is not omitted and not the JSON
306−// "null". To check if this field is omitted, use [param.IsOmitted].
307−func (f ChatCompletionAssistantMessageParam) IsPresent() bool {
308− return !param.IsOmitted(f) && !f.IsNull()
309−}
310336func (r ChatCompletionAssistantMessageParam) MarshalJSON() (data []byte, err error) {
311337 type shadow ChatCompletionAssistantMessageParam
312338 return param.MarshalObject(r, (*shadow)(&r))
313339}
340+func (r *ChatCompletionAssistantMessageParam) UnmarshalJSON(data []byte) error {
341+ return apijson.UnmarshalRoot(data, r)
342+}
314343
315344// Data about a previous audio response from the model.
316345// [Learn more](https://platform.openai.com/docs/guides/audio).
@@ -322,15 +351,13 @@ type ChatCompletionAssistantMessageParamAudio struct {
322351 paramObj
323352}
324353
325−// IsPresent returns true if the field's value is not omitted and not the JSON
326−// "null". To check if this field is omitted, use [param.IsOmitted].
327−func (f ChatCompletionAssistantMessageParamAudio) IsPresent() bool {
328− return !param.IsOmitted(f) && !f.IsNull()
329−}
330354func (r ChatCompletionAssistantMessageParamAudio) MarshalJSON() (data []byte, err error) {
331355 type shadow ChatCompletionAssistantMessageParamAudio
332356 return param.MarshalObject(r, (*shadow)(&r))
333357}
358+func (r *ChatCompletionAssistantMessageParamAudio) UnmarshalJSON(data []byte) error {
359+ return apijson.UnmarshalRoot(data, r)
360+}
334361
335362// Only one field can be non-zero.
336363//
@@ -341,13 +368,11 @@ type ChatCompletionAssistantMessageParamContentUnion struct {
341368 paramUnion
342369}
343370
344−// IsPresent returns true if the field's value is not omitted and not the JSON
345−// "null". To check if this field is omitted, use [param.IsOmitted].
346−func (u ChatCompletionAssistantMessageParamContentUnion) IsPresent() bool {
347− return !param.IsOmitted(u) && !u.IsNull()
348−}
349371func (u ChatCompletionAssistantMessageParamContentUnion) MarshalJSON() ([]byte, error) {
350− return param.MarshalUnion[ChatCompletionAssistantMessageParamContentUnion](u.OfString, u.OfArrayOfContentParts)
372+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
373+}
374+func (u *ChatCompletionAssistantMessageParamContentUnion) UnmarshalJSON(data []byte) error {
375+ return apijson.UnmarshalRoot(data, u)
351376}
352377
353378func (u *ChatCompletionAssistantMessageParamContentUnion) asAny() any {
@@ -368,13 +393,11 @@ type ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion struct {
368393 paramUnion
369394}
370395
371−// IsPresent returns true if the field's value is not omitted and not the JSON
372−// "null". To check if this field is omitted, use [param.IsOmitted].
373−func (u ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion) IsPresent() bool {
374− return !param.IsOmitted(u) && !u.IsNull()
375−}
376396func (u ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion) MarshalJSON() ([]byte, error) {
377− return param.MarshalUnion[ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion](u.OfText, u.OfRefusal)
397+ return param.MarshalUnion(u, u.OfText, u.OfRefusal)
398+}
399+func (u *ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion) UnmarshalJSON(data []byte) error {
400+ return apijson.UnmarshalRoot(data, u)
378401}
379402
380403func (u *ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion) asAny() any {
@@ -415,16 +438,8 @@ func (u ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion) GetTy
415438func init() {
416439 apijson.RegisterUnion[ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion](
417440 "type",
418− apijson.UnionVariant{
419− TypeFilter: gjson.JSON,
420− Type: reflect.TypeOf(ChatCompletionContentPartTextParam{}),
421− DiscriminatorValue: "text",
422− },
423− apijson.UnionVariant{
424− TypeFilter: gjson.JSON,
425− Type: reflect.TypeOf(ChatCompletionContentPartRefusalParam{}),
426− DiscriminatorValue: "refusal",
427− },
441+ apijson.Discriminator[ChatCompletionContentPartTextParam]("text"),
442+ apijson.Discriminator[ChatCompletionContentPartRefusalParam]("refusal"),
428443 )
429444}
430445
@@ -445,15 +460,13 @@ type ChatCompletionAssistantMessageParamFunctionCall struct {
445460 paramObj
446461}
447462
448−// IsPresent returns true if the field's value is not omitted and not the JSON
449−// "null". To check if this field is omitted, use [param.IsOmitted].
450−func (f ChatCompletionAssistantMessageParamFunctionCall) IsPresent() bool {
451− return !param.IsOmitted(f) && !f.IsNull()
452−}
453463func (r ChatCompletionAssistantMessageParamFunctionCall) MarshalJSON() (data []byte, err error) {
454464 type shadow ChatCompletionAssistantMessageParamFunctionCall
455465 return param.MarshalObject(r, (*shadow)(&r))
456466}
467+func (r *ChatCompletionAssistantMessageParamFunctionCall) UnmarshalJSON(data []byte) error {
468+ return apijson.UnmarshalRoot(data, r)
469+}
457470
458471// If the audio output modality is requested, this object contains data about the
459472// audio response from the model.
@@ -469,14 +482,13 @@ type ChatCompletionAudio struct {
469482 ExpiresAt int64 `json:"expires_at,required"`
470483 // Transcript of the audio generated by the model.
471484 Transcript string `json:"transcript,required"`
472− // Metadata for the response, check the presence of optional fields with the
473− // [resp.Field.IsPresent] method.
485+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
474486 JSON struct {
475− ID resp.Field
476− Data resp.Field
477− ExpiresAt resp.Field
478− Transcript resp.Field
479− ExtraFields map[string]resp.Field
487+ ID respjson.Field
488+ Data respjson.Field
489+ ExpiresAt respjson.Field
490+ Transcript respjson.Field
491+ ExtraFields map[string]respjson.Field
480492 raw string
481493 } `json:"-"`
482494}
@@ -496,23 +508,21 @@ type ChatCompletionAudioParam struct {
496508 // Specifies the output audio format. Must be one of `wav`, `mp3`, `flac`, `opus`,
497509 // or `pcm16`.
498510 //
499− // Any of "wav", "mp3", "flac", "opus", "pcm16".
511+ // Any of "wav", "aac", "mp3", "flac", "opus", "pcm16".
500512 Format ChatCompletionAudioParamFormat `json:"format,omitzero,required"`
501513 // The voice the model uses to respond. Supported voices are `alloy`, `ash`,
502− // `ballad`, `coral`, `echo`, `sage`, and `shimmer`.
503− //
504− // Any of "alloy", "ash", "ballad", "coral", "echo", "sage", "shimmer", "verse".
514+ // `ballad`, `coral`, `echo`, `fable`, `nova`, `onyx`, `sage`, and `shimmer`.
505515 Voice ChatCompletionAudioParamVoice `json:"voice,omitzero,required"`
506516 paramObj
507517}
508518
509−// IsPresent returns true if the field's value is not omitted and not the JSON
510−// "null". To check if this field is omitted, use [param.IsOmitted].
511−func (f ChatCompletionAudioParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
512519func (r ChatCompletionAudioParam) MarshalJSON() (data []byte, err error) {
513520 type shadow ChatCompletionAudioParam
514521 return param.MarshalObject(r, (*shadow)(&r))
515522}
523+func (r *ChatCompletionAudioParam) UnmarshalJSON(data []byte) error {
524+ return apijson.UnmarshalRoot(data, r)
525+}
516526
517527// Specifies the output audio format. Must be one of `wav`, `mp3`, `flac`, `opus`,
518528// or `pcm16`.
@@ -520,6 +530,7 @@ type ChatCompletionAudioParamFormat string
520530
521531const (
522532 ChatCompletionAudioParamFormatWAV ChatCompletionAudioParamFormat = "wav"
533+ ChatCompletionAudioParamFormatAAC ChatCompletionAudioParamFormat = "aac"
523534 ChatCompletionAudioParamFormatMP3 ChatCompletionAudioParamFormat = "mp3"
524535 ChatCompletionAudioParamFormatFLAC ChatCompletionAudioParamFormat = "flac"
525536 ChatCompletionAudioParamFormatOpus ChatCompletionAudioParamFormat = "opus"
@@ -527,7 +538,7 @@ const (
527538)
528539
529540// The voice the model uses to respond. Supported voices are `alloy`, `ash`,
530−// `ballad`, `coral`, `echo`, `sage`, and `shimmer`.
541+// `ballad`, `coral`, `echo`, `fable`, `nova`, `onyx`, `sage`, and `shimmer`.
531542type ChatCompletionAudioParamVoice string
532543
533544const (
@@ -536,6 +547,9 @@ const (
536547 ChatCompletionAudioParamVoiceBallad ChatCompletionAudioParamVoice = "ballad"
537548 ChatCompletionAudioParamVoiceCoral ChatCompletionAudioParamVoice = "coral"
538549 ChatCompletionAudioParamVoiceEcho ChatCompletionAudioParamVoice = "echo"
550+ ChatCompletionAudioParamVoiceFable ChatCompletionAudioParamVoice = "fable"
551+ ChatCompletionAudioParamVoiceOnyx ChatCompletionAudioParamVoice = "onyx"
552+ ChatCompletionAudioParamVoiceNova ChatCompletionAudioParamVoice = "nova"
539553 ChatCompletionAudioParamVoiceSage ChatCompletionAudioParamVoice = "sage"
540554 ChatCompletionAudioParamVoiceShimmer ChatCompletionAudioParamVoice = "shimmer"
541555 ChatCompletionAudioParamVoiceVerse ChatCompletionAudioParamVoice = "verse"
@@ -558,9 +572,25 @@ type ChatCompletionChunk struct {
558572 Model string `json:"model,required"`
559573 // The object type, which is always `chat.completion.chunk`.
560574 Object constant.ChatCompletionChunk `json:"object,required"`
561− // The service tier used for processing the request.
575+ // Specifies the processing type used for serving the request.
576+ //
577+ // - If set to 'auto', then the request will be processed with the service tier
578+ // configured in the Project settings. Unless otherwise configured, the Project
579+ // will use 'default'.
580+ // - If set to 'default', then the requset will be processed with the standard
581+ // pricing and performance for the selected model.
582+ // - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or
583+ // 'priority', then the request will be processed with the corresponding service
584+ // tier. [Contact sales](https://openai.com/contact-sales) to learn more about
585+ // Priority processing.
586+ // - When not set, the default behavior is 'auto'.
587+ //
588+ // When the `service_tier` parameter is set, the response body will include the
589+ // `service_tier` value based on the processing mode actually used to serve the
590+ // request. This response value may be different from the value set in the
591+ // parameter.
562592 //
563− // Any of "scale", "default".
593+ // Any of "auto", "default", "flex", "scale", "priority".
564594 ServiceTier ChatCompletionChunkServiceTier `json:"service_tier,nullable"`
565595 // This fingerprint represents the backend configuration that the model runs with.
566596 // Can be used in conjunction with the `seed` request parameter to understand when
@@ -574,18 +604,17 @@ type ChatCompletionChunk struct {
574604 // **NOTE:** If the stream is interrupted or cancelled, you may not receive the
575605 // final usage chunk which contains the total token usage for the request.
576606 Usage CompletionUsage `json:"usage,nullable"`
577− // Metadata for the response, check the presence of optional fields with the
578− // [resp.Field.IsPresent] method.
607+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
579608 JSON struct {
580− ID resp.Field
581− Choices resp.Field
582− Created resp.Field
583− Model resp.Field
584− Object resp.Field
585− ServiceTier resp.Field
586− SystemFingerprint resp.Field
587− Usage resp.Field
588− ExtraFields map[string]resp.Field
609+ ID respjson.Field
610+ Choices respjson.Field
611+ Created respjson.Field
612+ Model respjson.Field
613+ Object respjson.Field
614+ ServiceTier respjson.Field
615+ SystemFingerprint respjson.Field
616+ Usage respjson.Field
617+ ExtraFields map[string]respjson.Field
589618 raw string
590619 } `json:"-"`
591620}
@@ -612,14 +641,13 @@ type ChatCompletionChunkChoice struct {
612641 Index int64 `json:"index,required"`
613642 // Log probability information for the choice.
614643 Logprobs ChatCompletionChunkChoiceLogprobs `json:"logprobs,nullable"`
615− // Metadata for the response, check the presence of optional fields with the
616− // [resp.Field.IsPresent] method.
644+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
617645 JSON struct {
618− Delta resp.Field
619− FinishReason resp.Field
620− Index resp.Field
621− Logprobs resp.Field
622− ExtraFields map[string]resp.Field
646+ Delta respjson.Field
647+ FinishReason respjson.Field
648+ Index respjson.Field
649+ Logprobs respjson.Field
650+ ExtraFields map[string]respjson.Field
623651 raw string
624652 } `json:"-"`
625653}
@@ -646,15 +674,14 @@ type ChatCompletionChunkChoiceDelta struct {
646674 // Any of "developer", "system", "user", "assistant", "tool".
647675 Role string `json:"role"`
648676 ToolCalls []ChatCompletionChunkChoiceDeltaToolCall `json:"tool_calls"`
649− // Metadata for the response, check the presence of optional fields with the
650− // [resp.Field.IsPresent] method.
677+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
651678 JSON struct {
652− Content resp.Field
653− FunctionCall resp.Field
654− Refusal resp.Field
655− Role resp.Field
656− ToolCalls resp.Field
657− ExtraFields map[string]resp.Field
679+ Content respjson.Field
680+ FunctionCall respjson.Field
681+ Refusal respjson.Field
682+ Role respjson.Field
683+ ToolCalls respjson.Field
684+ ExtraFields map[string]respjson.Field
658685 raw string
659686 } `json:"-"`
660687}
@@ -677,12 +704,11 @@ type ChatCompletionChunkChoiceDeltaFunctionCall struct {
677704 Arguments string `json:"arguments"`
678705 // The name of the function to call.
679706 Name string `json:"name"`
680− // Metadata for the response, check the presence of optional fields with the
681− // [resp.Field.IsPresent] method.
707+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
682708 JSON struct {
683− Arguments resp.Field
684− Name resp.Field
685− ExtraFields map[string]resp.Field
709+ Arguments respjson.Field
710+ Name respjson.Field
711+ ExtraFields map[string]respjson.Field
686712 raw string
687713 } `json:"-"`
688714}
@@ -702,14 +728,13 @@ type ChatCompletionChunkChoiceDeltaToolCall struct {
702728 //
703729 // Any of "function".
704730 Type string `json:"type"`
705− // Metadata for the response, check the presence of optional fields with the
706− // [resp.Field.IsPresent] method.
731+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
707732 JSON struct {
708− Index resp.Field
709− ID resp.Field
710− Function resp.Field
711− Type resp.Field
712− ExtraFields map[string]resp.Field
733+ Index respjson.Field
734+ ID respjson.Field
735+ Function respjson.Field
736+ Type respjson.Field
737+ ExtraFields map[string]respjson.Field
713738 raw string
714739 } `json:"-"`
715740}
@@ -728,12 +753,11 @@ type ChatCompletionChunkChoiceDeltaToolCallFunction struct {
728753 Arguments string `json:"arguments"`
729754 // The name of the function to call.
730755 Name string `json:"name"`
731− // Metadata for the response, check the presence of optional fields with the
732− // [resp.Field.IsPresent] method.
756+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
733757 JSON struct {
734− Arguments resp.Field
735− Name resp.Field
736− ExtraFields map[string]resp.Field
758+ Arguments respjson.Field
759+ Name respjson.Field
760+ ExtraFields map[string]respjson.Field
737761 raw string
738762 } `json:"-"`
739763}
@@ -750,12 +774,11 @@ type ChatCompletionChunkChoiceLogprobs struct {
750774 Content []ChatCompletionTokenLogprob `json:"content,required"`
751775 // A list of message refusal tokens with log probability information.
752776 Refusal []ChatCompletionTokenLogprob `json:"refusal,required"`
753− // Metadata for the response, check the presence of optional fields with the
754− // [resp.Field.IsPresent] method.
777+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
755778 JSON struct {
756− Content resp.Field
757− Refusal resp.Field
758− ExtraFields map[string]resp.Field
779+ Content respjson.Field
780+ Refusal respjson.Field
781+ ExtraFields map[string]respjson.Field
759782 raw string
760783 } `json:"-"`
761784}
@@ -766,12 +789,31 @@ func (r *ChatCompletionChunkChoiceLogprobs) UnmarshalJSON(data []byte) error {
766789 return apijson.UnmarshalRoot(data, r)
767790}
768791
769−// The service tier used for processing the request.
792+// Specifies the processing type used for serving the request.
793+//
794+// - If set to 'auto', then the request will be processed with the service tier
795+// configured in the Project settings. Unless otherwise configured, the Project
796+// will use 'default'.
797+// - If set to 'default', then the requset will be processed with the standard
798+// pricing and performance for the selected model.
799+// - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or
800+// 'priority', then the request will be processed with the corresponding service
801+// tier. [Contact sales](https://openai.com/contact-sales) to learn more about
802+// Priority processing.
803+// - When not set, the default behavior is 'auto'.
804+//
805+// When the `service_tier` parameter is set, the response body will include the
806+// `service_tier` value based on the processing mode actually used to serve the
807+// request. This response value may be different from the value set in the
808+// parameter.
770809type ChatCompletionChunkServiceTier string
771810
772811const (
773− ChatCompletionChunkServiceTierScale ChatCompletionChunkServiceTier = "scale"
774− ChatCompletionChunkServiceTierDefault ChatCompletionChunkServiceTier = "default"
812+ ChatCompletionChunkServiceTierAuto ChatCompletionChunkServiceTier = "auto"
813+ ChatCompletionChunkServiceTierDefault ChatCompletionChunkServiceTier = "default"
814+ ChatCompletionChunkServiceTierFlex ChatCompletionChunkServiceTier = "flex"
815+ ChatCompletionChunkServiceTierScale ChatCompletionChunkServiceTier = "scale"
816+ ChatCompletionChunkServiceTierPriority ChatCompletionChunkServiceTier = "priority"
775817)
776818
777819func TextContentPart(text string) ChatCompletionContentPartUnionParam {
@@ -809,13 +851,11 @@ type ChatCompletionContentPartUnionParam struct {
809851 paramUnion
810852}
811853
812−// IsPresent returns true if the field's value is not omitted and not the JSON
813−// "null". To check if this field is omitted, use [param.IsOmitted].
814−func (u ChatCompletionContentPartUnionParam) IsPresent() bool {
815− return !param.IsOmitted(u) && !u.IsNull()
816−}
817854func (u ChatCompletionContentPartUnionParam) MarshalJSON() ([]byte, error) {
818− return param.MarshalUnion[ChatCompletionContentPartUnionParam](u.OfText, u.OfImageURL, u.OfInputAudio, u.OfFile)
855+ return param.MarshalUnion(u, u.OfText, u.OfImageURL, u.OfInputAudio, u.OfFile)
856+}
857+func (u *ChatCompletionContentPartUnionParam) UnmarshalJSON(data []byte) error {
858+ return apijson.UnmarshalRoot(data, u)
819859}
820860
821861func (u *ChatCompletionContentPartUnionParam) asAny() any {
@@ -880,26 +920,10 @@ func (u ChatCompletionContentPartUnionParam) GetType() *string {
880920func init() {
881921 apijson.RegisterUnion[ChatCompletionContentPartUnionParam](
882922 "type",
883− apijson.UnionVariant{
884− TypeFilter: gjson.JSON,
885− Type: reflect.TypeOf(ChatCompletionContentPartTextParam{}),
886− DiscriminatorValue: "text",
887− },
888− apijson.UnionVariant{
889− TypeFilter: gjson.JSON,
890− Type: reflect.TypeOf(ChatCompletionContentPartImageParam{}),
891− DiscriminatorValue: "image_url",
892− },
893− apijson.UnionVariant{
894− TypeFilter: gjson.JSON,
895− Type: reflect.TypeOf(ChatCompletionContentPartInputAudioParam{}),
896− DiscriminatorValue: "input_audio",
897− },
898− apijson.UnionVariant{
899− TypeFilter: gjson.JSON,
900− Type: reflect.TypeOf(ChatCompletionContentPartFileParam{}),
901− DiscriminatorValue: "file",
902− },
923+ apijson.Discriminator[ChatCompletionContentPartTextParam]("text"),
924+ apijson.Discriminator[ChatCompletionContentPartImageParam]("image_url"),
925+ apijson.Discriminator[ChatCompletionContentPartInputAudioParam]("input_audio"),
926+ apijson.Discriminator[ChatCompletionContentPartFileParam]("file"),
903927 )
904928}
905929
@@ -916,15 +940,13 @@ type ChatCompletionContentPartFileParam struct {
916940 paramObj
917941}
918942
919−// IsPresent returns true if the field's value is not omitted and not the JSON
920−// "null". To check if this field is omitted, use [param.IsOmitted].
921−func (f ChatCompletionContentPartFileParam) IsPresent() bool {
922− return !param.IsOmitted(f) && !f.IsNull()
923−}
924943func (r ChatCompletionContentPartFileParam) MarshalJSON() (data []byte, err error) {
925944 type shadow ChatCompletionContentPartFileParam
926945 return param.MarshalObject(r, (*shadow)(&r))
927946}
947+func (r *ChatCompletionContentPartFileParam) UnmarshalJSON(data []byte) error {
948+ return apijson.UnmarshalRoot(data, r)
949+}
928950
929951type ChatCompletionContentPartFileFileParam struct {
930952 // The base64 encoded file data, used when passing the file to the model as a
@@ -937,15 +959,13 @@ type ChatCompletionContentPartFileFileParam struct {
937959 paramObj
938960}
939961
940−// IsPresent returns true if the field's value is not omitted and not the JSON
941−// "null". To check if this field is omitted, use [param.IsOmitted].
942−func (f ChatCompletionContentPartFileFileParam) IsPresent() bool {
943− return !param.IsOmitted(f) && !f.IsNull()
944−}
945962func (r ChatCompletionContentPartFileFileParam) MarshalJSON() (data []byte, err error) {
946963 type shadow ChatCompletionContentPartFileFileParam
947964 return param.MarshalObject(r, (*shadow)(&r))
948965}
966+func (r *ChatCompletionContentPartFileFileParam) UnmarshalJSON(data []byte) error {
967+ return apijson.UnmarshalRoot(data, r)
968+}
949969
950970// Learn about [image inputs](https://platform.openai.com/docs/guides/vision).
951971//
@@ -959,15 +979,13 @@ type ChatCompletionContentPartImageParam struct {
959979 paramObj
960980}
961981
962−// IsPresent returns true if the field's value is not omitted and not the JSON
963−// "null". To check if this field is omitted, use [param.IsOmitted].
964−func (f ChatCompletionContentPartImageParam) IsPresent() bool {
965− return !param.IsOmitted(f) && !f.IsNull()
966−}
967982func (r ChatCompletionContentPartImageParam) MarshalJSON() (data []byte, err error) {
968983 type shadow ChatCompletionContentPartImageParam
969984 return param.MarshalObject(r, (*shadow)(&r))
970985}
986+func (r *ChatCompletionContentPartImageParam) UnmarshalJSON(data []byte) error {
987+ return apijson.UnmarshalRoot(data, r)
988+}
971989
972990// The property URL is required.
973991type ChatCompletionContentPartImageImageURLParam struct {
@@ -981,19 +999,17 @@ type ChatCompletionContentPartImageImageURLParam struct {
981999 paramObj
9821000}
9831001
984−// IsPresent returns true if the field's value is not omitted and not the JSON
985−// "null". To check if this field is omitted, use [param.IsOmitted].
986−func (f ChatCompletionContentPartImageImageURLParam) IsPresent() bool {
987− return !param.IsOmitted(f) && !f.IsNull()
988−}
9891002func (r ChatCompletionContentPartImageImageURLParam) MarshalJSON() (data []byte, err error) {
9901003 type shadow ChatCompletionContentPartImageImageURLParam
9911004 return param.MarshalObject(r, (*shadow)(&r))
9921005}
1006+func (r *ChatCompletionContentPartImageImageURLParam) UnmarshalJSON(data []byte) error {
1007+ return apijson.UnmarshalRoot(data, r)
1008+}
9931009
9941010func init() {
9951011 apijson.RegisterFieldValidator[ChatCompletionContentPartImageImageURLParam](
996− "Detail", false, "auto", "low", "high",
1012+ "detail", "auto", "low", "high",
9971013 )
9981014}
9991015
@@ -1009,15 +1025,13 @@ type ChatCompletionContentPartInputAudioParam struct {
10091025 paramObj
10101026}
10111027
1012−// IsPresent returns true if the field's value is not omitted and not the JSON
1013−// "null". To check if this field is omitted, use [param.IsOmitted].
1014−func (f ChatCompletionContentPartInputAudioParam) IsPresent() bool {
1015− return !param.IsOmitted(f) && !f.IsNull()
1016−}
10171028func (r ChatCompletionContentPartInputAudioParam) MarshalJSON() (data []byte, err error) {
10181029 type shadow ChatCompletionContentPartInputAudioParam
10191030 return param.MarshalObject(r, (*shadow)(&r))
10201031}
1032+func (r *ChatCompletionContentPartInputAudioParam) UnmarshalJSON(data []byte) error {
1033+ return apijson.UnmarshalRoot(data, r)
1034+}
10211035
10221036// The properties Data, Format are required.
10231037type ChatCompletionContentPartInputAudioInputAudioParam struct {
@@ -1030,19 +1044,17 @@ type ChatCompletionContentPartInputAudioInputAudioParam struct {
10301044 paramObj
10311045}
10321046
1033−// IsPresent returns true if the field's value is not omitted and not the JSON
1034−// "null". To check if this field is omitted, use [param.IsOmitted].
1035−func (f ChatCompletionContentPartInputAudioInputAudioParam) IsPresent() bool {
1036− return !param.IsOmitted(f) && !f.IsNull()
1037−}
10381047func (r ChatCompletionContentPartInputAudioInputAudioParam) MarshalJSON() (data []byte, err error) {
10391048 type shadow ChatCompletionContentPartInputAudioInputAudioParam
10401049 return param.MarshalObject(r, (*shadow)(&r))
10411050}
1051+func (r *ChatCompletionContentPartInputAudioInputAudioParam) UnmarshalJSON(data []byte) error {
1052+ return apijson.UnmarshalRoot(data, r)
1053+}
10421054
10431055func init() {
10441056 apijson.RegisterFieldValidator[ChatCompletionContentPartInputAudioInputAudioParam](
1045− "Format", false, "wav", "mp3",
1057+ "format", "wav", "mp3",
10461058 )
10471059}
10481060
@@ -1057,15 +1069,13 @@ type ChatCompletionContentPartRefusalParam struct {
10571069 paramObj
10581070}
10591071
1060−// IsPresent returns true if the field's value is not omitted and not the JSON
1061−// "null". To check if this field is omitted, use [param.IsOmitted].
1062−func (f ChatCompletionContentPartRefusalParam) IsPresent() bool {
1063− return !param.IsOmitted(f) && !f.IsNull()
1064−}
10651072func (r ChatCompletionContentPartRefusalParam) MarshalJSON() (data []byte, err error) {
10661073 type shadow ChatCompletionContentPartRefusalParam
10671074 return param.MarshalObject(r, (*shadow)(&r))
10681075}
1076+func (r *ChatCompletionContentPartRefusalParam) UnmarshalJSON(data []byte) error {
1077+ return apijson.UnmarshalRoot(data, r)
1078+}
10691079
10701080// Learn about
10711081// [text inputs](https://platform.openai.com/docs/guides/text-generation).
@@ -1081,15 +1091,13 @@ type ChatCompletionContentPartTextParam struct {
10811091 paramObj
10821092}
10831093
1084−// IsPresent returns true if the field's value is not omitted and not the JSON
1085−// "null". To check if this field is omitted, use [param.IsOmitted].
1086−func (f ChatCompletionContentPartTextParam) IsPresent() bool {
1087− return !param.IsOmitted(f) && !f.IsNull()
1088−}
10891094func (r ChatCompletionContentPartTextParam) MarshalJSON() (data []byte, err error) {
10901095 type shadow ChatCompletionContentPartTextParam
10911096 return param.MarshalObject(r, (*shadow)(&r))
10921097}
1098+func (r *ChatCompletionContentPartTextParam) UnmarshalJSON(data []byte) error {
1099+ return apijson.UnmarshalRoot(data, r)
1100+}
10931101
10941102type ChatCompletionDeleted struct {
10951103 // The ID of the chat completion that was deleted.
@@ -1098,13 +1106,12 @@ type ChatCompletionDeleted struct {
10981106 Deleted bool `json:"deleted,required"`
10991107 // The type of object being deleted.
11001108 Object constant.ChatCompletionDeleted `json:"object,required"`
1101− // Metadata for the response, check the presence of optional fields with the
1102− // [resp.Field.IsPresent] method.
1109+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
11031110 JSON struct {
1104− ID resp.Field
1105− Deleted resp.Field
1106− Object resp.Field
1107− ExtraFields map[string]resp.Field
1111+ ID respjson.Field
1112+ Deleted respjson.Field
1113+ Object respjson.Field
1114+ ExtraFields map[string]respjson.Field
11081115 raw string
11091116 } `json:"-"`
11101117}
@@ -1133,15 +1140,13 @@ type ChatCompletionDeveloperMessageParam struct {
11331140 paramObj
11341141}
11351142
1136−// IsPresent returns true if the field's value is not omitted and not the JSON
1137−// "null". To check if this field is omitted, use [param.IsOmitted].
1138−func (f ChatCompletionDeveloperMessageParam) IsPresent() bool {
1139− return !param.IsOmitted(f) && !f.IsNull()
1140−}
11411143func (r ChatCompletionDeveloperMessageParam) MarshalJSON() (data []byte, err error) {
11421144 type shadow ChatCompletionDeveloperMessageParam
11431145 return param.MarshalObject(r, (*shadow)(&r))
11441146}
1147+func (r *ChatCompletionDeveloperMessageParam) UnmarshalJSON(data []byte) error {
1148+ return apijson.UnmarshalRoot(data, r)
1149+}
11451150
11461151// Only one field can be non-zero.
11471152//
@@ -1152,13 +1157,11 @@ type ChatCompletionDeveloperMessageParamContentUnion struct {
11521157 paramUnion
11531158}
11541159
1155−// IsPresent returns true if the field's value is not omitted and not the JSON
1156−// "null". To check if this field is omitted, use [param.IsOmitted].
1157−func (u ChatCompletionDeveloperMessageParamContentUnion) IsPresent() bool {
1158− return !param.IsOmitted(u) && !u.IsNull()
1159−}
11601160func (u ChatCompletionDeveloperMessageParamContentUnion) MarshalJSON() ([]byte, error) {
1161− return param.MarshalUnion[ChatCompletionDeveloperMessageParamContentUnion](u.OfString, u.OfArrayOfContentParts)
1161+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
1162+}
1163+func (u *ChatCompletionDeveloperMessageParamContentUnion) UnmarshalJSON(data []byte) error {
1164+ return apijson.UnmarshalRoot(data, u)
11621165}
11631166
11641167func (u *ChatCompletionDeveloperMessageParamContentUnion) asAny() any {
@@ -1180,15 +1183,13 @@ type ChatCompletionFunctionCallOptionParam struct {
11801183 paramObj
11811184}
11821185
1183−// IsPresent returns true if the field's value is not omitted and not the JSON
1184−// "null". To check if this field is omitted, use [param.IsOmitted].
1185−func (f ChatCompletionFunctionCallOptionParam) IsPresent() bool {
1186− return !param.IsOmitted(f) && !f.IsNull()
1187−}
11881186func (r ChatCompletionFunctionCallOptionParam) MarshalJSON() (data []byte, err error) {
11891187 type shadow ChatCompletionFunctionCallOptionParam
11901188 return param.MarshalObject(r, (*shadow)(&r))
11911189}
1190+func (r *ChatCompletionFunctionCallOptionParam) UnmarshalJSON(data []byte) error {
1191+ return apijson.UnmarshalRoot(data, r)
1192+}
11921193
11931194// Deprecated: deprecated
11941195//
@@ -1205,15 +1206,13 @@ type ChatCompletionFunctionMessageParam struct {
12051206 paramObj
12061207}
12071208
1208−// IsPresent returns true if the field's value is not omitted and not the JSON
1209−// "null". To check if this field is omitted, use [param.IsOmitted].
1210−func (f ChatCompletionFunctionMessageParam) IsPresent() bool {
1211− return !param.IsOmitted(f) && !f.IsNull()
1212−}
12131209func (r ChatCompletionFunctionMessageParam) MarshalJSON() (data []byte, err error) {
12141210 type shadow ChatCompletionFunctionMessageParam
12151211 return param.MarshalObject(r, (*shadow)(&r))
12161212}
1213+func (r *ChatCompletionFunctionMessageParam) UnmarshalJSON(data []byte) error {
1214+ return apijson.UnmarshalRoot(data, r)
1215+}
12171216
12181217// A chat completion message generated by the model.
12191218type ChatCompletionMessage struct {
@@ -1237,17 +1236,16 @@ type ChatCompletionMessage struct {
12371236 FunctionCall ChatCompletionMessageFunctionCall `json:"function_call"`
12381237 // The tool calls generated by the model, such as function calls.
12391238 ToolCalls []ChatCompletionMessageToolCall `json:"tool_calls"`
1240− // Metadata for the response, check the presence of optional fields with the
1241− // [resp.Field.IsPresent] method.
1239+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
12421240 JSON struct {
1243− Content resp.Field
1244− Refusal resp.Field
1245− Role resp.Field
1246− Annotations resp.Field
1247− Audio resp.Field
1248− FunctionCall resp.Field
1249− ToolCalls resp.Field
1250− ExtraFields map[string]resp.Field
1241+ Content respjson.Field
1242+ Refusal respjson.Field
1243+ Role respjson.Field
1244+ Annotations respjson.Field
1245+ Audio respjson.Field
1246+ FunctionCall respjson.Field
1247+ ToolCalls respjson.Field
1248+ ExtraFields map[string]respjson.Field
12511249 raw string
12521250 } `json:"-"`
12531251}
@@ -1300,12 +1298,11 @@ type ChatCompletionMessageAnnotation struct {
13001298 Type constant.URLCitation `json:"type,required"`
13011299 // A URL citation when using web search.
13021300 URLCitation ChatCompletionMessageAnnotationURLCitation `json:"url_citation,required"`
1303− // Metadata for the response, check the presence of optional fields with the
1304− // [resp.Field.IsPresent] method.
1301+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13051302 JSON struct {
1306− Type resp.Field
1307− URLCitation resp.Field
1308− ExtraFields map[string]resp.Field
1303+ Type respjson.Field
1304+ URLCitation respjson.Field
1305+ ExtraFields map[string]respjson.Field
13091306 raw string
13101307 } `json:"-"`
13111308}
@@ -1326,14 +1323,13 @@ type ChatCompletionMessageAnnotationURLCitation struct {
13261323 Title string `json:"title,required"`
13271324 // The URL of the web resource.
13281325 URL string `json:"url,required"`
1329− // Metadata for the response, check the presence of optional fields with the
1330− // [resp.Field.IsPresent] method.
1326+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13311327 JSON struct {
1332− EndIndex resp.Field
1333− StartIndex resp.Field
1334− Title resp.Field
1335− URL resp.Field
1336− ExtraFields map[string]resp.Field
1328+ EndIndex respjson.Field
1329+ StartIndex respjson.Field
1330+ Title respjson.Field
1331+ URL respjson.Field
1332+ ExtraFields map[string]respjson.Field
13371333 raw string
13381334 } `json:"-"`
13391335}
@@ -1356,12 +1352,11 @@ type ChatCompletionMessageFunctionCall struct {
13561352 Arguments string `json:"arguments,required"`
13571353 // The name of the function to call.
13581354 Name string `json:"name,required"`
1359− // Metadata for the response, check the presence of optional fields with the
1360− // [resp.Field.IsPresent] method.
1355+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
13611356 JSON struct {
1362− Arguments resp.Field
1363− Name resp.Field
1364− ExtraFields map[string]resp.Field
1357+ Arguments respjson.Field
1358+ Name respjson.Field
1359+ ExtraFields map[string]respjson.Field
13651360 raw string
13661361 } `json:"-"`
13671362}
@@ -1448,17 +1443,17 @@ type ChatCompletionMessageParamUnion struct {
14481443 paramUnion
14491444}
14501445
1451−// IsPresent returns true if the field's value is not omitted and not the JSON
1452−// "null". To check if this field is omitted, use [param.IsOmitted].
1453−func (u ChatCompletionMessageParamUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() }
14541446func (u ChatCompletionMessageParamUnion) MarshalJSON() ([]byte, error) {
1455− return param.MarshalUnion[ChatCompletionMessageParamUnion](u.OfDeveloper,
1447+ return param.MarshalUnion(u, u.OfDeveloper,
14561448 u.OfSystem,
14571449 u.OfUser,
14581450 u.OfAssistant,
14591451 u.OfTool,
14601452 u.OfFunction)
14611453}
1454+func (u *ChatCompletionMessageParamUnion) UnmarshalJSON(data []byte) error {
1455+ return apijson.UnmarshalRoot(data, u)
1456+}
14621457
14631458func (u *ChatCompletionMessageParamUnion) asAny() any {
14641459 if !param.IsOmitted(u.OfDeveloper) {
@@ -1495,7 +1490,7 @@ func (u ChatCompletionMessageParamUnion) GetFunctionCall() *ChatCompletionAssist
14951490
14961491// Returns a pointer to the underlying variant's property, if present.
14971492func (u ChatCompletionMessageParamUnion) GetRefusal() *string {
1498− if vt := u.OfAssistant; vt != nil && vt.Refusal.IsPresent() {
1493+ if vt := u.OfAssistant; vt != nil && vt.Refusal.Valid() {
14991494 return &vt.Refusal.Value
15001495 }
15011496 return nil
@@ -1537,13 +1532,13 @@ func (u ChatCompletionMessageParamUnion) GetRole() *string {
15371532
15381533// Returns a pointer to the underlying variant's property, if present.
15391534func (u ChatCompletionMessageParamUnion) GetName() *string {
1540− if vt := u.OfDeveloper; vt != nil && vt.Name.IsPresent() {
1535+ if vt := u.OfDeveloper; vt != nil && vt.Name.Valid() {
15411536 return &vt.Name.Value
1542− } else if vt := u.OfSystem; vt != nil && vt.Name.IsPresent() {
1537+ } else if vt := u.OfSystem; vt != nil && vt.Name.Valid() {
15431538 return &vt.Name.Value
1544− } else if vt := u.OfUser; vt != nil && vt.Name.IsPresent() {
1539+ } else if vt := u.OfUser; vt != nil && vt.Name.Valid() {
15451540 return &vt.Name.Value
1546− } else if vt := u.OfAssistant; vt != nil && vt.Name.IsPresent() {
1541+ } else if vt := u.OfAssistant; vt != nil && vt.Name.Valid() {
15471542 return &vt.Name.Value
15481543 } else if vt := u.OfFunction; vt != nil {
15491544 return (*string)(&vt.Name)
@@ -1556,32 +1551,25 @@ func (u ChatCompletionMessageParamUnion) GetName() *string {
15561551// Or use AsAny() to get the underlying value
15571552func (u ChatCompletionMessageParamUnion) GetContent() (res chatCompletionMessageParamUnionContent) {
15581553 if vt := u.OfDeveloper; vt != nil {
1559− res.ofChatCompletionDeveloperMessageContent = &vt.Content
1554+ res.any = vt.Content.asAny()
15601555 } else if vt := u.OfSystem; vt != nil {
1561− res.ofChatCompletionSystemMessageContent = &vt.Content
1556+ res.any = vt.Content.asAny()
15621557 } else if vt := u.OfUser; vt != nil {
1563− res.ofChatCompletionUserMessageContent = &vt.Content
1558+ res.any = vt.Content.asAny()
15641559 } else if vt := u.OfAssistant; vt != nil {
1565− res.ofChatCompletionAssistantMessageContent = &vt.Content
1560+ res.any = vt.Content.asAny()
15661561 } else if vt := u.OfTool; vt != nil {
1567− res.ofChatCompletionToolMessageContent = &vt.Content
1568− } else if vt := u.OfFunction; vt != nil && vt.Content.IsPresent() {
1569− res.ofString = &vt.Content.Value
1562+ res.any = vt.Content.asAny()
1563+ } else if vt := u.OfFunction; vt != nil && vt.Content.Valid() {
1564+ res.any = &vt.Content.Value
15701565 }
15711566 return
15721567}
15731568
1574−// Only one field can be non-zero.
1575−//
1576−// Use [param.IsOmitted] to confirm if a field is set.
1577−type chatCompletionMessageParamUnionContent struct {
1578− ofChatCompletionDeveloperMessageContent *ChatCompletionDeveloperMessageParamContentUnion
1579− ofChatCompletionSystemMessageContent *ChatCompletionSystemMessageParamContentUnion
1580− ofChatCompletionUserMessageContent *ChatCompletionUserMessageParamContentUnion
1581− ofChatCompletionAssistantMessageContent *ChatCompletionAssistantMessageParamContentUnion
1582− ofChatCompletionToolMessageContent *ChatCompletionToolMessageParamContentUnion
1583− ofString *string
1584−}
1569+// Can have the runtime types [*string], [_[]ChatCompletionContentPartTextParam],
1570+// [_[]ChatCompletionContentPartUnionParam],
1571+// [\*[]ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion]
1572+type chatCompletionMessageParamUnionContent struct{ any }
15851573
15861574// Use the following switch statement to get the type of the union:
15871575//
@@ -1593,56 +1581,17 @@ type chatCompletionMessageParamUnionContent struct {
15931581// default:
15941582// fmt.Errorf("not present")
15951583// }
1596−func (u chatCompletionMessageParamUnionContent) AsAny() any {
1597− if !param.IsOmitted(u.ofChatCompletionDeveloperMessageContent) {
1598− return u.ofChatCompletionDeveloperMessageContent.asAny()
1599− } else if !param.IsOmitted(u.ofChatCompletionSystemMessageContent) {
1600− return u.ofChatCompletionSystemMessageContent.asAny()
1601− } else if !param.IsOmitted(u.ofChatCompletionUserMessageContent) {
1602− return u.ofChatCompletionUserMessageContent.asAny()
1603− } else if !param.IsOmitted(u.ofChatCompletionAssistantMessageContent) {
1604− return u.ofChatCompletionAssistantMessageContent.asAny()
1605− } else if !param.IsOmitted(u.ofChatCompletionToolMessageContent) {
1606− return u.ofChatCompletionToolMessageContent.asAny()
1607− } else if !param.IsOmitted(u.ofString) {
1608− return u.ofString
1609− }
1610− return nil
1611−}
1584+func (u chatCompletionMessageParamUnionContent) AsAny() any { return u.any }
16121585
16131586func init() {
16141587 apijson.RegisterUnion[ChatCompletionMessageParamUnion](
16151588 "role",
1616− apijson.UnionVariant{
1617− TypeFilter: gjson.JSON,
1618− Type: reflect.TypeOf(ChatCompletionDeveloperMessageParam{}),
1619− DiscriminatorValue: "developer",
1620− },
1621− apijson.UnionVariant{
1622− TypeFilter: gjson.JSON,
1623− Type: reflect.TypeOf(ChatCompletionSystemMessageParam{}),
1624− DiscriminatorValue: "system",
1625− },
1626− apijson.UnionVariant{
1627− TypeFilter: gjson.JSON,
1628− Type: reflect.TypeOf(ChatCompletionUserMessageParam{}),
1629− DiscriminatorValue: "user",
1630− },
1631− apijson.UnionVariant{
1632− TypeFilter: gjson.JSON,
1633− Type: reflect.TypeOf(ChatCompletionAssistantMessageParam{}),
1634− DiscriminatorValue: "assistant",
1635− },
1636− apijson.UnionVariant{
1637− TypeFilter: gjson.JSON,
1638− Type: reflect.TypeOf(ChatCompletionToolMessageParam{}),
1639− DiscriminatorValue: "tool",
1640− },
1641− apijson.UnionVariant{
1642− TypeFilter: gjson.JSON,
1643− Type: reflect.TypeOf(ChatCompletionFunctionMessageParam{}),
1644− DiscriminatorValue: "function",
1645− },
1589+ apijson.Discriminator[ChatCompletionDeveloperMessageParam]("developer"),
1590+ apijson.Discriminator[ChatCompletionSystemMessageParam]("system"),
1591+ apijson.Discriminator[ChatCompletionUserMessageParam]("user"),
1592+ apijson.Discriminator[ChatCompletionAssistantMessageParam]("assistant"),
1593+ apijson.Discriminator[ChatCompletionToolMessageParam]("tool"),
1594+ apijson.Discriminator[ChatCompletionFunctionMessageParam]("function"),
16461595 )
16471596}
16481597
@@ -1653,13 +1602,12 @@ type ChatCompletionMessageToolCall struct {
16531602 Function ChatCompletionMessageToolCallFunction `json:"function,required"`
16541603 // The type of the tool. Currently, only `function` is supported.
16551604 Type constant.Function `json:"type,required"`
1656− // Metadata for the response, check the presence of optional fields with the
1657− // [resp.Field.IsPresent] method.
1605+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
16581606 JSON struct {
1659− ID resp.Field
1660− Function resp.Field
1661− Type resp.Field
1662− ExtraFields map[string]resp.Field
1607+ ID respjson.Field
1608+ Function respjson.Field
1609+ Type respjson.Field
1610+ ExtraFields map[string]respjson.Field
16631611 raw string
16641612 } `json:"-"`
16651613}
@@ -1675,9 +1623,9 @@ func (r *ChatCompletionMessageToolCall) UnmarshalJSON(data []byte) error {
16751623//
16761624// Warning: the fields of the param type will not be present. ToParam should only
16771625// be used at the last possible moment before sending a request. Test for this with
1678−// ChatCompletionMessageToolCallParam.IsOverridden()
1626+// ChatCompletionMessageToolCallParam.Overrides()
16791627func (r ChatCompletionMessageToolCall) ToParam() ChatCompletionMessageToolCallParam {
1680− return param.OverrideObj[ChatCompletionMessageToolCallParam](r.RawJSON())
1628+ return param.Override[ChatCompletionMessageToolCallParam](json.RawMessage(r.RawJSON()))
16811629}
16821630
16831631// The function that the model called.
@@ -1689,12 +1637,11 @@ type ChatCompletionMessageToolCallFunction struct {
16891637 Arguments string `json:"arguments,required"`
16901638 // The name of the function to call.
16911639 Name string `json:"name,required"`
1692− // Metadata for the response, check the presence of optional fields with the
1693− // [resp.Field.IsPresent] method.
1640+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
16941641 JSON struct {
1695− Arguments resp.Field
1696− Name resp.Field
1697− ExtraFields map[string]resp.Field
1642+ Arguments respjson.Field
1643+ Name respjson.Field
1644+ ExtraFields map[string]respjson.Field
16981645 raw string
16991646 } `json:"-"`
17001647}
@@ -1718,15 +1665,13 @@ type ChatCompletionMessageToolCallParam struct {
17181665 paramObj
17191666}
17201667
1721−// IsPresent returns true if the field's value is not omitted and not the JSON
1722−// "null". To check if this field is omitted, use [param.IsOmitted].
1723−func (f ChatCompletionMessageToolCallParam) IsPresent() bool {
1724− return !param.IsOmitted(f) && !f.IsNull()
1725−}
17261668func (r ChatCompletionMessageToolCallParam) MarshalJSON() (data []byte, err error) {
17271669 type shadow ChatCompletionMessageToolCallParam
17281670 return param.MarshalObject(r, (*shadow)(&r))
17291671}
1672+func (r *ChatCompletionMessageToolCallParam) UnmarshalJSON(data []byte) error {
1673+ return apijson.UnmarshalRoot(data, r)
1674+}
17301675
17311676// The function that the model called.
17321677//
@@ -1742,15 +1687,13 @@ type ChatCompletionMessageToolCallFunctionParam struct {
17421687 paramObj
17431688}
17441689
1745−// IsPresent returns true if the field's value is not omitted and not the JSON
1746−// "null". To check if this field is omitted, use [param.IsOmitted].
1747−func (f ChatCompletionMessageToolCallFunctionParam) IsPresent() bool {
1748− return !param.IsOmitted(f) && !f.IsNull()
1749−}
17501690func (r ChatCompletionMessageToolCallFunctionParam) MarshalJSON() (data []byte, err error) {
17511691 type shadow ChatCompletionMessageToolCallFunctionParam
17521692 return param.MarshalObject(r, (*shadow)(&r))
17531693}
1694+func (r *ChatCompletionMessageToolCallFunctionParam) UnmarshalJSON(data []byte) error {
1695+ return apijson.UnmarshalRoot(data, r)
1696+}
17541697
17551698// Specifies a tool the model should use. Use to force the model to call a specific
17561699// function.
@@ -1765,15 +1708,13 @@ type ChatCompletionNamedToolChoiceParam struct {
17651708 paramObj
17661709}
17671710
1768−// IsPresent returns true if the field's value is not omitted and not the JSON
1769−// "null". To check if this field is omitted, use [param.IsOmitted].
1770−func (f ChatCompletionNamedToolChoiceParam) IsPresent() bool {
1771− return !param.IsOmitted(f) && !f.IsNull()
1772−}
17731711func (r ChatCompletionNamedToolChoiceParam) MarshalJSON() (data []byte, err error) {
17741712 type shadow ChatCompletionNamedToolChoiceParam
17751713 return param.MarshalObject(r, (*shadow)(&r))
17761714}
1715+func (r *ChatCompletionNamedToolChoiceParam) UnmarshalJSON(data []byte) error {
1716+ return apijson.UnmarshalRoot(data, r)
1717+}
17771718
17781719// The property Name is required.
17791720type ChatCompletionNamedToolChoiceFunctionParam struct {
@@ -1782,15 +1723,13 @@ type ChatCompletionNamedToolChoiceFunctionParam struct {
17821723 paramObj
17831724}
17841725
1785−// IsPresent returns true if the field's value is not omitted and not the JSON
1786−// "null". To check if this field is omitted, use [param.IsOmitted].
1787−func (f ChatCompletionNamedToolChoiceFunctionParam) IsPresent() bool {
1788− return !param.IsOmitted(f) && !f.IsNull()
1789−}
17901726func (r ChatCompletionNamedToolChoiceFunctionParam) MarshalJSON() (data []byte, err error) {
17911727 type shadow ChatCompletionNamedToolChoiceFunctionParam
17921728 return param.MarshalObject(r, (*shadow)(&r))
17931729}
1730+func (r *ChatCompletionNamedToolChoiceFunctionParam) UnmarshalJSON(data []byte) error {
1731+ return apijson.UnmarshalRoot(data, r)
1732+}
17941733
17951734// Static predicted output content, such as the content of a text file that is
17961735// being regenerated.
@@ -1809,15 +1748,13 @@ type ChatCompletionPredictionContentParam struct {
18091748 paramObj
18101749}
18111750
1812−// IsPresent returns true if the field's value is not omitted and not the JSON
1813−// "null". To check if this field is omitted, use [param.IsOmitted].
1814−func (f ChatCompletionPredictionContentParam) IsPresent() bool {
1815− return !param.IsOmitted(f) && !f.IsNull()
1816−}
18171751func (r ChatCompletionPredictionContentParam) MarshalJSON() (data []byte, err error) {
18181752 type shadow ChatCompletionPredictionContentParam
18191753 return param.MarshalObject(r, (*shadow)(&r))
18201754}
1755+func (r *ChatCompletionPredictionContentParam) UnmarshalJSON(data []byte) error {
1756+ return apijson.UnmarshalRoot(data, r)
1757+}
18211758
18221759// Only one field can be non-zero.
18231760//
@@ -1828,13 +1765,11 @@ type ChatCompletionPredictionContentContentUnionParam struct {
18281765 paramUnion
18291766}
18301767
1831−// IsPresent returns true if the field's value is not omitted and not the JSON
1832−// "null". To check if this field is omitted, use [param.IsOmitted].
1833−func (u ChatCompletionPredictionContentContentUnionParam) IsPresent() bool {
1834− return !param.IsOmitted(u) && !u.IsNull()
1835−}
18361768func (u ChatCompletionPredictionContentContentUnionParam) MarshalJSON() ([]byte, error) {
1837− return param.MarshalUnion[ChatCompletionPredictionContentContentUnionParam](u.OfString, u.OfArrayOfContentParts)
1769+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
1770+}
1771+func (u *ChatCompletionPredictionContentContentUnionParam) UnmarshalJSON(data []byte) error {
1772+ return apijson.UnmarshalRoot(data, u)
18381773}
18391774
18401775func (u *ChatCompletionPredictionContentContentUnionParam) asAny() any {
@@ -1850,11 +1785,10 @@ func (u *ChatCompletionPredictionContentContentUnionParam) asAny() any {
18501785type ChatCompletionStoreMessage struct {
18511786 // The identifier of the chat message.
18521787 ID string `json:"id,required"`
1853− // Metadata for the response, check the presence of optional fields with the
1854− // [resp.Field.IsPresent] method.
1788+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
18551789 JSON struct {
1856− ID resp.Field
1857− ExtraFields map[string]resp.Field
1790+ ID respjson.Field
1791+ ExtraFields map[string]respjson.Field
18581792 raw string
18591793 } `json:"-"`
18601794 ChatCompletionMessage
@@ -1879,13 +1813,13 @@ type ChatCompletionStreamOptionsParam struct {
18791813 paramObj
18801814}
18811815
1882−// IsPresent returns true if the field's value is not omitted and not the JSON
1883−// "null". To check if this field is omitted, use [param.IsOmitted].
1884−func (f ChatCompletionStreamOptionsParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
18851816func (r ChatCompletionStreamOptionsParam) MarshalJSON() (data []byte, err error) {
18861817 type shadow ChatCompletionStreamOptionsParam
18871818 return param.MarshalObject(r, (*shadow)(&r))
18881819}
1820+func (r *ChatCompletionStreamOptionsParam) UnmarshalJSON(data []byte) error {
1821+ return apijson.UnmarshalRoot(data, r)
1822+}
18891823
18901824// Developer-provided instructions that the model should follow, regardless of
18911825// messages sent by the user. With o1 models and newer, use `developer` messages
@@ -1905,13 +1839,13 @@ type ChatCompletionSystemMessageParam struct {
19051839 paramObj
19061840}
19071841
1908−// IsPresent returns true if the field's value is not omitted and not the JSON
1909−// "null". To check if this field is omitted, use [param.IsOmitted].
1910−func (f ChatCompletionSystemMessageParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
19111842func (r ChatCompletionSystemMessageParam) MarshalJSON() (data []byte, err error) {
19121843 type shadow ChatCompletionSystemMessageParam
19131844 return param.MarshalObject(r, (*shadow)(&r))
19141845}
1846+func (r *ChatCompletionSystemMessageParam) UnmarshalJSON(data []byte) error {
1847+ return apijson.UnmarshalRoot(data, r)
1848+}
19151849
19161850// Only one field can be non-zero.
19171851//
@@ -1922,13 +1856,11 @@ type ChatCompletionSystemMessageParamContentUnion struct {
19221856 paramUnion
19231857}
19241858
1925−// IsPresent returns true if the field's value is not omitted and not the JSON
1926−// "null". To check if this field is omitted, use [param.IsOmitted].
1927−func (u ChatCompletionSystemMessageParamContentUnion) IsPresent() bool {
1928− return !param.IsOmitted(u) && !u.IsNull()
1929−}
19301859func (u ChatCompletionSystemMessageParamContentUnion) MarshalJSON() ([]byte, error) {
1931− return param.MarshalUnion[ChatCompletionSystemMessageParamContentUnion](u.OfString, u.OfArrayOfContentParts)
1860+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
1861+}
1862+func (u *ChatCompletionSystemMessageParamContentUnion) UnmarshalJSON(data []byte) error {
1863+ return apijson.UnmarshalRoot(data, u)
19321864}
19331865
19341866func (u *ChatCompletionSystemMessageParamContentUnion) asAny() any {
@@ -1956,14 +1888,13 @@ type ChatCompletionTokenLogprob struct {
19561888 // position. In rare cases, there may be fewer than the number of requested
19571889 // `top_logprobs` returned.
19581890 TopLogprobs []ChatCompletionTokenLogprobTopLogprob `json:"top_logprobs,required"`
1959− // Metadata for the response, check the presence of optional fields with the
1960− // [resp.Field.IsPresent] method.
1891+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
19611892 JSON struct {
1962− Token resp.Field
1963− Bytes resp.Field
1964− Logprob resp.Field
1965− TopLogprobs resp.Field
1966− ExtraFields map[string]resp.Field
1893+ Token respjson.Field
1894+ Bytes respjson.Field
1895+ Logprob respjson.Field
1896+ TopLogprobs respjson.Field
1897+ ExtraFields map[string]respjson.Field
19671898 raw string
19681899 } `json:"-"`
19691900}
@@ -1986,13 +1917,12 @@ type ChatCompletionTokenLogprobTopLogprob struct {
19861917 // tokens. Otherwise, the value `-9999.0` is used to signify that the token is very
19871918 // unlikely.
19881919 Logprob float64 `json:"logprob,required"`
1989− // Metadata for the response, check the presence of optional fields with the
1990− // [resp.Field.IsPresent] method.
1920+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
19911921 JSON struct {
1992− Token resp.Field
1993− Bytes resp.Field
1994− Logprob resp.Field
1995− ExtraFields map[string]resp.Field
1922+ Token respjson.Field
1923+ Bytes respjson.Field
1924+ Logprob respjson.Field
1925+ ExtraFields map[string]respjson.Field
19961926 raw string
19971927 } `json:"-"`
19981928}
@@ -2013,13 +1943,13 @@ type ChatCompletionToolParam struct {
20131943 paramObj
20141944}
20151945
2016−// IsPresent returns true if the field's value is not omitted and not the JSON
2017−// "null". To check if this field is omitted, use [param.IsOmitted].
2018−func (f ChatCompletionToolParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
20191946func (r ChatCompletionToolParam) MarshalJSON() (data []byte, err error) {
20201947 type shadow ChatCompletionToolParam
20211948 return param.MarshalObject(r, (*shadow)(&r))
20221949}
1950+func (r *ChatCompletionToolParam) UnmarshalJSON(data []byte) error {
1951+ return apijson.UnmarshalRoot(data, r)
1952+}
20231953
20241954func ChatCompletionToolChoiceOptionParamOfChatCompletionNamedToolChoice(function ChatCompletionNamedToolChoiceFunctionParam) ChatCompletionToolChoiceOptionUnionParam {
20251955 var variant ChatCompletionNamedToolChoiceParam
@@ -2037,13 +1967,11 @@ type ChatCompletionToolChoiceOptionUnionParam struct {
20371967 paramUnion
20381968}
20391969
2040−// IsPresent returns true if the field's value is not omitted and not the JSON
2041−// "null". To check if this field is omitted, use [param.IsOmitted].
2042−func (u ChatCompletionToolChoiceOptionUnionParam) IsPresent() bool {
2043− return !param.IsOmitted(u) && !u.IsNull()
2044−}
20451970func (u ChatCompletionToolChoiceOptionUnionParam) MarshalJSON() ([]byte, error) {
2046− return param.MarshalUnion[ChatCompletionToolChoiceOptionUnionParam](u.OfAuto, u.OfChatCompletionNamedToolChoice)
1971+ return param.MarshalUnion(u, u.OfAuto, u.OfChatCompletionNamedToolChoice)
1972+}
1973+func (u *ChatCompletionToolChoiceOptionUnionParam) UnmarshalJSON(data []byte) error {
1974+ return apijson.UnmarshalRoot(data, u)
20471975}
20481976
20491977func (u *ChatCompletionToolChoiceOptionUnionParam) asAny() any {
@@ -2055,21 +1983,16 @@ func (u *ChatCompletionToolChoiceOptionUnionParam) asAny() any {
20551983 return nil
20561984}
20571985
2058−// Returns a pointer to the underlying variant's property, if present.
2059−func (u ChatCompletionToolChoiceOptionUnionParam) GetFunction() *ChatCompletionNamedToolChoiceFunctionParam {
2060− if vt := u.OfChatCompletionNamedToolChoice; vt != nil {
2061− return &vt.Function
2062− }
2063− return nil
2064−}
1986+// `none` means the model will not call any tool and instead generates a message.
1987+// `auto` means the model can pick between generating a message or calling one or
1988+// more tools. `required` means the model must call one or more tools.
1989+type ChatCompletionToolChoiceOptionAuto string
20651990
2066−// Returns a pointer to the underlying variant's property, if present.
2067−func (u ChatCompletionToolChoiceOptionUnionParam) GetType() *string {
2068− if vt := u.OfChatCompletionNamedToolChoice; vt != nil {
2069− return (*string)(&vt.Type)
2070− }
2071− return nil
2072−}
1991+const (
1992+ ChatCompletionToolChoiceOptionAutoNone ChatCompletionToolChoiceOptionAuto = "none"
1993+ ChatCompletionToolChoiceOptionAutoAuto ChatCompletionToolChoiceOptionAuto = "auto"
1994+ ChatCompletionToolChoiceOptionAutoRequired ChatCompletionToolChoiceOptionAuto = "required"
1995+)
20731996
20741997// The properties Content, Role, ToolCallID are required.
20751998type ChatCompletionToolMessageParam struct {
@@ -2084,13 +2007,13 @@ type ChatCompletionToolMessageParam struct {
20842007 paramObj
20852008}
20862009
2087−// IsPresent returns true if the field's value is not omitted and not the JSON
2088−// "null". To check if this field is omitted, use [param.IsOmitted].
2089−func (f ChatCompletionToolMessageParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
20902010func (r ChatCompletionToolMessageParam) MarshalJSON() (data []byte, err error) {
20912011 type shadow ChatCompletionToolMessageParam
20922012 return param.MarshalObject(r, (*shadow)(&r))
20932013}
2014+func (r *ChatCompletionToolMessageParam) UnmarshalJSON(data []byte) error {
2015+ return apijson.UnmarshalRoot(data, r)
2016+}
20942017
20952018// Only one field can be non-zero.
20962019//
@@ -2101,13 +2024,11 @@ type ChatCompletionToolMessageParamContentUnion struct {
21012024 paramUnion
21022025}
21032026
2104−// IsPresent returns true if the field's value is not omitted and not the JSON
2105−// "null". To check if this field is omitted, use [param.IsOmitted].
2106−func (u ChatCompletionToolMessageParamContentUnion) IsPresent() bool {
2107− return !param.IsOmitted(u) && !u.IsNull()
2108−}
21092027func (u ChatCompletionToolMessageParamContentUnion) MarshalJSON() ([]byte, error) {
2110− return param.MarshalUnion[ChatCompletionToolMessageParamContentUnion](u.OfString, u.OfArrayOfContentParts)
2028+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
2029+}
2030+func (u *ChatCompletionToolMessageParamContentUnion) UnmarshalJSON(data []byte) error {
2031+ return apijson.UnmarshalRoot(data, u)
21112032}
21122033
21132034func (u *ChatCompletionToolMessageParamContentUnion) asAny() any {
@@ -2136,13 +2057,13 @@ type ChatCompletionUserMessageParam struct {
21362057 paramObj
21372058}
21382059
2139−// IsPresent returns true if the field's value is not omitted and not the JSON
2140−// "null". To check if this field is omitted, use [param.IsOmitted].
2141−func (f ChatCompletionUserMessageParam) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
21422060func (r ChatCompletionUserMessageParam) MarshalJSON() (data []byte, err error) {
21432061 type shadow ChatCompletionUserMessageParam
21442062 return param.MarshalObject(r, (*shadow)(&r))
21452063}
2064+func (r *ChatCompletionUserMessageParam) UnmarshalJSON(data []byte) error {
2065+ return apijson.UnmarshalRoot(data, r)
2066+}
21462067
21472068// Only one field can be non-zero.
21482069//
@@ -2153,13 +2074,11 @@ type ChatCompletionUserMessageParamContentUnion struct {
21532074 paramUnion
21542075}
21552076
2156−// IsPresent returns true if the field's value is not omitted and not the JSON
2157−// "null". To check if this field is omitted, use [param.IsOmitted].
2158−func (u ChatCompletionUserMessageParamContentUnion) IsPresent() bool {
2159− return !param.IsOmitted(u) && !u.IsNull()
2160−}
21612077func (u ChatCompletionUserMessageParamContentUnion) MarshalJSON() ([]byte, error) {
2162− return param.MarshalUnion[ChatCompletionUserMessageParamContentUnion](u.OfString, u.OfArrayOfContentParts)
2078+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfContentParts)
2079+}
2080+func (u *ChatCompletionUserMessageParamContentUnion) UnmarshalJSON(data []byte) error {
2081+ return apijson.UnmarshalRoot(data, u)
21632082}
21642083
21652084func (u *ChatCompletionUserMessageParamContentUnion) asAny() any {
@@ -2179,7 +2098,7 @@ type ChatCompletionNewParams struct {
21792098 // [images](https://platform.openai.com/docs/guides/vision), and
21802099 // [audio](https://platform.openai.com/docs/guides/audio).
21812100 Messages []ChatCompletionMessageParamUnion `json:"messages,omitzero,required"`
2182− // Model ID used to generate the response, like `gpt-4o` or `o1`. OpenAI offers a
2101+ // Model ID used to generate the response, like `gpt-4o` or `o3`. OpenAI offers a
21832102 // wide range of models with different capabilities, performance characteristics,
21842103 // and price points. Refer to the
21852104 // [model guide](https://platform.openai.com/docs/models) to browse and compare
@@ -2203,7 +2122,7 @@ type ChatCompletionNewParams struct {
22032122 //
22042123 // This value is now deprecated in favor of `max_completion_tokens`, and is not
22052124 // compatible with
2206− // [o1 series models](https://platform.openai.com/docs/guides/reasoning).
2125+ // [o-series models](https://platform.openai.com/docs/guides/reasoning).
22072126 MaxTokens param.Opt[int64] `json:"max_tokens,omitzero"`
22082127 // How many chat completion choices to generate for each input message. Note that
22092128 // you will be charged based on the number of generated tokens across all of the
@@ -2222,6 +2141,8 @@ type ChatCompletionNewParams struct {
22222141 // Whether or not to store the output of this chat completion request for use in
22232142 // our [model distillation](https://platform.openai.com/docs/guides/distillation)
22242143 // or [evals](https://platform.openai.com/docs/guides/evals) products.
2144+ //
2145+ // Supports text and image inputs. Note: image inputs over 10MB will be dropped.
22252146 Store param.Opt[bool] `json:"store,omitzero"`
22262147 // What sampling temperature to use, between 0 and 2. Higher values like 0.8 will
22272148 // make the output more random, while lower values like 0.2 will make it more
@@ -2242,8 +2163,8 @@ type ChatCompletionNewParams struct {
22422163 // [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling)
22432164 // during tool use.
22442165 ParallelToolCalls param.Opt[bool] `json:"parallel_tool_calls,omitzero"`
2245− // A unique identifier representing your end-user, which can help OpenAI to monitor
2246− // and detect abuse.
2166+ // A stable identifier for your end-users. Used to boost cache hit rates by better
2167+ // bucketing similar requests and to help OpenAI detect and prevent abuse.
22472168 // [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids).
22482169 User param.Opt[string] `json:"user,omitzero"`
22492170 // Parameters for audio output. Required when audio output is requested with
@@ -2265,7 +2186,7 @@ type ChatCompletionNewParams struct {
22652186 //
22662187 // Keys are strings with a maximum length of 64 characters. Values are strings with
22672188 // a maximum length of 512 characters.
2268− Metadata shared.MetadataParam `json:"metadata,omitzero"`
2189+ Metadata shared.Metadata `json:"metadata,omitzero"`
22692190 // Output types that you would like the model to generate. Most models are capable
22702191 // of generating text, which is the default:
22712192 //
@@ -2276,6 +2197,8 @@ type ChatCompletionNewParams struct {
22762197 // this model generate both text and audio responses, you can use:
22772198 //
22782199 // `["text", "audio"]`
2200+ //
2201+ // Any of "text", "audio".
22792202 Modalities []string `json:"modalities,omitzero"`
22802203 // **o-series models only**
22812204 //
@@ -2286,23 +2209,28 @@ type ChatCompletionNewParams struct {
22862209 //
22872210 // Any of "low", "medium", "high".
22882211 ReasoningEffort shared.ReasoningEffort `json:"reasoning_effort,omitzero"`
2289− // Specifies the latency tier to use for processing the request. This parameter is
2290− // relevant for customers subscribed to the scale tier service:
2291− //
2292− // - If set to 'auto', and the Project is Scale tier enabled, the system will
2293− // utilize scale tier credits until they are exhausted.
2294− // - If set to 'auto', and the Project is not Scale tier enabled, the request will
2295− // be processed using the default service tier with a lower uptime SLA and no
2296− // latency guarentee.
2297− // - If set to 'default', the request will be processed using the default service
2298− // tier with a lower uptime SLA and no latency guarentee.
2212+ // Specifies the processing type used for serving the request.
2213+ //
2214+ // - If set to 'auto', then the request will be processed with the service tier
2215+ // configured in the Project settings. Unless otherwise configured, the Project
2216+ // will use 'default'.
2217+ // - If set to 'default', then the requset will be processed with the standard
2218+ // pricing and performance for the selected model.
2219+ // - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or
2220+ // 'priority', then the request will be processed with the corresponding service
2221+ // tier. [Contact sales](https://openai.com/contact-sales) to learn more about
2222+ // Priority processing.
22992223 // - When not set, the default behavior is 'auto'.
23002224 //
2301− // When this parameter is set, the response body will include the `service_tier`
2302− // utilized.
2225+ // When the `service_tier` parameter is set, the response body will include the
2226+ // `service_tier` value based on the processing mode actually used to serve the
2227+ // request. This response value may be different from the value set in the
2228+ // parameter.
23032229 //
2304− // Any of "auto", "default".
2230+ // Any of "auto", "default", "flex", "scale", "priority".
23052231 ServiceTier ChatCompletionNewParamsServiceTier `json:"service_tier,omitzero"`
2232+ // Not supported with latest reasoning models `o3` and `o4-mini`.
2233+ //
23062234 // Up to 4 sequences where the API will stop generating further tokens. The
23072235 // returned text will not contain the stop sequence.
23082236 Stop ChatCompletionNewParamsStopUnion `json:"stop,omitzero"`
@@ -2362,14 +2290,13 @@ type ChatCompletionNewParams struct {
23622290 paramObj
23632291}
23642292
2365−// IsPresent returns true if the field's value is not omitted and not the JSON
2366−// "null". To check if this field is omitted, use [param.IsOmitted].
2367−func (f ChatCompletionNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
2368−
23692293func (r ChatCompletionNewParams) MarshalJSON() (data []byte, err error) {
23702294 type shadow ChatCompletionNewParams
23712295 return param.MarshalObject(r, (*shadow)(&r))
23722296}
2297+func (r *ChatCompletionNewParams) UnmarshalJSON(data []byte) error {
2298+ return apijson.UnmarshalRoot(data, r)
2299+}
23732300
23742301// Only one field can be non-zero.
23752302//
@@ -2381,13 +2308,11 @@ type ChatCompletionNewParamsFunctionCallUnion struct {
23812308 paramUnion
23822309}
23832310
2384−// IsPresent returns true if the field's value is not omitted and not the JSON
2385−// "null". To check if this field is omitted, use [param.IsOmitted].
2386−func (u ChatCompletionNewParamsFunctionCallUnion) IsPresent() bool {
2387− return !param.IsOmitted(u) && !u.IsNull()
2388−}
23892311func (u ChatCompletionNewParamsFunctionCallUnion) MarshalJSON() ([]byte, error) {
2390− return param.MarshalUnion[ChatCompletionNewParamsFunctionCallUnion](u.OfFunctionCallMode, u.OfFunctionCallOption)
2312+ return param.MarshalUnion(u, u.OfFunctionCallMode, u.OfFunctionCallOption)
2313+}
2314+func (u *ChatCompletionNewParamsFunctionCallUnion) UnmarshalJSON(data []byte) error {
2315+ return apijson.UnmarshalRoot(data, u)
23912316}
23922317
23932318func (u *ChatCompletionNewParamsFunctionCallUnion) asAny() any {
@@ -2399,13 +2324,15 @@ func (u *ChatCompletionNewParamsFunctionCallUnion) asAny() any {
23992324 return nil
24002325}
24012326
2402−// Returns a pointer to the underlying variant's property, if present.
2403−func (u ChatCompletionNewParamsFunctionCallUnion) GetName() *string {
2404− if vt := u.OfFunctionCallOption; vt != nil {
2405− return &vt.Name
2406− }
2407− return nil
2408−}
2327+// `none` means the model will not call a function and instead generates a message.
2328+// `auto` means the model can pick between generating a message or calling a
2329+// function.
2330+type ChatCompletionNewParamsFunctionCallFunctionCallMode string
2331+
2332+const (
2333+ ChatCompletionNewParamsFunctionCallFunctionCallModeNone ChatCompletionNewParamsFunctionCallFunctionCallMode = "none"
2334+ ChatCompletionNewParamsFunctionCallFunctionCallModeAuto ChatCompletionNewParamsFunctionCallFunctionCallMode = "auto"
2335+)
24092336
24102337// Deprecated: deprecated
24112338//
@@ -2428,13 +2355,13 @@ type ChatCompletionNewParamsFunction struct {
24282355 paramObj
24292356}
24302357
2431−// IsPresent returns true if the field's value is not omitted and not the JSON
2432−// "null". To check if this field is omitted, use [param.IsOmitted].
2433−func (f ChatCompletionNewParamsFunction) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
24342358func (r ChatCompletionNewParamsFunction) MarshalJSON() (data []byte, err error) {
24352359 type shadow ChatCompletionNewParamsFunction
24362360 return param.MarshalObject(r, (*shadow)(&r))
24372361}
2362+func (r *ChatCompletionNewParamsFunction) UnmarshalJSON(data []byte) error {
2363+ return apijson.UnmarshalRoot(data, r)
2364+}
24382365
24392366// Only one field can be non-zero.
24402367//
@@ -2446,13 +2373,11 @@ type ChatCompletionNewParamsResponseFormatUnion struct {
24462373 paramUnion
24472374}
24482375
2449−// IsPresent returns true if the field's value is not omitted and not the JSON
2450−// "null". To check if this field is omitted, use [param.IsOmitted].
2451−func (u ChatCompletionNewParamsResponseFormatUnion) IsPresent() bool {
2452− return !param.IsOmitted(u) && !u.IsNull()
2453−}
24542376func (u ChatCompletionNewParamsResponseFormatUnion) MarshalJSON() ([]byte, error) {
2455− return param.MarshalUnion[ChatCompletionNewParamsResponseFormatUnion](u.OfText, u.OfJSONSchema, u.OfJSONObject)
2377+ return param.MarshalUnion(u, u.OfText, u.OfJSONSchema, u.OfJSONObject)
2378+}
2379+func (u *ChatCompletionNewParamsResponseFormatUnion) UnmarshalJSON(data []byte) error {
2380+ return apijson.UnmarshalRoot(data, u)
24562381}
24572382
24582383func (u *ChatCompletionNewParamsResponseFormatUnion) asAny() any {
@@ -2486,48 +2411,54 @@ func (u ChatCompletionNewParamsResponseFormatUnion) GetType() *string {
24862411 return nil
24872412}
24882413
2489−// Specifies the latency tier to use for processing the request. This parameter is
2490−// relevant for customers subscribed to the scale tier service:
2414+// Specifies the processing type used for serving the request.
24912415//
2492−// - If set to 'auto', and the Project is Scale tier enabled, the system will
2493−// utilize scale tier credits until they are exhausted.
2494−// - If set to 'auto', and the Project is not Scale tier enabled, the request will
2495−// be processed using the default service tier with a lower uptime SLA and no
2496−// latency guarentee.
2497−// - If set to 'default', the request will be processed using the default service
2498−// tier with a lower uptime SLA and no latency guarentee.
2416+// - If set to 'auto', then the request will be processed with the service tier
2417+// configured in the Project settings. Unless otherwise configured, the Project
2418+// will use 'default'.
2419+// - If set to 'default', then the requset will be processed with the standard
2420+// pricing and performance for the selected model.
2421+// - If set to '[flex](https://platform.openai.com/docs/guides/flex-processing)' or
2422+// 'priority', then the request will be processed with the corresponding service
2423+// tier. [Contact sales](https://openai.com/contact-sales) to learn more about
2424+// Priority processing.
24992425// - When not set, the default behavior is 'auto'.
25002426//
2501−// When this parameter is set, the response body will include the `service_tier`
2502−// utilized.
2427+// When the `service_tier` parameter is set, the response body will include the
2428+// `service_tier` value based on the processing mode actually used to serve the
2429+// request. This response value may be different from the value set in the
2430+// parameter.
25032431type ChatCompletionNewParamsServiceTier string
25042432
25052433const (
2506− ChatCompletionNewParamsServiceTierAuto ChatCompletionNewParamsServiceTier = "auto"
2507− ChatCompletionNewParamsServiceTierDefault ChatCompletionNewParamsServiceTier = "default"
2434+ ChatCompletionNewParamsServiceTierAuto ChatCompletionNewParamsServiceTier = "auto"
2435+ ChatCompletionNewParamsServiceTierDefault ChatCompletionNewParamsServiceTier = "default"
2436+ ChatCompletionNewParamsServiceTierFlex ChatCompletionNewParamsServiceTier = "flex"
2437+ ChatCompletionNewParamsServiceTierScale ChatCompletionNewParamsServiceTier = "scale"
2438+ ChatCompletionNewParamsServiceTierPriority ChatCompletionNewParamsServiceTier = "priority"
25082439)
25092440
25102441// Only one field can be non-zero.
25112442//
25122443// Use [param.IsOmitted] to confirm if a field is set.
25132444type ChatCompletionNewParamsStopUnion struct {
2514− OfString param.Opt[string] `json:",omitzero,inline"`
2515− OfChatCompletionNewsStopArray []string `json:",omitzero,inline"`
2445+ OfString param.Opt[string] `json:",omitzero,inline"`
2446+ OfStringArray []string `json:",omitzero,inline"`
25162447 paramUnion
25172448}
25182449
2519−// IsPresent returns true if the field's value is not omitted and not the JSON
2520−// "null". To check if this field is omitted, use [param.IsOmitted].
2521−func (u ChatCompletionNewParamsStopUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() }
25222450func (u ChatCompletionNewParamsStopUnion) MarshalJSON() ([]byte, error) {
2523− return param.MarshalUnion[ChatCompletionNewParamsStopUnion](u.OfString, u.OfChatCompletionNewsStopArray)
2451+ return param.MarshalUnion(u, u.OfString, u.OfStringArray)
2452+}
2453+func (u *ChatCompletionNewParamsStopUnion) UnmarshalJSON(data []byte) error {
2454+ return apijson.UnmarshalRoot(data, u)
25242455}
25252456
25262457func (u *ChatCompletionNewParamsStopUnion) asAny() any {
25272458 if !param.IsOmitted(u.OfString) {
25282459 return &u.OfString.Value
2529− } else if !param.IsOmitted(u.OfChatCompletionNewsStopArray) {
2530− return &u.OfChatCompletionNewsStopArray
2460+ } else if !param.IsOmitted(u.OfStringArray) {
2461+ return &u.OfStringArray
25312462 }
25322463 return nil
25332464}
@@ -2546,19 +2477,17 @@ type ChatCompletionNewParamsWebSearchOptions struct {
25462477 paramObj
25472478}
25482479
2549−// IsPresent returns true if the field's value is not omitted and not the JSON
2550−// "null". To check if this field is omitted, use [param.IsOmitted].
2551−func (f ChatCompletionNewParamsWebSearchOptions) IsPresent() bool {
2552− return !param.IsOmitted(f) && !f.IsNull()
2553−}
25542480func (r ChatCompletionNewParamsWebSearchOptions) MarshalJSON() (data []byte, err error) {
25552481 type shadow ChatCompletionNewParamsWebSearchOptions
25562482 return param.MarshalObject(r, (*shadow)(&r))
25572483}
2484+func (r *ChatCompletionNewParamsWebSearchOptions) UnmarshalJSON(data []byte) error {
2485+ return apijson.UnmarshalRoot(data, r)
2486+}
25582487
25592488func init() {
25602489 apijson.RegisterFieldValidator[ChatCompletionNewParamsWebSearchOptions](
2561− "SearchContextSize", false, "low", "medium", "high",
2490+ "search_context_size", "low", "medium", "high",
25622491 )
25632492}
25642493
@@ -2575,15 +2504,13 @@ type ChatCompletionNewParamsWebSearchOptionsUserLocation struct {
25752504 paramObj
25762505}
25772506
2578−// IsPresent returns true if the field's value is not omitted and not the JSON
2579−// "null". To check if this field is omitted, use [param.IsOmitted].
2580−func (f ChatCompletionNewParamsWebSearchOptionsUserLocation) IsPresent() bool {
2581− return !param.IsOmitted(f) && !f.IsNull()
2582−}
25832507func (r ChatCompletionNewParamsWebSearchOptionsUserLocation) MarshalJSON() (data []byte, err error) {
25842508 type shadow ChatCompletionNewParamsWebSearchOptionsUserLocation
25852509 return param.MarshalObject(r, (*shadow)(&r))
25862510}
2511+func (r *ChatCompletionNewParamsWebSearchOptionsUserLocation) UnmarshalJSON(data []byte) error {
2512+ return apijson.UnmarshalRoot(data, r)
2513+}
25872514
25882515// Approximate location parameters for the search.
25892516type ChatCompletionNewParamsWebSearchOptionsUserLocationApproximate struct {
@@ -2600,15 +2527,13 @@ type ChatCompletionNewParamsWebSearchOptionsUserLocationApproximate struct {
26002527 paramObj
26012528}
26022529
2603−// IsPresent returns true if the field's value is not omitted and not the JSON
2604−// "null". To check if this field is omitted, use [param.IsOmitted].
2605−func (f ChatCompletionNewParamsWebSearchOptionsUserLocationApproximate) IsPresent() bool {
2606− return !param.IsOmitted(f) && !f.IsNull()
2607−}
26082530func (r ChatCompletionNewParamsWebSearchOptionsUserLocationApproximate) MarshalJSON() (data []byte, err error) {
26092531 type shadow ChatCompletionNewParamsWebSearchOptionsUserLocationApproximate
26102532 return param.MarshalObject(r, (*shadow)(&r))
26112533}
2534+func (r *ChatCompletionNewParamsWebSearchOptionsUserLocationApproximate) UnmarshalJSON(data []byte) error {
2535+ return apijson.UnmarshalRoot(data, r)
2536+}
26122537
26132538type ChatCompletionUpdateParams struct {
26142539 // Set of 16 key-value pairs that can be attached to an object. This can be useful
@@ -2617,18 +2542,17 @@ type ChatCompletionUpdateParams struct {
26172542 //
26182543 // Keys are strings with a maximum length of 64 characters. Values are strings with
26192544 // a maximum length of 512 characters.
2620− Metadata shared.MetadataParam `json:"metadata,omitzero,required"`
2545+ Metadata shared.Metadata `json:"metadata,omitzero,required"`
26212546 paramObj
26222547}
26232548
2624−// IsPresent returns true if the field's value is not omitted and not the JSON
2625−// "null". To check if this field is omitted, use [param.IsOmitted].
2626−func (f ChatCompletionUpdateParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
2627−
26282549func (r ChatCompletionUpdateParams) MarshalJSON() (data []byte, err error) {
26292550 type shadow ChatCompletionUpdateParams
26302551 return param.MarshalObject(r, (*shadow)(&r))
26312552}
2553+func (r *ChatCompletionUpdateParams) UnmarshalJSON(data []byte) error {
2554+ return apijson.UnmarshalRoot(data, r)
2555+}
26322556
26332557type ChatCompletionListParams struct {
26342558 // Identifier for the last chat completion from the previous pagination request.
@@ -2640,7 +2564,7 @@ type ChatCompletionListParams struct {
26402564 // A list of metadata keys to filter the Chat Completions by. Example:
26412565 //
26422566 // `metadata[key1]=value1&metadata[key2]=value2`
2643− Metadata shared.MetadataParam `query:"metadata,omitzero" json:"-"`
2567+ Metadata shared.Metadata `query:"metadata,omitzero" json:"-"`
26442568 // Sort order for Chat Completions by timestamp. Use `asc` for ascending order or
26452569 // `desc` for descending order. Defaults to `asc`.
26462570 //
@@ -2649,13 +2573,9 @@ type ChatCompletionListParams struct {
26492573 paramObj
26502574}
26512575
2652−// IsPresent returns true if the field's value is not omitted and not the JSON
2653−// "null". To check if this field is omitted, use [param.IsOmitted].
2654−func (f ChatCompletionListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
2655−
26562576// URLQuery serializes [ChatCompletionListParams]'s query parameters as
26572577// `url.Values`.
2658−func (r ChatCompletionListParams) URLQuery() (v url.Values) {
2578+func (r ChatCompletionListParams) URLQuery() (v url.Values, err error) {
26592579 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
26602580 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
26612581 NestedFormat: apiquery.NestedQueryFormatBrackets,
vendor/github.com/openai/openai-go/chatcompletionmessage.go+1−5
@@ -77,13 +77,9 @@ type ChatCompletionMessageListParams struct {
7777 paramObj
7878}
7979
80−// IsPresent returns true if the field's value is not omitted and not the JSON
81−// "null". To check if this field is omitted, use [param.IsOmitted].
82−func (f ChatCompletionMessageListParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
83−
8480// URLQuery serializes [ChatCompletionMessageListParams]'s query parameters as
8581// `url.Values`.
86−func (r ChatCompletionMessageListParams) URLQuery() (v url.Values) {
82+func (r ChatCompletionMessageListParams) URLQuery() (v url.Values, err error) {
8783 return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
8884 ArrayFormat: apiquery.ArrayQueryFormatBrackets,
8985 NestedFormat: apiquery.NestedQueryFormatBrackets,
vendor/github.com/openai/openai-go/client.go+25−10
@@ -10,6 +10,7 @@ import (
1010 "github.com/openai/openai-go/internal/requestconfig"
1111 "github.com/openai/openai-go/option"
1212 "github.com/openai/openai-go/responses"
13+ "github.com/openai/openai-go/webhooks"
1314)
1415
1516// Client creates a struct with services and top level methods that help with
@@ -26,17 +27,24 @@ type Client struct {
2627 Moderations ModerationService
2728 Models ModelService
2829 FineTuning FineTuningService
30+ Graders GraderService
2931 VectorStores VectorStoreService
32+ Webhooks webhooks.WebhookService
3033 Beta BetaService
3134 Batches BatchService
3235 Uploads UploadService
3336 Responses responses.ResponseService
37+ Containers ContainerService
3438}
3539
3640// DefaultClientOptions read from the environment (OPENAI_API_KEY, OPENAI_ORG_ID,
37−// OPENAI_PROJECT_ID). This should be used to initialize new clients.
41+// OPENAI_PROJECT_ID, OPENAI_WEBHOOK_SECRET, OPENAI_BASE_URL). This should be used
42+// to initialize new clients.
3843func DefaultClientOptions() []option.RequestOption {
3944 defaults := []option.RequestOption{option.WithEnvironmentProduction()}
45+ if o, ok := os.LookupEnv("OPENAI_BASE_URL"); ok {
46+ defaults = append(defaults, option.WithBaseURL(o))
47+ }
4048 if o, ok := os.LookupEnv("OPENAI_API_KEY"); ok {
4149 defaults = append(defaults, option.WithAPIKey(o))
4250 }
@@ -46,13 +54,17 @@ func DefaultClientOptions() []option.RequestOption {
4654 if o, ok := os.LookupEnv("OPENAI_PROJECT_ID"); ok {
4755 defaults = append(defaults, option.WithProject(o))
4856 }
57+ if o, ok := os.LookupEnv("OPENAI_WEBHOOK_SECRET"); ok {
58+ defaults = append(defaults, option.WithWebhookSecret(o))
59+ }
4960 return defaults
5061}
5162
5263// NewClient generates a new client with the default option read from the
53−// environment (OPENAI_API_KEY, OPENAI_ORG_ID, OPENAI_PROJECT_ID). The option
54−// passed in as arguments are applied after these default arguments, and all option
55−// will be passed down to the services and requests that this client makes.
64+// environment (OPENAI_API_KEY, OPENAI_ORG_ID, OPENAI_PROJECT_ID,
65+// OPENAI_WEBHOOK_SECRET, OPENAI_BASE_URL). The option passed in as arguments are
66+// applied after these default arguments, and all option will be passed down to the
67+// services and requests that this client makes.
5668func NewClient(opts ...option.RequestOption) (r Client) {
5769 opts = append(DefaultClientOptions(), opts...)
5870
@@ -67,11 +79,14 @@ func NewClient(opts ...option.RequestOption) (r Client) {
6779 r.Moderations = NewModerationService(opts...)
6880 r.Models = NewModelService(opts...)
6981 r.FineTuning = NewFineTuningService(opts...)
82+ r.Graders = NewGraderService(opts...)
7083 r.VectorStores = NewVectorStoreService(opts...)
84+ r.Webhooks = webhooks.NewWebhookService(opts...)
7185 r.Beta = NewBetaService(opts...)
7286 r.Batches = NewBatchService(opts...)
7387 r.Uploads = NewUploadService(opts...)
7488 r.Responses = responses.NewResponseService(opts...)
89+ r.Containers = NewContainerService(opts...)
7590
7691 return
7792}
@@ -107,40 +122,40 @@ func NewClient(opts ...option.RequestOption) (r Client) {
107122//
108123// For even greater flexibility, see [option.WithResponseInto] and
109124// [option.WithResponseBodyInto].
110−func (r *Client) Execute(ctx context.Context, method string, path string, params interface{}, res interface{}, opts ...option.RequestOption) error {
125+func (r *Client) Execute(ctx context.Context, method string, path string, params any, res any, opts ...option.RequestOption) error {
111126 opts = append(r.Options, opts...)
112127 return requestconfig.ExecuteNewRequest(ctx, method, path, params, res, opts...)
113128}
114129
115130// Get makes a GET request with the given URL, params, and optionally deserializes
116131// to a response. See [Execute] documentation on the params and response.
117−func (r *Client) Get(ctx context.Context, path string, params interface{}, res interface{}, opts ...option.RequestOption) error {
132+func (r *Client) Get(ctx context.Context, path string, params any, res any, opts ...option.RequestOption) error {
118133 return r.Execute(ctx, http.MethodGet, path, params, res, opts...)
119134}
120135
121136// Post makes a POST request with the given URL, params, and optionally
122137// deserializes to a response. See [Execute] documentation on the params and
123138// response.
124−func (r *Client) Post(ctx context.Context, path string, params interface{}, res interface{}, opts ...option.RequestOption) error {
139+func (r *Client) Post(ctx context.Context, path string, params any, res any, opts ...option.RequestOption) error {
125140 return r.Execute(ctx, http.MethodPost, path, params, res, opts...)
126141}
127142
128143// Put makes a PUT request with the given URL, params, and optionally deserializes
129144// to a response. See [Execute] documentation on the params and response.
130−func (r *Client) Put(ctx context.Context, path string, params interface{}, res interface{}, opts ...option.RequestOption) error {
145+func (r *Client) Put(ctx context.Context, path string, params any, res any, opts ...option.RequestOption) error {
131146 return r.Execute(ctx, http.MethodPut, path, params, res, opts...)
132147}
133148
134149// Patch makes a PATCH request with the given URL, params, and optionally
135150// deserializes to a response. See [Execute] documentation on the params and
136151// response.
137−func (r *Client) Patch(ctx context.Context, path string, params interface{}, res interface{}, opts ...option.RequestOption) error {
152+func (r *Client) Patch(ctx context.Context, path string, params any, res any, opts ...option.RequestOption) error {
138153 return r.Execute(ctx, http.MethodPatch, path, params, res, opts...)
139154}
140155
141156// Delete makes a DELETE request with the given URL, params, and optionally
142157// deserializes to a response. See [Execute] documentation on the params and
143158// response.
144−func (r *Client) Delete(ctx context.Context, path string, params interface{}, res interface{}, opts ...option.RequestOption) error {
159+func (r *Client) Delete(ctx context.Context, path string, params any, res any, opts ...option.RequestOption) error {
145160 return r.Execute(ctx, http.MethodDelete, path, params, res, opts...)
146161}
vendor/github.com/openai/openai-go/completion.go+70−62
@@ -10,7 +10,7 @@ import (
1010 "github.com/openai/openai-go/internal/requestconfig"
1111 "github.com/openai/openai-go/option"
1212 "github.com/openai/openai-go/packages/param"
13− "github.com/openai/openai-go/packages/resp"
13+ "github.com/openai/openai-go/packages/respjson"
1414 "github.com/openai/openai-go/packages/ssestream"
1515 "github.com/openai/openai-go/shared/constant"
1616)
@@ -75,17 +75,16 @@ type Completion struct {
7575 SystemFingerprint string `json:"system_fingerprint"`
7676 // Usage statistics for the completion request.
7777 Usage CompletionUsage `json:"usage"`
78− // Metadata for the response, check the presence of optional fields with the
79− // [resp.Field.IsPresent] method.
78+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
8079 JSON struct {
81− ID resp.Field
82− Choices resp.Field
83− Created resp.Field
84− Model resp.Field
85− Object resp.Field
86− SystemFingerprint resp.Field
87− Usage resp.Field
88− ExtraFields map[string]resp.Field
80+ ID respjson.Field
81+ Choices respjson.Field
82+ Created respjson.Field
83+ Model respjson.Field
84+ Object respjson.Field
85+ SystemFingerprint respjson.Field
86+ Usage respjson.Field
87+ ExtraFields map[string]respjson.Field
8988 raw string
9089 } `json:"-"`
9190}
@@ -107,14 +106,13 @@ type CompletionChoice struct {
107106 Index int64 `json:"index,required"`
108107 Logprobs CompletionChoiceLogprobs `json:"logprobs,required"`
109108 Text string `json:"text,required"`
110− // Metadata for the response, check the presence of optional fields with the
111− // [resp.Field.IsPresent] method.
109+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
112110 JSON struct {
113− FinishReason resp.Field
114− Index resp.Field
115− Logprobs resp.Field
116− Text resp.Field
117− ExtraFields map[string]resp.Field
111+ FinishReason respjson.Field
112+ Index respjson.Field
113+ Logprobs respjson.Field
114+ Text respjson.Field
115+ ExtraFields map[string]respjson.Field
118116 raw string
119117 } `json:"-"`
120118}
@@ -142,14 +140,13 @@ type CompletionChoiceLogprobs struct {
142140 TokenLogprobs []float64 `json:"token_logprobs"`
143141 Tokens []string `json:"tokens"`
144142 TopLogprobs []map[string]float64 `json:"top_logprobs"`
145− // Metadata for the response, check the presence of optional fields with the
146− // [resp.Field.IsPresent] method.
143+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
147144 JSON struct {
148− TextOffset resp.Field
149− TokenLogprobs resp.Field
150− Tokens resp.Field
151− TopLogprobs resp.Field
152− ExtraFields map[string]resp.Field
145+ TextOffset respjson.Field
146+ TokenLogprobs respjson.Field
147+ Tokens respjson.Field
148+ TopLogprobs respjson.Field
149+ ExtraFields map[string]respjson.Field
153150 raw string
154151 } `json:"-"`
155152}
@@ -172,15 +169,14 @@ type CompletionUsage struct {
172169 CompletionTokensDetails CompletionUsageCompletionTokensDetails `json:"completion_tokens_details"`
173170 // Breakdown of tokens used in the prompt.
174171 PromptTokensDetails CompletionUsagePromptTokensDetails `json:"prompt_tokens_details"`
175− // Metadata for the response, check the presence of optional fields with the
176− // [resp.Field.IsPresent] method.
172+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
177173 JSON struct {
178− CompletionTokens resp.Field
179− PromptTokens resp.Field
180− TotalTokens resp.Field
181− CompletionTokensDetails resp.Field
182− PromptTokensDetails resp.Field
183− ExtraFields map[string]resp.Field
174+ CompletionTokens respjson.Field
175+ PromptTokens respjson.Field
176+ TotalTokens respjson.Field
177+ CompletionTokensDetails respjson.Field
178+ PromptTokensDetails respjson.Field
179+ ExtraFields map[string]respjson.Field
184180 raw string
185181 } `json:"-"`
186182}
@@ -205,14 +201,13 @@ type CompletionUsageCompletionTokensDetails struct {
205201 // still counted in the total completion tokens for purposes of billing, output,
206202 // and context window limits.
207203 RejectedPredictionTokens int64 `json:"rejected_prediction_tokens"`
208− // Metadata for the response, check the presence of optional fields with the
209− // [resp.Field.IsPresent] method.
204+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
210205 JSON struct {
211− AcceptedPredictionTokens resp.Field
212− AudioTokens resp.Field
213− ReasoningTokens resp.Field
214− RejectedPredictionTokens resp.Field
215− ExtraFields map[string]resp.Field
206+ AcceptedPredictionTokens respjson.Field
207+ AudioTokens respjson.Field
208+ ReasoningTokens respjson.Field
209+ RejectedPredictionTokens respjson.Field
210+ ExtraFields map[string]respjson.Field
216211 raw string
217212 } `json:"-"`
218213}
@@ -229,12 +224,11 @@ type CompletionUsagePromptTokensDetails struct {
229224 AudioTokens int64 `json:"audio_tokens"`
230225 // Cached tokens present in the prompt.
231226 CachedTokens int64 `json:"cached_tokens"`
232− // Metadata for the response, check the presence of optional fields with the
233− // [resp.Field.IsPresent] method.
227+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
234228 JSON struct {
235− AudioTokens resp.Field
236− CachedTokens resp.Field
237− ExtraFields map[string]resp.Field
229+ AudioTokens respjson.Field
230+ CachedTokens respjson.Field
231+ ExtraFields map[string]respjson.Field
238232 raw string
239233 } `json:"-"`
240234}
@@ -258,7 +252,7 @@ type CompletionNewParams struct {
258252 // see all of your available models, or see our
259253 // [Model overview](https://platform.openai.com/docs/models) for descriptions of
260254 // them.
261− Model string `json:"model,omitzero,required"`
255+ Model CompletionNewParamsModel `json:"model,omitzero,required"`
262256 // Generates `best_of` completions server-side and returns the "best" (the one with
263257 // the highest log probability per token). Results cannot be streamed.
264258 //
@@ -344,6 +338,8 @@ type CompletionNewParams struct {
344338 // As an example, you can pass `{"50256": -100}` to prevent the <|endoftext|> token
345339 // from being generated.
346340 LogitBias map[string]int64 `json:"logit_bias,omitzero"`
341+ // Not supported with latest reasoning models `o3` and `o4-mini`.
342+ //
347343 // Up to 4 sequences where the API will stop generating further tokens. The
348344 // returned text will not contain the stop sequence.
349345 Stop CompletionNewParamsStopUnion `json:"stop,omitzero"`
@@ -352,14 +348,26 @@ type CompletionNewParams struct {
352348 paramObj
353349}
354350
355−// IsPresent returns true if the field's value is not omitted and not the JSON
356−// "null". To check if this field is omitted, use [param.IsOmitted].
357−func (f CompletionNewParams) IsPresent() bool { return !param.IsOmitted(f) && !f.IsNull() }
358−
359351func (r CompletionNewParams) MarshalJSON() (data []byte, err error) {
360352 type shadow CompletionNewParams
361353 return param.MarshalObject(r, (*shadow)(&r))
362354}
355+func (r *CompletionNewParams) UnmarshalJSON(data []byte) error {
356+ return apijson.UnmarshalRoot(data, r)
357+}
358+
359+// ID of the model to use. You can use the
360+// [List models](https://platform.openai.com/docs/api-reference/models/list) API to
361+// see all of your available models, or see our
362+// [Model overview](https://platform.openai.com/docs/models) for descriptions of
363+// them.
364+type CompletionNewParamsModel string
365+
366+const (
367+ CompletionNewParamsModelGPT3_5TurboInstruct CompletionNewParamsModel = "gpt-3.5-turbo-instruct"
368+ CompletionNewParamsModelDavinci002 CompletionNewParamsModel = "davinci-002"
369+ CompletionNewParamsModelBabbage002 CompletionNewParamsModel = "babbage-002"
370+)
363371
364372// Only one field can be non-zero.
365373//
@@ -372,11 +380,11 @@ type CompletionNewParamsPromptUnion struct {
372380 paramUnion
373381}
374382
375−// IsPresent returns true if the field's value is not omitted and not the JSON
376−// "null". To check if this field is omitted, use [param.IsOmitted].
377−func (u CompletionNewParamsPromptUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() }
378383func (u CompletionNewParamsPromptUnion) MarshalJSON() ([]byte, error) {
379− return param.MarshalUnion[CompletionNewParamsPromptUnion](u.OfString, u.OfArrayOfStrings, u.OfArrayOfTokens, u.OfArrayOfTokenArrays)
384+ return param.MarshalUnion(u, u.OfString, u.OfArrayOfStrings, u.OfArrayOfTokens, u.OfArrayOfTokenArrays)
385+}
386+func (u *CompletionNewParamsPromptUnion) UnmarshalJSON(data []byte) error {
387+ return apijson.UnmarshalRoot(data, u)
380388}
381389
382390func (u *CompletionNewParamsPromptUnion) asAny() any {
@@ -396,23 +404,23 @@ func (u *CompletionNewParamsPromptUnion) asAny() any {
396404//
397405// Use [param.IsOmitted] to confirm if a field is set.
398406type CompletionNewParamsStopUnion struct {
399− OfString param.Opt[string] `json:",omitzero,inline"`
400− OfCompletionNewsStopArray []string `json:",omitzero,inline"`
407+ OfString param.Opt[string] `json:",omitzero,inline"`
408+ OfStringArray []string `json:",omitzero,inline"`
401409 paramUnion
402410}
403411
404−// IsPresent returns true if the field's value is not omitted and not the JSON
405−// "null". To check if this field is omitted, use [param.IsOmitted].
406−func (u CompletionNewParamsStopUnion) IsPresent() bool { return !param.IsOmitted(u) && !u.IsNull() }
407412func (u CompletionNewParamsStopUnion) MarshalJSON() ([]byte, error) {
408− return param.MarshalUnion[CompletionNewParamsStopUnion](u.OfString, u.OfCompletionNewsStopArray)
413+ return param.MarshalUnion(u, u.OfString, u.OfStringArray)
414+}
415+func (u *CompletionNewParamsStopUnion) UnmarshalJSON(data []byte) error {
416+ return apijson.UnmarshalRoot(data, u)
409417}
410418
411419func (u *CompletionNewParamsStopUnion) asAny() any {
412420 if !param.IsOmitted(u.OfString) {
413421 return &u.OfString.Value
414− } else if !param.IsOmitted(u.OfCompletionNewsStopArray) {
415− return &u.OfCompletionNewsStopArray
422+ } else if !param.IsOmitted(u.OfStringArray) {
423+ return &u.OfStringArray
416424 }
417425 return nil
418426}
vendor/github.com/openai/openai-go/container.gonew file+352

This diff is too big to show here.

vendor/github.com/openai/openai-go/containerfile.gonew file+286

This diff is too big to show here.

vendor/github.com/openai/openai-go/containerfilecontent.gonew file+49

This diff is too big to show here.

vendor/github.com/openai/openai-go/embedding.go+27−30

This diff is too big to show here.

vendor/github.com/openai/openai-go/file.go+22−29

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuning.go+8−2

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuningalpha.gonew file+28

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuningalphagrader.gonew file+672

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuningcheckpoint.gonew file+28

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuningcheckpointpermission.gonew file+254

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuningjob.go+160−796

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuningjobcheckpoint.go+20−28

This diff is too big to show here.

vendor/github.com/openai/openai-go/finetuningmethod.gonew file+1487

This diff is too big to show here.

vendor/github.com/openai/openai-go/grader.gonew file+28

This diff is too big to show here.

vendor/github.com/openai/openai-go/gradergradermodel.gonew file+1179

This diff is too big to show here.

vendor/github.com/openai/openai-go/image.go+386−89

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apierror/apierror.go+7−8

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apiform/encoder.go+96−32

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apiform/richparam.go+6−6

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apijson/decoder.go+91−79

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apijson/encoder.go+3−9

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apijson/enum.go+91−33

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apijson/registry.go+11−2

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apijson/subfield.go+9−9

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apijson/union.go+111−10

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apiquery/encoder.go+115−59

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apiquery/query.go+11−6

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/apiquery/richparam.go+9−9

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/encoding/json/encode.go+3−10

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/encoding/json/sentinel/null.go+25−36

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/encoding/json/time.go+12−10

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/param/field.godeleted−27

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/paramutil/field.gonew file+30

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/param/union.go → vendor/github.com/openai/openai-go/internal/paramutil/union.gorenamed+3−2

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/requestconfig/requestconfig.go+60−18

This diff is too big to show here.

vendor/github.com/openai/openai-go/internal/version.go+1−1

This diff is too big to show here.

vendor/github.com/openai/openai-go/model.go+12−14

This diff is too big to show here.

vendor/github.com/openai/openai-go/moderation.go+108−102

This diff is too big to show here.

vendor/github.com/openai/openai-go/option/middleware.gonew file+38

This diff is too big to show here.

vendor/github.com/openai/openai-go/option/requestoption.go+55−14

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/pagination/pagination.go+21−13

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/param/encoder.go+33−57

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/param/null.gonew file+19

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/param/option.go+73−55

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/param/param.go+109−48

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/param/sentinel.godeleted−31

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/resp/resp.godeleted−56

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/respjson/respjson.gonew file+88

This diff is too big to show here.

vendor/github.com/openai/openai-go/packages/ssestream/ssestream.go+8−4

This diff is too big to show here.

vendor/github.com/openai/openai-go/polling.go+2−41

This diff is too big to show here.

vendor/github.com/openai/openai-go/responses/aliases.go+76−24

This diff is too big to show here.

vendor/github.com/openai/openai-go/responses/inputitem.go+14−16

This diff is too big to show here.

vendor/github.com/openai/openai-go/responses/response.go+8769−3514

This diff is too big to show here.

vendor/github.com/openai/openai-go/shared/constant/constants.go+346−145

This diff is too big to show here.

vendor/github.com/openai/openai-go/shared/shared.go+171−123

This diff is too big to show here.

vendor/github.com/openai/openai-go/streamaccumulator.go+6−6

This diff is too big to show here.

vendor/github.com/openai/openai-go/upload.go+18−21

This diff is too big to show here.

vendor/github.com/openai/openai-go/uploadpart.go+11−14

This diff is too big to show here.

vendor/github.com/openai/openai-go/vectorstore.go+129−150

This diff is too big to show here.

vendor/github.com/openai/openai-go/vectorstorefile.go+43−57

This diff is too big to show here.

vendor/github.com/openai/openai-go/vectorstorefilebatch.go+24−35

This diff is too big to show here.

vendor/github.com/openai/openai-go/webhooks/aliases.gonew file+440

This diff is too big to show here.

vendor/github.com/openai/openai-go/webhooks/webhook.gonew file+1208

This diff is too big to show here.

vendor/github.com/spf13/cast/.gitignorenew file+25

This diff is too big to show here.

vendor/github.com/spf13/cast/LICENSEnew file+21

This diff is too big to show here.

vendor/github.com/spf13/cast/Makefilenew file+40

This diff is too big to show here.

vendor/github.com/spf13/cast/README.mdnew file+75

This diff is too big to show here.

vendor/github.com/spf13/cast/cast.gonew file+176

This diff is too big to show here.

vendor/github.com/spf13/cast/caste.gonew file+1510

This diff is too big to show here.

vendor/github.com/spf13/cast/timeformattype_string.gonew file+27

This diff is too big to show here.

vendor/modules.txt+16−9

This diff is too big to show here.