Go SDK
Installa e configura l'Anthropic Go SDK con cancellazione basata sul contesto e opzioni funzionali
La libreria Anthropic Go fornisce un accesso comodo alla Claude API da applicazioni scritte in Go.
Installazione
import (
"github.com/anthropics/anthropic-sdk-go" // imported as anthropic
)Installa con go get:
go get github.com/anthropics/anthropic-sdk-goRequisiti
Questa libreria richiede Go 1.24+.
Utilizzo
package main
import (
"context"
"fmt"
"github.com/anthropics/anthropic-sdk-go"
"github.com/anthropics/anthropic-sdk-go/option"
)
func main() {
client := anthropic.NewClient(
option.WithAPIKey("my-anthropic-api-key"), // defaults to os.LookupEnv("ANTHROPIC_API_KEY")
)
message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What is a quaternion?")),
},
Model: anthropic.ModelClaudeOpus5,
})
if err != nil {
panic(err.Error())
}
for _, block := range message.Content {
if textBlock, ok := block.AsAny().(anthropic.TextBlock); ok {
fmt.Println(textBlock.Text)
}
}
}Per le opzioni di autenticazione, inclusa la Workload Identity Federation, consulta Autenticazione. Se la tua chiave API è una chiave personale o di account di servizio con accesso a più workspace, imposta l'ID del workspace nell'header di richiesta anthropic-workspace-id; Seleziona un workspace mostra l'opzione per singola richiesta per questo SDK.
messages := []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("What is my first name?")),
}
message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5,
Messages: messages,
MaxTokens: 1024,
})
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", message.Content)
messages = append(messages, message.ToParam())
messages = append(messages, anthropic.NewUserMessage(
anthropic.NewTextBlock("My full name is John Doe"),
))
message, err = client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5,
Messages: messages,
MaxTokens: 1024,
})
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", message.Content)message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5,
MaxTokens: 1024,
System: []anthropic.TextBlockParam{
{Text: "Be very serious at all times."},
},
Messages: messages,
})
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", message.Content)content := "What is a quaternion?"
stream := client.Messages.NewStreaming(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock(content)),
},
})
message := anthropic.Message{}
for stream.Next() {
event := stream.Current()
err := message.Accumulate(event)
if err != nil {
panic(err)
}
switch eventVariant := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
switch deltaVariant := eventVariant.Delta.AsAny().(type) {
case anthropic.TextDelta:
print(deltaVariant.Text)
}
}
}
if stream.Err() != nil {
panic(stream.Err())
}messages := []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock(content)),
}
toolParams := []anthropic.ToolParam{
{
Name: "get_coordinates",
Description: anthropic.String("Accepts a place as an address, then returns the latitude and longitude coordinates."),
InputSchema: GetCoordinatesInputSchema,
},
}
tools := make([]anthropic.ToolUnionParam, len(toolParams))
for i, toolParam := range toolParams {
tools[i] = anthropic.ToolUnionParam{OfTool: &toolParam}
}
for {
message, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeOpus5,
MaxTokens: 1024,
Messages: messages,
Tools: tools,
})
if err != nil {
panic(err)
}
print(color("[assistant]: "))
for _, block := range message.Content {
switch block := block.AsAny().(type) {
case anthropic.TextBlock:
println(block.Text)
println()
case anthropic.ToolUseBlock:
inputJSON, _ := json.Marshal(block.Input)
println(block.Name + ": " + string(inputJSON))
println()
}
}
messages = append(messages, message.ToParam())
toolResults := []anthropic.ContentBlockParamUnion{}
for _, block := range message.Content {
switch variant := block.AsAny().(type) {
case anthropic.ToolUseBlock:
print(color("[user (" + block.Name + ")]: "))
var response interface{}
switch block.Name {
case "get_coordinates":
var input struct {
Location string `json:"location"`
}
err := json.Unmarshal([]byte(variant.JSON.Input.Raw()), &input)
if err != nil {
panic(err)
}
response = GetCoordinates(input.Location)
}
b, err := json.Marshal(response)
if err != nil {
panic(err)
}
println(string(b))
toolResults = append(toolResults, anthropic.NewToolResultBlock(block.ID, string(b), false))
}
}
if len(toolResults) == 0 {
break
}
messages = append(messages, anthropic.NewUserMessage(toolResults...))
}Campi della richiesta
La libreria anthropic usa la semantica omitzero
della release encoding/json di Go 1.24+ per i campi della richiesta.
I campi primitivi obbligatori (come int64 o string) presentano il tag `json:"...,required"`. Questi
campi vengono sempre serializzati, anche con i loro valori zero.
I tipi primitivi opzionali sono racchiusi in un param.Opt[T]. Questi campi possono essere impostati con i costruttori forniti, come anthropic.String(string) o anthropic.Int(int64).
Qualsiasi param.Opt[T], map, slice, struct o enum di stringhe usa il
tag `json:"...,omitzero"`. Il suo valore zero è considerato omesso.
La funzione param.IsOmitted(any) può confermare la presenza di qualsiasi campo omitzero.
p := anthropic.ExampleParams{
ID: "id_xxx", // required property
Name: anthropic.String("..."), // optional property
Point: anthropic.Point{
X: 0, // required field will serialize as 0
Y: anthropic.Int(1), // optional field will serialize as 1
// ... i campi non obbligatori omessi non verranno serializzati
},
Origin: anthropic.Origin{}, // the zero value of [Origin] is considered omitted
}Per inviare null al posto di un param.Opt[T], usa param.Null[T]().
Per inviare null al posto di una struct T, usa param.NullStruct[T]().
p.Name = param.Null[string]() // 'null' instead of string
p.Point = param.NullStruct[Point]() // 'null' instead of struct
param.IsNull(p.Name) // true
param.IsNull(p.Point) // trueLe struct di richiesta contengono un metodo .SetExtraFields(map[string]any) che può inviare campi non conformi
nel corpo della richiesta. I campi extra sovrascrivono qualsiasi campo della struct con una chiave
corrispondente.
Per inviare un valore personalizzato al posto di una struct, usa la funzione generica param.Override (ad esempio, param.Override[anthropic.FooParams](12)).
// Nei casi in cui l'API specifica un determinato tipo,
// ma vuoi inviare qualcos'altro, usa [SetExtraFields]:
p.SetExtraFields(map[string]any{
"x": 0.01, // send "x" as a float instead of int
})
// Invia un numero invece di un oggetto
custom := param.Override[anthropic.FooParams](12)Union nelle richieste
Le union sono rappresentate come una struct con campi prefissati da "Of" per ciascuna delle sue varianti; solo un campo può essere diverso da zero. Il campo diverso da zero verrà serializzato.
Le sottoproprietà della union sono accessibili tramite metodi sulla struct della union. Questi metodi restituiscono un puntatore mutabile ai dati sottostanti, se presenti.
// Solo un campo può essere diverso da zero, usa param.IsOmitted() per verificare se un campo è impostato
type AnimalUnionParam struct {
OfCat *Cat `json:",omitzero,inline"`
OfDog *Dog `json:",omitzero,inline"`
}
animal := AnimalUnionParam{
OfCat: &Cat{
Name: "Whiskers",
Owner: PersonParam{
Address: AddressParam{Street: "3333 Coyote Hill Rd", ZipCode: 0},
},
},
}
// Modifica di un campo
if address := animal.GetOwner().GetAddress(); address != nil {
address.ZipCode = 94304
}Deserializzazione dei param
I tipi param (tipi che terminano in Param, come MessageNewParams o ToolUnionParam) sono progettati solo per le richieste in uscita. Vengono serializzati correttamente in JSON ma non supportano completamente la deserializzazione round-trip. Se esegui l'unmarshal di JSON grezzo in una struct param, i campi union tipizzati come OfBashTool20250124 saranno nil anche quando il JSON sottostante è valido.
Se hai bisogno di ricostruire i param da JSON grezzo (ad esempio, da un database, un middleware o una richiesta precedente), chiama UnmarshalJSON per popolare i campi non union, quindi usa param.SetJSON per allegare i byte grezzi per una corretta ri-serializzazione:
// Serializza i params (ad esempio, per l'archiviazione o l'inoltro)
b, err := json.Marshal(original)
if err != nil {
panic(err)
}
// In seguito, ricostruisci i params dal JSON archiviato
var params anthropic.MessageNewParams
if err := params.UnmarshalJSON(b); err != nil {
panic(err)
}
param.SetJSON(b, ¶ms)
// params.Model e gli altri campi scalari sono popolati da UnmarshalJSON.
// params.Tools[0].OfBashTool20250124 è nil (la limitazione delle union),
// ma il JSON grezzo viene preservato. Quando params viene serializzato di nuovo
// per la chiamata API, gli strumenti vengono serializzati correttamente.
b2, _ := json.Marshal(params)
fmt.Println(string(b) == string(b2)) // truePer questo caso d'uso, param.SetJSON (disponibile dalla v1.20.0) è preferibile rispetto al più generale param.Override[T](any) perché non richiede di esplicitare il parametro di tipo e rende esplicita l'intenzione di round-trip.
Oggetti di risposta
Tutti i campi nelle struct di risposta sono tipi valore ordinari (non puntatori o wrapper).
Le struct di risposta includono anche un campo speciale JSON contenente metadati su
ciascuna proprietà.
type Animal struct {
Name string `json:"name,nullable"`
Owners int `json:"owners"`
Age int `json:"age"`
JSON struct {
Name respjson.Field
Owners respjson.Field
Age respjson.Field
ExtraFields map[string]respjson.Field
} `json:"-"`
}Per gestire dati opzionali, usa il metodo .Valid() sul campo JSON.
.Valid() restituisce true quando il campo è presente, non null, ed è stato deserializzato con successo.
Se .Valid() è false, il campo corrispondente avrà il suo valore zero.
raw := `{"owners": 1, "name": null}`
var res Animal
json.Unmarshal([]byte(raw), &res)
// Accesso ai campi normali
res.Owners // 1
res.Name // ""
res.Age // 0
// Controlli dei campi opzionali
res.JSON.Owners.Valid() // true
res.JSON.Name.Valid() // false
res.JSON.Age.Valid() // false
// Valori JSON grezzi
res.JSON.Owners.Raw() // "1"
res.JSON.Name.Raw() == "null" // true
res.JSON.Name.Raw() == respjson.Null // true
res.JSON.Age.Raw() == "" // true
res.JSON.Age.Raw() == respjson.Omitted // trueQueste struct .JSON includono anche una map ExtraFields contenente
tutte le proprietà nella risposta json che non erano specificate
nella struct. Questo può essere utile per funzionalità dell'API non ancora
presenti nell'SDK.
body := res.JSON.ExtraFields["my_unexpected_field"].Raw()Union nelle risposte
Nelle risposte, le union sono rappresentate da una struct appiattita contenente tutti i possibili campi di ciascuna delle
varianti dell'oggetto.
Per convertirla in una variante usa il metodo .AsFooVariant() o il metodo .AsAny() se presente.
Se una union di valori di risposta contiene valori primitivi, i campi primitivi si troveranno accanto
alle proprietà ma prefissati con Of e presenteranno il tag json:"...,inline".
type AnimalUnion struct {
// Dalle varianti [Dog], [Cat]
Owner Person `json:"owner"`
// Dalla variante [Dog]
DogBreed string `json:"dog_breed"`
// Dalla variante [Cat]
CatBreed string `json:"cat_breed"`
// ...
JSON struct {
Owner respjson.Field
// ...
} `json:"-"`
}
// Se la variante è animal
if animal.Owner.Address.ZipCode == "" {
panic("missing zip code")
}
// Switch sulla variante
switch variant := animal.AsAny().(type) {
case Dog:
case Cat:
default:
panic("unexpected type")
}Gestione degli errori
Quando l'API restituisce un codice di stato non di successo, l'SDK restituisce un errore di tipo
*anthropic.Error. Questo contiene i valori StatusCode, *http.Request e
*http.Response della richiesta, insieme al JSON del corpo dell'errore
(in modo simile agli altri oggetti di risposta nell'SDK). L'errore include anche il RequestID
dagli header della risposta, utile per la risoluzione dei problemi con il supporto Anthropic.
Per gestire gli errori, usa il pattern errors.As:
_, err := client.Messages.New(context.TODO(), anthropic.MessageNewParams{
MaxTokens: 1024,
Messages: []anthropic.MessageParam{{
Content: []anthropic.ContentBlockParamUnion{{
OfText: &anthropic.TextBlockParam{
Text: "What is a quaternion?",
},
}},
Role: anthropic.MessageParamRoleUser,
}},
Model: anthropic.ModelClaudeOpus5,
})
if err != nil {
var apierr *anthropic.Error
if errors.As(err, &apierr) {
println("Request ID:", apierr.RequestID)
println(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request
println(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response
}
panic(err.Error()) // POST "/v1/messages": 400 Bad Request (Request-ID: req_xxx) { ... }
}Quando si verificano altri errori, vengono restituiti senza wrapping; ad esempio,
se il trasporto HTTP fallisce, potresti ricevere *url.Error che racchiude *net.OpError.
Tentativi ripetuti
Alcuni errori verranno automaticamente ritentati 2 volte per impostazione predefinita, con un breve backoff esponenziale. L'SDK ritenta per impostazione predefinita tutti gli errori di connessione, 408 Request Timeout, 409 Conflict, 429 Rate Limit e gli errori interni >=500.
Puoi usare l'opzione WithMaxRetries per configurare o disabilitare questo comportamento:
// Configura il valore predefinito per tutte le richieste:
client := anthropic.NewClient(
option.WithMaxRetries(0), // default is 2
)
// Sovrascrivi per singola richiesta:
client.Messages.New(
context.TODO(),
anthropic.MessageNewParams{
MaxTokens: 1024,
Messages: []anthropic.MessageParam{{
Content: []anthropic.ContentBlockParamUnion{{
OfText: &anthropic.TextBlockParam{
Text: "What is a quaternion?",
},
}},
Role: anthropic.MessageParamRoleUser,
}},
Model: anthropic.ModelClaudeOpus5,
},
option.WithMaxRetries(5),
)Timeout
Le richieste Messages non in streaming vanno in timeout dopo 10 minuti per impostazione predefinita; le altre richieste non hanno un timeout predefinito. Usa il context per configurare un timeout per il ciclo di vita di una richiesta.
Nota che se una richiesta viene ritentata, il timeout del context non riparte da zero.
Per impostare un timeout per singolo tentativo, usa option.WithRequestTimeout().
// Imposta il timeout per la richiesta, inclusi tutti i tentativi ripetuti.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
defer cancel()
client.Messages.New(
ctx,
anthropic.MessageNewParams{
MaxTokens: 1024,
Messages: []anthropic.MessageParam{{
Content: []anthropic.ContentBlockParamUnion{{
OfText: &anthropic.TextBlockParam{
Text: "What is a quaternion?",
},
}},
Role: anthropic.MessageParamRoleUser,
}},
Model: anthropic.ModelClaudeOpus5,
},
// Imposta il timeout per singolo tentativo
option.WithRequestTimeout(20*time.Second),
)Richieste lunghe
Evita di impostare un valore MaxTokens elevato senza usare lo streaming, poiché alcune reti potrebbero interrompere le connessioni inattive dopo un certo periodo di tempo, il che
può causare il fallimento della richiesta o un timeout senza ricevere una risposta da Anthropic.
Questo SDK restituirà inoltre un errore se si prevede che una richiesta non in streaming duri più di circa 10 minuti.
Chiamare .Messages.NewStreaming() o impostare un timeout personalizzato disabilita questo errore.
Caricamento di file
I parametri di richiesta che corrispondono a caricamenti di file nelle richieste multipart sono tipizzati come
io.Reader. Il contenuto dell'io.Reader verrà inviato per impostazione predefinita come parte di un form multipart
con il nome file "anonymous_file" e content-type "application/octet-stream", quindi l'approccio consigliato è specificare un content-type personalizzato con l'helper anthropic.File(reader io.Reader, filename string, contentType string),
che racchiude qualsiasi io.Reader con il nome file e il content type appropriati.
// Un file dal file system
file, err := os.Open("/path/to/file.json")
anthropic.FileUploadParams{
File: anthropic.File(file, "custom-name.json", "application/json"),
}
// Un file da una stringa
anthropic.FileUploadParams{
File: anthropic.File(strings.NewReader("my file contents"), "custom-name.json", "application/json"),
}Il nome file e il content-type possono anche essere personalizzati implementando Name() string o ContentType() string sul tipo a run-time di io.Reader. Nota che os.File implementa Name() string, quindi un
file restituito da os.Open verrà inviato con il nome file presente su disco.
Paginazione
Questa libreria fornisce alcune comodità per lavorare con gli endpoint di elenco paginati.
Puoi usare i metodi .ListAutoPaging() per iterare sugli elementi attraverso tutte le pagine:
iter := client.Messages.Batches.ListAutoPaging(context.TODO(), anthropic.MessageBatchListParams{
Limit: anthropic.Int(20),
})
// Recupera automaticamente altre pagine secondo necessità.
for iter.Next() {
messageBatch := iter.Current()
fmt.Println(messageBatch.ID)
}
if err := iter.Err(); err != nil {
panic(err.Error())
}Oppure puoi usare i semplici metodi .List() per recuperare una singola pagina e ricevere un oggetto di risposta standard
con metodi helper aggiuntivi come .GetNextPage():
page, err := client.Messages.Batches.List(context.TODO(), anthropic.MessageBatchListParams{
Limit: anthropic.Int(20),
})
for page != nil {
for _, batch := range page.Data {
fmt.Println(batch.ID)
}
page, err = page.GetNextPage()
}
if err != nil {
panic(err.Error())
}RequestOptions
Questa libreria usa il pattern delle opzioni funzionali. Le funzioni definite nel
package option restituiscono una RequestOption, che è una closure che modifica una
RequestConfig. Queste opzioni possono essere fornite al client o alle singole
richieste. Ad esempio:
client := anthropic.NewClient(
// Aggiunge un header a ogni richiesta effettuata dal client
option.WithHeader("X-Some-Header", "custom_header_info"),
)
client.Messages.New(context.TODO(), // ...,
// Sovrascrive l'header
option.WithHeader("X-Some-Header", "some_other_custom_header_info"),
// Aggiunge un campo non documentato al corpo della richiesta, usando la sintassi sjson
option.WithJSONSet("some.json.path", map[string]string{"my": "object"}),
)L'opzione di richiesta option.WithDebugLog(nil) può essere utile durante il debug.
Consulta l'elenco completo delle opzioni di richiesta.
Personalizzazione del client HTTP
Per il middleware delle richieste (option.WithMiddleware) e la sostituzione dell'http.Client predefinito (option.WithHTTPClient), consulta Middleware dell'SDK.
Integrazioni con le piattaforme
Il Go SDK supporta le seguenti piattaforme:
- Agent Platform:
import "github.com/anthropics/anthropic-sdk-go/vertex". Usavertex.WithGoogleAuth(ctx, region, projectID)overtex.WithCredentials(ctx, region, projectID, creds). - Bedrock:
import "github.com/anthropics/anthropic-sdk-go/bedrock". Usabedrock.NewMantleClientper l'endpoint Bedrock della Messages API (streaming tramite SSE), oppurebedrock.WithLoadDefaultConfig(ctx)/bedrock.WithConfig(cfg)(percorsobedrock-runtime). L'importazione del packagebedrockregistra globalmente un decoder perapplication/vnd.amazon.eventstreamnel livello di streaming dell'SDK (tramite l'init()del package). Questo vale sia che tu usi il percorsobedrock-runtimeWithConfig/WithLoadDefaultConfigsiaNewMantleClient. - Claude Platform on AWS:
import anthropicaws "github.com/anthropics/anthropic-sdk-go/aws". Usaanthropicaws.NewClient(ctx, cfg)con un valoreanthropicaws.ClientConfigper costruire un client; impostaWorkspaceIDnella config o la variabile d'ambienteANTHROPIC_AWS_WORKSPACE_ID. L'alias di importazioneanthropicawsevita una collisione di nomi congithub.com/aws/aws-sdk-go-v2/awsquando entrambi sono importati. Disponibile in beta. - Foundry: Attualmente non supportato nel Go SDK. Consulta Claude in Microsoft Foundry per gli SDK supportati.
Usa bedrock.NewMantleClient per i nuovi progetti; bedrock.WithLoadDefaultConfig/WithConfig rimangono disponibili per le applicazioni esistenti che usano l'API InvokeModel di Bedrock.
Utilizzo avanzato
Accesso ai dati grezzi della risposta (ad esempio, gli header della risposta)
Puoi accedere ai dati grezzi della risposta HTTP usando l'opzione di richiesta option.WithResponseInto(). Questo è utile quando
hai bisogno di esaminare gli header della risposta, i codici di stato o altri dettagli.
// Crea una variabile per memorizzare la risposta HTTP
var response *http.Response
message, err := client.Messages.New(
context.TODO(),
anthropic.MessageNewParams{
MaxTokens: 1024,
Messages: []anthropic.MessageParam{{
Content: []anthropic.ContentBlockParamUnion{{
OfText: &anthropic.TextBlockParam{
Text: "What is a quaternion?",
},
}},
Role: anthropic.MessageParamRoleUser,
}},
Model: anthropic.ModelClaudeOpus5,
},
option.WithResponseInto(&response),
)
if err != nil {
// gestisci l'errore
}
fmt.Printf("%+v\n", message.Content)
fmt.Printf("Status Code: %d\n", response.StatusCode)
fmt.Printf("Headers: %+#v\n", response.Header)Effettuare richieste personalizzate/non documentate
Questa libreria è tipizzata per un accesso comodo all'API documentata. Se hai bisogno di accedere a endpoint, param o proprietà di risposta non documentati, la libreria può comunque essere usata.
Endpoint non documentati
Per effettuare richieste a endpoint non documentati, puoi usare client.Get, client.Post e altri verbi HTTP.
Le RequestOptions sul client, come i tentativi ripetuti, verranno rispettate quando si effettuano queste richieste.
var (
// params può essere un io.Reader, un []byte, un oggetto serializzabile con encoding/json,
// oppure una struct "...Params" definita in questa libreria.
params map[string]any
// result può essere un []byte, *http.Response, un oggetto deserializzabile con encoding/json,
// oppure un modello definito in questa libreria.
result *http.Response
)
err := client.Post(context.Background(), "/unspecified", params, &result)
if err != nil {
// ...
}Param di richiesta non documentati
Per effettuare richieste usando parametri non documentati, puoi usare i metodi option.WithQuerySet()
oppure option.WithJSONSet().
params := FooNewParams{
ID: "id_xxxx",
Data: FooNewParamsData{
FirstName: anthropic.String("John"),
},
}
client.Foo.New(context.Background(), params, option.WithJSONSet("data.last_name", "Doe"))Proprietà di risposta non documentate
Per accedere a proprietà di risposta non documentate, puoi accedere al JSON grezzo della risposta come stringa
con result.JSON.RawJSON(), oppure ottenere il JSON grezzo di un particolare campo del risultato con
result.JSON.Foo.Raw().
Tutti i campi non presenti nella struct di risposta vengono salvati e sono accessibili tramite result.JSON.ExtraFields, che è una map[string]respjson.Field.
Versionamento semantico
Questo package segue generalmente le convenzioni SemVer, anche se alcune modifiche non retrocompatibili potrebbero essere rilasciate come versioni minor:
- Modifiche agli interni della libreria che sono tecnicamente pubblici ma non destinati o documentati per l'uso esterno.
- Modifiche che non si prevede abbiano un impatto sulla grande maggioranza degli utenti nella pratica.
La retrocompatibilità è presa seriamente per garantire che tu possa contare su un'esperienza di aggiornamento senza intoppi.
Il tuo feedback è benvenuto; apri una issue con domande, bug o suggerimenti.
Risorse aggiuntive
Was this page helpful?