Service configuration

Akka SDK reference configuration

Akka SDK Services are configured through configuration files in the HOCON format.

Below shows the complete default configuration for Akka Services.

For configuration of AI model providers, please refer to AI model provider configuration.

# This is the reference config file that contains the default settings.
# Make your edits/overrides in your application.conf.

akka.javasdk {
  dev-mode {

    # the port it will use when running locally
    http-port = 9000

    # defaults to empty, but maven will set akka.javasdk.dev-mode.project-artifact-id to ${project.artifactId}
    # this is only filled in dev-mode, in prod the name will be the one chosen when the service is created
    # users can override this in their application.conf
    service-name = ""
    service-name =${?akka.javasdk.dev-mode.project-artifact-id}


    eventing {
      # Valid options are: "none", "/dev/null", "logging", "google-pubsub", "kafka",  "google-pubsub-emulator" and "eventhubs"
      support = "none"

      # The configuration for kafka brokers
      kafka {
        # One or more bootstrap servers, comma separated.
        bootstrap-servers = "localhost:9092"

        # Supported are
        # NONE (for easy local/dev mode with no auth at all)
        # PLAIN (for easy local/dev mode - plaintext, for non dev-mode TLS)
        # SCRAM-SHA-256 and SCRAM-SHA-512 (TLS)
        auth-mechanism = "NONE"
        auth-username = ""
        auth-password = ""
        broker-ca-pem-file = ""
      }
    }

    object-storage {
      # Named bucket configurations for dev mode. When this list is empty (the default), any bucket
      # name is accepted and objects are stored under a shared local filesystem directory.
      # When one or more buckets are configured here, only those named buckets are accessible
      # (same strict-matching behaviour as production).
      #
      # Each entry requires a "name" and a "provider". Supported providers:
      #   filesystem  - local directory (always available, no credentials needed)
      #   s3          - Amazon S3 or compatible (e.g. MinIO); requires bucket, region and credentials
      #   gcs         - Google Cloud Storage; requires bucket and credentials
      #
      # filesystem example:
      #   { name = "my-images", provider = "filesystem" }
      #   { name = "my-images", provider = "filesystem", directory = "/tmp/my-images" }
      #
      # s3 example (static credentials, suitable for MinIO or a real S3 bucket with API keys):
      #   { name = "my-data", provider = "s3", bucket = "real-bucket", region = "us-east-1"
      #     credentials { type = "static", access-key-id = "AKID", secret-access-key = "secret" } }
      #
      # To use an S3-compatible service (e.g. MinIO), set "endpoint-url" to its address. Without
      # "endpoint-url" the endpoint comes from the region, which addresses Amazon S3.
      #
      # "access-style" is how the bucket is addressed at the endpoint:
      #   path        - as a path at the endpoint
      #   virtual     - as a subdomain of the endpoint, substituted for a {bucket} placeholder
      #                 in "endpoint-url" when it has one
      # It defaults to "path" when "endpoint-url" is set, and an explicit value overrides that
      # default. Subdomain addressing needs wildcard DNS, so an S3-compatible service usually
      # requires path access style.
      #
      # s3 example against a local MinIO server:
      #   { name = "my-data", provider = "s3", bucket = "real-bucket", region = "us-east-1"
      #     endpoint-url = "http://localhost:9000"
      #     credentials { type = "static", access-key-id = "AKID", secret-access-key = "secret" } }
      #
      # gcs example (service-account key file):
      #   { name = "my-docs", provider = "gcs", bucket = "real-bucket"
      #     credentials { type = "service-account-key", path = "/secrets/sa-key.json" } }
      buckets = []
    }

    acl {
      # Whether ACL checking is enabled
      enabled = true
    }

    persistence {
      # Whether persistence is enabled
      enabled = false
    }

    backoffice {
      # The refresh token. Will attempt to read it by running the Akka CLI command if not set
      refresh-token = ""
      refresh-token = ${?AKKA_REFRESH_TOKEN}

      # The api server. If not set, will detect it by running the Akka CLI, or default to api.kalix.io:443
      api-server = ""
      api-server = ${?AKKA_API_SERVER}

      # The context to use when running Akka CLI commands. Uses the default context if not set.
      cli-context = ""

      # The path of the Akka CLI. If not set, will default to looking for akka.exe on Windows and akka on other OS's on
      # the systems configured PATH.
      cli-path = ""

      # Whether backoffice services are enabled. This is true by default so that all a user needs to do is
      # configure the backoffice services to enable it. This flag then serves as a convenient means to disable
      # backoffice support when backoffice services are configured.
      enabled = true
      enabled = ${?AKKA_BACKOFFICE_SERVICES_ENABLED}

      # Timeout for making requests on the API server
      request-timeout = 10s

      services {
        # Specify services that should delegate to the cloud
        # "some-service-name" {
        #    # Optional, if set will override the service name to use in the cloud
        #    # service-name = "my-service"
        #
        #    # The project to use. May be a project id, or friendly name.
        #    project = "my-project"
        #
        #    # The organization. Only needed if referring to a project by friendly name, but multiple projects
        #    # from different organizations that the user is a member of have the same friendly name. May be the
        #    # organization id or friendly name
        #    # organization = "my-organization"
        #
        #    # The region. Optional, only needed for multi-region projects if a region other than the primary region
        #    # should be used.
        #    # region = "my-region"
        # }
      }
    }
  }

  testkit {
    # The port used by the testkit when running integration tests, for HTTP and gRPC alike. It is
    # used exactly as configured, and startup fails right away if it is already in use.
    #
    # Set it to 0, or use TestKit.Settings.withEphemeralPort(), to have the operating system
    # assign a free port instead. Read the assigned port with TestKit.getPort(): a config entry
    # that interpolates ${akka.javasdk.testkit.http-port} resolves to 0, because that is resolved
    # when the config is loaded, before a port is assigned.
    http-port = 19390
  }

  agent {
    # The default model provider that is used if an Agent doesn't specify a specific model.
    # References a config section for the model provider, such as anthropic or openai.
    model-provider = ""

    # Configuration for the session history (memory) between an Agent and the LLM model
    memory {
      # By default, the session history is turned on for all agents. It can be turned off with this setting.
      enabled = true

      # The maximum size of the memory window for the session history.
      # This is calculated as the sum of all messages content length in bytes.
      # Once the limit is reached, older messages will be automatically removed in a FIFO approach.
      # The default value is 510 KiB and this is actually the maximum value allowed. This is due to the fact that these
      # messages might be routed around the Akka cluster and as such some resource contraints apply.
      limited-window.max-size = 510 KiB
    }

    # Additional HTTP headers to include in each request to the model API.
    # Format: list of "name:value" strings, e.g. ["Authorization:Bearer token", "X-Custom-Header:value"]
    # This global setting is inherited by each provider config and can be overridden per provider.
    # Can also be set via environment variables, using a special naming where each entry is specified with a list index:
    # ADDITIONAL_MODEL_REQUEST_HEADERS_0="Authorization:Bearer token ..."
    # ADDITIONAL_MODEL_REQUEST_HEADERS_1="X-Custom-Header:value"
    additional-model-request-headers = []
    additional-model-request-headers = ${?ADDITIONAL_MODEL_REQUEST_HEADERS[]}

    # Send the agent id, flow id and interaction id as HTTP headers with each request to the model API.
    # When tracing is on, also send the W3C trace context.
    # A gateway or proxy in front of the model API can use them to attribute the request.
    # The runtime does not send them for Local AI and custom providers, and does not send the
    # trace context to Bedrock.
    # The other provider sections inherit this value and can override it.
    identity-headers = on

    # Inside a single request/response cycle, an LLM can successively request the agent to call functions tools.
    # After analysing the result of a tool call, the LLM might decide to request another call to gather more context.
    # This setting limits how many such steps may occur between a user request and the final Ai response.
    # Once this limit is reached, the process will stop even if the LLM has not yet produced its final response.
    max-tool-call-steps = 100

    # Guardrails are enabled by this configuration. Each guardrail is a named config section and it must have
    # the following mandatory properties:
    # - class: implementation class of the guardrail. It must implement one of
    #          akka.javasdk.agent.ToolCallGuardrail, akka.javasdk.agent.ModelCallGuardrail,
    #          akka.javasdk.agent.AgentResponseGuardrail, or the deprecated
    #          akka.javasdk.agent.TextGuardrail. The class must be public and have a public constructor,
    #          optionally with a akka.javasdk.agent.GuardrailContext parameter, which includes the config
    #          section for the specific guardrail
    # - category: the type of validation, such as JAILBREAK, PROMPT_INJECTION, PII, TOXIC, HALLUCINATED, NSFW, FORMAT
    # - report-only: if it didn't pass the evaluation criteria, the execution can either be aborted
    #                or continue anyway. In both cases, the result is tracked in logs, metrics and traces
    #
    # The guardrail type sets where the runtime evaluates it:
    # - ToolCallGuardrail: before each function tool call and each MCP tool call
    # - ModelCallGuardrail: before each model call
    # - AgentResponseGuardrail: once, on the final agent reply
    #
    # Optional properties:
    # - tools: tool-name filter for a ToolCallGuardrail; empty or absent means all tools on the agent.
    #          For an MCP tool, use the name on the MCP server. The filter matches by name only.
    # - control-id: the id of the control that the guardrail implements
    #
    # Deprecated TextGuardrail only:
    # - use-for: mandatory. One or more of model-request, model-response, mcp-tool-request,
    #            mcp-tool-response, or "*" for all four. The other guardrail types must not define use-for.
    #            All use-for values are deprecated.
    #
    # Additionally, to enable the guardrail specify one or both lists of:
    # - agents: enabled for agents with these component ids
    # - agent-roles: enabled for agents with these roles
    #
    # If both agents and agent-roles are defined it's enough that one of them matches to enable the guardrail for
    # an agent.
    #
    # If agents contain "*" the guardrail is enabled for all agents.
    # If agent-roles contain "*" the guardrail is enabled for all agents that has a role, but not for agents without
    # a role.
    #
    # An agent implementation can have additional configuration properties.
    guardrails {

      # Built-in jailbreak guardrail, evaluated before each model call.
      "default model-call jailbreak" {
        class = "akka.javasdk.agent.ModelCallSimilarityGuard"
        # not enabled until agents or agent-roles are defined
        agents = []
        agent-roles = []
        category = JAILBREAK
        report-only = false
        threshold = 0.75
        bad-examples-resource-dir = "guardrail/jailbreak"
      }

      # Deprecated: use "default model-call jailbreak" instead.
      "default jailbreak" {
        class = "akka.javasdk.agent.SimilarityGuard"
        # not enabled until agents or agent-roles are defined
        agents = []
        agent-roles = []
        category = JAILBREAK
        report-only = false
        use-for = ["model-request"]
        threshold = 0.75
        bad-examples-resource-dir = "guardrail/jailbreak"
      }

    }

    # Classifiers map an input to a Classification (a score and/or label, with optional
    # confidence and metadata). Unlike guardrails, a classifier has no boundary binding and is
    # never dispatched by the runtime -- it is looked up by name from an injected
    # ClassifierClient and invoked inline wherever a guardrail, an evaluator, or application code
    # needs it.
    #
    # A classifier implementation can have additional configuration properties.
    classifiers {

    }

    evaluators {
      toxicity-evaluator {
        model-provider = ${akka.javasdk.agent.model-provider}
      }

      summarization-evaluator {
        model-provider = ${akka.javasdk.agent.model-provider}
      }

      hallucination-evaluator {
        model-provider = ${akka.javasdk.agent.model-provider}
      }

    }

    # Settings for autonomous agents
    autonomous {
      # Default maximum iterations per task before the agent fails it.
      # Can be overridden per task group via TaskAcceptance.maxIterationsPerTask().
      max-iterations-per-task = 10

      delegation {
        # Default maximum number of worker agents that can execute delegated subtasks concurrently.
        # Can be overridden per delegation via Delegation.maxParallelWorkers().
        max-parallel-workers = 3
      }
    }

    # All agent interactions with the model, including tool calls, are stored in an interaction log.
    # The purpose is for visibility in the console, troubleshooting, and auditing.
    # This has a performance overhead, but compared to the LLM response times it is typically
    # neglectible. It can be disabled with this configuration. It will always be enabled in local
    # dev mode since it's useful insights in the local console.
    interaction-log {
      enabled = true
    }
  }

  evaluation {
    # Bindings for evaluator components (classes extending akka.javasdk.evaluation.Evaluator).
    #
    # Each entry is keyed by the evaluator's component id and declares which agents it evaluates.
    # The agents are keyed by agent component id. Each agent binding must set `trigger`, what
    # triggers an evaluation, currently only "interaction" (an interaction of the agent).
    # Under `agent-roles` a binding is keyed by agent role instead, and binds every agent with that role.
    # "*" there binds every agent that has a role. The most specific binding decides for an agent: its
    # entry under `agents`, then the entry for its role, then "*".
    # Bindings can be added or overridden per deployment via application.conf.
    #
    # Both an evaluator and an individual binding may also set `enabled` (defaults to true); set it to
    # false, for example in a deployment override, to disable the whole evaluator or a single binding.
    # An evaluator, not a binding, may also set `control-id`, the id of the control that it implements.
    #
    # A binding, not an evaluator, may also set `sampling-ratio` and `trigger-on-failure`. Their
    # defaults are under `defaults.agent`.
    #
    # An evaluator implementation can have additional configuration properties, on the evaluator and
    # in a binding. It reads them through `EvaluationContext.config()`, which returns the binding that
    # the runtime used for the agent with the evaluator entry as fallback. The keys `enabled`,
    # `trigger`, `sampling-ratio`, `trigger-on-failure`, `control-id`, `agents` and `agent-roles` are
    # reserved for the SDK, on the evaluator and in a binding.
    #
    # Example:
    #   evaluators {
    #     conversation-quality {
    #       threshold = 0.7
    #       agents {
    #         support-agent { trigger = interaction }
    #         billing-agent { trigger = interaction, enabled = false }
    #       }
    #       agent-roles {
    #         customer-facing { trigger = interaction, threshold = 0.9 }
    #       }
    #     }
    #   }
    evaluators {}

    # Defaults merged (as a config fallback) into each evaluator and binding under `evaluators`. A binding
    # under `agent-roles` takes the `agent` defaults.
    # Change a default here to affect all of them; set the same key on an individual entry to override
    # just that one. Only the keys listed here, and `trigger` under `agent`, are allowed. A configuration
    # property of an evaluator implementation has no default.
    defaults {
      evaluator {
        enabled = true
      }
      agent {
        enabled = true
        # The probability, from 0.0 to 1.0, that the evaluator evaluates an interaction of the agent.
        sampling-ratio = 1.0
        # Whether the evaluator also evaluates the failed interactions of the agent.
        trigger-on-failure = false
      }
    }
  }

  entity {
    # When an EventSourcedEntity, KeyValueEntity or Workflow is deleted the existence of the entity is completely cleaned up after
    # this duration. The events and snapshots will be deleted later to give downstream consumers time to process all
    # prior events, including the final deleted event.
    cleanup-deleted-after = 7 days
  }

  delete-entity.cleanup-interval = 1 hour

  event-sourced-entity {
    # It is strongly recommended to not disable snapshotting unless it is known that
    # event sourced entities will never have more than 100 events (in which case
    # the default will anyway not trigger any snapshots)
    snapshot-every = 100
  }

  eventing {
    google-pubsub {
      # Possible values:
      #  * automatic - runtime creates topic and subscription if they do not exist
      #  * automatic-subscription - runtime creates subscription if it do not exist, topic must be manually created
      #  * manual - both topic and subscription must be manually created
      mode = "automatic-subscription"
    }

    # All eventing of the service will start from this timestamp and ignore older events. Setting this to a value
    # leads to the timestamp being persisted for all consumers and views in the service, the only way to start consumers
    # and views after having set this, is to reset to empty, and use new view and consumer ids.
    # This is a migration feature and should not generally be used without a very good understanding of the
    # consequences - using it incorrectly can lead to data loss in views and consumers.
    # Accepted format is an ISO-8601 instant, for example "2026-02-17T16:50:00Z"
    # Note: this also applies to dev mode.
    start-from-timestamp = ""
  }

  library {
    # Components defined in library jars on the classpath that the service loads as if they were defined
    # in the service itself. List the fully qualified class names under the component type they implement,
    # for example: http-endpoint = ["com.example.library.OrderEndpoint"]
    components {
      event-sourced-entity = []
      key-value-entity = []
      workflow = []
      view = []
      consumer = []
      timed-action = []
      agent = []
      autonomous-agent = []
      http-endpoint = []
      grpc-endpoint = []
      mcp-endpoint = []
      evaluator = []
      durable-evaluator = []
    }
    # On startup, the service logs the components in library component descriptors that are not listed
    # in components. It logs a warning when no components are listed, and info when some are listed.
    # It also logs a warning for a service setup class in a library component descriptor, which it ignores.
    # Set to false to log these at debug level, for a service that uses a library only for its other classes.
    log-unlisted-components = true
  }

  discovery {
    # By default all environment variables of the process are passed along to the runtime, they are used only for
    # substitution in the descriptor options such as topic names. To selectively pick only a few variables,
    # this setting needs to be set to false and `pass-along-env-allow` should be configured with
    # a list of variables we want to pass along.
    pass-along-env-all = true

    # By default all environment variables of the process are passed along to the runtime, they are used only for
    # substitution in the descriptor options such as topic names. This setting can
    # limit which variables are passed configuring this as a list of allowed names:
    # pass-along-env-allow = ["ENV_NAME1", "ENV_NAME2"]
    # This setting only take effect if pass-along-env-all is set to false, otherwise all env variables will be pass along.
    # To disable any environment variable pass along, this setting needs to be an empty list pass-along-env-allow = []
    # and pass-along-env-all = false
    pass-along-env-allow = []
  }

  grpc.client {
    # Specify entries for the full service DNS names to apply
    # customizations for interacting with external gRPC services.
    # The example block shows the customizations keys that are accepted:
    #
    # "com.example" {
    #   host = "192.168.1.7"
    #   port = 5000
    #   use-tls = false
    # }
  }

  # Sanitization masks found matching substrings, replacing each character of a match with a *.
  #
  # Each sanitizer is a named config section, and it must have exactly one of the following properties:
  # - pattern: a Java regular expression matching the text to mask
  # - predefined: a built-in group of patterns, one of CREDIT_CARD, IBAN, PHONE, EMAIL, IP_ADDRESS
  # - class: implementation class of the sanitizer. It must implement akka.javasdk.TextSanitizer to mask the
  #          text of agents, akka.javasdk.LogSanitizer to mask log messages, or both. The class must be public
  #          and have a public constructor, optionally with an akka.javasdk.SanitizerContext parameter, which
  #          includes the config section for the specific sanitizer. A LogSanitizer constructor takes nothing else
  #
  # Optional properties:
  # - apply-at: where to mask. Each value is one of:
  #             - model-call: every text that reaches the model in a model call of an agent
  #             - tool-result: what a tool returned, and the message of a tool failure
  #             - logs: log messages and the subject id of an unhandled exception
  #             - client: nothing on its own, for a sanitizer that application code only calls by name with
  #                       akka.javasdk.SanitizerClient. Every sanitizer can be called by name.
  #             - "*": the same as defining no apply-at. Points named beside it are added.
  # - agents: enabled for agents with these component ids
  # - agent-roles: enabled for agents with these roles
  # - enabled: set to false to drop the sanitizer, defaults to true
  # - control-id: the id of the control that the sanitizer implements
  #
  # A pattern or predefined sanitizer that defines no apply-at masks at every application point it can. A class
  # sanitizer masks where its interfaces allow: a TextSanitizer at model-call and tool-result, a LogSanitizer at
  # logs. A sanitizer that defines neither agents nor agent-roles masks for every agent.
  #
  # If agents contain "*" the sanitizer is enabled for all agents.
  # If agent-roles contain "*" the sanitizer is enabled for all agents that has a role, but not for agents
  # without a role.
  #
  # The logs and client application points cannot be combined with agents or agent-roles. A log message and
  # a call by name belong to no agent, so the runtime has no agent to match the scope against.
  #
  # A sanitizer that masks log messages is called for every log line of the service, while the log event is
  # written, and the thread that writes the event waits for it.
  #
  # A sanitizer implementation can have additional configuration properties.
  #
  # By default, no sanitization is applied.
  sanitization {
    sanitizers {

      # Example (case insensitive warm colors, masked everywhere)
      # "warm-colors" = { pattern = "(?i)(red|orange|yellow)" }

    }
  }

  telemetry {
    tracing {
      collector-endpoint = ""
      collector-endpoint = ${?COLLECTOR_ENDPOINT}
    }
  }
}