argyll

package module
v0.0.0-...-70b8d44 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

README

Argyll Go SDK

Go SDK for building steps and flows with the Argyll Goal-Driven Orchestrator.

Installation

go get github.com/kode4food/argyll/sdk/go

Documentation

Quick Start

Define a Sync Step
package main

import (
    "context"
    "log"
    "time"

    argyll "github.com/kode4food/argyll/sdk/go"
)

func main() {
    client := argyll.NewClient("http://localhost:8080", 30*time.Second)

    handler := func(ctx *argyll.StepContext, args api.Args) (api.Args, error) {
        name := args["name"].(string)
        return api.Args{"greeting": "Hello, " + name}, nil
    }

    if err := client.NewStep().WithName("Greeting").
        Required("name", api.TypeString).
        Output("greeting", api.TypeString).
        Start(handler); err != nil {
        log.Fatal(err)
    }
}
Define an Async Step
package main

import (
    "context"
    "log"
    "time"

    "github.com/kode4food/argyll/engine/pkg/api"
    argyll "github.com/kode4food/argyll/sdk/go"
)

func main() {
    client := argyll.NewClient("http://localhost:8080", 30*time.Second)

    handler := func(ctx *argyll.StepContext, args api.Args) (api.Args, error) {
        asyncCtx, err := argyll.NewAsyncContext(ctx)
        if err != nil {
            return nil, err
        }

        // Start background work
        go func() {
            time.Sleep(5 * time.Second)
            asyncCtx.Success(api.Args{"result": "done"})
        }()

        return api.Args{}, nil
    }

    if err := client.NewStep().WithName("AsyncTask").
        WithAsyncExecution().
        Output("result", api.TypeString).
        Start(handler); err != nil {
        log.Fatal(err)
    }
}
Define a Script Step
package main

import (
    "context"
    "log"
    "time"

    "github.com/kode4food/argyll/engine/pkg/api"
    argyll "github.com/kode4food/argyll/sdk/go"
)

func main() {
    client := argyll.NewClient("http://localhost:8080", 30*time.Second)

    if err := client.NewStep().WithName("Double").
        Required("value", api.TypeNumber).
        Output("result", api.TypeNumber).
        WithScript("(* value 2)").
        Register(context.Background()); err != nil {
        log.Fatal(err)
    }
}
Execute a Flow
package main

import (
    "context"
    "log"
    "time"

    "github.com/kode4food/argyll/engine/pkg/api"
    argyll "github.com/kode4food/argyll/sdk/go"
)

func main() {
    client := argyll.NewClient("http://localhost:8080", 30*time.Second)

    if err := client.NewFlow("greeting-flow-123").
        WithGoals("greeting").
        WithInitialState(api.InitArgs{"name": {"Alice"}}).
        WithLabel("team", "examples").
        Start(context.Background()); err != nil {
        log.Fatal(err)
    }
}
Define a Flow Step
package main

import (
    "context"
    "log"
    "time"

    "github.com/kode4food/argyll/engine/pkg/api"
    argyll "github.com/kode4food/argyll/sdk/go"
)

func main() {
    client := argyll.NewClient("http://localhost:8080", 30*time.Second)

    if err := client.NewStep().WithName("Child Flow Wrapper").
        WithFlowGoals("child-goal").
        Register(context.Background()); err != nil {
        log.Fatal(err)
    }
}

Features

  • Type-safe builders - Immutable builder pattern with method chaining
  • Sync and async steps - Support for both synchronous and asynchronous execution
  • Configurable HTTP methods - POST by default, with explicit GET, PUT, or DELETE when needed
  • Script steps - Execute Lua scripts
  • Flow orchestration - Define and execute multi-step flows
  • Result memoization - Cache step results for efficiency
  • Conditional execution - Use predicates to control step execution
  • Array iteration - Process arrays with for_each

Builder Pattern

All builders use Go's value semantics for immutability:

builder1 := client.NewStep().WithName("Test")
builder2 := builder1.WithID("custom-id")

// builder1 is unchanged
// builder2 has the custom ID

Advanced Features

Conditional Execution
client.NewStep().WithName("ConditionalStep").
    Required("value", api.TypeNumber).
    WithLuaPredicate("return value > 10").
    WithMethod("POST").
    WithEndpoint("http://localhost:8081/step").
    Register(ctx)
HTTP Methods

POST is the default when no method is specified:

client.NewStep().WithName("LookupUser").
    Required("user_id", api.TypeString).
    Output("user", api.TypeObject).
    WithMethod("GET").
    WithEndpoint("http://localhost:8081/users/{user_id}").
    Register(ctx)
Array Processing
client.NewStep().WithName("ProcessItems").
    Required("items", api.TypeArray).
    WithForEach("items").
    Output("processed", api.TypeString).
    WithEndpoint("http://localhost:8081/process").
    Register(ctx)
Result Memoization
client.NewStep().WithName("ExpensiveComputation").
    Required("input", api.TypeNumber).
    Output("result", api.TypeNumber).
    WithMemoizable().
    WithEndpoint("http://localhost:8081/compute").
    Register(ctx)
Labels
client.NewStep().WithName("DataProcessor").
    WithLabels(api.Labels{"team": "data", "env": "prod"}).
    WithEndpoint("http://localhost:8081/process").
    Register(ctx)

Environment Variables

Configure step server settings:

export STEP_PORT=8081           # Server port (default: 8081)
export STEP_HOSTNAME=localhost  # Server hostname (default: localhost)

Error Handling

handler := func(ctx *argyll.StepContext, args api.Args) (api.Args, error) {
    if !authorized {
        return nil, argyll.NewHTTPError(401, "Unauthorized")
    }
    // ... process step
}

Testing

cd sdk/go
go test ./...

Examples

See the examples directory for complete working examples:

  • simple-step - Basic synchronous step
  • payment-processor - Payment processing with validation
  • inventory-resolver - Inventory lookup
  • notification-sender - Async notification sending

API Reference

Client
  • NewClient(engineURL string, timeout time.Duration) *Client - Create a new client
  • NewStep() Step - Create a step builder template
  • NewFlow(flowID api.FlowID) Flow - Create a flow builder
  • Flow(flowID api.FlowID) *FlowClient - Get flow client
StepBuilder
  • WithName(name api.Name) Step - Set step name (auto-generates ID if unset)
  • WithID(id string) Step - Set custom step ID
  • Required(name, type) Step - Add required input
  • Optional(name, type, default) Step - Add optional input
  • Const(name, type, value) Step - Add const input
  • Output(name, type) Step - Declare output
  • WithForEach(name) Step - Enable array iteration
  • WithLabel(key, value) Step - Add label
  • WithLabels(labels) Step - Add multiple labels
  • WithFlowGoals(...stepIDs) Step - Configure a flow step with child goals
  • WithEndpoint(url) Step - Set HTTP endpoint
  • WithMethod(method string) Step - Set HTTP method (GET, POST, PUT, DELETE)
  • WithHealthCheck(url) Step - Set health check endpoint
  • WithTimeout(ms) Step - Set execution timeout
  • WithScript(script) Step - Set Lua script
  • WithScriptLanguage(lang, script) Step - Set script with language
  • WithPredicate(lang, script) Step - Set predicate
  • WithAsyncExecution() Step - Enable async execution
  • WithSyncExecution() Step - Enable sync execution
  • WithMemoizable() Step - Enable result caching
  • Build() (*api.Step, error) - Build step
  • Register(ctx) error - Register step
  • Start(handler) error - Register and start server
FlowBuilder
  • WithGoal(stepID) Flow - Add single goal
  • WithGoals(...stepIDs) Flow - Set all goals
  • WithInitialState(args) Flow - Set initial state
  • WithLabel(key, value) Flow - Add label
  • WithLabels(labels) Flow - Add multiple labels
  • Start(ctx) error - Execute flow
StepContext
  • Context - Standard Go context
  • Client - Flow client for operations
  • StepID - Current step ID
  • Metadata - Request metadata
AsyncContext
  • Success(outputs) error - Mark as successful
  • Fail(err) error - Mark as failed
  • Complete(result) error - Complete with full result

License

Apache 2.0

Documentation

Overview

Package argyll provides an API for creating and managing flow steps and flows

It offers client functionality for interacting with the orchestrator, including step registration, flow execution, and async step management, along with the runtime that argyll-gen generated adapters call

Index

Constants

View Source
const (
	MaxRegistrationAttempts = 5
	BackoffMultiplier       = 2 * time.Second
	DefaultEngineURL        = "http://localhost:8080"
)
View Source
const (
	DefaultStepPort = 8081
)

Variables

View Source
var (
	ErrMetadataNotFound   = errors.New("metadata not found in step context")
	ErrWebhookURLNotFound = errors.New("webhook_url not found in metadata")
	ErrWebhookError       = errors.New("webhook returned error status")
)
View Source
var (
	ErrRegisterStep  = errors.New("failed to register step")
	ErrUpdateStep    = errors.New("failed to update step")
	ErrListSteps     = errors.New("failed to list steps")
	ErrStartFlow     = errors.New("failed to start flow")
	ErrGetFlow       = errors.New("failed to get flow")
	ErrGetFlowStatus = errors.New("failed to get flow status")
)
View Source
var (
	ErrStepRegistration = errors.New("failed to register step after retries")
	ErrHandlerPanic     = errors.New("step handler panicked")
)

Functions

func NewFlowID

func NewFlowID(prefix string) api.FlowID

NewFlowID generates a unique flow ID with a readable prefix

Types

type AsyncContext

type AsyncContext struct {
	*StepContext
	// contains filtered or unexported fields
}

AsyncContext provides functionality to manage asynchronous step execution and embeds StepContext with the webhook URL for result delivery

func NewAsyncContext

func NewAsyncContext(ctx *StepContext) (*AsyncContext, error)

NewAsyncContext creates a new async context from a StepContext and extracts webhook_url from the StepContext metadata

func (*AsyncContext) Complete

func (c *AsyncContext) Complete(outputs api.Args) error

Complete sends output arguments to the orchestrator via webhook

func (*AsyncContext) Fail

func (c *AsyncContext) Fail(err error) error

Fail marks the async step as failed with the given error

func (*AsyncContext) FlowID

func (c *AsyncContext) FlowID() string

FlowID returns the flow ID for this async context

func (*AsyncContext) StepID

func (c *AsyncContext) StepID() string

StepID returns the step ID for this async context

func (*AsyncContext) Success

func (c *AsyncContext) Success(outputs api.Args) error

Success marks an async step as successfully completed with the given outputs

func (*AsyncContext) WebhookURL

func (c *AsyncContext) WebhookURL() string

WebhookURL returns the webhook URL for delivering step results

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client provides functionality for interacting with the orchestrator API, including step registration, flow management, and state queries

func NewClient

func NewClient(baseURL string, timeout time.Duration) *Client

NewClient creates a new orchestrator client with the specified base URL and timeout

func (*Client) Flow

func (c *Client) Flow(id api.FlowID) *FlowClient

Flow returns a client for accessing a specific flow

func (*Client) ListSteps

func (c *Client) ListSteps(
	ctx context.Context,
) (*api.StepsListResponse, error)

ListSteps retrieves all registered steps from the orchestrator

func (*Client) NewFlow

func (c *Client) NewFlow(id api.FlowID) Flow

NewFlow creates a new flow builder with the specified ID

func (*Client) NewStep

func (c *Client) NewStep() Step

NewStep creates a new step builder template

type CompensateHandler

type CompensateHandler func(*StepContext, api.Args, api.Args) error

CompensateHandler undoes a completed work item given its inputs and outputs

type Flow

type Flow struct {
	// contains filtered or unexported fields
}

Flow is a builder for creating and starting flow executions

func (Flow) Start

func (f Flow) Start(ctx context.Context) error

Start creates and starts the flow

func (Flow) WithGoal

func (f Flow) WithGoal(goal api.StepID) Flow

WithGoal adds a single goal step ID to the flow

func (Flow) WithGoals

func (f Flow) WithGoals(goals ...api.StepID) Flow

WithGoals sets the goal step IDs for the flow

func (Flow) WithInitialState

func (f Flow) WithInitialState(init api.InitArgs) Flow

WithInitialState sets the initial state for the flow

func (Flow) WithLabel

func (f Flow) WithLabel(key, value string) Flow

WithLabel sets a single label for the flow

func (Flow) WithLabels

func (f Flow) WithLabels(labels api.Labels) Flow

WithLabels merges the provided labels into the flow's labels

type FlowClient

type FlowClient struct {
	*Client
	// contains filtered or unexported fields
}

FlowClient provides access to a specific flow

func (*FlowClient) FlowID

func (c *FlowClient) FlowID() api.FlowID

FlowID returns the flow ID for this client

func (*FlowClient) GetState

func (c *FlowClient) GetState(ctx context.Context) (api.FlowState, error)

GetState retrieves the current state of the flow

func (*FlowClient) GetStatus

func (c *FlowClient) GetStatus(
	ctx context.Context,
) (*api.FlowStatusResponse, error)

GetStatus retrieves the current status of the flow

type HTTPError

type HTTPError struct {
	StatusCode int
	Message    string
}

HTTPError allows step handlers to return specific HTTP status codes

func NewHTTPError

func NewHTTPError(statusCode int, message string) *HTTPError

NewHTTPError creates a new HTTPError with the given status code and message

func (*HTTPError) Error

func (e *HTTPError) Error() string

Error implements the error interface for HTTPError

type Step

type Step struct {
	// contains filtered or unexported fields
}

Step is a builder for creating and configuring flow steps. It provides an API for defining step attributes, predicates, and execution settings

func (Step) Build

func (s Step) Build() (*api.Step, error)

Build validates and creates the final Step API object

func (Step) Const

func (s Step) Const(
	name api.Name, argType api.AttributeType, defaultValue string,
) Step

Const declares a const input attribute with a fixed value

func (Step) Meta

func (s Step) Meta(name api.Name, metaKey string) Step

Meta declares a metadata input attribute, injecting the named metadata key as a step input at execution time

func (Step) Optional

func (s Step) Optional(
	name api.Name, argType api.AttributeType, defaultValue string,
) Step

Optional declares an optional input attribute with a default value

func (Step) Output

func (s Step) Output(name api.Name, argType api.AttributeType) Step

Output declares an output attribute that the step will produce

func (Step) Register

func (s Step) Register(ctx context.Context) error

Register builds and registers the step with the engine

func (Step) Required

func (s Step) Required(name api.Name, argType api.AttributeType) Step

Required declares a required input attribute for the step

func (Step) Start

func (s Step) Start(handler StepHandler) error

Start builds and registers the step, creates an HTTP server, and starts handling requests

func (Step) Update

func (s Step) Update() Step

Update marks this step as modified, so the next Start() will update the existing step registration rather than creating a new one

func (Step) WithAsyncExecution

func (s Step) WithAsyncExecution() Step

WithAsyncExecution configures the step to execute asynchronously

func (Step) WithCompensate

func (s Step) WithCompensate(endpoint string) Step

WithCompensate sets the compensate endpoint for the step

func (Step) WithCompensateHandler

func (s Step) WithCompensateHandler(handler CompensateHandler) Step

WithCompensateHandler registers a handler for compensation requests

func (Step) WithCompensateMethod

func (s Step) WithCompensateMethod(method string) Step

WithCompensateMethod sets the HTTP method used to compensate the step

func (Step) WithCompensateTimeout

func (s Step) WithCompensateTimeout(timeout int64) Step

WithCompensateTimeout sets the compensate timeout in milliseconds, overriding the step's execution timeout for compensation requests

func (Step) WithEndpoint

func (s Step) WithEndpoint(endpoint string) Step

WithEndpoint sets the HTTP endpoint where the step handler is listening

func (Step) WithFlowGoals

func (s Step) WithFlowGoals(goals ...api.StepID) Step

WithFlowGoals configures a flow step with child flow goal IDs

func (Step) WithForEach

func (s Step) WithForEach(name api.Name) Step

WithForEach marks an attribute as supporting multi work items (arrays)

func (Step) WithHealthCheck

func (s Step) WithHealthCheck(endpoint string) Step

WithHealthCheck sets the HTTP health check endpoint for the step

func (Step) WithID

func (s Step) WithID(id string) Step

WithID sets the step ID, overriding the auto-generated ID from the step name

func (Step) WithLabel

func (s Step) WithLabel(key, value string) Step

WithLabel sets a single label for the step

func (Step) WithLabels

func (s Step) WithLabels(labels api.Labels) Step

WithLabels merges the provided labels into the step's labels

func (Step) WithLuaPredicate

func (s Step) WithLuaPredicate(script string) Step

WithLuaPredicate sets a Lua language predicate script

func (Step) WithMemoizable

func (s Step) WithMemoizable() Step

WithMemoizable marks the step as eligible for result memoization

func (Step) WithMethod

func (s Step) WithMethod(method string) Step

WithMethod sets the HTTP method used to invoke the step endpoint

func (Step) WithName

func (s Step) WithName(name api.Name) Step

WithName sets the step name. If no ID is set, it will be derived

func (Step) WithPredicate

func (s Step) WithPredicate(language, script string) Step

WithPredicate sets a predicate script that determines if the step should execute

func (Step) WithRequiredMatch

func (s Step) WithRequiredMatch(
	name api.Name, language, script string,
) Step

WithRequiredMatch sets a match predicate for a required attribute. The predicate receives each candidate attribute value as "value" before collect semantics are applied

func (Step) WithScript

func (s Step) WithScript(script string) Step

WithScript sets a Lua script to execute for this step

func (Step) WithScriptExecution

func (s Step) WithScriptExecution() Step

WithScriptExecution configures the step to execute via a script

func (Step) WithScriptLanguage

func (s Step) WithScriptLanguage(lang, script string) Step

WithScriptLanguage sets a script with a specific language to execute for this step

func (Step) WithSyncExecution

func (s Step) WithSyncExecution() Step

WithSyncExecution configures the step to execute synchronously

func (Step) WithTimeout

func (s Step) WithTimeout(timeout int64) Step

WithTimeout sets the execution timeout for the step in milliseconds

func (Step) WithType

func (s Step) WithType(stepType api.StepType) Step

WithType sets the step execution type (sync, async, or script)

type StepContext

type StepContext struct {
	// Context is the standard Go context for cancellation and deadlines
	context.Context

	// Client provides access to the current flow's state and operations
	Client *FlowClient

	// StepID is the ID of the current step being executed
	StepID api.StepID

	// Metadata contains additional context passed to step handlers
	Metadata api.Metadata
}

StepContext provides context and client capabilities to step handlers

type StepHandler

type StepHandler func(*StepContext, api.Args) (api.Args, error)

StepHandler is the function signature for step implementations and receives a StepContext which includes both context and flow client

Directories

Path Synopsis
Package codec provides composable JSON codecs over encoding/json/jsontext
Package codec provides composable JSON codecs over encoding/json/jsontext
Package example contains the step functions used to exercise argyll-gen
Package example contains the step functions used to exercise argyll-gen
gen
cmd/argyll-gen command
Command argyll-gen generates Argyll step adapters for Go functions marked with //argyll:step or //argyll:wrap directives
Command argyll-gen generates Argyll step adapters for Go functions marked with //argyll:step or //argyll:wrap directives

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL