Skip to Content
Next — You're reading the unreleased preview docs. APIs and pages may change before the next release.Switch to the current docs →
How-To GuidesScalaCalling Agents from External Applications (Scala)

Calling Agents from External Applications (Scala)

Generate a Scala Bridge SDK

Golem can generate typed Scala bridge SDKs for calling agents from external JVM applications. The bridge target language is independent of the agent’s source language: a Scala bridge can call agents written in Rust, TypeScript, Scala, or MoonBit.

Configure bridge generation in golem.yaml:

bridge: scala: external: agents: "*" outputDir: ./scala-bridge # Optional custom output directory

Then let golem build produce the bridge as part of the normal build:

golem build --yes

Without outputDir, the bridge is generated under golem-temp/bridge-sdk/scala/. Re-running golem build after agent changes keeps the generated client in sync automatically.

Avoid invoking golem generate-bridge manually — it exists as a low-level escape hatch, but the manifest-driven flow above is the supported way to keep bridges configured, reproducible, and up to date.

The generated output is a self-contained sbt project per agent type (e.g., counter-agent-client/). For an agent type named CounterAgent, the client package is golem.bridge.client.counter_agent and the generated client object is CounterAgentClient.

Setup

Use the generated sbt project as a dependency from your external Scala application, or add your application entry point inside the generated project while prototyping.

// build.sbt scalaVersion := "3.8.2" name := "external-client" lazy val bridge = RootProject(file("../scala-bridge/counter-agent-client")) lazy val root = (project in file(".")) .dependsOn(bridge)

Example

import golem.bridge.client.counter_agent.CounterAgentClient import golem.bridge.runtime.GolemServer import scala.concurrent.Await import scala.concurrent.duration._ @main def main(): Unit = CounterAgentClient.configure(GolemServer.Local, "my-app", "local") val timeout = 30.seconds val counter = Await.result(CounterAgentClient.get("my-counter"), timeout) val result = Await.result(counter.increment(), timeout) println(result)

Building and Running

sbt run

Authentication

  • Local server: Use GolemServer.Local.
  • Golem Cloud: Use GolemServer.Cloud(token) with your API token.
  • Custom deployment: Use GolemServer.Custom(url, token).

Agent Constructors and Methods

Generated Scala bridge clients follow the same conventions as agent-to-agent RPC:

  • Client.get(...) addresses a durable agent; ephemeral clients have only the phantom factories.
  • Durable bridges expose Client.getPhantom(...) to address a specific phantom UUID. Ephemeral CLI bridges (guest and JVM) do not expose it.
  • Client.newPhantom(...) returns a logical proxy; the first invocation creates the instance, not the factory call.
  • For durable targets, awaited methods return Future[T]; stream-free trigger and schedule methods return Future[Unit].
  • For ephemeral targets, awaited methods return Future[golem.bridge.runtime.InvocationResult[T]]; stream-free trigger and schedule methods return Future[golem.bridge.runtime.InvocationReceipt].
  • External JVM factories return futures (as in the example), unlike synchronous guest factories. External phantom UUIDs are java.util.UUID, as in guest code. External REST bridge types live under golem.bridge.runtime, not golem.runtime.rpc. CLI-generated internal guest clients use golem.runtime.rpc.InvocationResult, InvocationReceipt, CancelableAsyncInvocation, and CancelableInvocationReceipt for ephemeral operations.
  • Bridge clients omit trigger and schedule helpers for recursively stream-bearing methods; use awaited streaming calls.
  • A bare text schema, also a refined one with languages, a length or a regex, maps to golem.bridge.runtime.Text(text, language) in external bridges and to the SDK’s golem.schema.Text(text, language) in internal clients. The client does not check the restrictions; the server does.

Streaming Calls: Reconnect Window and Cancellation

A streaming call reconnects with a growing delay (50 ms up to 3 s) while the server accepts neither its start nor a resume; HTTP 429 and 5xx on the upgrade and retryable rejections are retried too. The reconnectWindow argument of configure bounds the time without progress (default Configuration.DefaultReconnectWindow, 5 minutes; Duration.Inf removes the limit). Past the window the call fails with golem.bridge.runtime.BridgeUnreachableException (a BridgeException with endpoint, reconnectWindow and lastCause).

CounterAgentClient.configure(GolemServer.Local, "my-app", "local", reconnectWindow = 30.seconds)

Every streaming method also has a cancelable form that returns the future and a golem.bridge.runtime.CancellationToken. Cancelling stops the reconnect attempts before the server accepted the call and cancels the invocation after it; the future fails with BridgeCancelledException.

val (result, cancellation) = agent.numbers.cancelable() cancellation.cancel()

Generate Scala Internal Clients for Component-to-Component Calls

When one Golem component needs to call another agent or tool from Scala code, generate an internal Scala client instead of an external REST bridge:

bridge: scala: internal: agents: - CounterAgent tools: - echo outputDir: ./bridge-sdk/scala/internal # Optional custom output directory

The internal mode generates client code that is linked into a Golem component. It does not generate a standalone JVM REST client, and it does not generate a component by itself.

Re-running golem build generates one Scala.js sbt project per selected internal dependency:

  • agent clients use <agent-name>-guest-client/, for example counter-agent-guest-client/;
  • tool clients use <tool-name>-tool-guest-client/, for example echo-tool-guest-client/.

With no custom outputDir, generated internal clients are written under golem-temp/bridge-sdk/scala/internal/. With outputDir, they are written directly under that directory.

Each generated internal client project is a Scala.js library. Its build.sbt enables ScalaJSPlugin, sets ModuleKind.ESModule, and depends on the Scala SDK artifacts:

libraryDependencies ++= Seq( "cloud.golem" %%% "golem-scala-core" % "<golem-scala-version>", "cloud.golem" %%% "golem-scala-model" % "<golem-scala-version>" )

Add the generated project as a dependency of the Scala component that performs the call, then import the generated client package from that component. Do not add agent_guest.wasm or extra linker settings to the generated internal client project; those belong to the consuming Scala component build/injection flow, while the client project itself is just a Scala.js library.

Internal clients use SDK-side types such as golem.schema.SchemaValue and golem.Datetime. Do not mix them with the external REST bridge runtime types under golem.bridge.runtime, which have a separate wire model.

Using a Generated TypeScript or Rust Bridge

You can also generate a TypeScript or Rust bridge SDK for agents written in Scala. The bridge target language is independent of the agent’s source language:

bridge: ts: external: agents: "*" rust: external: agents: "*"

Then use the generated TypeScript or Rust client from your external application. See the golem-call-from-external-ts or golem-call-from-external-rust skills (available in TypeScript and Rust project templates) for details.