Pedal Assist Coding logo

Pedal Assist Coding

Archives
RSS Feed
CommonsWare
Log in
Subscribe
July 16, 2026

Thursdays with Koog: PromptExecutor vs. AIAgent

In Which the Author Dives Into the Layers Again

Knosh uses Koog to execute prompts. Koog has a PromptExecutor, which executes prompts. Hence, it would seem like Knosh would use PromptExecutor, right?

Nope.

PromptExecutor indeed executes prompts. It even does so in a one-shot fashion, the way Knosh operates. You hand PromptExecutor a prompt, it passes the prompt along to the LLM model via its provider, and PromptExecutor hands back the response. Easy, peasy.

However, that is pretty much all that PromptExecutor does. If you want anything else, you need to use something else.

For example, like any coding agent, Knosh has tools. If you have used Claude Code, Codex, OpenCode, or the like, you will be used to seeing mentions of the agent using tools like Read or Write or Bash. You might think that tools are a dedicated communications channel between the LLM and the agent, completely independent from your prompt and its response.

Alas, no.

The way tool calls work is:

  • You hand the agent a prompt
  • The agent augments that prompt with a bunch of additional stuff, including details of the available tools
  • The agents sends the augmented prompt to the LLM
  • The LLM, in its infinite artificial wisdom, determines that the right thing to do is invoke a tool
  • The LLM's response is not a true response to the prompt, but instead is a tool call: a JSON object that identifies the tool and the parameters to pass to that tool
  • The agent looks at the response, realizes that it is a tool call, and invokes the tool, capturing its result
  • The agent appends that result to the end of the earlier augmented prompt
  • The agent sends this updated augmented prompt to the LLM
  • The LLM, for the purposes of this example, sends back an ordinary response
  • The agent hands that ordinary response to you

That covers a single tool call in a one-shot prompt. The LLM could elect to call tools several times in succession -- the agent handles all that back-and-forth. In an interactive coding agent or any other "chatbot"-style interface, there are lots of prompts in a conversation -- the agent handles chaining all this stuff into the "context" that the initial prompt evolves into.

PromptExecutor does none of that. In Koog, AIAgent offers that sort of high-level interface. For my Android developer audience: PromptExecutor is to OkHttp as AIAgent is to Retrofit. AIAgent wraps a PromptExecutor and handles multi-turn conversations, tool calls, and lots of other stuff that agents need.

Because Knosh needs tools, Knosh uses AIAgent.

Knosh's AIAgentFactory builds the AIAgent that a particular command uses. The core of that is the AIAgent constructor call:

    return AIAgent(
      promptExecutor = promptExecutor,
      llmModel = resolveModel(llmProvider, agentConfig.modelName, agentConfig.contextLength),
      toolRegistry =
        toolSet.build(agentConfig, commandPermissions, commandExternalDirectories, logFullToolCalls, allowedToolIds),
      temperature = temperature ?: agentConfig.temperature,
      maxIterations = maxIterations,
      systemPrompt =
        assembleSystemPrompt(
          listOf(agentConfig.systemPrompt) +
            loadAgentsMarkdown(
              configDir = System.getProperty("user.home").toPath() / ".config" / "knosh",
              workingDir = System.getProperty("user.dir").toPath(),
              fileSystem = fileSystem,
            )
        ),
    )

Knosh uses MultiLLMPromptExecutor as its PromptExecutor implementation. This wraps a map of LLMProvider objects to LLMClient objects — we covered those a week ago. The LLMProvider is a simple identifier of a provider (e.g., LLMProvider.OpenAI), while LLMClient knows things like the API key to use. MultiLLMPromptExecutor lets you configure all possible providers/clients that you wish to use.

We will explore many of those other AIAgent constructor parameters in future issues. The two of importance for now is promptExecutor and llmModel. Those combine to let the AIAgent know how to talk to the LLM:

  • The agent provides the PromptExecutor with the LLModel
  • MultiLLMPromptExecutor uses that to identify what LLMClient to use, based on which LLMProvider the LLModel is tied to
  • When the agent tells the PromptExecutor to execute a prompt, MultiLLMPromptExecutor uses the LLMClient

To have an AIAgent execute a prompt, you call run(), passing in the desired prompt, perhaps just as a simple String. We will explore prompts and how Koog works with them in next week's issue!

Don't miss what's next. Subscribe to Pedal Assist Coding:
← Newer Updates and Options Older → Red Team All the Things

Add a comment:

Posting this comment will subscribe you to this newsletter with the email address you enter.
Bluesky
androiddev.social
commonsware.com
Powered by Buttondown, the easiest way to start and grow your newsletter.