github.com/anthropics/anthropic-sdk-go@v1.70.1/messageutil.go (about)

     1  package anthropic
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/tidwall/gjson"
     9  	"github.com/tidwall/sjson"
    10  
    11  	"github.com/anthropics/anthropic-sdk-go/internal/apijson"
    12  	"github.com/anthropics/anthropic-sdk-go/internal/paramutil"
    13  	"github.com/anthropics/anthropic-sdk-go/packages/param"
    14  )
    15  
    16  // Accumulate builds up the Message incrementally from a MessageStreamEvent. The Message then can be used as
    17  // any other Message, including the Message.JSON field, which holds the wire JSON with the streamed deltas
    18  // applied and is complete once message_stop arrives.
    19  //
    20  //	message := anthropic.Message{}
    21  //	for stream.Next() {
    22  //		event := stream.Current()
    23  //		message.Accumulate(event)
    24  //	}
    25  func (acc *Message) Accumulate(event MessageStreamEventUnion) error {
    26  	if acc == nil {
    27  		return fmt.Errorf("accumulate: cannot accumulate into nil Message")
    28  	}
    29  
    30  	switch event.Type {
    31  	case "message_start":
    32  		*acc = event.Message
    33  	case "message_delta":
    34  		// stop_reason, stop_sequence and stop_details are always sent and null is
    35  		// their final value when the turn carries no such detail.
    36  		acc.StopReason = event.Delta.StopReason
    37  		acc.StopSequence = event.Delta.StopSequence
    38  		acc.StopDetails = event.Delta.StopDetails
    39  		if event.Delta.JSON.Container.Valid() {
    40  			acc.Container = event.Delta.Container
    41  		}
    42  		// Every usage count here is a cumulative whole-message total, so it
    43  		// overwrites rather than adds; the ones that do not apply are omitted, and
    44  		// message_start keeps the last word on those.
    45  		acc.Usage.OutputTokens = event.Usage.OutputTokens
    46  		if event.Usage.JSON.InputTokens.Valid() {
    47  			acc.Usage.InputTokens = event.Usage.InputTokens
    48  		}
    49  		if event.Usage.JSON.CacheCreationInputTokens.Valid() {
    50  			acc.Usage.CacheCreationInputTokens = event.Usage.CacheCreationInputTokens
    51  		}
    52  		if event.Usage.JSON.CacheReadInputTokens.Valid() {
    53  			acc.Usage.CacheReadInputTokens = event.Usage.CacheReadInputTokens
    54  		}
    55  		if event.Usage.JSON.ServerToolUse.Valid() {
    56  			acc.Usage.ServerToolUse = event.Usage.ServerToolUse
    57  		}
    58  		if event.Usage.JSON.OutputTokensDetails.Valid() {
    59  			acc.Usage.OutputTokensDetails = event.Usage.OutputTokensDetails
    60  		}
    61  		acc.JSON.raw = mergeRaw(acc.JSON.raw, "", event.Delta.JSON.raw)
    62  		acc.JSON.raw = mergeRaw(acc.JSON.raw, "usage", event.Usage.RawJSON())
    63  	case "content_block_start":
    64  		// Content blocks start in index order with no gaps: a start event always
    65  		// addresses the slot right after the previous block, even when deltas and
    66  		// stops for still-open blocks interleave after it.
    67  		if event.Index != int64(len(acc.Content)) {
    68  			return fmt.Errorf("received event of type %s for content block at index %d, expected index %d", event.Type, event.Index, len(acc.Content))
    69  		}
    70  		acc.Content = append(acc.Content, ContentBlockUnion{})
    71  		err := acc.Content[event.Index].UnmarshalJSON([]byte(event.ContentBlock.RawJSON()))
    72  		if err != nil {
    73  			return err
    74  		}
    75  	case "content_block_delta":
    76  		if err := checkContentBlockIndex(event.Type, event.Index, len(acc.Content)); err != nil {
    77  			return err
    78  		}
    79  		cb := &acc.Content[event.Index]
    80  		switch event.Delta.Type {
    81  		case "text_delta":
    82  			cb.Text += event.Delta.Text
    83  		case "input_json_delta":
    84  			if len(event.Delta.PartialJSON) != 0 {
    85  				if string(cb.Input) == "{}" {
    86  					cb.Input = []byte(event.Delta.PartialJSON)
    87  				} else {
    88  					cb.Input = append(cb.Input, event.Delta.PartialJSON...)
    89  				}
    90  			}
    91  		case "thinking_delta":
    92  			cb.Thinking += event.Delta.Thinking
    93  		case "signature_delta":
    94  			cb.Signature += event.Delta.Signature
    95  		case "citations_delta":
    96  			citation := TextCitationUnion{}
    97  			err := citation.UnmarshalJSON([]byte(event.Delta.Citation.RawJSON()))
    98  			if err != nil {
    99  				return fmt.Errorf("could not unmarshal citation delta into citation type: %w", err)
   100  			}
   101  			cb.Citations = append(cb.Citations, citation)
   102  		}
   103  	case "message_stop":
   104  		// A block whose stop event never arrived has not been refreshed yet.
   105  		for i := range acc.Content {
   106  			refreshContentBlockRaw(&acc.Content[i])
   107  		}
   108  		acc.JSON.raw, _ = sjson.SetRaw(acc.JSON.raw, "content", rawArray(acc.Content))
   109  	case "content_block_stop":
   110  		if err := checkContentBlockIndex(event.Type, event.Index, len(acc.Content)); err != nil {
   111  			return err
   112  		}
   113  		refreshContentBlockRaw(&acc.Content[event.Index])
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  // refreshContentBlockRaw overlays the delta-mutated fields onto the block's
   120  // wire JSON, leaving a block that received no deltas byte for byte.
   121  func refreshContentBlockRaw(cb *ContentBlockUnion) {
   122  	raw := cb.JSON.raw
   123  	if cb.Text != "" {
   124  		raw, _ = sjson.SetRaw(raw, "text", jsonString(cb.Text))
   125  	}
   126  	if cb.Thinking != "" {
   127  		raw, _ = sjson.SetRaw(raw, "thinking", jsonString(cb.Thinking))
   128  	}
   129  	if cb.Signature != "" {
   130  		raw, _ = sjson.SetRaw(raw, "signature", jsonString(cb.Signature))
   131  	}
   132  	if json.Valid(cb.Input) {
   133  		raw, _ = sjson.SetRaw(raw, "input", string(cb.Input))
   134  	} else if len(cb.Input) > 0 {
   135  		// A cut-off tool call left non-JSON input; empty it so the block marshals.
   136  		cb.Input = json.RawMessage(`{}`)
   137  	}
   138  	if len(cb.Citations) > 0 {
   139  		raw, _ = sjson.SetRaw(raw, "citations", rawArray(cb.Citations))
   140  	}
   141  	cb.JSON.raw = raw
   142  }
   143  
   144  // jsonString encodes s as the server does, leaving <, > and & literal, which
   145  // sjson.Set does inconsistently.
   146  func jsonString(s string) string {
   147  	var b strings.Builder
   148  	enc := json.NewEncoder(&b)
   149  	enc.SetEscapeHTML(false)
   150  	enc.Encode(s)
   151  	return strings.TrimSuffix(b.String(), "\n")
   152  }
   153  
   154  // mergeRaw merges the wire object src into dst at path, skipping the nulls
   155  // message_delta sends for values it is not updating.
   156  func mergeRaw(dst, path, src string) string {
   157  	if path != "" {
   158  		path += "."
   159  	}
   160  	gjson.Parse(src).ForEach(func(key, value gjson.Result) bool {
   161  		if value.Type == gjson.Null {
   162  			return true
   163  		}
   164  		dst, _ = sjson.SetRaw(dst, path+apijson.EscapeSJSONKey(key.String()), value.Raw)
   165  		return true
   166  	})
   167  	return dst
   168  }
   169  
   170  // rawArray renders the wire JSON of each item as an array, skipping any item
   171  // with none, such as a block whose start event carried no content_block.
   172  func rawArray[T interface{ RawJSON() string }](items []T) string {
   173  	raws := make([]string, 0, len(items))
   174  	for _, item := range items {
   175  		if raw := item.RawJSON(); raw != "" {
   176  			raws = append(raws, raw)
   177  		}
   178  	}
   179  	return "[" + strings.Join(raws, ",") + "]"
   180  }
   181  
   182  // checkContentBlockIndex reports an error if a stream event's index does not
   183  // address one of the numBlocks content blocks accumulated so far. Delta and
   184  // stop events may interleave across open content blocks, so they address
   185  // blocks by index rather than applying to the most recently started block.
   186  func checkContentBlockIndex(eventType string, index int64, numBlocks int) error {
   187  	if index < 0 || index >= int64(numBlocks) {
   188  		return fmt.Errorf("received event of type %s for content block at index %d but there are only %d content blocks", eventType, index, numBlocks)
   189  	}
   190  	return nil
   191  }
   192  
   193  // ToParam converters
   194  
   195  func (r Message) ToParam() MessageParam {
   196  	var p MessageParam
   197  	p.Role = MessageParamRole(r.Role)
   198  	p.Content = make([]ContentBlockParamUnion, len(r.Content))
   199  	for i, c := range r.Content {
   200  		p.Content[i] = c.ToParam()
   201  	}
   202  	return p
   203  }
   204  
   205  func (r ContentBlockUnion) ToParam() ContentBlockParamUnion {
   206  	return r.AsAny().toParamUnion()
   207  }
   208  
   209  func (variant TextBlock) toParamUnion() ContentBlockParamUnion {
   210  	p := variant.ToParam()
   211  	return ContentBlockParamUnion{OfText: &p}
   212  }
   213  
   214  func (variant ToolUseBlock) toParamUnion() ContentBlockParamUnion {
   215  	p := variant.ToParam()
   216  	return ContentBlockParamUnion{OfToolUse: &p}
   217  }
   218  
   219  func (variant WebSearchToolResultBlock) toParamUnion() ContentBlockParamUnion {
   220  	p := variant.ToParam()
   221  	return ContentBlockParamUnion{OfWebSearchToolResult: &p}
   222  }
   223  
   224  func (variant ServerToolUseBlock) toParamUnion() ContentBlockParamUnion {
   225  	p := variant.ToParam()
   226  	return ContentBlockParamUnion{OfServerToolUse: &p}
   227  }
   228  
   229  func (variant ThinkingBlock) toParamUnion() ContentBlockParamUnion {
   230  	p := variant.ToParam()
   231  	return ContentBlockParamUnion{OfThinking: &p}
   232  }
   233  
   234  func (variant RedactedThinkingBlock) toParamUnion() ContentBlockParamUnion {
   235  	p := variant.ToParam()
   236  	return ContentBlockParamUnion{OfRedactedThinking: &p}
   237  }
   238  
   239  func (r RedactedThinkingBlock) ToParam() RedactedThinkingBlockParam {
   240  	var p RedactedThinkingBlockParam
   241  	p.Type = r.Type
   242  	p.Data = r.Data
   243  	return p
   244  }
   245  
   246  func (r ToolUseBlock) ToParam() ToolUseBlockParam {
   247  	var toolUse ToolUseBlockParam
   248  	toolUse.Type = r.Type
   249  	toolUse.ID = r.ID
   250  	toolUse.Input = r.Input
   251  	toolUse.Name = r.Name
   252  	toolUse.ToolsetName = paramutil.ToOpt(r.ToolsetName, r.JSON.ToolsetName)
   253  	if r.JSON.Caller.Valid() {
   254  		toolUse.Caller = r.Caller.toParam()
   255  	}
   256  	return toolUse
   257  }
   258  
   259  // toParam converts a caller. The other three caller unions share this layout
   260  // and convert through it.
   261  func (r ToolUseBlockCallerUnion) toParam() ToolUseBlockParamCallerUnion {
   262  	var p ToolUseBlockParamCallerUnion
   263  	switch v := r.AsAny().(type) {
   264  	case DirectCaller:
   265  		c := v.ToParam()
   266  		p.OfDirect = &c
   267  	case ServerToolCaller:
   268  		c := v.ToParam()
   269  		p.OfCodeExecution20250825 = &c
   270  	case ServerToolCaller20260120:
   271  		c := v.ToParam()
   272  		p.OfCodeExecution20260120 = &c
   273  	default:
   274  		p = param.Override[ToolUseBlockParamCallerUnion](json.RawMessage(r.RawJSON()))
   275  	}
   276  	return p
   277  }
   278  
   279  func (r ServerToolUseBlockCallerUnion) toParam() ServerToolUseBlockParamCallerUnion {
   280  	return ServerToolUseBlockParamCallerUnion(ToolUseBlockCallerUnion(r).toParam())
   281  }
   282  
   283  func (r WebSearchToolResultBlockCallerUnion) toParam() WebSearchToolResultBlockParamCallerUnion {
   284  	return WebSearchToolResultBlockParamCallerUnion(ToolUseBlockCallerUnion(r).toParam())
   285  }
   286  
   287  func (r WebFetchToolResultBlockCallerUnion) toParam() WebFetchToolResultBlockParamCallerUnion {
   288  	return WebFetchToolResultBlockParamCallerUnion(ToolUseBlockCallerUnion(r).toParam())
   289  }
   290  
   291  func (citationVariant CitationCharLocation) toParamUnion() TextCitationParamUnion {
   292  	var citationParam CitationCharLocationParam
   293  	citationParam.Type = citationVariant.Type
   294  	citationParam.DocumentTitle = paramutil.ToOpt(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle)
   295  	citationParam.CitedText = citationVariant.CitedText
   296  	citationParam.DocumentIndex = citationVariant.DocumentIndex
   297  	citationParam.EndCharIndex = citationVariant.EndCharIndex
   298  	citationParam.StartCharIndex = citationVariant.StartCharIndex
   299  	return TextCitationParamUnion{OfCharLocation: &citationParam}
   300  }
   301  
   302  func (citationVariant CitationPageLocation) toParamUnion() TextCitationParamUnion {
   303  	var citationParam CitationPageLocationParam
   304  	citationParam.Type = citationVariant.Type
   305  	citationParam.DocumentTitle = paramutil.ToOpt(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle)
   306  	citationParam.CitedText = citationVariant.CitedText
   307  	citationParam.DocumentIndex = citationVariant.DocumentIndex
   308  	citationParam.EndPageNumber = citationVariant.EndPageNumber
   309  	citationParam.StartPageNumber = citationVariant.StartPageNumber
   310  	return TextCitationParamUnion{OfPageLocation: &citationParam}
   311  }
   312  
   313  func (citationVariant CitationContentBlockLocation) toParamUnion() TextCitationParamUnion {
   314  	var citationParam CitationContentBlockLocationParam
   315  	citationParam.Type = citationVariant.Type
   316  	citationParam.DocumentTitle = paramutil.ToOpt(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle)
   317  	citationParam.CitedText = citationVariant.CitedText
   318  	citationParam.DocumentIndex = citationVariant.DocumentIndex
   319  	citationParam.EndBlockIndex = citationVariant.EndBlockIndex
   320  	citationParam.StartBlockIndex = citationVariant.StartBlockIndex
   321  	return TextCitationParamUnion{OfContentBlockLocation: &citationParam}
   322  }
   323  
   324  func (citationVariant CitationsSearchResultLocation) toParamUnion() TextCitationParamUnion {
   325  	var citationParam CitationSearchResultLocationParam
   326  	citationParam.Type = citationVariant.Type
   327  	citationParam.CitedText = citationVariant.CitedText
   328  	citationParam.Title = paramutil.ToOpt(citationVariant.Title, citationVariant.JSON.Title)
   329  	citationParam.EndBlockIndex = citationVariant.EndBlockIndex
   330  	citationParam.SearchResultIndex = citationVariant.SearchResultIndex
   331  	citationParam.Source = citationVariant.Source
   332  	citationParam.StartBlockIndex = citationVariant.StartBlockIndex
   333  	return TextCitationParamUnion{OfSearchResultLocation: &citationParam}
   334  }
   335  
   336  func (citationVariant CitationsWebSearchResultLocation) toParamUnion() TextCitationParamUnion {
   337  	var citationParam CitationWebSearchResultLocationParam
   338  	citationParam.Type = citationVariant.Type
   339  	citationParam.CitedText = citationVariant.CitedText
   340  	citationParam.Title = paramutil.ToOpt(citationVariant.Title, citationVariant.JSON.Title)
   341  	citationParam.EncryptedIndex = citationVariant.EncryptedIndex
   342  	citationParam.URL = citationVariant.URL
   343  	return TextCitationParamUnion{OfWebSearchResultLocation: &citationParam}
   344  }
   345  
   346  func (r TextBlock) ToParam() TextBlockParam {
   347  	var p TextBlockParam
   348  	p.Type = r.Type
   349  	p.Text = r.Text
   350  
   351  	// Distinguish between a nil and zero length slice, since some compatible
   352  	// APIs may not require citations.
   353  	if r.Citations != nil {
   354  		p.Citations = make([]TextCitationParamUnion, 0, len(r.Citations))
   355  	}
   356  
   357  	for _, citation := range r.Citations {
   358  		p.Citations = append(p.Citations, citation.AsAny().toParamUnion())
   359  	}
   360  
   361  	return p
   362  }
   363  
   364  func (r ThinkingBlock) ToParam() ThinkingBlockParam {
   365  	var p ThinkingBlockParam
   366  	p.Type = r.Type
   367  	p.Signature = r.Signature
   368  	p.Thinking = r.Thinking
   369  	return p
   370  }
   371  
   372  func (r ServerToolUseBlock) ToParam() ServerToolUseBlockParam {
   373  	var p ServerToolUseBlockParam
   374  	p.Type = r.Type
   375  	p.ID = r.ID
   376  	p.Input = r.Input
   377  	p.Name = ServerToolUseBlockParamName(r.Name)
   378  	if r.JSON.Caller.Valid() {
   379  		p.Caller = r.Caller.toParam()
   380  	}
   381  	return p
   382  }
   383  
   384  func (r WebSearchToolResultBlock) ToParam() WebSearchToolResultBlockParam {
   385  	var p WebSearchToolResultBlockParam
   386  	p.Type = r.Type
   387  	p.ToolUseID = r.ToolUseID
   388  	p.Content = r.Content.ToParam()
   389  	if r.JSON.Caller.Valid() {
   390  		p.Caller = r.Caller.toParam()
   391  	}
   392  	return p
   393  }
   394  
   395  func (r WebSearchResultBlock) ToParam() WebSearchResultBlockParam {
   396  	var p WebSearchResultBlockParam
   397  	p.Type = r.Type
   398  	p.EncryptedContent = r.EncryptedContent
   399  	p.Title = r.Title
   400  	p.URL = r.URL
   401  	p.PageAge = paramutil.ToOpt(r.PageAge, r.JSON.PageAge)
   402  	return p
   403  }
   404  
   405  func (r WebSearchToolResultBlockContentUnion) ToParam() WebSearchToolResultBlockParamContentUnion {
   406  	var p WebSearchToolResultBlockParamContentUnion
   407  
   408  	if r.JSON.OfWebSearchResultBlockArray.Valid() {
   409  		// content is required, so send [] rather than omitting it.
   410  		p.OfWebSearchToolResultBlockItem = make([]WebSearchResultBlockParam, 0, len(r.OfWebSearchResultBlockArray))
   411  		for _, block := range r.OfWebSearchResultBlockArray {
   412  			p.OfWebSearchToolResultBlockItem = append(p.OfWebSearchToolResultBlockItem, block.ToParam())
   413  		}
   414  		return p
   415  	}
   416  
   417  	p.OfRequestWebSearchToolResultError = &WebSearchToolRequestErrorParam{
   418  		ErrorCode: WebSearchToolResultErrorCode(r.ErrorCode),
   419  	}
   420  	return p
   421  }
   422  
   423  func (variant WebFetchToolResultBlock) toParamUnion() ContentBlockParamUnion {
   424  	p := variant.ToParam()
   425  	return ContentBlockParamUnion{OfWebFetchToolResult: &p}
   426  }
   427  
   428  func (variant CodeExecutionToolResultBlock) toParamUnion() ContentBlockParamUnion {
   429  	p := variant.ToParam()
   430  	return ContentBlockParamUnion{OfCodeExecutionToolResult: &p}
   431  }
   432  
   433  func (variant BashCodeExecutionToolResultBlock) toParamUnion() ContentBlockParamUnion {
   434  	p := variant.ToParam()
   435  	return ContentBlockParamUnion{OfBashCodeExecutionToolResult: &p}
   436  }
   437  
   438  func (variant TextEditorCodeExecutionToolResultBlock) toParamUnion() ContentBlockParamUnion {
   439  	p := variant.ToParam()
   440  	return ContentBlockParamUnion{OfTextEditorCodeExecutionToolResult: &p}
   441  }
   442  
   443  func (variant ToolSearchToolResultBlock) toParamUnion() ContentBlockParamUnion {
   444  	p := variant.ToParam()
   445  	return ContentBlockParamUnion{OfToolSearchToolResult: &p}
   446  }
   447  
   448  func (variant ContainerUploadBlock) toParamUnion() ContentBlockParamUnion {
   449  	p := variant.ToParam()
   450  	return ContentBlockParamUnion{OfContainerUpload: &p}
   451  }
   452  
   453  func (r WebFetchToolResultBlock) ToParam() WebFetchToolResultBlockParam {
   454  	var p WebFetchToolResultBlockParam
   455  	p.Type = r.Type
   456  	p.ToolUseID = r.ToolUseID
   457  	if r.Content.JSON.ErrorCode.Valid() {
   458  		p.Content.OfRequestWebFetchToolResultError = &WebFetchToolResultErrorBlockParam{
   459  			ErrorCode: r.Content.ErrorCode,
   460  		}
   461  	} else {
   462  		p.Content = param.Override[WebFetchToolResultBlockParamContentUnion](json.RawMessage(r.Content.RawJSON()))
   463  	}
   464  	if r.JSON.Caller.Valid() {
   465  		p.Caller = r.Caller.toParam()
   466  	}
   467  	return p
   468  }
   469  
   470  func (r ContainerUploadBlock) ToParam() ContainerUploadBlockParam {
   471  	var p ContainerUploadBlockParam
   472  	p.Type = r.Type
   473  	p.FileID = r.FileID
   474  	return p
   475  }
   476  
   477  func (r BashCodeExecutionToolResultBlock) ToParam() BashCodeExecutionToolResultBlockParam {
   478  	var p BashCodeExecutionToolResultBlockParam
   479  	p.Type = r.Type
   480  	p.ToolUseID = r.ToolUseID
   481  
   482  	if r.Content.JSON.ErrorCode.Valid() {
   483  		p.Content.OfRequestBashCodeExecutionToolResultError = &BashCodeExecutionToolResultErrorParam{
   484  			ErrorCode: BashCodeExecutionToolResultErrorCode(r.Content.ErrorCode),
   485  		}
   486  	} else {
   487  		requestBashContentResult := &BashCodeExecutionResultBlockParam{
   488  			// content is required, so send [] rather than omitting it.
   489  			Content:    make([]BashCodeExecutionOutputBlockParam, 0, len(r.Content.Content)),
   490  			ReturnCode: r.Content.ReturnCode,
   491  			Stderr:     r.Content.Stderr,
   492  			Stdout:     r.Content.Stdout,
   493  		}
   494  		for _, block := range r.Content.Content {
   495  			requestBashContentResult.Content = append(requestBashContentResult.Content, block.ToParam())
   496  		}
   497  		p.Content.OfRequestBashCodeExecutionResultBlock = requestBashContentResult
   498  	}
   499  
   500  	return p
   501  }
   502  
   503  func (r BashCodeExecutionOutputBlock) ToParam() BashCodeExecutionOutputBlockParam {
   504  	var p BashCodeExecutionOutputBlockParam
   505  	p.Type = r.Type
   506  	p.FileID = r.FileID
   507  	return p
   508  }
   509  
   510  func (r CodeExecutionToolResultBlock) ToParam() CodeExecutionToolResultBlockParam {
   511  	var p CodeExecutionToolResultBlockParam
   512  	p.Type = r.Type
   513  	p.ToolUseID = r.ToolUseID
   514  	// content is required, so send [] rather than omitting it.
   515  	files := make([]CodeExecutionOutputBlockParam, 0, len(r.Content.Content))
   516  	for _, block := range r.Content.Content {
   517  		files = append(files, block.ToParam())
   518  	}
   519  	switch {
   520  	case r.Content.JSON.ErrorCode.Valid():
   521  		p.Content.OfRequestCodeExecutionToolResultError = &CodeExecutionToolResultErrorParam{
   522  			ErrorCode: r.Content.ErrorCode,
   523  		}
   524  	case r.Content.JSON.EncryptedStdout.Valid():
   525  		p.Content.OfRequestEncryptedCodeExecutionResultBlock = &EncryptedCodeExecutionResultBlockParam{
   526  			Content:         files,
   527  			EncryptedStdout: r.Content.EncryptedStdout,
   528  			ReturnCode:      r.Content.ReturnCode,
   529  			Stderr:          r.Content.Stderr,
   530  		}
   531  	default:
   532  		p.Content.OfRequestCodeExecutionResultBlock = &CodeExecutionResultBlockParam{
   533  			Content:    files,
   534  			ReturnCode: r.Content.ReturnCode,
   535  			Stderr:     r.Content.Stderr,
   536  			Stdout:     r.Content.Stdout,
   537  		}
   538  	}
   539  	return p
   540  }
   541  
   542  func (r CodeExecutionOutputBlock) ToParam() CodeExecutionOutputBlockParam {
   543  	var p CodeExecutionOutputBlockParam
   544  	p.Type = r.Type
   545  	p.FileID = r.FileID
   546  	return p
   547  }
   548  
   549  func (r TextEditorCodeExecutionToolResultBlock) ToParam() TextEditorCodeExecutionToolResultBlockParam {
   550  	var p TextEditorCodeExecutionToolResultBlockParam
   551  	p.Type = r.Type
   552  	p.ToolUseID = r.ToolUseID
   553  	if r.Content.JSON.ErrorCode.Valid() {
   554  		p.Content.OfRequestTextEditorCodeExecutionToolResultError = &TextEditorCodeExecutionToolResultErrorParam{
   555  			ErrorCode:    TextEditorCodeExecutionToolResultErrorCode(r.Content.ErrorCode),
   556  			ErrorMessage: paramutil.ToOpt(r.Content.ErrorMessage, r.Content.JSON.ErrorMessage),
   557  		}
   558  	} else {
   559  		p.Content = param.Override[TextEditorCodeExecutionToolResultBlockParamContentUnion](json.RawMessage(r.Content.RawJSON()))
   560  	}
   561  	return p
   562  }
   563  
   564  func (r ToolSearchToolResultBlock) ToParam() ToolSearchToolResultBlockParam {
   565  	var p ToolSearchToolResultBlockParam
   566  	p.Type = r.Type
   567  	p.ToolUseID = r.ToolUseID
   568  	if r.Content.JSON.ErrorCode.Valid() {
   569  		p.Content.OfRequestToolSearchToolResultError = &ToolSearchToolResultErrorParam{
   570  			ErrorCode:    ToolSearchToolResultErrorCode(r.Content.ErrorCode),
   571  			ErrorMessage: paramutil.ToOpt(r.Content.ErrorMessage, r.Content.JSON.ErrorMessage),
   572  		}
   573  	} else {
   574  		p.Content.OfRequestToolSearchToolSearchResultBlock = &ToolSearchToolSearchResultBlockParam{
   575  			// tool_references is required, so send [] rather than omitting it.
   576  			ToolReferences: make([]ToolReferenceBlockParam, 0, len(r.Content.ToolReferences)),
   577  		}
   578  		for _, block := range r.Content.ToolReferences {
   579  			p.Content.OfRequestToolSearchToolSearchResultBlock.ToolReferences = append(
   580  				p.Content.OfRequestToolSearchToolSearchResultBlock.ToolReferences,
   581  				block.ToParam(),
   582  			)
   583  		}
   584  	}
   585  	return p
   586  }
   587  
   588  func (r ToolReferenceBlock) ToParam() ToolReferenceBlockParam {
   589  	var p ToolReferenceBlockParam
   590  	p.Type = r.Type
   591  	p.ToolName = r.ToolName
   592  	return p
   593  }