bindings

package
v0.1.5 Latest Latest
Warning

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

Go to latest
Published: Apr 16, 2026 License: MIT Imports: 16 Imported by: 0

Documentation

Overview

Package bindings assembles host capabilities into a script.Env for any script.Runtime implementation (jsrt, luart, etc.).

Purpose

bindings does two things: (1) expose Go-side interfaces as script-callable globals/tables; (2) provide common presets to reduce boilerplate. Business policy (who may call what, quotas, auth) belongs to the caller: pass pre-trimmed dependencies or tighten capabilities via Options. VM-agnostic: bindings never parses syntax; Lua/JS are handled by script sub-packages.

Dependency constraint

bindings depends only on workflow and llm — never on graph. Type aliases in the graph package (graph.Board = workflow.Board, etc.) allow graph/node/scriptnode to pass *graph.Board to bindings without conversion.

Layering model

  1. core: BindingFunc, BuildEnv — language-agnostic assembly primitives.
  2. atomic bridges: one file per host capability, named New<Domain>Bridge; the injected global is typically the lowercase domain name (board, fs, …).
  3. expr subsystem: compiled-program LRU cache (see expr.go), transparent to scripts.
  4. presets: common combinations as convenience functions; presets express "default assembly" and do not replace caller-level policy.
  5. LLM bridge (bridge_llm.go): calls llm.RunRound / llm.StreamRound and returns structured results to scripts; does NOT write to the board (scripts control data flow explicitly). Supports blocking llm.run() and iterator-based llm.stream() modes.

Directory layout

doc.go            package-level design notes (this file)
core.go           BindingFunc, BuildEnv
bridge_board.go   workflow board variables
bridge_stream.go  streaming events (backed by workflow.StreamCallback)
bridge_expr.go    expr-lang expressions (eval)
bridge_shell.go   sandboxed subprocesses (allowlist via ShellOption)
bridge_fs.go      workspace files
bridge_runtime.go sub-script execScript (inherits parent bindings)
run.go            run metadata (run_id, task_id)
bridge_llm.go     NewLLMBridge → global "llm" (run / stream); delegates to llm.RunRound / llm.StreamRound
tools.go          tool.Registry (deny-by-default, explicit allowlist or AllowAll)
expr.go           LRU cache and evalExpr (unexported)
presets.go        AgentStepBindings and other combinations
*_test.go         table-driven / jsrt integration tests

Global naming convention

Script global names match the name returned by BindingFunc: board, stream, expr, shell, fs, runtime (injected by scriptnode), run, tools, llm. Methods exposed by each bridge use lowercase_underscore style, consistent with existing script conventions.

Integration with Graph / workflow

  • Graph ScriptNode: composes board+stream+expr+runtime in ExecuteBoard, then appends shell/fs per node type (see graph/node/scriptnode).
  • Workflow Agent: uses presets or manual composition; add NewLLMBridge when LLM access is needed.

Checklist for adding a new bridge

  1. Are closure-captured dependencies thread-safe and context-cancellable?
  2. Are defaults least-privilege (e.g. tools deny-by-default, shell recommends allowlist)?
  3. Are return values stable on the script side (map field names, multi-return mapping in luart/jsrt)?
  4. Should it be included in a preset? Document which execution paths it is compatible with.

Testing conventions

Integration tests use jsrt to execute small script snippets that verify bindings; pure Go logic (e.g. LRU) is covered by *_test.go unit tests.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildEnv

func BuildEnv(ctx context.Context, config map[string]any, fns ...BindingFunc) *script.Env

BuildEnv creates a script.Env from binding funcs evaluated against ctx.

func RuntimeBinding

func RuntimeBinding(ctx context.Context, rt script.Runtime, parentBindings map[string]any) map[string]any

RuntimeBinding returns the host object for global "runtime" (e.g. execScript). Parent bindings are inherited by sub-scripts.

Types

type AgentStepOptions

type AgentStepOptions struct {
	Board *workflow.Board
	// TaskID / RunID mirror workflow.Request fields; RunID overrides board when non-empty.
	TaskID string
	RunID  string

	ToolRegistry *tool.Registry
	// AllowedTools is passed to WithAllowedToolNames when non-empty (ignored if ToolRegistry is nil).
	AllowedTools []string
}

AgentStepOptions selects common bindings for one workflow agent step (Lua/JS), without pulling in LLM streaming (add NewStreamBridge at the call site if needed).

type BindingFunc

type BindingFunc func(ctx context.Context) (name string, value any)

BindingFunc creates a named binding for script execution. The returned name becomes the global variable name in the script scope, and the value is typically a map[string]any of callable Go functions.

func AgentStepBindings

func AgentStepBindings(o AgentStepOptions) []BindingFunc

AgentStepBindings returns a typical binding set: board, run, expr, optional tools. Caller still supplies config + script.Runtime-specific globals (signal, etc.).

func NewBoardBridge

func NewBoardBridge(board *workflow.Board) BindingFunc

NewBoardBridge exposes workflow board variables as global "board".

func NewExprBridge

func NewExprBridge() BindingFunc

NewExprBridge exposes expr-lang as global "expr" (eval).

func NewFSBridge

func NewFSBridge(ws workspace.Workspace) BindingFunc

NewFSBridge exposes workspace file ops as global "fs".

func NewLLMBridge

func NewLLMBridge(opts LLMBridgeOptions) BindingFunc

NewLLMBridge exposes LLM calls to scripts as global "llm":

llm.run()                  — blocking, returns full result
llm.run({ temperature: 0.2 }) — with config overrides
llm.stream()               — returns iterator { next, token, finish }

Neither mode writes to the board; the script controls what to do with results.

func NewRunBridge

func NewRunBridge(opts RunBridgeOptions) BindingFunc

NewRunBridge exposes read-only run metadata to scripts as global "run":

  • get_run_id() string
  • get_task_id() string

func NewShellBridge

func NewShellBridge(runner workspace.CommandRunner, opts ...ShellOption) BindingFunc

NewShellBridge exposes shell execution as global "shell".

func NewStreamBridge

func NewStreamBridge(stream workflow.StreamCallback, nodeID string) BindingFunc

NewStreamBridge exposes streaming as global "stream" (emit).

func NewToolBridge

func NewToolBridge(reg *tool.Registry, opts ...ToolBridgeOption) BindingFunc

NewToolBridge exposes tool execution to scripts as global "tools":

  • call(name, argumentsJSON) -> { content, is_error, tool_call_id }
  • list() -> []string (names the script is allowed to call)

Security: by default no tool is callable until WithAllowedToolNames or WithToolAllowAll is set.

type LLMBridgeOptions

type LLMBridgeOptions struct {
	Stream  workflow.StreamCallback
	EventID string

	Resolver llm.LLMResolver
	Registry *tool.Registry

	// BaseConfig is merged with overrides passed from the script.
	BaseConfig llm.RoundConfig

	// ReadMessages returns the messages to send to the LLM.
	// The caller controls where messages come from (board, parameters, etc.).
	// When nil, an empty slice is used.
	ReadMessages func(ctx context.Context) []model.Message
}

LLMBridgeOptions configures NewLLMBridge.

type RunBridgeOptions

type RunBridgeOptions struct {
	Board *workflow.Board
	// TaskID is optional (e.g. workflow.Request.TaskID).
	TaskID string
	// RunID, if non-empty, is returned by get_run_id instead of reading the board.
	RunID string
}

RunBridgeOptions configures NewRunBridge (workflow / agent metadata on the board).

type ShellOption

type ShellOption func(*shellConfig)

ShellOption configures a shell bridge.

func WithAllowedCommands

func WithAllowedCommands(cmds ...string) ShellOption

WithAllowedCommands restricts the shell bridge to only execute the specified commands. When set, any command not in the list is rejected.

type ToolBridgeOption

type ToolBridgeOption func(*toolBridgeConfig)

ToolBridgeOption configures NewToolBridge.

func WithAllowedToolNames

func WithAllowedToolNames(names ...string) ToolBridgeOption

WithAllowedToolNames restricts script-visible tools; names must match registry entries.

func WithToolAllowAll

func WithToolAllowAll() ToolBridgeOption

WithToolAllowAll allows calling any tool registered in the registry. Use only when scripts are fully trusted.

Jump to

Keyboard shortcuts

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