Documentation
¶
Overview ¶
Package execshared holds behavior shared by the executor implementations (claudeexecutor, googleexecutor, openaiexecutor) so each backend applies identical semantics: prompt-suffix handling, resource-label defaults, the submit routing predicate, the bounded tool-call dispatch pool, and the submit-gate validation tail.
Index ¶
- func AppendUserPromptSuffix(prompt string, suffix *promptbuilder.Prompt) (string, error)
- func DefaultResourceLabels(labels map[string]string) map[string]string
- func DispatchToolCalls[Call any](calls []Call, concurrency int, isSubmit func(Call) bool, ...)
- func GateSubmission[Response any](ctx context.Context, outcome toolcall.SubmitOutcome[Response], ...) (map[string]any, bool, error)
- func SubmitPredicate[Meta any](tools map[string]Meta, submitToolName string, submitConfigured bool) func(name string) bool
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func AppendUserPromptSuffix ¶
func AppendUserPromptSuffix(prompt string, suffix *promptbuilder.Prompt) (string, error)
AppendUserPromptSuffix appends the built suffix to the prompt with a blank-line separator. A nil suffix returns the prompt unchanged. The suffix must be fully bound; a Build failure (for example an unbound placeholder) is returned wrapped.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/executor/internal/execshared"
"chainguard.dev/driftlessaf/agents/promptbuilder"
)
func main() {
suffix, err := promptbuilder.NewPrompt("Focus on error handling.")
if err != nil {
panic(err)
}
prompt, err := execshared.AppendUserPromptSuffix("changeset payload", suffix)
if err != nil {
panic(err)
}
fmt.Println(prompt)
}
Output: changeset payload Focus on error handling.
func DefaultResourceLabels ¶
DefaultResourceLabels returns the resource labels for billing and observability attribution, starting from defaults derived from environment variables:
- service_name: from K_SERVICE, falling back to CLOUD_RUN_JOB (defaults to "unknown")
- product: from CHAINGUARD_PRODUCT (defaults to "unknown")
- team: from CHAINGUARD_TEAM (defaults to "unknown")
Custom labels override defaults if they use the same keys.
Reading the environment here is deliberate: these labels attribute a deployment, so the defaults come from deployment-level env vars set by the service's infrastructure, mirroring how cloudrun resolves the workload identity. The labels parameter is the explicit configuration path for callers that need to override or extend them.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/executor/internal/execshared"
)
func main() {
// Custom labels override the environment-derived defaults on key match.
labels := execshared.DefaultResourceLabels(map[string]string{"team": "platform"})
fmt.Println(labels["team"])
}
Output: platform
func DispatchToolCalls ¶ added in v0.7.76
func DispatchToolCalls[Call any](calls []Call, concurrency int, isSubmit func(Call) bool, run func(i int, call Call))
DispatchToolCalls runs a single turn's tool calls under a bounded errgroup pool. The model may emit several independent tool calls in one turn (parallel tool use); a concurrency of 1 (or less) runs them strictly in order, higher values run them concurrently. run(i, call) must record its outcome in per-index slots so concurrent handlers never race on shared state, and must be safe for concurrent use when concurrency exceeds 1.
Calls matching isSubmit are held out of the pool and run sequentially only after every pooled handler has finished: a submission claims the turn's work is complete, and its result validators may read state the other handlers produce (worktrees, files), so they must observe the finished state rather than race the handlers still producing it. Slot order is preserved, so the callers' in-order result consumption is unaffected.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/executor/internal/execshared"
)
func main() {
// Submit calls are held out of the pool and run only after every other
// handler has finished; a concurrency of 1 runs the pooled calls
// strictly in order.
calls := []string{"submit_result", "read_file", "list_dir"}
var order []string
execshared.DispatchToolCalls(calls, 1,
func(call string) bool { return call == "submit_result" },
func(_ int, call string) { order = append(order, call) },
)
fmt.Println(order)
}
Output: [read_file list_dir submit_result]
func GateSubmission ¶ added in v0.7.76
func GateSubmission[Response any]( ctx context.Context, outcome toolcall.SubmitOutcome[Response], trace *agenttrace.Trace[Response], callID, toolName string, args map[string]any, validators []callbacks.ResultValidator[Response], rec *telemetry.Recorder, submitToolName string, resultPtr *Response, ) (map[string]any, bool, error)
GateSubmission gates a terminal submit tool call on the registered result validators — the provider-neutral tail of every executor's evaluateSubmission, applied after the backend's submit handler has parsed the call into outcome. callID, toolName, and args identify the call on the trace; submitToolName names the tool in the rejection payload. It returns the tool result to send back to the model and whether the response committed as the run's final result (written through resultPtr). A rejected submission returns the validators' findings so the model can address them and submit again; a validator error aborts the run.
Example ¶
package main
import (
"context"
"fmt"
"chainguard.dev/driftlessaf/agents/agenttrace"
"chainguard.dev/driftlessaf/agents/executor/internal/execshared"
"chainguard.dev/driftlessaf/agents/executor/internal/telemetry"
"chainguard.dev/driftlessaf/agents/metrics"
"chainguard.dev/driftlessaf/agents/toolcall"
)
func main() {
type reviewResult struct {
Verdict string `json:"verdict"`
}
ctx := context.Background()
trace, _ := agenttrace.StartTrace[reviewResult](ctx, "prompt")
rec := telemetry.NewRecorder(metrics.NewGenAI("example"), "model", "provider", nil, nil)
// The backend's submit handler parsed the model's call into an accepted
// outcome; the gate runs the validators and commits the response.
var result reviewResult
toolResult, committed, err := execshared.GateSubmission(ctx,
toolcall.SubmitOutcome[reviewResult]{
Accepted: true,
Response: reviewResult{Verdict: "pass"},
Reasoning: "all checks passed",
ToolResult: map[string]any{"success": true},
},
trace, "call-1", "submit_result", map[string]any{"verdict": "pass"},
nil, rec, "submit_result", &result)
if err != nil {
panic(err)
}
fmt.Println(committed, result.Verdict, toolResult["success"])
}
Output: true pass true
func SubmitPredicate ¶ added in v0.7.76
func SubmitPredicate[Meta any](tools map[string]Meta, submitToolName string, submitConfigured bool) func(name string) bool
SubmitPredicate returns the routing predicate for a run's terminal submit tool: a call routes to submit when its name is not registered as a regular tool, matches the submit tool's name, and a submit handler is configured (submitConfigured). Each executor builds one instance per Execute and uses it for both executeToolCall's dispatch switch and DispatchToolCalls' held-out-of-pool partition, so the two sites cannot drift.
Example ¶
package main
import (
"fmt"
"chainguard.dev/driftlessaf/agents/executor/internal/execshared"
)
func main() {
tools := map[string]struct{}{"read_file": {}}
isSubmit := execshared.SubmitPredicate(tools, "submit_result", true)
fmt.Println(isSubmit("submit_result"), isSubmit("read_file"), isSubmit("other"))
}
Output: true false false
Types ¶
This section is empty.