triggers

package
v0.1.133 Latest Latest
Warning

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

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

Documentation

Overview

Package triggers provides types and factories for declaring inbound webhook and cron-schedule bindings on Go SDK reasoners.

A reasoner declares external event sources via WithTriggers on RegisterReasoner. The canonical form passes typed Binding values created by Event() / Schedule() factories.

The control plane registers a code-managed Trigger row per binding when the agent registers, so the agent never has to provision webhooks itself.

Field-for-field equivalent of sdk/python/agentfield/triggers.py and sdk/typescript/src/triggers/types.ts.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyTransform

func ApplyTransform(tc *Context, bindings []Binding, input map[string]any) any

ApplyTransform picks the best-matching binding for tc and runs its Transform against input, returning the transformed value.

Matching rules (identical to the Python and TypeScript SDKs):

  1. binding.Source must equal tc.Source
  2. when the binding declares EventTypes, tc.EventType must match one of them exactly or by prefix ("pull_request" matches "pull_request.opened")
  3. a binding with explicit EventTypes wins over a catch-all binding
  4. if the winning binding has no Transform, input is returned unchanged

A panicking Transform is recovered and the raw input returned, so a buggy transform degrades to pass-through instead of failing the dispatch.

func FixtureNames

func FixtureNames() []string

FixtureNames returns the source names of every fixture in the library, for table-driven tests that want to exercise all providers.

func IsEnvelope

func IsEnvelope(body map[string]any) bool

IsEnvelope reports whether the decoded request body is a dispatcher trigger envelope: an object carrying both "event" and "_meta" keys, where "_meta" contains a "trigger_id".

func LoadFixture

func LoadFixture(t *testing.T, name string) map[string]any

LoadFixture reads a captured provider payload from the embedded fixture library and returns it as a decoded map.

The name may be given with or without the .json suffix, so both "stripe" and "stripe.json" resolve to the same fixture.

fixture := triggers.LoadFixture(t, "stripe")
result, err := triggers.SimulateEvent(t, handlePayment, triggers.SimulateEventOpts{
    Source: "stripe",
    Body:   fixture,
})

LoadFixture calls t.Fatalf when the fixture is missing or malformed, so a typo surfaces as a clear test failure rather than a nil-map panic later.

func NewContext

func NewContext(parent context.Context, tc *Context) context.Context

NewContext returns a copy of parent carrying the trigger context tc. Called by the SDK dispatch path; user code normally uses FromContext.

func RawFixture

func RawFixture(t *testing.T, name string) []byte

RawFixture returns the undecoded bytes of a fixture. Useful for tests that need to assert on the exact JSON (for example, verifying byte-for-byte parity with another SDK's copy).

func SimulateEvent

func SimulateEvent(t *testing.T, handler HandlerFunc, opts SimulateEventOpts) (any, error)

SimulateEvent runs handler as if a trigger of opts.Source had fired with opts.Body, without a control plane, HTTP server, or real provider.

It builds the *Context the runtime would have produced, applies the matching binding's Transform when Bindings are supplied, and invokes the handler with the trigger context attached — the same shape the live dispatch path delivers.

func TestHandlePayment(t *testing.T) {
    result, err := triggers.SimulateEvent(t, handlePayment, triggers.SimulateEventOpts{
        Source:    "stripe",
        EventType: "payment_intent.succeeded",
        Body:      triggers.LoadFixture(t, "stripe"),
    })
    ...
}

func SimulateSchedule

func SimulateSchedule(t *testing.T, handler HandlerFunc, opts SimulateScheduleOpts) (any, error)

SimulateSchedule runs a cron-triggered handler with a synthetic tick event.

Convenience wrapper around SimulateEvent with Source "cron" and EventType "tick". The cron expression is recorded on the body for test introspection but nothing is actually scheduled — this is a single invocation.

Types

type Binding

type Binding struct {
	// Source is the provider name (for quick filtering without inspecting Wire).
	Source string
	// EventTypes is the set of subscribed event types (empty = all).
	EventTypes []string
	// SecretEnv is the env var name for the provider secret.
	SecretEnv string
	// Config is source-specific JSON config.
	Config json.RawMessage
	// Transform is the optional sync transform (not serialised to wire).
	TransformFn Transform
	// CodeOrigin is the source file:line where the binding was declared.
	CodeOrigin string
	// Kind distinguishes event from schedule bindings.
	Kind BindingKind
}

Binding is a typed trigger binding — either an event trigger or a schedule trigger. Created via Event() or Schedule() factory functions. Carries both the wire-serialisable payload and the non-serialisable Transform.

func Event

func Event(opts EventOpts) Binding

Event creates an event trigger binding from the given options.

func Schedule

func Schedule(opts ScheduleOpts) Binding

Schedule creates a schedule (cron) trigger binding from the given options. The expression and timezone are always merged into Config so the control plane sees them regardless of whether custom Config was provided.

type BindingKind

type BindingKind int

BindingKind enumerates the types of trigger bindings.

const (
	// EventBinding represents a webhook event trigger.
	EventBinding BindingKind = iota
	// ScheduleBinding represents a cron schedule trigger.
	ScheduleBinding
)

type Context

type Context struct {
	// AgentField trigger row ID; stable, equals the public URL slug.
	TriggerID string
	// Provider source ("stripe", "github", "slack", "cron", "generic_hmac", "generic_bearer").
	Source string
	// Provider's event type (or "" for cron tick).
	EventType string
	// AgentField inbound_event ID (replay key).
	EventID string
	// Provider's idempotency key (e.g. evt_xxx).
	IdempotencyKey string
	// When the control plane received the inbound event.
	ReceivedAt time.Time
	// Trigger event VC ID, if DID enabled.
	VCID string
}

Context is the webhook-trigger metadata exposed to reasoners at runtime.

Retrieve it inside a handler with FromContext(ctx). It is nil when the reasoner was invoked directly (app.Call, Execute with a flat input) rather than dispatched by an inbound event, so a nil check distinguishes the two:

if tc := triggers.FromContext(ctx); tc != nil {
    // dispatched via a trigger
}

VCID may be empty until the DID/VC chain wiring lands (tracked separately under SDK Feature Parity).

func FromContext

func FromContext(ctx context.Context) *Context

FromContext returns the *Context carried by ctx, or nil when the reasoner was invoked directly rather than dispatched by an inbound trigger.

Usage in a reasoner handler:

func handlePayment(ctx context.Context, in map[string]any) (any, error) {
    if tc := triggers.FromContext(ctx); tc != nil {
        // dispatched via a trigger — tc.Source, tc.EventID, etc.
    }
    return nil, nil
}

func SimulatedContextFrom

func SimulatedContextFrom(ctx context.Context) *Context

SimulatedContextFrom returns the *Context attached by SimulateEvent or SimulateSchedule, or nil when ctx carries none.

This is an alias for FromContext: the helpers attach the context through the same mechanism the live dispatch path uses, so a handler reading FromContext(ctx) in production sees the simulated context unchanged under test. Prefer FromContext in handler code; this name is kept for symmetry with the Simulate* helpers.

func Unwrap

func Unwrap(body map[string]any) (map[string]any, *Context)

Unwrap detects and unwraps a dispatcher trigger envelope.

For a trigger dispatch it returns the inner event payload and a populated *Context. For a direct call (not an envelope) it returns the body unchanged and a nil *Context, so callers can treat both uniformly.

type EventOpts

type EventOpts struct {
	// Registered Source name (e.g. "stripe", "github", "slack",
	// "generic_hmac", "generic_bearer").
	Source string
	// Event types the reasoner cares about. Empty means "all".
	// Supports prefix-match: "pull_request" matches "pull_request.opened".
	Types []string
	// Name of the env var on the control plane that holds the provider's
	// webhook secret. Required for Sources whose secret_required is true.
	SecretEnv string
	// Source-specific JSON config (timestamp tolerance, custom header names, etc).
	Config json.RawMessage
	// Optional sync transform to convert raw provider event to reasoner input.
	// Runs before the handler on trigger dispatches, skipped on direct calls.
	// See Transform.
	Transform Transform
}

EventOpts configures an event trigger binding.

type HandlerFunc

type HandlerFunc func(ctx context.Context, input map[string]any) (any, error)

HandlerFunc mirrors the Go SDK's reasoner handler signature. Declared here rather than imported from the agent package so the triggers package stays dependency-free (and importable from agent without a cycle).

type ScheduleOpts

type ScheduleOpts struct {
	// Cron is the 5-field cron expression (minute hour dom month dow).
	Cron string
	// IANA timezone name. Defaults to "UTC".
	Timezone string
	// Optional source-specific config, merged into the binding config. Must
	// marshal to a JSON object; malformed or non-object config is ignored.
	// The "expression" and "timezone" keys are controlled by the Cron and
	// Timezone fields: a custom "expression" is always overridden by Cron,
	// and a custom "timezone" is kept only when Timezone is empty.
	Config json.RawMessage
}

ScheduleOpts configures a cron schedule trigger binding.

type SimulateEventOpts

type SimulateEventOpts struct {
	// Source is the provider name ("stripe", "github", ...). Required.
	Source string
	// Body is the inbound event payload, typically from LoadFixture.
	Body map[string]any
	// EventType is the provider's event type. Defaults to "".
	EventType string
	// Bindings are the reasoner's declared bindings. When supplied, the
	// matching binding's Transform runs before the handler, exactly as the
	// live dispatch path does.
	Bindings []Binding
	// The remaining fields override the auto-generated values.
	TriggerID      string
	EventID        string
	IdempotencyKey string
	ReceivedAt     time.Time
	VCID           string
	// Ctx is the parent context. Defaults to context.Background().
	Ctx context.Context
}

SimulateEventOpts configures a simulated event dispatch.

Only Source is required; every identifier defaults to a fresh random value so repeated simulations are independently dedup-safe.

type SimulateScheduleOpts

type SimulateScheduleOpts struct {
	// Cron is the expression recorded on the synthetic body for test
	// introspection. It does NOT schedule anything — this is a one-shot call.
	Cron string
	// Bindings are the reasoner's declared bindings.
	Bindings []Binding
	// ReceivedAt overrides the auto-generated timestamp.
	ReceivedAt time.Time
	// Ctx is the parent context. Defaults to context.Background().
	Ctx context.Context
}

SimulateScheduleOpts configures a simulated cron dispatch.

type Transform

type Transform func(rawEvent map[string]any) any

Transform is an optional sync function to convert a raw provider event into the reasoner's input. Must be synchronous.

When a binding declaring a Transform matches the dispatched event, the SDK runs Transform(rawEvent) and the handler's input is the return value rather than the raw event. A Transform that panics degrades to pass-through: the handler receives the raw event instead of failing the dispatch.

Transforms are only applied to trigger dispatches, never to direct calls.

Jump to

Keyboard shortcuts

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