Skip to content

CoreNovus/convilyn-consumer-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Convilyn Go SDK

Go Reference

The official Go client for the Convilyn API — file conversion, agentic goal workflows, and the community workflow library, behind a single ck_ API key.

It is the Go-idiomatic sibling of the Python (convilyn) and TypeScript (@convilyn/sdk) consumer SDKs: the same data-plane behaviour, rendered the Go way — context.Context on every network call, (_, error) returns, typed structs, io.Reader streaming, *http.Client injection, and errors.Is / errors.As-friendly errors.

import convilyn "github.com/CoreNovus/convilyn-consumer-go"
go get github.com/CoreNovus/convilyn-consumer-go

Requires Go 1.22+. No third-party dependencies (standard library only).

Quickstart

package main

import (
	"context"
	"log"
	"os"
	"time"

	convilyn "github.com/CoreNovus/convilyn-consumer-go"
)

func main() {
	client, err := convilyn.NewClient(
		convilyn.WithAPIKey(os.Getenv("CONVILYN_API_KEY")),
		convilyn.WithTimeout(30 * time.Second),
		convilyn.WithMaxRetries(2),
	)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	ctx := context.Background()

	file, err := client.Files.Upload(ctx, convilyn.UploadFileRequest{Path: "report.docx"})
	if err != nil {
		log.Fatal(err)
	}

	job, err := client.Convert.CreateAndWait(ctx, convilyn.ConvertCreateRequest{
		File:         file,
		TargetFormat: "pdf",
	})
	if err != nil {
		log.Fatal(err)
	}

	if _, err := client.Convert.DownloadTo(ctx, job, "report.pdf"); err != nil {
		log.Fatal(err)
	}
}

Authentication

Pass a consumer key with WithAPIKey, or set CONVILYN_API_KEY and omit it. Keys start with ck_ and are sent as Authorization: Bearer ck_.... The key is masked in every fmt verb and never appears in logs or error messages:

client, _ := convilyn.NewClient(convilyn.WithAPIKey("ck_live_abcdef...90"))
fmt.Printf("%+v\n", client) // convilyn.Client{baseURL:"...", apiKey:ck_l…90}

Uploading files

Files.Upload runs the presign → S3 PUT → confirm flow and streams the body, so large files are never buffered into memory. Upload from a path or any io.Reader:

// From a path (size + content-type inferred):
file, err := client.Files.Upload(ctx, convilyn.UploadFileRequest{Path: "data.csv"})

// From a stream:
f, _ := os.Open("big.mp4")
defer f.Close()
file, err = client.Files.Upload(ctx, convilyn.UploadFileRequest{
	Reader:   f,
	Filename: "big.mp4",
	Size:     fileSize, // recommended for streams so S3 gets a Content-Length
})

Goal workflows (agentic)

Goals.Run starts a job and polls until it finishes or pauses for human input:

job, err := client.Goals.Run(ctx, convilyn.GoalRunRequest{
	WorkflowID: "wf_summarize",
	Files:      []string{file.ID},
})
if err != nil {
	log.Fatal(err)
}
if job.NeedsInput() {
	for _, slot := range job.PendingSlots {
		fmt.Println("agent asks:", slot.Question)
	}
}

Human-in-the-loop

When a job pauses at slots_pending, answer the slots, confirm, and let it run — or cancel / retry:

// Answer one slot (or FillSlots for several at once):
job, _ = client.Goals.FillSlot(ctx, job.JobSpecID, "sheet", "Q1")

// Confirm and wait for the run to finish:
job, _ = client.Goals.Confirm(ctx, job.JobSpecID)
job, _ = client.Goals.Wait(ctx, job.JobSpecID)

// Or cancel / retry:
job, _ = client.Goals.Cancel(ctx, job.JobSpecID)
job, _ = client.Goals.Retry(ctx, job.JobSpecID, convilyn.RetryOptions{RerunMode: convilyn.RerunFresh})

Pass ExpectedVersion (from job.ItemVersion) to FillSlots/Confirm for optimistic locking — a stale write returns a 409 *APIError.

Live event stream (Events)

Goals.Events opens a WebSocket and streams GoalEvents — tool calls, agent steps, progress, and agent text — until a terminal event (completed / failed / cancelled). It iterates with the same Next / Current / Err cursor shape as the paginator:

stream, err := client.Goals.Events(ctx, job.JobSpecID)
if err != nil {
	log.Fatal(err)
}
defer stream.Close()
for stream.Next() {
	ev := stream.Current()
	fmt.Println(ev.Type, ev.Seq)
}
if err := stream.Err(); err != nil {
	log.Fatal(err) // a dropped connection surfaces as *WebSocketError
}

Backend status: the WebSocket gateway does not yet accept ck_ keys for the event stream. Until that lands, prefer polling with Goals.Wait (which uses standard HTTP auth and works today); Events is wired and ready for when the gateway gains ck_ support. There is no auto-reconnect — the backend does not replay missed events, so a silent reconnect would hide gaps.

Because Go has no standard-library WebSocket client, the SDK ships no default transport: inject one implementing the WSTransport interface (Connect / Send / Recv / Close) via WithWSTransport, and set the endpoint with WithWSURL or the CONVILYN_WS_URL environment variable (a per-call EventsOptions.WSURL overrides both). Without a transport, Events returns a *WebSocketError.

Community workflows

page, err := client.Workflows.Search(ctx, convilyn.WorkflowSearchRequest{
	Sort:  "popular",
	Limit: 50,
})

// Or iterate every page lazily:
it := client.Workflows.SearchAll(ctx, convilyn.WorkflowSearchRequest{Limit: 50})
for it.Next() {
	fmt.Println(it.Current().WorkflowID)
}
if err := it.Err(); err != nil {
	log.Fatal(err)
}

Managing your workflows

Fork a curated/public source, edit it, publish it, or like one (some actions need Pro tier — a 402 surfaces as *PlanRequiredError):

wf, _ := client.Workflows.Fork(ctx, convilyn.ForkRequest{SourceSpecID: "doc_analyzer"})

// Partial update (optimistic-locked on ItemVersion); only set fields are sent:
name := "My report pipeline"
wf, _ = client.Workflows.Patch(ctx, wf.WorkflowID, convilyn.PatchWorkflowRequest{
	ItemVersion: wf.ItemVersion,
	Name:        &name,
	Tags:        []string{"reports"},
})

wf, _ = client.Workflows.Publish(ctx, wf.WorkflowID, wf.ItemVersion) // visibility → public
like, _ := client.Workflows.Like(ctx, "wf_community_123")            // toggle; like.Liked is the new state

Account, quota & cost

All amounts are in credits (1 credit = $0.01):

est, _ := client.Account.GetQuota(ctx, convilyn.QuotaRequest{
	Tools: []string{"pdf-mcp:extract_text"},
})
fmt.Printf("~%.2f credits (state=%s)\n", est.EstimatedCredits, est.QuotaCheck.State)

plan, _ := client.Account.GetPlan(ctx)
usage, _ := client.Account.UsageHistory(ctx)

Error handling

Every error is inspectable with errors.Is (category sentinels) and errors.As (typed details):

_, err := client.Goals.Run(ctx, req)

var apiErr *convilyn.APIError
var quota  *convilyn.QuotaExceededError
switch {
case errors.Is(err, convilyn.ErrRateLimited):
	// back off and retry later
case errors.As(err, &quota):
	fmt.Printf("need %.2f credits, have %.2f — top up at %s\n",
		quota.CostCredits, quota.BalanceCredits, quota.TopUpURL)
case errors.As(err, &apiErr):
	fmt.Printf("status=%d code=%s request_id=%s\n",
		apiErr.StatusCode, apiErr.Code, apiErr.RequestID)
}

Sentinels: ErrAuthentication, ErrPermissionDenied, ErrRateLimited, ErrTimeout, ErrQuotaExceeded, ErrPlanRequired. Typed errors: APIError, RateLimitError, QuotaExceededError, PlanRequiredError, AuthError, S3UploadError, RetryExhaustedError, JobFailedError, JobTimeoutError, GoalJobFailedError, GoalJobTimeoutError.

Timeouts, retries & idempotency

  • TimeoutWithTimeout(d) sets a per-request timeout (default 30s); cancelling the ctx aborts in flight.
  • Retries — transient failures (408/429/5xx, connection resets) are retried with exponential backoff + jitter, honoring Retry-After. Tune with WithMaxRetries(n) or supply a custom RetryPolicy (e.g. NoRetry{}).
  • Idempotency — mutating requests carry an auto-generated Idempotency-Key, stable across retries, so a retried create/run never double-charges. Disable with WithDisableIdempotency(true).

Injecting a custom HTTP client / base URL

client, _ := convilyn.NewClient(
	convilyn.WithAPIKey(key),
	convilyn.WithHTTPClient(myHTTPClient), // proxy, tracing, httptest, ...
	convilyn.WithBaseURL("http://localhost:8080"),
)

Scope

This is the consumer SDK. Author/console concerns (tool servers, workflow-spec compilation, MCP, inbound HMAC, cvl_ deploy tokens) live in the separate author SDK, github.com/CoreNovus/convilyn-author-go.

The full consumer surface is implemented: Goals HITL actions (FillSlot / FillSlots / Confirm / Cancel / Retry), the workflow mutations (Fork / Publish / Patch / Like), and the Goals.Events WebSocket stream. Events is wired and ready but gated on a backend dependency — the WS gateway does not yet accept ck_ keys, and the SDK ships no default transport (inject a WSTransport); prefer Goals.Wait polling until that lands. See the live event-stream section above.

Development

make test       # go test ./... -cover
make race       # go test -race ./...
make vet        # go vet ./...
make fmtcheck   # gofmt -l (must be empty)
make build      # go build ./...

License

Apache-2.0

About

Official Go consumer SDK for the Convilyn AI workflow platform

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors