Dashboard › opencode › Distillation
ea6e7f18-91c0-41c8-9194-58cabb9a368c["lore_tm_v1_CGa8qTnX7XExfl_qvniEbymYA_XfWA2ScvpS3a4YdBg","lore_tm_v1_AdH1fAhMSzBkJZEhKz8QEi8Lo44uZHEx1bh8cKNFOdw","lore_tm_v1_i8QVB6YJKSWwqDQRollF-lkkvV3ipofvBxn4NOLO1Ss","lore_tm_v1_iJV56OoK-KBdaRD6uNYkEUj0FO1kQQ3C7MTd8kcK5So","lore_tm_v1_3Sc_Nn_dDvmnECd9CA1Nw4PYGA0TspDDaanwCSUBuZY","lore_tm_v1_N15GspeAniorJBLEV0FyWQsuns-UsqXWuaHB8ZWLMz4","lore_tm_v1_gw8ZKQPgy05f6s2RS39PPxpzrz7oQWZCeWjSVPhvSWU","lore_tm_v1_ysCItpllNxrKhzWKymSDsjq3H-4sDXeD4zCQeQxBwI0","lore_tm_v1_L_9j65df3gPa4isCtVxuYi-MhgAKap_3RXhIAR_g1iE","lore_tm_v1_a6fH28VWJzSTBoN3Y6DMa5RpZv0nbC_baLc6b1WBnHk"]
/home/byk/Code/opencode-lore/packages/core/src/fetch-interceptor.ts documents interceptor processing in this order: 1. match outgoing URLs against known LLM API paths; 2. rewrite to the gateway while preserving the path; 3. add X-Lore-Upstream-URL for the base and X-Lore-Upstream-Path for the original endpoint pathname; 4. inject dynamic X-Lore-* context headers from getHeaders(); 5. preserve all original headers, including auth and content type. Cleanup restores the original globalThis.fetch.const ORIGINAL_FETCH_KEY = Symbol.for("lore.fetchInterceptor.originalFetch"), storing the original fetch in a process-global symbol slot shared by every bundled or instantiated copy of @loreai/core.#1027. The shared slot makes it safe to inline core in the Bun gateway bundle configured by gateway script/bundle.ts.readOriginalFetchSlot() returns the shared fetch handle or null, while writeOriginalFetchSlot(fn) sets it and cleanup releases it by writing null.installFetchInterceptor(config) returns a no-op cleanup when readOriginalFetchSlot() !== null; otherwise it captures globalThis.fetch, writes that handle to the shared slot, and pre-parses config.gatewayBase into a URL once to avoid per-fetch URL construction.buildGatewayHeaders() so their header handling can never drift between them.buildGatewayHeaders(input, init, upstreamBase, upstreamPath, config) supports both fetch(url, { headers }) and fetch(new Request(url, { headers })), preserves existing headers, sets x-lore-upstream-url to the resolved upstream base, and sets x-lore-upstream-path only when the original pathname starts with /.x-lore-upstream-path enables verbatim passthrough for noncanonical provider paths such as GitHub Copilot’s /chat/completions from issue #1052, rather than forcing a synthesized /v1/... path.config.getHeaders() are added only when not already present, allowing per-request hooks to take precedence; failures are caught and logged as "fetch-interceptor: getHeaders() failed:".observeRequestHeaders(headers, config) is inert without config.onRequestHeaders; callback failures are caught and logged as "fetch-interceptor: onRequestHeaders() failed:".StartOptions.processBoundary?: boolean in /home/byk/Code/opencode-lore/packages/gateway/src/cli/start.ts is a CLI-owned process-boundary marker and is never set by in-process plugins.StartOptions.local?: boolean disables hosted mode even for lore start and corresponds to CLI flags --local / -l; StartOptions.bg?: boolean corresponds to --bg / --daemon and daemonizes by respawning detached, polling until healthy, printing the address, PID, and log path, then exiting 0.GatewayHandle contains config, port, owned, owner-only managementToken, shutdown(), and optional internal processShutdown; shutdown() is a no-op when owned is false.GatewayHealthIdentity contains pid; GatewayIdentityProbe is one of { kind: "authenticated"; identity }, { kind: "rejected" }, { kind: "unavailable" }, or { kind: "timeout" }; GatewayShutdownRequestResult is "accepted" | "unsupported" | "failed".opts.local === true always disables remote mode, mirroring hosted-mode disabling.0 always succeeds or throws a non-EADDRINUSE error; therefore the fallback throw new Error("Failed to bind to any port.") is unreachable./home/byk/Code/opencode-lore/packages/opencode/src/internal.ts rather than the plugin entry module: OpenCode’s legacy getServerPlugin/getLegacyPlugins loader treats every exported function as a plugin and invokes it. Exporting applyLoreProviderConfig from the entry module caused its undefined return value to enter the hooks array and crash first hook dispatch with undefined is not an object (evaluating 'A.event'); keeping helpers internal leaves the entry module exposing only the plugin function while allowing direct test imports.isLoopbackUrl(value) accepts localhost, localhost., ::1, and IPv4 strings matching /^127(?:\.\d{1,3}){3}$/, strips IPv6 brackets, lowercases the hostname, and returns false for malformed URLs.gatewayAccessHeadersForRemote(gatewayBase, env = process.env) injects { [GATEWAY_AUTH_HEADER]: LORE_GATEWAY_AUTH_TOKEN } only when the trailing-slash-normalized LORE_REMOTE_URL exactly matches the normalized gatewayBase and a token exists.shouldForwardUpstreamExtraHeader(name) prevents this hop from forwarding headers beginning with x-lore- and the credential headers x-api-key, x-goog-api-key, and authorization; provider and Lore credentials are instead applied by the gateway.probeLoopback(url, signal) uses node:http or node:https according to protocol, performs a GET, drains the response with response.resume(), and considers only HTTP status codes 200–299 successful.applyLoreProviderConfig(cfg, gatewayBase) returns immediately for an empty gateway base; otherwise it pins every object-valued cfg.provider[id] to ${gatewayBase}/v1 via provider.<id>.options.baseURL, deep-merging provider and option fields so custom headers, model overrides, and other user settings survive.OPENAI_BASE_URL could influence an Anthropic base URL with /v1 stripped, sending requests to http://host/messages; the gateway only routes /v1/messages, and the fetch interceptor skips 127.0.0.1 to prevent loops, so the request otherwise ends as a bare /messages 404.resolveSDK() always passes options.baseURL to the @ai-sdk factory, loadOptionalSetting() consults an environment variable only when the factory receives an undefined baseURL, and providers including Google, Mistral, Groq, Cohere, xAI, Perplexity, Together AI, Vercel, Alibaba, DeepInfra, Gateway, OpenRouter, and Cerebras have no base-URL environment variable.applyLoreProviderConfig() forces headerTimeout: false for provider IDs "openai" and "openai-codex" because Lore context preparation can exceed OpenCode Codex’s 10s header deadline; the gateway owns the foreground request deadline. If no OpenAI provider exists, it creates pinned.openai = { options: { baseURL: baseUrl, headerTimeout: false } }.probeGateway(baseURL, timeoutMs = 1500) checks ${baseURL}/health with an AbortController; loopback URLs use probeLoopback, non-loopback URLs use fetch(...).ok, all failures return false, and the timeout is always cleared.surfaceGatewayUnavailable(client, message) logs the failure and uses an OpenCode TUI toast because embedded mode silences logger stderr. The toast is TUI-safe because it goes through the OpenCode server and render loop rather than writing raw terminal bytes; it is fire-and-forget and swallows every failure so a missing/headless TUI or older server without /tui/show-toast cannot crash a degraded-but-running session./home/byk/Code/opencode-v2-pilot/packages/core/src/plugin/host.ts defines RpcEvent as an event whose type is rpc.${string}, with readonly location: Location.Ref and readonly record data; isRpcEvent() checks event.type.startsWith("rpc.").PluginHost.make(plugin, pluginID = "test") resolves services for app metadata, agents, AISDK, catalog, commands, bus, integration, KV, MCP, location, reference, RPC, skill, tools, VCS, web search, generation, permission, plugin hooks, sessions, persistent PTY, location-service mappings, and worktrees.locationInfo() returns Location.Info with the current directory, workspaceID, and project; locationRef(input) defaults a supplied location’s missing directory/workspace to the current location, and isCurrentLocation(ref) compares both directory and workspace ID.atWorktree(ref, run) rejects workspace-qualified references with Worktree.UnsupportedLocationError; it immediately runs against the current worktree when the reference is absent or current. For another worktree, it lazily imports ../plugin.js to avoid a construction cycle, gets Plugin.Service and Worktree.Service, awaits plugins.awaitActivation, runs against the target, and provides locations.get(ref).PluginHost.listAgents(ref) runs under locations.get(ref), returns both location metadata and agents.list(), and applies Effect.orDie.agent.get(input) queries a remote location through listAgents(ref) when needed, otherwise uses the current agents.get(input.agentID) response; it fails with Error("Agent not found: ...") when the requested agent is absent.