NewLocalRuntime creates a new LocalRuntime without the persistence wrapper. This is useful for testing or when persistence is handled externally.
(ctx context.Context, agents *team.Team, opts ...Opt)
| 565 | // NewLocalRuntime creates a new LocalRuntime without the persistence wrapper. |
| 566 | // This is useful for testing or when persistence is handled externally. |
| 567 | func NewLocalRuntime(ctx context.Context, agents *team.Team, opts ...Opt) (*LocalRuntime, error) { |
| 568 | defaultAgent, err := agents.DefaultAgent() |
| 569 | if err != nil { |
| 570 | return nil, err |
| 571 | } |
| 572 | |
| 573 | r := &LocalRuntime{ |
| 574 | ctx: func() context.Context { return context.WithoutCancel(ctx) }, |
| 575 | toolMap: make(map[string]ToolHandlerFunc), |
| 576 | team: agents, |
| 577 | agents: newAgentRouter(agents, defaultAgent.Name()), |
| 578 | resumeChan: make(chan ResumeRequest), |
| 579 | elicitationRequestCh: make(chan ElicitationResult), |
| 580 | steerQueue: NewInMemoryMessageQueue(defaultSteerQueueCapacity), |
| 581 | followUpQueue: NewInMemoryMessageQueue(defaultFollowUpQueueCapacity), |
| 582 | sessionCompaction: true, |
| 583 | managedOAuth: true, |
| 584 | sessionStore: session.NewInMemorySessionStore(), |
| 585 | fallback: newFallbackExecutor(), |
| 586 | now: time.Now, |
| 587 | telemetry: defaultTelemetry{}, |
| 588 | providerRegistry: provider.DefaultRegistry(), |
| 589 | maxOverflowCompactions: defaultMaxOverflowCompactions, |
| 590 | toolListTimeout: defaultToolListTimeout, |
| 591 | toolStartTimeout: defaultToolStartTimeout, |
| 592 | dmrModelLister: dmr.ListModels, |
| 593 | } |
| 594 | r.bgAgents = agenttool.NewHandler(r) |
| 595 | |
| 596 | // stripUnsupportedModalitiesTransform captures the runtime closure to |
| 597 | // resolve the agent from Input.AgentName, so it lives here rather |
| 598 | // than as a stateless builtin in pkg/hooks/builtins. It drops image |
| 599 | // content for text-only models on every model call. |
| 600 | // |
| 601 | // redact_secrets used to live here as a sibling [MessageTransform]; |
| 602 | // it now ships entirely as a [hooks.BuiltinFunc] in |
| 603 | // pkg/hooks/builtins/redact_secrets.go and is wired into all three |
| 604 | // of pre_tool_use, before_llm_call, and tool_response_transform via |
| 605 | // [builtins.ApplyAgentDefaults] (or a user's hooks YAML directly), |
| 606 | // so the rewrite path is the same for every leak vector and there |
| 607 | // is no flag-only code path to keep in sync. |
| 608 | r.transforms = append(r.transforms, |
| 609 | registeredTransform{ |
| 610 | name: BuiltinStripUnsupportedModalities, |
| 611 | fn: r.stripUnsupportedModalitiesTransform, |
| 612 | }, |
| 613 | ) |
| 614 | |
| 615 | for _, opt := range opts { |
| 616 | opt(r) |
| 617 | } |
| 618 | |
| 619 | // Set up the hooks registry. Use the embedder-supplied registry |
| 620 | // (via [WithHooksRegistry]) when present so any builtins the |
| 621 | // embedder pre-registered — typically the snapshot builtin from |
| 622 | // [builtins.RegisterSnapshot] — are visible to the runtime, then |
| 623 | // register the runtime-owned builtins on top. |
| 624 | if r.hooksRegistry == nil { |