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

     1  package anthropic
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  
     7  	"github.com/tidwall/sjson"
     8  
     9  	"github.com/anthropics/anthropic-sdk-go/internal/paramutil"
    10  	"github.com/anthropics/anthropic-sdk-go/packages/param"
    11  )
    12  
    13  // Accumulate builds up the Message incrementally from a MessageStreamEvent. The Message then can be used as
    14  // any other Message, including the Message.JSON field, which holds the wire JSON with the streamed deltas
    15  // applied and is complete once message_stop arrives.
    16  //
    17  //	message := anthropic.Message{}
    18  //	for stream.Next() {
    19  //		event := stream.Current()
    20  //		message.Accumulate(event)
    21  //	}
    22  func (acc *BetaMessage) Accumulate(event BetaRawMessageStreamEventUnion) error {
    23  	if acc == nil {
    24  		return fmt.Errorf("accumulate: cannot accumulate into nil Message")
    25  	}
    26  
    27  	switch event.Type {
    28  	case "message_start":
    29  		*acc = event.Message
    30  	case "message_delta":
    31  		// stop_reason, stop_sequence and stop_details are always sent and null is
    32  		// their final value when the turn carries no such detail.
    33  		acc.StopReason = event.Delta.StopReason
    34  		acc.StopSequence = event.Delta.StopSequence
    35  		acc.StopDetails = event.Delta.StopDetails
    36  		if event.Delta.JSON.Container.Valid() {
    37  			acc.Container = event.Delta.Container
    38  		}
    39  		// Every usage count here is a cumulative whole-message total, so it
    40  		// overwrites rather than adds; the ones that do not apply are omitted, and
    41  		// message_start keeps the last word on those.
    42  		acc.Usage.OutputTokens = event.Usage.OutputTokens
    43  		if event.Usage.JSON.InputTokens.Valid() {
    44  			acc.Usage.InputTokens = event.Usage.InputTokens
    45  		}
    46  		if event.Usage.JSON.CacheCreationInputTokens.Valid() {
    47  			acc.Usage.CacheCreationInputTokens = event.Usage.CacheCreationInputTokens
    48  		}
    49  		if event.Usage.JSON.CacheReadInputTokens.Valid() {
    50  			acc.Usage.CacheReadInputTokens = event.Usage.CacheReadInputTokens
    51  		}
    52  		if event.Usage.JSON.ServerToolUse.Valid() {
    53  			acc.Usage.ServerToolUse = event.Usage.ServerToolUse
    54  		}
    55  		if event.Usage.JSON.OutputTokensDetails.Valid() {
    56  			acc.Usage.OutputTokensDetails = event.Usage.OutputTokensDetails
    57  		}
    58  		if event.Usage.JSON.FallbackCredit.Valid() {
    59  			acc.Usage.FallbackCredit = event.Usage.FallbackCredit
    60  		}
    61  		if event.Usage.JSON.Iterations.Valid() {
    62  			acc.Usage.Iterations = event.Usage.Iterations
    63  		}
    64  		if event.JSON.ContextManagement.Valid() {
    65  			acc.ContextManagement = event.ContextManagement
    66  			acc.JSON.raw, _ = sjson.SetRaw(acc.JSON.raw, "context_management", event.ContextManagement.RawJSON())
    67  		}
    68  		// Sent only when a mid-stream model fallback served the response; it then
    69  		// replaces the list from message_start, even when empty.
    70  		if event.JSON.InputTransformations.Valid() {
    71  			acc.InputTransformations = event.InputTransformations
    72  			acc.JSON.InputTransformations = event.JSON.InputTransformations
    73  			acc.JSON.raw, _ = sjson.SetRaw(acc.JSON.raw, "input_transformations", event.JSON.InputTransformations.Raw())
    74  		}
    75  		acc.JSON.raw = mergeRaw(acc.JSON.raw, "", event.Delta.JSON.raw)
    76  		acc.JSON.raw = mergeRaw(acc.JSON.raw, "usage", event.Usage.RawJSON())
    77  	case "content_block_start":
    78  		// Content blocks start in index order with no gaps: a start event always
    79  		// addresses the slot right after the previous block, even when deltas and
    80  		// stops for still-open blocks interleave after it.
    81  		if event.Index != int64(len(acc.Content)) {
    82  			return fmt.Errorf("received event of type %s for content block at index %d, expected index %d", event.Type, event.Index, len(acc.Content))
    83  		}
    84  		acc.Content = append(acc.Content, BetaContentBlockUnion{})
    85  		err := acc.Content[event.Index].UnmarshalJSON([]byte(event.ContentBlock.RawJSON()))
    86  		if err != nil {
    87  			return err
    88  		}
    89  		// The final hop's fallback block names the model that served the response;
    90  		// non-streaming responses already report that model, so relabel the
    91  		// accumulated snapshot to match. Last block wins on multi-hop chains.
    92  		if fallback, ok := acc.Content[event.Index].AsAny().(BetaFallbackBlock); ok {
    93  			acc.Model = fallback.To.Model
    94  			acc.JSON.raw, _ = sjson.SetRaw(acc.JSON.raw, "model", jsonString(string(fallback.To.Model)))
    95  		}
    96  	case "content_block_delta":
    97  		if err := checkContentBlockIndex(event.Type, event.Index, len(acc.Content)); err != nil {
    98  			return err
    99  		}
   100  		cb := &acc.Content[event.Index]
   101  		switch event.Delta.Type {
   102  		case "text_delta":
   103  			cb.Text += event.Delta.Text
   104  		case "input_json_delta":
   105  			if len(event.Delta.PartialJSON) != 0 {
   106  				if string(cb.Input) == "{}" {
   107  					cb.Input = []byte(event.Delta.PartialJSON)
   108  				} else {
   109  					cb.Input = append(cb.Input, event.Delta.PartialJSON...)
   110  				}
   111  			}
   112  		case "thinking_delta":
   113  			cb.Thinking += event.Delta.Thinking
   114  		case "signature_delta":
   115  			cb.Signature += event.Delta.Signature
   116  		case "citations_delta":
   117  			citation := BetaTextCitationUnion{}
   118  			err := citation.UnmarshalJSON([]byte(event.Delta.Citation.RawJSON()))
   119  			if err != nil {
   120  				return fmt.Errorf("could not unmarshal citation delta into citation type: %w", err)
   121  			}
   122  			cb.Citations = append(cb.Citations, citation)
   123  		case "compaction_delta":
   124  			cb.Content.OfString = event.Delta.Content
   125  			cb.EncryptedContent = event.Delta.EncryptedContent
   126  		}
   127  	case "message_stop":
   128  		// A block whose stop event never arrived has not been refreshed yet.
   129  		for i := range acc.Content {
   130  			refreshBetaContentBlockRaw(&acc.Content[i])
   131  		}
   132  		acc.JSON.raw, _ = sjson.SetRaw(acc.JSON.raw, "content", rawArray(acc.Content))
   133  	case "content_block_stop":
   134  		if err := checkContentBlockIndex(event.Type, event.Index, len(acc.Content)); err != nil {
   135  			return err
   136  		}
   137  		refreshBetaContentBlockRaw(&acc.Content[event.Index])
   138  	}
   139  
   140  	return nil
   141  }
   142  
   143  // refreshBetaContentBlockRaw overlays the delta-mutated fields onto the block's
   144  // wire JSON, leaving a block that received no deltas byte for byte.
   145  func refreshBetaContentBlockRaw(cb *BetaContentBlockUnion) {
   146  	raw := cb.JSON.raw
   147  	if cb.Text != "" {
   148  		raw, _ = sjson.SetRaw(raw, "text", jsonString(cb.Text))
   149  	}
   150  	if cb.Thinking != "" {
   151  		raw, _ = sjson.SetRaw(raw, "thinking", jsonString(cb.Thinking))
   152  	}
   153  	if cb.Signature != "" {
   154  		raw, _ = sjson.SetRaw(raw, "signature", jsonString(cb.Signature))
   155  	}
   156  	if json.Valid(cb.Input) {
   157  		raw, _ = sjson.SetRaw(raw, "input", string(cb.Input))
   158  	} else if len(cb.Input) > 0 {
   159  		// A cut-off tool call left non-JSON input; empty it so the block marshals.
   160  		cb.Input = json.RawMessage(`{}`)
   161  	}
   162  	if len(cb.Citations) > 0 {
   163  		raw, _ = sjson.SetRaw(raw, "citations", rawArray(cb.Citations))
   164  	}
   165  	if cb.Content.OfString != "" {
   166  		raw, _ = sjson.SetRaw(raw, "content", jsonString(cb.Content.OfString))
   167  	}
   168  	if cb.EncryptedContent != "" {
   169  		raw, _ = sjson.SetRaw(raw, "encrypted_content", jsonString(cb.EncryptedContent))
   170  	}
   171  	cb.JSON.raw = raw
   172  }
   173  
   174  // ParseOutput finds the first text content block in the message and unmarshals it
   175  // into dest. This is useful for streaming workflows where you accumulate the message
   176  // first and then parse the structured output.
   177  //
   178  //	var msg anthropic.BetaMessage
   179  //	for stream.Next() { msg.Accumulate(stream.Current()) }
   180  //	msg.ParseOutput(&myStruct)
   181  func (r *BetaMessage) ParseOutput(dest any) error {
   182  	return parseOutputContent(r, dest)
   183  }
   184  
   185  // Param converters
   186  
   187  func (r BetaContentBlockUnion) ToParam() BetaContentBlockParamUnion {
   188  	return r.AsAny().toParamUnion()
   189  }
   190  
   191  func (variant BetaTextBlock) toParamUnion() BetaContentBlockParamUnion {
   192  	p := variant.ToParam()
   193  	return BetaContentBlockParamUnion{OfText: &p}
   194  }
   195  
   196  func (variant BetaToolUseBlock) toParamUnion() BetaContentBlockParamUnion {
   197  	p := variant.ToParam()
   198  	return BetaContentBlockParamUnion{OfToolUse: &p}
   199  }
   200  
   201  func (variant BetaThinkingBlock) toParamUnion() BetaContentBlockParamUnion {
   202  	p := variant.ToParam()
   203  	return BetaContentBlockParamUnion{OfThinking: &p}
   204  }
   205  
   206  func (variant BetaRedactedThinkingBlock) toParamUnion() BetaContentBlockParamUnion {
   207  	p := variant.ToParam()
   208  	return BetaContentBlockParamUnion{OfRedactedThinking: &p}
   209  }
   210  
   211  func (variant BetaWebSearchToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   212  	p := variant.ToParam()
   213  	return BetaContentBlockParamUnion{OfWebSearchToolResult: &p}
   214  }
   215  
   216  func (variant BetaBashCodeExecutionToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   217  	p := variant.ToParam()
   218  	return BetaContentBlockParamUnion{OfBashCodeExecutionToolResult: &p}
   219  }
   220  
   221  func (variant BetaCodeExecutionToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   222  	p := variant.ToParam()
   223  	return BetaContentBlockParamUnion{OfCodeExecutionToolResult: &p}
   224  }
   225  
   226  func (variant BetaContainerUploadBlock) toParamUnion() BetaContentBlockParamUnion {
   227  	p := variant.ToParam()
   228  	return BetaContentBlockParamUnion{OfContainerUpload: &p}
   229  }
   230  
   231  func (variant BetaAdvisorToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   232  	p := variant.ToParam()
   233  	return BetaContentBlockParamUnion{OfAdvisorToolResult: &p}
   234  }
   235  
   236  func (r BetaAdvisorToolResultBlock) ToParam() BetaAdvisorToolResultBlockParam {
   237  	var p BetaAdvisorToolResultBlockParam
   238  	p.Type = r.Type
   239  	p.ToolUseID = r.ToolUseID
   240  	switch {
   241  	case r.Content.JSON.ErrorCode.Valid():
   242  		p.Content.OfRequestAdvisorToolResultError = &BetaAdvisorToolResultErrorParam{
   243  			ErrorCode: BetaAdvisorToolResultErrorParamErrorCode(r.Content.ErrorCode),
   244  		}
   245  	case r.Content.JSON.EncryptedContent.Valid():
   246  		p.Content.OfRequestAdvisorRedactedResultBlock = &BetaAdvisorRedactedResultBlockParam{
   247  			EncryptedContent: r.Content.EncryptedContent,
   248  			StopReason:       paramutil.ToOpt(r.Content.StopReason, r.Content.JSON.StopReason),
   249  		}
   250  	default:
   251  		p.Content.OfRequestAdvisorResultBlock = &BetaAdvisorResultBlockParam{
   252  			Text:       r.Content.Text,
   253  			StopReason: paramutil.ToOpt(r.Content.StopReason, r.Content.JSON.StopReason),
   254  		}
   255  	}
   256  	return p
   257  }
   258  
   259  func (variant BetaMCPToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   260  	p := variant.ToParam()
   261  	return BetaContentBlockParamUnion{OfMCPToolResult: &p}
   262  }
   263  
   264  func (variant BetaMCPToolUseBlock) toParamUnion() BetaContentBlockParamUnion {
   265  	p := variant.ToParam()
   266  	return BetaContentBlockParamUnion{OfMCPToolUse: &p}
   267  }
   268  
   269  func (variant BetaServerToolUseBlock) toParamUnion() BetaContentBlockParamUnion {
   270  	p := variant.ToParam()
   271  	return BetaContentBlockParamUnion{OfServerToolUse: &p}
   272  }
   273  
   274  func (variant BetaTextEditorCodeExecutionToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   275  	p := variant.ToParam()
   276  	return BetaContentBlockParamUnion{OfTextEditorCodeExecutionToolResult: &p}
   277  }
   278  
   279  func (variant BetaWebFetchToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   280  	p := variant.ToParam()
   281  	return BetaContentBlockParamUnion{OfWebFetchToolResult: &p}
   282  }
   283  
   284  func (variant BetaToolSearchToolResultBlock) toParamUnion() BetaContentBlockParamUnion {
   285  	p := variant.ToParam()
   286  	return BetaContentBlockParamUnion{OfToolSearchToolResult: &p}
   287  }
   288  
   289  func (variant BetaCompactionBlock) toParamUnion() BetaContentBlockParamUnion {
   290  	p := variant.ToParam()
   291  	return BetaContentBlockParamUnion{OfCompaction: &p}
   292  }
   293  
   294  func (variant BetaFallbackBlock) toParamUnion() BetaContentBlockParamUnion {
   295  	p := variant.ToParam()
   296  	return BetaContentBlockParamUnion{OfFallback: &p}
   297  }
   298  
   299  func (r BetaMessage) ToParam() BetaMessageParam {
   300  	var p BetaMessageParam
   301  	p.Role = BetaMessageParamRole(r.Role)
   302  	p.Content = make([]BetaContentBlockParamUnion, len(r.Content))
   303  	for i, c := range r.Content {
   304  		contentParams := c.ToParam()
   305  		p.Content[i] = contentParams
   306  	}
   307  	return p
   308  }
   309  
   310  func (r BetaRedactedThinkingBlock) ToParam() BetaRedactedThinkingBlockParam {
   311  	var p BetaRedactedThinkingBlockParam
   312  	p.Type = r.Type
   313  	p.Data = r.Data
   314  	return p
   315  }
   316  
   317  func (r BetaTextBlock) ToParam() BetaTextBlockParam {
   318  	var p BetaTextBlockParam
   319  	p.Type = r.Type
   320  	p.Text = r.Text
   321  
   322  	// Distinguish between a nil and zero length slice, since some compatible
   323  	// APIs may not require citations.
   324  	if r.Citations != nil {
   325  		p.Citations = make([]BetaTextCitationParamUnion, 0, len(r.Citations))
   326  	}
   327  	for _, citation := range r.Citations {
   328  		p.Citations = append(p.Citations, citation.AsAny().toParamUnion())
   329  	}
   330  	return p
   331  }
   332  
   333  func (r BetaCitationCharLocation) toParamUnion() BetaTextCitationParamUnion {
   334  	var citationParam BetaCitationCharLocationParam
   335  	citationParam.Type = r.Type
   336  	citationParam.DocumentTitle = paramutil.ToOpt(r.DocumentTitle, r.JSON.DocumentTitle)
   337  	citationParam.CitedText = r.CitedText
   338  	citationParam.DocumentIndex = r.DocumentIndex
   339  	citationParam.EndCharIndex = r.EndCharIndex
   340  	citationParam.StartCharIndex = r.StartCharIndex
   341  	return BetaTextCitationParamUnion{OfCharLocation: &citationParam}
   342  }
   343  
   344  func (citationVariant BetaCitationPageLocation) toParamUnion() BetaTextCitationParamUnion {
   345  	var citationParam BetaCitationPageLocationParam
   346  	citationParam.Type = citationVariant.Type
   347  	citationParam.DocumentTitle = paramutil.ToOpt(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle)
   348  	citationParam.CitedText = citationVariant.CitedText
   349  	citationParam.DocumentIndex = citationVariant.DocumentIndex
   350  	citationParam.EndPageNumber = citationVariant.EndPageNumber
   351  	citationParam.StartPageNumber = citationVariant.StartPageNumber
   352  	return BetaTextCitationParamUnion{OfPageLocation: &citationParam}
   353  }
   354  
   355  func (citationVariant BetaCitationContentBlockLocation) toParamUnion() BetaTextCitationParamUnion {
   356  	var citationParam BetaCitationContentBlockLocationParam
   357  	citationParam.Type = citationVariant.Type
   358  	citationParam.DocumentTitle = paramutil.ToOpt(citationVariant.DocumentTitle, citationVariant.JSON.DocumentTitle)
   359  	citationParam.CitedText = citationVariant.CitedText
   360  	citationParam.DocumentIndex = citationVariant.DocumentIndex
   361  	citationParam.EndBlockIndex = citationVariant.EndBlockIndex
   362  	citationParam.StartBlockIndex = citationVariant.StartBlockIndex
   363  	return BetaTextCitationParamUnion{OfContentBlockLocation: &citationParam}
   364  }
   365  
   366  func (citationVariant BetaCitationsWebSearchResultLocation) toParamUnion() BetaTextCitationParamUnion {
   367  	var citationParam BetaCitationWebSearchResultLocationParam
   368  	citationParam.Type = citationVariant.Type
   369  	citationParam.CitedText = citationVariant.CitedText
   370  	citationParam.Title = paramutil.ToOpt(citationVariant.Title, citationVariant.JSON.Title)
   371  	citationParam.EncryptedIndex = citationVariant.EncryptedIndex
   372  	citationParam.URL = citationVariant.URL
   373  	return BetaTextCitationParamUnion{OfWebSearchResultLocation: &citationParam}
   374  }
   375  
   376  func (citationVariant BetaCitationSearchResultLocation) toParamUnion() BetaTextCitationParamUnion {
   377  	var citationParam BetaCitationSearchResultLocationParam
   378  	citationParam.Type = citationVariant.Type
   379  	citationParam.CitedText = citationVariant.CitedText
   380  	citationParam.Title = paramutil.ToOpt(citationVariant.Title, citationVariant.JSON.Title)
   381  	citationParam.EndBlockIndex = citationVariant.EndBlockIndex
   382  	citationParam.SearchResultIndex = citationVariant.SearchResultIndex
   383  	citationParam.Source = citationVariant.Source
   384  	citationParam.StartBlockIndex = citationVariant.StartBlockIndex
   385  	return BetaTextCitationParamUnion{OfSearchResultLocation: &citationParam}
   386  }
   387  
   388  func (r BetaThinkingBlock) ToParam() BetaThinkingBlockParam {
   389  	var p BetaThinkingBlockParam
   390  	p.Type = r.Type
   391  	p.Signature = r.Signature
   392  	p.Thinking = r.Thinking
   393  	return p
   394  }
   395  
   396  func (r BetaToolUseBlock) ToParam() BetaToolUseBlockParam {
   397  	var p BetaToolUseBlockParam
   398  	p.Type = r.Type
   399  	p.ID = r.ID
   400  	p.Input = r.Input
   401  	p.Name = r.Name
   402  	p.ToolsetName = paramutil.ToOpt(r.ToolsetName, r.JSON.ToolsetName)
   403  	if r.JSON.Caller.Valid() {
   404  		p.Caller = r.Caller.toParam()
   405  	}
   406  	return p
   407  }
   408  
   409  // toParam converts a caller. The other three caller unions share this layout
   410  // and convert through it.
   411  func (r BetaToolUseBlockCallerUnion) toParam() BetaToolUseBlockParamCallerUnion {
   412  	var p BetaToolUseBlockParamCallerUnion
   413  	switch v := r.AsAny().(type) {
   414  	case BetaDirectCaller:
   415  		c := v.ToParam()
   416  		p.OfDirect = &c
   417  	case BetaServerToolCaller:
   418  		c := v.ToParam()
   419  		p.OfCodeExecution20250825 = &c
   420  	case BetaServerToolCaller20260120:
   421  		c := v.ToParam()
   422  		p.OfCodeExecution20260120 = &c
   423  	default:
   424  		p = param.Override[BetaToolUseBlockParamCallerUnion](json.RawMessage(r.RawJSON()))
   425  	}
   426  	return p
   427  }
   428  
   429  func (r BetaServerToolUseBlockCallerUnion) toParam() BetaServerToolUseBlockParamCallerUnion {
   430  	return BetaServerToolUseBlockParamCallerUnion(BetaToolUseBlockCallerUnion(r).toParam())
   431  }
   432  
   433  func (r BetaWebSearchToolResultBlockCallerUnion) toParam() BetaWebSearchToolResultBlockParamCallerUnion {
   434  	return BetaWebSearchToolResultBlockParamCallerUnion(BetaToolUseBlockCallerUnion(r).toParam())
   435  }
   436  
   437  func (r BetaWebFetchToolResultBlockCallerUnion) toParam() BetaWebFetchToolResultBlockParamCallerUnion {
   438  	return BetaWebFetchToolResultBlockParamCallerUnion(BetaToolUseBlockCallerUnion(r).toParam())
   439  }
   440  
   441  func (r BetaWebSearchResultBlock) ToParam() BetaWebSearchResultBlockParam {
   442  	var p BetaWebSearchResultBlockParam
   443  	p.Type = r.Type
   444  	p.EncryptedContent = r.EncryptedContent
   445  	p.Title = r.Title
   446  	p.URL = r.URL
   447  	p.PageAge = paramutil.ToOpt(r.PageAge, r.JSON.PageAge)
   448  	return p
   449  }
   450  
   451  func (r BetaWebSearchToolResultBlock) ToParam() BetaWebSearchToolResultBlockParam {
   452  	var p BetaWebSearchToolResultBlockParam
   453  	p.Type = r.Type
   454  	p.ToolUseID = r.ToolUseID
   455  
   456  	if r.Content.JSON.OfBetaWebSearchResultBlockArray.Valid() {
   457  		// content is required, so send [] rather than omitting it.
   458  		p.Content.OfResultBlock = make([]BetaWebSearchResultBlockParam, 0, len(r.Content.OfBetaWebSearchResultBlockArray))
   459  		for _, block := range r.Content.OfBetaWebSearchResultBlockArray {
   460  			p.Content.OfResultBlock = append(p.Content.OfResultBlock, block.ToParam())
   461  		}
   462  	} else {
   463  		p.Content.OfError = &BetaWebSearchToolRequestErrorParam{
   464  			Type:      r.Content.Type,
   465  			ErrorCode: r.Content.ErrorCode,
   466  		}
   467  	}
   468  	if r.JSON.Caller.Valid() {
   469  		p.Caller = r.Caller.toParam()
   470  	}
   471  	return p
   472  }
   473  
   474  func (r BetaWebFetchToolResultBlock) ToParam() BetaWebFetchToolResultBlockParam {
   475  	var p BetaWebFetchToolResultBlockParam
   476  	p.Type = r.Type
   477  	p.ToolUseID = r.ToolUseID
   478  	if r.Content.JSON.ErrorCode.Valid() {
   479  		p.Content.OfRequestWebFetchToolResultError = &BetaWebFetchToolResultErrorBlockParam{
   480  			ErrorCode: r.Content.ErrorCode,
   481  		}
   482  	} else {
   483  		p.Content = param.Override[BetaWebFetchToolResultBlockParamContentUnion](json.RawMessage(r.Content.RawJSON()))
   484  	}
   485  	if r.JSON.Caller.Valid() {
   486  		p.Caller = r.Caller.toParam()
   487  	}
   488  	return p
   489  }
   490  
   491  func (r BetaMCPToolUseBlock) ToParam() BetaMCPToolUseBlockParam {
   492  	var p BetaMCPToolUseBlockParam
   493  	p.Type = r.Type
   494  	p.ID = r.ID
   495  	p.Input = r.Input
   496  	p.Name = r.Name
   497  	p.ServerName = r.ServerName
   498  	return p
   499  }
   500  
   501  func (r BetaContainerUploadBlock) ToParam() BetaContainerUploadBlockParam {
   502  	var p BetaContainerUploadBlockParam
   503  	p.Type = r.Type
   504  	p.FileID = r.FileID
   505  	return p
   506  }
   507  
   508  func (r BetaServerToolUseBlock) ToParam() BetaServerToolUseBlockParam {
   509  	var p BetaServerToolUseBlockParam
   510  	p.Type = r.Type
   511  	p.ID = r.ID
   512  	p.Input = r.Input
   513  	p.Name = BetaServerToolUseBlockParamName(r.Name)
   514  	if r.JSON.Caller.Valid() {
   515  		p.Caller = r.Caller.toParam()
   516  	}
   517  	return p
   518  }
   519  
   520  func (r BetaTextEditorCodeExecutionToolResultBlock) ToParam() BetaTextEditorCodeExecutionToolResultBlockParam {
   521  	var p BetaTextEditorCodeExecutionToolResultBlockParam
   522  	p.Type = r.Type
   523  	p.ToolUseID = r.ToolUseID
   524  	if r.Content.JSON.ErrorCode.Valid() {
   525  		p.Content.OfRequestTextEditorCodeExecutionToolResultError = &BetaTextEditorCodeExecutionToolResultErrorParam{
   526  			ErrorCode:    BetaTextEditorCodeExecutionToolResultErrorParamErrorCode(r.Content.ErrorCode),
   527  			ErrorMessage: paramutil.ToOpt(r.Content.ErrorMessage, r.Content.JSON.ErrorMessage),
   528  		}
   529  	} else {
   530  		p.Content = param.Override[BetaTextEditorCodeExecutionToolResultBlockParamContentUnion](json.RawMessage(r.Content.RawJSON()))
   531  	}
   532  	return p
   533  }
   534  
   535  func (r BetaMCPToolResultBlock) ToParam() BetaRequestMCPToolResultBlockParam {
   536  	var p BetaRequestMCPToolResultBlockParam
   537  	p.Type = r.Type
   538  	p.ToolUseID = r.ToolUseID
   539  	p.IsError = paramutil.ToOpt(r.IsError, r.JSON.IsError)
   540  	if r.Content.JSON.OfString.Valid() {
   541  		p.Content.OfString = paramutil.ToOpt(r.Content.OfString, r.Content.JSON.OfString)
   542  	} else if r.Content.JSON.OfBetaMCPToolResultBlockContent.Valid() {
   543  		// Send [] for an empty result rather than omitting content.
   544  		p.Content.OfBetaMCPToolResultBlockContent = make([]BetaTextBlockParam, 0, len(r.Content.OfBetaMCPToolResultBlockContent))
   545  		for _, block := range r.Content.OfBetaMCPToolResultBlockContent {
   546  			p.Content.OfBetaMCPToolResultBlockContent = append(p.Content.OfBetaMCPToolResultBlockContent, block.ToParam())
   547  		}
   548  	}
   549  	return p
   550  }
   551  
   552  func (r BetaBashCodeExecutionToolResultBlock) ToParam() BetaBashCodeExecutionToolResultBlockParam {
   553  	var p BetaBashCodeExecutionToolResultBlockParam
   554  	p.Type = r.Type
   555  	p.ToolUseID = r.ToolUseID
   556  
   557  	if r.Content.JSON.ErrorCode.Valid() {
   558  		p.Content.OfRequestBashCodeExecutionToolResultError = &BetaBashCodeExecutionToolResultErrorParam{
   559  			ErrorCode: BetaBashCodeExecutionToolResultErrorParamErrorCode(r.Content.ErrorCode),
   560  		}
   561  	} else {
   562  		requestBashContentResult := &BetaBashCodeExecutionResultBlockParam{
   563  			// content is required, so send [] rather than omitting it.
   564  			Content:    make([]BetaBashCodeExecutionOutputBlockParam, 0, len(r.Content.Content)),
   565  			ReturnCode: r.Content.ReturnCode,
   566  			Stderr:     r.Content.Stderr,
   567  			Stdout:     r.Content.Stdout,
   568  		}
   569  		for _, block := range r.Content.Content {
   570  			requestBashContentResult.Content = append(requestBashContentResult.Content, block.ToParam())
   571  		}
   572  		p.Content.OfRequestBashCodeExecutionResultBlock = requestBashContentResult
   573  	}
   574  
   575  	return p
   576  }
   577  
   578  func (r BetaBashCodeExecutionOutputBlock) ToParam() BetaBashCodeExecutionOutputBlockParam {
   579  	var p BetaBashCodeExecutionOutputBlockParam
   580  	p.Type = r.Type
   581  	p.FileID = r.FileID
   582  	return p
   583  }
   584  
   585  func (r BetaCodeExecutionToolResultBlock) ToParam() BetaCodeExecutionToolResultBlockParam {
   586  	var p BetaCodeExecutionToolResultBlockParam
   587  	p.Type = r.Type
   588  	p.ToolUseID = r.ToolUseID
   589  	// content is required, so send [] rather than omitting it.
   590  	files := make([]BetaCodeExecutionOutputBlockParam, 0, len(r.Content.Content))
   591  	for _, block := range r.Content.Content {
   592  		files = append(files, block.ToParam())
   593  	}
   594  	switch {
   595  	case r.Content.JSON.ErrorCode.Valid():
   596  		p.Content.OfError = &BetaCodeExecutionToolResultErrorParam{
   597  			ErrorCode: r.Content.ErrorCode,
   598  		}
   599  	case r.Content.JSON.EncryptedStdout.Valid():
   600  		p.Content.OfRequestEncryptedCodeExecutionResultBlock = &BetaEncryptedCodeExecutionResultBlockParam{
   601  			Content:         files,
   602  			EncryptedStdout: r.Content.EncryptedStdout,
   603  			ReturnCode:      r.Content.ReturnCode,
   604  			Stderr:          r.Content.Stderr,
   605  		}
   606  	default:
   607  		p.Content.OfResultBlock = &BetaCodeExecutionResultBlockParam{
   608  			Content:    files,
   609  			ReturnCode: r.Content.ReturnCode,
   610  			Stderr:     r.Content.Stderr,
   611  			Stdout:     r.Content.Stdout,
   612  		}
   613  	}
   614  	return p
   615  }
   616  
   617  func (r BetaCodeExecutionOutputBlock) ToParam() BetaCodeExecutionOutputBlockParam {
   618  	var p BetaCodeExecutionOutputBlockParam
   619  	p.Type = r.Type
   620  	p.FileID = r.FileID
   621  	return p
   622  }
   623  
   624  func (r BetaToolSearchToolResultBlock) ToParam() BetaToolSearchToolResultBlockParam {
   625  	var p BetaToolSearchToolResultBlockParam
   626  	p.Type = r.Type
   627  	p.ToolUseID = r.ToolUseID
   628  	if r.Content.JSON.ErrorCode.Valid() {
   629  		p.Content.OfRequestToolSearchToolResultError = &BetaToolSearchToolResultErrorParam{
   630  			ErrorCode:    BetaToolSearchToolResultErrorParamErrorCode(r.Content.ErrorCode),
   631  			ErrorMessage: paramutil.ToOpt(r.Content.ErrorMessage, r.Content.JSON.ErrorMessage),
   632  		}
   633  	} else {
   634  		p.Content.OfRequestToolSearchToolSearchResultBlock = &BetaToolSearchToolSearchResultBlockParam{
   635  			// tool_references is required, so send [] rather than omitting it.
   636  			ToolReferences: make([]BetaToolReferenceBlockParam, 0, len(r.Content.ToolReferences)),
   637  		}
   638  		for _, block := range r.Content.ToolReferences {
   639  			p.Content.OfRequestToolSearchToolSearchResultBlock.ToolReferences = append(
   640  				p.Content.OfRequestToolSearchToolSearchResultBlock.ToolReferences,
   641  				block.ToParam(),
   642  			)
   643  		}
   644  	}
   645  	return p
   646  }
   647  
   648  func (r BetaToolReferenceBlock) ToParam() BetaToolReferenceBlockParam {
   649  	var p BetaToolReferenceBlockParam
   650  	p.Type = r.Type
   651  	p.ToolName = r.ToolName
   652  	return p
   653  }
   654  
   655  func (r BetaCompactionBlock) ToParam() BetaCompactionBlockParam {
   656  	var p BetaCompactionBlockParam
   657  	p.Type = r.Type
   658  	// A failed compaction has null content, which must stay null rather than
   659  	// become "".
   660  	p.Content = paramutil.ToOpt(r.Content, r.JSON.Content)
   661  	p.EncryptedContent = paramutil.ToOpt(r.EncryptedContent, r.JSON.EncryptedContent)
   662  	return p
   663  }
   664  
   665  func (r BetaFallbackBlock) ToParam() BetaFallbackBlockParam {
   666  	var p BetaFallbackBlockParam
   667  	p.Type = r.Type
   668  	p.From = BetaFallbackInfoParam{Model: r.From.Model}
   669  	p.To = BetaFallbackInfoParam{Model: r.To.Model}
   670  	if r.JSON.Trigger.Valid() {
   671  		p.Trigger = json.RawMessage(r.Trigger.RawJSON())
   672  	}
   673  	return p
   674  }