update
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
# YiemAgent: Agile Agent Framework
|
||||
|
||||
## 1. Business Context & Success Metrics
|
||||
|
||||
### Business Goal
|
||||
|
||||
YiemAgent is a Julia-based AI agent framework that enables building chatbot assistants with tool-calling capabilities, model-agnostic LLM integration, and runtime tool discovery via MCP (Model Context Protocol). It provides an asynchronous agent loop with channel-based message passing, supporting both single-turn and multi-turn conversations with automatic tool call resolution.
|
||||
|
||||
### User Stories
|
||||
|
||||
- **US-001**: As a developer, I want to create an AI agent with a simple constructor so that I can quickly prototype chatbot functionality in Julia
|
||||
- **US-002**: As a developer, I want the agent to discover tools automatically from an MCP server so that I don't need to manually register tool APIs
|
||||
- **US-003**: As a developer, I want the agent to handle tool calls automatically in a loop so that the LLM can use tools without external orchestration
|
||||
- **US-004**: As a developer, I want to intercept tool calls with before/after hooks so that I can add user approval, logging, or result sanitization
|
||||
- **US-005**: As a developer, I want the framework to support multiple LLM models and providers through a pluggable `llmCall` interface so that I can swap models without changing agent logic
|
||||
|
||||
### KPIs & Targets
|
||||
|
||||
- **KPI-001**: Agent loop processes messages with <500ms overhead for sequential tool calls (validates US-003)
|
||||
- **KPI-002**: MCP tool discovery completes within 2 seconds for 50+ tools (validates US-002)
|
||||
- **KPI-003**: 100% of message types have OpenAI format conversion (validates US-001)
|
||||
|
||||
## 2. Technical Boundaries
|
||||
|
||||
### In Scope
|
||||
|
||||
- Julia module implementing an AI agent with asynchronous message processing
|
||||
- Channel-based input (user→agent), follow-up (async queue), and output (agent→user) interfaces
|
||||
- LLM model abstraction with tool call extraction from multiple response formats (OpenAI content blocks, LMStudio/vLLM format)
|
||||
- Tool registry with MCP server integration (tools/list, tools/call via JSON-RPC 2.0)
|
||||
- Agent loop with before/after tool call hooks for lifecycle management
|
||||
- Message type system with OpenAI format conversion utilities
|
||||
- Abort signal and termination flag support via tool implementations
|
||||
|
||||
### Out of Scope
|
||||
|
||||
- GUI/CLI interface (exposed via channels only; UI layer is external)
|
||||
- Persistent chat history or long-term memory (TODO comments in code)
|
||||
- Multi-agent orchestration (single agent instance per `yiemAgent` struct)
|
||||
- Embedding generation or retrieval-augmented generation (RAG)
|
||||
- Natural language-to-code generation or execution sandboxes
|
||||
|
||||
### Dependencies
|
||||
|
||||
- **Julia Standard Library**: `Dates`, `UUIDs`, `Base.Threads`
|
||||
- **External Packages**: `JSON`, `DataStructures`, `HTTP`, `PrettyPrinting`, `Serialization`, `DataFrames`
|
||||
- **Internal Package**: `GeneralUtils` (project-specific utility library)
|
||||
- **Optional**: `NATS` (MCP server communication), `LibPQ` (PostgreSQL)
|
||||
|
||||
### Deployment Constraints
|
||||
|
||||
- **NFR-001**: Library designed for embedded use in Docker containers (MicroK8s cluster, per `NFR-501` from template)
|
||||
- **NFR-002**: Must support Julia 1.9+ for module include/export semantics compatibility
|
||||
- **NFR-003**: Thread-safe channel operations; single-agent instance processes messages sequentially on background `@spawn` task
|
||||
|
||||
## 3. Functional Requirements (FR)
|
||||
|
||||
### FR-001: Agent Message Processing
|
||||
|
||||
The agent shall process user messages through an asynchronous loop that:
|
||||
- Accepts messages via `inputChannel` (capacity 16) and `followUpChannel` (capacity 32)
|
||||
- Prioritizes `inputChannel` messages over `followUpChannel` messages
|
||||
- Feeds responses to `outputChannel` (capacity 16) in OpenAI message format
|
||||
- Exits cleanly on `:shutdown` signal
|
||||
|
||||
**Traceability**: US-001, US-003
|
||||
|
||||
### FR-002: LLM Model Agnosticism
|
||||
|
||||
The agent shall accept a pluggable `llmCall` function that:
|
||||
- Receives formatted messages and returns an LLM response dict
|
||||
- The response dict may contain `message.tool_calls` (LMStudio format) or `content` blocks (OpenAI format)
|
||||
- The framework extracts tool calls regardless of response format
|
||||
|
||||
**Traceability**: US-005
|
||||
|
||||
### FR-003: Tool Call Execution Loop
|
||||
|
||||
The agent shall automatically execute tool calls returned by the LLM:
|
||||
- Extract tool calls via `_extractToolCalls()` which supports both `message.tool_calls` and `content[{type="tool_calls"}]` formats
|
||||
- Build `agentContext` via `prepareContext()` (pluggable hook)
|
||||
- Format messages via `formatMsgForLLM()` to OpenAI format
|
||||
- Extract tool calls → loop: execute tool calls → append results to history → call LLM again
|
||||
- Break loop when LLM response has no tool calls
|
||||
- Support `terminate` flag: if `toolResultBatch.terminate == true`, break loop and return final response
|
||||
|
||||
**Traceability**: US-003
|
||||
|
||||
### FR-004: Tool Discovery and Registration
|
||||
|
||||
The agent shall:
|
||||
- Query MCP server via `mcpserver("tools/list")` (JSON-RPC 2.0) to discover tools
|
||||
- Support pagination via `nextCursor` field
|
||||
- Wrap each MCP tool definition as an `agentTool` with `execute` hook that calls `mcpserver("tools/call", name, args, sessionId)`
|
||||
- Register a builtin `listTools` tool that triggers runtime discovery and lists all available tools
|
||||
- Skip tools already registered (idempotent)
|
||||
|
||||
**Traceability**: US-002
|
||||
|
||||
### FR-005: Tool Call Lifecycle Hooks
|
||||
|
||||
The agent shall support two lifecycle hooks:
|
||||
- `beforeToolCall(beforeToolCallContext, signal)` — can block execution by returning `beforeToolCallResult(true, reason)`
|
||||
- `afterToolCall(afterToolCallContext)` — can transform result by returning modified `agentToolResult`
|
||||
- Errors from hooks are caught and converted to `immediateOutcome`/error tool result messages (never throw)
|
||||
|
||||
**Traceability**: US-004
|
||||
|
||||
### FR-006: Message Type Conversion
|
||||
|
||||
The agent shall:
|
||||
- Convert internal message types (`userMessage`, `assistantMessage`, `assistantMessageToolCall`, `toolResultMessage`) to OpenAI format via `_userMessageToOpenAI()`, `_assistantMessageToOpenAI()`, `_assistantMessageToolCallToOpenAI()`, `_toolResultMessageToOpenAI()`
|
||||
- Convert internal `messageContent` types (`textContent`, `imageContent`, `reasoningContent`) to OpenAI content blocks via `_messageContentToBlocks()`
|
||||
- Convert `agentTool` definitions to OpenAI function tool format via `_toolsToOpenAI()`
|
||||
|
||||
**Traceability**: US-001
|
||||
|
||||
## 4. Non-Functional Requirements (NFRs)
|
||||
|
||||
### 4.1 Performance & Scalability
|
||||
|
||||
- **NFR-101**: Agent loop message processing overhead <500ms per sequential tool call (measured KPI: KPI-001)
|
||||
- **NFR-102**: MCP tool discovery for 50+ tools completes within 2 seconds (measured KPI: KPI-002)
|
||||
- **NFR-103**: Channel buffers prevent unbounded memory growth — `inputChannel` (16), `followUpChannel` (32), `outputChannel` (16)
|
||||
|
||||
### 4.2 Availability & Reliability
|
||||
|
||||
- **NFR-201**: Agent loop catches all errors via `try/catch` in `_agentLoop()` and calls `eventSink(errMsg)` before exit (measured by event sink logging)
|
||||
- **NFR-202**: `prepareToolCall()` never throws errors — validation failures return `immediateOutcome` with error tool result
|
||||
|
||||
### 4.3 Privacy & Security
|
||||
|
||||
- **Data Classification**: Tool arguments and results may contain PII (user messages); MCP tool results treated as untrusted input
|
||||
- **No built-in auth/authz**: Responsibility of `mcpServer` implementation and `beforeToolCall` hook
|
||||
- **Input validation**: JSON schema validation via `validateToolArguments()` checks required fields only (tools need custom validation via `validateRequiredArgs` hook)
|
||||
|
||||
### 4.4 Observability & Telemetry
|
||||
|
||||
- **Required Logs**: `agentLoop` events (via `eventSink`) emit state machine steps (`_agentLoop 1` through `_agentLoop 6`), `_processMessage` steps (1 through 18), `prepareToolCall` steps (1 through 10)
|
||||
- **Critical Metrics**:
|
||||
- `agent._state.messages.length` — conversation history size (logged at each step)
|
||||
- `toolExecutionStart`/`toolExecutionEnd` events (via `toolExecStartEvent`, `toolExecEndEvent` structs)
|
||||
- **Retention**: No built-in log retention; agent is a library, does not manage external logging
|
||||
|
||||
## 5. Acceptance Conditions
|
||||
|
||||
- [ ] **FR-001**: Agent processes messages through channel system with priority ordering (inputChannel > followUpChannel)
|
||||
- [ ] **FR-002**: `llmCall` is pluggable; response formats supported include `message.tool_calls` dict and `content` array blocks
|
||||
- [ ] **FR-003**: Agent loops on tool calls until LLM returns no tool calls or terminate flag is set
|
||||
- [ ] **FR-004**: MCP tools are discovered via `tools/list` with pagination; all registered tools are callable via `tools/call`
|
||||
- [ ] **FR-005**: `beforeToolCall` hook can block; `afterToolCall` hook can transform result; errors return error tool result
|
||||
- [ ] **FR-006**: All message types (userMessage, assistantMessage, assistantMessageToolCall, toolResultMessage) convert to OpenAI format
|
||||
- [ ] **NFR-101**: Message processing overhead <500ms per sequential tool call
|
||||
- [ ] **NFR-102**: MCP discovery for 50+ tools completes <2 seconds
|
||||
- [ ] **NFR-201**: Agent loop catches errors and exits gracefully without panics
|
||||
Reference in New Issue
Block a user