SDK Go
Ce guide montre comment installer le SDK Go (module github.com/enterprise-ai/enterprise-ai-go, paquet eai), le
connecter au Control Plane de la Navin Platform et appeler chaque groupe de ressources de l'API v1 avec des erreurs
typées, des reprises, la pagination et le streaming. Source : sdks/go. Chaque type, fonction et champ figure dans
la référence générée.
English version: go.md
Vue d'ensemble
eai.NewClient(opts...) renvoie un *eai.Client avec un champ de service par groupe de ressources de l'API v1
(client.Agents, client.Gateway, client.FinOps...). Chaque méthode prend un context.Context, correspond à une
route documentée et renvoie un json.RawMessage, une structure typée ou une *eai.Page. Les erreurs sont des
valeurs *eai.APIError, reconnues avec errors.As, errors.Is et les sentinelles Err*. Des sous-paquets
ajoutent des briques pour les services :
| Paquet | Rôle |
|---|---|
eai (racine du module) | Le client du Control Plane, les modèles, les erreurs, la pagination, SSE, les contrats. |
manager | Le client du Navin Manager (SDK du Navin Manager). |
gatewaymw | Middleware net/http : contrôle de politique, réservation de quota, libération. |
worker | Workers asynchrones de médias et d'outils avec un kill switch. |
usage | Construction et émission par lots des événements d'usage. |
realtime | Client WebSocket des sessions vocales en direct (guide temps réel). |
Prérequis et compatibilité
| Élément | Pris en charge |
|---|---|
| Go | 1.26 ou plus (go 1.26.0 dans sdks/go/go.mod) |
| Systèmes d'exploitation | Chaque plateforme prise en charge par la chaîne Go (Linux, macOS, Windows ; amd64 et arm64) |
| Dépendances | github.com/santhosh-tekuri/jsonschema/v6 (contrats), golang.org/x/net (WebSocket) |
| API du Control Plane | v1 (eai.Version est la version du SDK, 1.0.2) |
Installation
-
Téléchargez le module depuis Harbor. Les paquets des SDK sont hébergés dans le projet
sdkdu registre Harbor de Navinspire (artefactsdk/go, tag = version du SDK). Le registre Navinspire estregistry.navinspire.ai; connectez-vous avec un compte robot qui peut lire (pull) le projetsdk(fourni par l'équipe plateforme). Si votre organisation réplique le projetsdkdans son propre Harbor, utilisez l'adresse de ce miroir.oras login registry.navinspire.aioras pull registry.navinspire.ai/sdk/go:1.0.2 -o third_party/enterprise-ai-goRésultat attendu :
third_party/enterprise-ai-go/go.modexiste. -
Ajoutez le module à votre projet avec une directive
replacequi pointe vers le dossier téléchargé.go mod edit -require=github.com/enterprise-ai/enterprise-ai-go@v1.0.2go mod edit -replace=github.com/enterprise-ai/enterprise-ai-go=./third_party/enterprise-ai-gogo mod tidyRésultat attendu :
go.modliste le module et sa lignereplace, etgo build ./...réussit. Le nomgithub.com/enterprise-ai/enterprise-ai-goest le nom de module déclaré dans lego.moddu SDK et utilisé dans les imports. C'est un identifiant, pas une adresse de téléchargement : rien n'est récupéré à cette adresse.En cas d'échec : vérifiez
go version(1.26 ou plus) et le chemin de la directivereplace.
Installation hors ligne
-
Intégrez le module au dépôt (vendoring). Sur une machine connectée,
go mod vendorcopie chaque dépendance, SDK compris, dansvendor/; la construction hors ligne ne lit ensuite que ce dossier.go mod vendorgo build -mod=vendor ./... -
Ou pointez vers une copie de ce dépôt avec une directive
replacedansgo.mod:replace github.com/enterprise-ai/enterprise-ai-go => ../sdks/go.
Démarrage rapide
Cet exemple construit un client, lit l'identité de l'appelant et envoie une complétion de chat par le gateway.
client, err := eai.NewClient(eai.WithBaseURL("<control-plane-url>"), eai.WithAPIKey(os.Getenv("EAI_API_KEY")))
if err != nil {
return err
}
me, err := client.Meta.Me(ctx)
if err != nil {
return err
}
reply, err := client.Gateway.ChatCompletions(ctx, eai.ChatRequest{Model: "gpt-4o-mini", Messages: []eai.ChatMessage{{Role: "user", Content: "Bonjour"}}})
if err != nil {
return err
}
fmt.Println(string(me), reply.Content, reply.CostMeasured)
Ce qui se passe : NewClient vérifie les options (une URL de base est obligatoire, https sauf sur localhost),
chaque appel envoie la clé dans X-API-Key et un traceparent W3C, et la complétion part avec une
Idempotency-Key. Résultat attendu : le document d'identité, puis le texte de la réponse et son coût mesuré.
Authentification
Le serveur résout le tenant à partir de l'identifiant. Le SDK ne lit aucune variable d'environnement : passez les
valeurs aux options, par exemple avec os.Getenv.
| Méthode | Option | En-tête envoyé |
|---|---|---|
Clé API de tenant eai_<prefix>_<secret> | eai.WithAPIKey(key) | X-API-Key |
| Jeton d'accès OIDC | eai.WithToken(token) | Authorization: Bearer <token> |
Mode développement (serveur lancé avec EAI_AUTH_DEV=1), seulement sans identifiant | eai.WithTenant(slug) | X-Dev-Tenant |
| Identité de workload, mTLS | eai.WithHTTPClient(...) avec un certificat client | certificat client TLS |
import eai "github.com/enterprise-ai/enterprise-ai-go"
client, err := eai.NewClient(
eai.WithBaseURL("<control-plane-url>"),
eai.WithAPIKey(os.Getenv("EAI_API_KEY")),
eai.WithTenant("acme"),
eai.WithLocale("en"),
)
Configuration du client
eai.NewClient(opts ...eai.Option) (*eai.Client, error) :
| Option | Type | Défaut | Description |
|---|---|---|---|
WithBaseURL(u) | string | aucun, obligatoire | URL du Control Plane sans /v1 ; https sauf pour localhost, 127.0.0.1, ::1. |
WithAPIKey(k) | string | aucun | Clé API du tenant, envoyée dans X-API-Key. |
WithToken(t) | string | aucun | Jeton d'accès OIDC, envoyé dans Authorization: Bearer. |
WithTenant(t) | string | aucun | Slug du tenant ; envoyé dans X-Dev-Tenant seulement sans identifiant. |
WithProject(p) | string | aucun | Envoyé dans X-Project. |
WithEnvironment(e) | string | aucun | dev, test, staging ou prod, envoyé dans X-Environment. |
WithLocale(l) | string | "en" | en ou fr (toute valeur qui commence par fr donne fr) ; envoyé dans Accept-Language. |
WithRetries(n) | int | 2 | Reprises après la première tentative ; les valeurs négatives sont refusées. |
WithRetryBaseDelay(d) | time.Duration | 250ms | Premier délai d'attente, doublé à chaque tentative. |
WithHTTPClient(h) | *http.Client | &http.Client{Timeout: 60 * time.Second} | Client personnalisé (délai, proxy, mTLS). |
WithHeader(name, value) | string, string | aucun | En-tête envoyé avec chaque requête. |
WithTraceparent(f) | func() string | aléatoire par requête | Renvoie le traceparent W3C du span courant. |
WithCABundle(pem) | []byte | magasin du système | Autorités de certification supplémentaires (PEM) ; la vérification reste active. |
WithDangerouslyDisableTLSVerificationForLocalhost() | aucun | désactivé | Désactive le contrôle des certificats ; refusé sauf si l'hôte est local. |
Options par appel (eai.CallOption, derniers arguments de chaque méthode) :
| Option | Description |
|---|---|
WithQuery(map[string]string) | Paramètres de la chaîne de requête (filtres). |
WithLimit(n), WithCursor(c) | Taille de page et curseur d'un appel de liste. |
WithIdempotencyKey(k) | Idempotency-Key d'un POST ; sinon une clé est générée et conservée entre les reprises. |
WithCallTraceparent(tp) | Traceparent W3C de cet appel. |
WithCallHeader(name, value) | En-tête supplémentaire de cet appel. |
tuned, err := eai.NewClient(
eai.WithBaseURL("<control-plane-url>"),
eai.WithToken(os.Getenv("EAI_TOKEN")),
eai.WithProject("invoices"),
eai.WithEnvironment("prod"),
eai.WithRetries(4),
eai.WithRetryBaseDelay(500*time.Millisecond),
eai.WithHTTPClient(&http.Client{Timeout: 30 * time.Second}),
eai.WithHeader("X-Client", "billing"),
)
if err != nil {
return err
}
agent, err := tuned.Agents.Get(ctx, "agt_ap", eai.WithCallHeader("X-Correlation-Id", "c-1"))
fmt.Println(client) masque la clé API et le jeton. Les redirections ne sont jamais suivies et TLS 1.2 est le
minimum.
Requêtes et réponses
La plupart des méthodes prennent un corps any (une structure ou une map[string]any, encodée en JSON) et
renvoient un json.RawMessage ; décodez-le dans votre propre type avec eai.Decode[T] ou json.Unmarshal. Des
aides typées renvoient des structures : Gateway.ChatCompletions renvoie un *eai.ChatResponse avec Content,
Usage, DecisionID, CostEstimated et CostMeasured.
resp, err := client.Gateway.ChatCompletions(ctx, eai.ChatRequest{Model: "gpt-4o-mini", Messages: []eai.ChatMessage{{Role: "user", Content: "Bonjour"}}, Eai: &eai.EaiExtension{Effort: eai.EffortLow, AgentID: "agt_ap"}})
if err != nil { return err }
fmt.Println(resp.CostMeasured, resp.DecisionID)
raw, err := client.Agents.Get(ctx, "agt_ap")
if err != nil {
return err
}
type agentView struct {
ID string `json:"id"`
Status string `json:"status"`
}
decode := eai.Decode[agentView]
view, err := decode(raw)
fmt.Println(view.ID, view.Status)
Erreurs
Chaque réponse d'erreur utilise l'enveloppe {"error": {"code", "message", "message_i18n", "details", "request_id"}}. Le SDK renvoie un *eai.APIError avec Status (0 pour une erreur réseau), Code, Message (dans
la langue du client), MessageI18n, Details (clés d'allure secrète masquées), RequestID, RetryAfter et
HasRetryAfter. Sans enveloppe, le code vient du statut : 400 et 422 validation_error, 401 unauthenticated, 403
forbidden, 404 not_found, 409 conflict, 429 rate_limited, 5xx server_error.
| Sentinelle ou aide | Reconnaît | Reprise par le SDK |
|---|---|---|
ErrPolicyDenied, IsPolicyDenied | policy_denied | non |
ErrQuotaExceeded, IsQuotaExceeded | quota_exceeded, budget_exceeded | oui quand le statut est 429, puis renvoyée |
ErrEffortNotSupported, IsEffortNotSupported | effort_not_supported | non |
ErrContextOverflow, IsContextOverflow | context_overflow | non |
ErrApprovalRequired, IsApprovalRequired, APIError.ApprovalID() | approval_required | non |
ErrNotFound, IsNotFound | not_found ou HTTP 404 | non |
ErrAuth, IsAuth | unauthenticated, forbidden, HTTP 401, HTTP 403 autre que policy_denied | non |
ErrRateLimited | rate_limited | oui, puis renvoyée |
ErrEgressDenied, IsEgressDenied, EgressDeniedReason | egress_denied | non |
ErrPromptInjectionBlocked, IsPromptInjectionBlocked | prompt_injection_blocked | non |
ErrPayloadTooLarge, IsPayloadTooLarge | payload_too_large | non |
Code == "network_error" | pas de réponse (errors.Unwrap donne la cause) | oui, puis renvoyée |
Code == "server_error" et autres 5xx | HTTP 502, 503, 504 repris ; 500 renvoyé aussitôt | en partie |
_, err = client.Gateway.ChatCompletions(ctx, req)
var apiErr *eai.APIError
if errors.As(err, &apiErr) && apiErr.Code == "quota_exceeded" { log.Println(apiErr.MessageI18n["fr"], apiErr.RequestID) }
if errors.Is(err, eai.ErrQuotaExceeded) { /* same check */ }
Reprises et délais
Une erreur réseau et les statuts HTTP 408, 429, 502, 503 et 504 sont repris jusqu'à WithRetries fois (2 par
défaut), pour toutes les méthodes : un POST garde son Idempotency-Key entre les reprises, donc le serveur le
dédoublonne. Le délai commence à WithRetryBaseDelay (250 ms), double à chaque tentative jusqu'à 20 s et ajoute
jusqu'à 20 % d'aléa ; un en-tête Retry-After l'emporte, plafonné à 60 s. L'échéance du contexte borne l'appel
entier, reprises comprises ; le délai du http.Client (60 s par défaut) borne chaque tentative. Un contexte annulé
arrête l'appel aussitôt.
callCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
_, err = client.Meta.Ready(callCtx)
Pagination
Les méthodes de liste renvoient une *eai.Page (Items []json.RawMessage, NextCursor, HasNext(),
Next(ctx)). Iter() parcourt chaque élément à travers les pages, en les chargeant à la demande ; All(ctx) les
rassemble.
run, err := client.Runs.Start(ctx, "agt_ap", map[string]any{"task": "Process invoice med_01HZX3K9"}, eai.WithIdempotencyKey("inv-2291"))
page, err := client.Runs.List(ctx, eai.WithLimit(50))
it := page.Iter()
for it.Next(ctx) { fmt.Println(string(it.Item())) }
first, err := client.Agents.List(ctx, eai.WithLimit(100), eai.WithQuery(map[string]string{"status": "active"}))
if err != nil {
return err
}
all, err := first.Iter().All(ctx)
fmt.Println(len(all), first.HasNext())
Vérifiez it.Err() après la boucle : il contient l'erreur qui a arrêté le parcours.
Idempotence et opérations longues
Chaque POST envoie une Idempotency-Key : la valeur de WithIdempotencyKey, sinon un UUID généré et conservé entre
les reprises de l'appel. Le Control Plane rejoue la première réponse pour une clé déjà vue. Une création longue
répond avec les en-têtes Operation-Id et Operation-Location ; client.Operations.Get(ctx, id) lit l'opération,
sa ressource suivie et son état courant. client.Exchange(...) renvoie le statut et les en-têtes de n'importe quel
appel.
op, err := client.Operations.Get(ctx, "op_1")
execution, err := client.Sandbox.Get(ctx, "sbx_1")
fmt.Println(string(op), string(execution))
Asynchrone et concurrence
*eai.Client est sûr en usage concurrent : partagez un seul client entre les goroutines. L'annulation et les
échéances voyagent dans le context.Context de chaque appel. Le paquet worker exécute des tâches asynchrones avec
une concurrence bornée.
import "github.com/enterprise-ai/enterprise-ai-go/worker"
jobs := make(chan *worker.Job)
w, err := worker.New(worker.Config{
Client: client,
Source: &worker.ChanSource{Jobs: jobs},
Concurrency: 4,
Handler: func(ctx context.Context, job *worker.Job) (any, error) {
return map[string]any{"frames": 118}, nil
},
})
err = w.Run(ctx)
Streaming et temps réel
Gateway.ChatCompletionsStream renvoie un *eai.ChatStream sur Server-Sent Events : Next(), Chunk() (avec
Delta, FinishReason, Usage), Err(), Close() et CollectText(). Les sessions vocales en direct utilisent
le paquet realtime (guide temps réel).
stream, err := client.Gateway.ChatCompletionsStream(ctx, eai.ChatRequest{Model: "gpt-4o-mini", Messages: []eai.ChatMessage{{Role: "user", Content: "Bonjour"}}})
if err != nil {
return err
}
defer stream.Close()
for stream.Next() {
fmt.Print(stream.Chunk().Delta)
}
err = stream.Err()
import "github.com/enterprise-ai/enterprise-ai-go/realtime"
raw, err := client.Realtime.CreateSession(ctx, map[string]any{"pipeline": "stt", "config": map[string]any{"agent_id": "agt_voice", "language": "fr"}})
var sess struct{ SessionID string `json:"session_id"` }
err = json.Unmarshal(raw, &sess)
defer client.Realtime.EndSession(ctx, sess.SessionID)
conn, err := realtime.Dial(ctx, client, sess.SessionID)
defer conn.Close()
for { ev, err := conn.Recv(); if err != nil { break }; if ev.Type == realtime.UsageUpdate { log.Println(string(ev.Raw)) } }
Journalisation et débogage
Le SDK n'écrit aucun journal. client.Exchange renvoie le statut et les en-têtes de n'importe quel appel, dont le
X-Request-Id à donner à l'équipe plateforme ; fmt.Println(client) affiche les réglages avec les secrets masqués.
resp, err := client.Exchange(ctx, "GET", "/v1/meta", nil, nil)
if err != nil {
return err
}
log.Printf("status=%d request_id=%s", resp.Status, resp.Header.Get("X-Request-Id"))
fmt.Println(client)
Pour journaliser chaque appel, donnez à eai.WithHTTPClient un http.Client dont le Transport enveloppe
http.DefaultTransport et journalise la méthode, l'URL, le statut et le X-Request-Id ; ne journalisez jamais les
en-têtes de la requête, qui portent les identifiants.
Tests
Dirigez le client vers un serveur httptest : le vrai transport s'exécute (en-têtes, reprises, erreurs), sur
127.0.0.1.
import "net/http/httptest"
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
if r.URL.Path == "/v1/agents/missing" {
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(`{"error":{"code":"not_found","message":"Resource not found."}}`))
return
}
_, _ = w.Write([]byte(`{"items":[{"id":"agt_1"}],"next_cursor":null}`))
}))
defer srv.Close()
testClient, err := eai.NewClient(eai.WithBaseURL(srv.URL), eai.WithAPIKey("eai_test_key"), eai.WithRetries(0))
if err != nil {
return err
}
listed, err := testClient.Agents.List(ctx)
_, err = testClient.Agents.Get(ctx, "missing")
if !eai.IsNotFound(err) {
return err
}
fmt.Println(len(listed.Items))
Versions et compatibilité
- Le module suit le versionnage sémantique :
v1.xgarde chaque nom exporté ; un changement incompatible utiliserait un chemin de module/v2. - Il cible l'API
v1et les contratsv1; les résultatsjson.RawMessagegardent les champs qu'un serveur plus récent ajoute. eai.Versionet l'en-têteUser-Agentidentifient le SDK dans la piste d'audit.- Fixez la version dans
go.modet lisez les notes de version avant une mise à jour.
Guides des ressources
Une sous-section par groupe de ressources, avec un exemple par appel courant. Chaque méthode est dans la référence générée.
Système, identité et tenancy
Meta, Catalog, Roadmap, Operations, Contracts, Manifests, Tenants, Projects, Members,
APIKeys, ServiceIdentities, Authz, Secrets.
meta, err := client.Meta.Get(ctx)
project, err := client.Projects.Create(ctx, map[string]any{"slug": "invoices", "name": "Invoices"})
key, err := client.APIKeys.Create(ctx, map[string]any{"name": "ci-pipeline", "scopes": []string{"agents:run"}})
fmt.Println(string(meta), string(project), string(key))
Gateway, modèles et FinOps
Providers, Models, Routes, LiteLLM, Adapters, Context, Gateway, FinOps, Quotas.
est, _ := client.FinOps.Estimate(ctx, map[string]any{"usage_type": "stt", "provider": "local", "model_id": "faster-whisper-large-v3", "units": map[string]any{"audio_seconds": 600}})
v, _ := client.Audit.Verify(ctx)
g, _ := client.Evaluations.CheckGate(ctx, map[string]any{"target": map[string]any{"type": "agent", "ref": "agt_ap"}})
Middleware du gateway
gatewaymw.New enveloppe un http.Handler : il évalue la politique, réserve le quota, appelle le handler et libère
la réservation sauf si le handler l'a confirmée.
import "github.com/enterprise-ai/enterprise-ai-go/gatewaymw"
// Evaluate the policy, reserve the quota, call the wrapped handler, release the reservation unless the handler committed it.
h := gatewaymw.New(gatewaymw.Config{
Client: client,
Action: func(r *http.Request) string { return "model.invoke" },
Reserve: func(r *http.Request) map[string]any { return map[string]any{"tokens": 4000, "scope": map[string]any{"agent_id": r.Header.Get("X-Agent-Id")}} },
})(upstream)
http.ListenAndServe(":8081", h)
Événements d'usage
Le paquet usage construit les événements d'usage et les envoie par lots (POST /v1/finops/usage/batch).
import "github.com/enterprise-ai/enterprise-ai-go/usage"
ev, err := usage.NewEvent("acme", "gpu_local", "runtime").Model("local", "llama-70b-local", "", "").Execution("agt_ap", "", "", "").Unit("gpu_seconds", 12.4).Unit("energy_wh", 1.7).Build()
em := usage.NewEmitter(client, usage.Options{BatchSize: 500, FlushInterval: 5 * time.Second}) // POST /v1/finops/usage/batch
defer em.Close(ctx)
err = em.Emit(ev)
Agents, runs, webhooks et heartbeats
Agents, Runs, Checkpoints, Heartbeats, A2A, Sessions, Schedules, Triggers, Events, Sandbox,
Webhooks. Une réponse de heartbeat avec Stop() vrai signifie : enregistrer un point de reprise et sortir.
h := eai.WebhookHeaders(raw, secret, "acme", "evt-42", time.Now())
_, err := c.Webhooks.DeliverSigned(ctx, "sap", raw, secret, "acme", "")
hb, err := c.Heartbeats.Heartbeat(ctx, runID, map[string]any{"progress": 0.5})
if hb.Stop() { /* checkpoint and exit */ }
b, err := usage.NewEvent(tenantID, "llm", "runtime").TokenTotals(1200, 300, 800, 120)
ks := worker.RunKillSwitch(c, runID) // trips on action "stop"
Licence, SOC, contexte, place de marché et politiques
License, SOC, Context, Delegations, Mandates, BreakGlass, Marketplace, Evidence, Storage,
Policies, Approvals.
lic, err := c.License.Get(ctx)
order, err := c.SOC.CreateOrder(ctx, map[string]any{"incident_id": incID, "action": "kill_switch"})
_, err = c.SOC.ApproveOrder(ctx, orderID) // a second approver, four eyes
proof, err := c.SOC.VerifyKillSwitch(ctx, switchID)
tok, err := c.Context.Issue(ctx, map[string]any{"subject": "agent:billing", "purpose": "invoice"})
pre, err := c.Marketplace.Preflight(ctx, map[string]any{"package": "crm-sync", "version": "1.2.0"})
archive, err := c.Policies.DownloadBundle(ctx, revision) // []byte, tar.gz
res, err := eai.ValidateContract("en", "storage-profile", profile)
Interfaces de l'architecture
Méthodes nommées sur des routes documentées. Un refus se propage en *eai.APIError (relation_required,
approval_closed, storage_object_protected), et une réponse qui ne confirme pas le résultat est renvoyée comme
une erreur, jamais comme un succès.
assumed, err := c.ServiceIdentities.AssumeService(ctx, "si_billing", eai.AssumeRequest{Purpose: "invoice sync", Audience: []string{"erp"}, TTLSeconds: 600})
var ae *eai.APIError
if errors.As(err, &ae) && ae.Code == "relation_required" {
return err // write the can_assume relation first (POST /v1/authz/tuples)
}
_, err = c.Audit.Record(ctx, map[string]any{"action": "app.invoice.validated", "resource": map[string]any{"type": "invoice", "id": "inv-42"}, "outcome": "success"})
_, err = c.Approvals.Cancel(ctx, "apr_1", map[string]any{"reason": "request withdrawn"})
objects, err := c.Storage.List(ctx, "stp_1", eai.WithQuery(map[string]string{"prefix": "exports/"}), eai.WithLimit(100))
_, err = c.Storage.Delete(ctx, "stp_1", "exports/old.json", "")
Espace Platform Manager (platform_admin)
client.PlatformManager atteint l'espace Platform Manager de la console, relayé par le Control Plane au nom de
l'appelant.
summary, err := c.PlatformManager.Summary(ctx)
services, err := c.PlatformManager.Services(ctx, "c1")
op, err := c.PlatformManager.RequestOperation(ctx, "c1", "opa", map[string]any{"action": "rolling_restart", "batch_size": 1})
restore, err := c.PlatformManager.PlanRestore(ctx, map[string]any{"artifact_id": "b1", "environment": "isolated"}) // ADR-0162
exercises, err := c.PlatformManager.DRExercises(ctx) // observed RPO and RTO
Client du Navin Manager
Le paquet manager appelle directement l'API du Navin Manager avec un jeton du manager nmt_<12 hex>_<secret> ;
GET, PUT et DELETE sont repris, POST et PATCH jamais. Le guide complet est SDK du Navin Manager.
import "github.com/enterprise-ai/enterprise-ai-go/manager"
nm, err := manager.New(manager.WithBaseURL("<manager-url>"), manager.WithToken(os.Getenv("NM_MANAGER_TOKEN")), manager.WithOnBehalfOf("alice"))
if err != nil {
return err
}
action, err := nm.Services.Action(ctx, "c1", "kafka", map[string]any{"action": "restart"})
fmt.Println(string(action))
Référence
- Référence Go générée : chaque type, fonction, méthode et champ.
- API v1 du Control Plane, Contrats v1, guide temps réel.
- Autres SDK.