Files
ekko cd15791d3f [codex] Add global Ekko runtime context handling (#1950)
* Add global Ekko runtime context handling

* Pass managed MCP servers to Ekko runs

* Register MCP tools in Ekko runtime

* Watch Ekko agent sources in dev

* Document Ekko chat chain changes
2026-07-05 19:40:34 +08:00
..

Ekko Agent

Ekko Agent is a package scaffold for future Hermes Web UI agent integration.

The first implemented layer is model-provider requests. Internally, the agent uses one request shape and provider adapters translate it to external APIs.

Supported request styles:

  • OpenAI Chat Completions style
  • OpenAI-compatible providers such as DeepSeek, Qwen, Moonshot, Ollama
  • OpenAI Responses
  • Anthropic Messages
  • Gemini Contents
  • prompt completion
  • custom runtime

Default endpoints:

Style Default endpoint
openai-chat https://api.openai.com/v1/chat/completions
openai-responses https://api.openai.com/v1/responses
anthropic-messages https://api.anthropic.com/v1/messages
gemini-contents https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent
prompt-completion https://api.openai.com/v1/completions
custom-runtime http://127.0.0.1:11434/v1/agent

Use baseUrl and endpointPath to override these defaults.

Message Shape

All adapters receive the same internal message shape:

type AgentMessage = {
  role: 'system' | 'user' | 'assistant' | 'tool'
  content: string
  name?: string
  toolCallId?: string
  toolCalls?: AgentToolCall[]
}

Use normalizeAgentMessage() or normalizeAgentMessages() at the boundary. Model responses can be converted back to a single assistant message with modelResponseToAgentMessage(). Streaming events can be collected into the same shape with collectModelEvents().

Tools

Built-in tools:

  • read_file reads a text file.
  • write_file writes text content and creates parent directories by default.
  • terminal_exec runs a command with an argument array and shell: false.

Use workspaceRoot to keep file and terminal working directories inside a specific workspace.

import { createDefaultToolRegistry } from './src/index'

const tools = createDefaultToolRegistry()

await tools.execute('write_file', {
  path: 'notes/todo.txt',
  content: 'ship tools',
}, {
  workspaceRoot: process.cwd(),
})

const result = await tools.execute('terminal_exec', {
  command: 'node',
  args: ['-v'],
}, {
  workspaceRoot: process.cwd(),
})

Runtime

AgentRuntime ties messages, model requests, tools, skills, system prompt, and events together. The default maxSteps is 90, matching Hermes' regular agent turn budget.

import { AgentRuntime, createDefaultToolRegistry } from './src/index'

const runtime = new AgentRuntime({
  modelClient: client,
  tools: createDefaultToolRegistry(),
  skills: [{
    id: 'project',
    name: 'Project Skill',
    instructions: 'Follow the project conventions before editing files.',
  }],
})

const result = await runtime.run({
  messages: ['Read README.md and summarize it.'],
  toolContext: {
    workspaceRoot: process.cwd(),
  },
  onEvent(event) {
    console.log(event.type)
  },
})

Commands

npm --prefix packages/ekko-agent run check

Example

import { createModelClient } from './src/index'

const client = createModelClient({
  id: 'deepseek',
  type: 'openai-compatible',
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseUrl: 'https://api.deepseek.com/v1',
  defaultModel: 'deepseek-chat',
})

const response = await client.create({
  messages: [{ role: 'user', content: 'Say hello.' }],
})