690519:1631 224 to 226 AI #01
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# Architecture Checklist: AI Tool Layer
|
||||
|
||||
**Created**: 2026-05-19
|
||||
**Feature**: 225-ai-tool-layer-architecture
|
||||
|
||||
## System Architecture
|
||||
|
||||
- [x] Does not break any existing core functionality.
|
||||
- [x] Fits within the described boundaries of ADR-023A and ADR-025.
|
||||
- [x] Maintains isolation: AI Tool Layer does not directly access database, uses Domain Services.
|
||||
- [x] Correctly implements Server-side intent routing.
|
||||
|
||||
## Security (CASL & Audit)
|
||||
|
||||
- [x] Every tool function enforces CASL rules using `CaslAbilityFactory`.
|
||||
- [x] Audit logs are written for every tool execution.
|
||||
- [x] ADR-019 check: No `id: number` exists in `ToolCallResult` data payloads.
|
||||
- [x] No side effects (writes) allowed unless explicitly modeled and protected (Read-only predominantly for V1).
|
||||
|
||||
## Observability
|
||||
|
||||
- [x] All tool layer failures log the exception details to the server logs.
|
||||
- [x] The `ToolCallResult` returns user-friendly messages for failures without leaking technical details.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: AI Tool Layer Architecture
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-05-19
|
||||
**Feature**: spec.md
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Checked against ADR-025 requirements. Everything is well-specified.
|
||||
@@ -0,0 +1,18 @@
|
||||
# Task Checklist: AI Tool Layer Architecture
|
||||
|
||||
**Created**: 2026-05-19
|
||||
**Feature**: 225-ai-tool-layer-architecture
|
||||
|
||||
## Task Completeness
|
||||
|
||||
- [x] All requirements from `spec.md` are covered by at least one task.
|
||||
- [x] Tasks are broken down into logical phases.
|
||||
- [x] Each task has clear verification criteria.
|
||||
- [x] Tasks do not introduce changes that conflict with ADR-019 (no integer IDs).
|
||||
- [x] Tasks explicitly account for CASL authorization.
|
||||
|
||||
## Execution Order
|
||||
|
||||
- [x] Base types and Registry are created before Handlers (Phase 1).
|
||||
- [x] Handlers are created before Integration (Phase 2 -> Phase 3).
|
||||
- [x] End-to-end integration is the final step.
|
||||
@@ -0,0 +1,5 @@
|
||||
export type ToolCallReason = 'FORBIDDEN' | 'NOT_FOUND' | 'INVALID_PARAMS' | 'SERVICE_ERROR';
|
||||
|
||||
export type ToolCallResult<T> =
|
||||
| { ok: true; data: T }
|
||||
| { ok: false; reason: ToolCallReason; message: string };
|
||||
@@ -0,0 +1,48 @@
|
||||
# Data Model: AI Tool Layer Architecture
|
||||
|
||||
## Database Changes
|
||||
No new tables required. The feature leverages the existing `ai_audit_logs` table.
|
||||
|
||||
### `ai_audit_logs` Schema Re-use
|
||||
```sql
|
||||
-- Represents how tool execution results are persisted:
|
||||
INSERT INTO ai_audit_logs (
|
||||
public_id,
|
||||
action, -- 'tool_call'
|
||||
intent, -- e.g., 'GET_RFA'
|
||||
params, -- JSON representation of input
|
||||
result, -- 'ok', 'forbidden', 'not_found', 'service_error'
|
||||
latency_ms,
|
||||
project_public_id,
|
||||
user_public_id,
|
||||
created_at
|
||||
) VALUES (...);
|
||||
```
|
||||
|
||||
## Internal Data Types
|
||||
|
||||
### `ToolCallResult<T>`
|
||||
```typescript
|
||||
export type ToolCallReason = 'FORBIDDEN' | 'NOT_FOUND' | 'INVALID_PARAMS' | 'SERVICE_ERROR';
|
||||
|
||||
export type ToolCallResult<T> =
|
||||
| { ok: true; data: T }
|
||||
| { ok: false; reason: ToolCallReason; message: string };
|
||||
```
|
||||
|
||||
### Tool Result DTOs
|
||||
All return structures adhere to ADR-019 (no integer IDs).
|
||||
|
||||
**Example: `RfaToolResult`**
|
||||
```typescript
|
||||
export interface RfaToolResult {
|
||||
publicId: string;
|
||||
rfaNumber: string;
|
||||
revisionCode: string;
|
||||
statusCode: string;
|
||||
drawingCount: number;
|
||||
submittedAt: string | null;
|
||||
respondedAt: string | null;
|
||||
contractPublicId: string;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,74 @@
|
||||
# Implementation Plan: AI Tool Layer Architecture
|
||||
|
||||
**Branch**: `225-ai-tool-layer-architecture` | **Date**: 2026-05-19 | **Spec**: spec.md
|
||||
**Input**: Feature specification from `specs/200-fullstacks/225-ai-tool-layer-architecture/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Implement the AI Tool Layer Architecture as specified in ADR-025. This layer acts as a bridge between the AI Gateway (ADR-023A) and the business modules. It maps `ServerIntent` to business service calls (`AiToolRegistryService`), enforces CASL authorization, formats responses into LLM-friendly DTOs (adhering to ADR-019), handles structured errors (ADR-007), and writes audit logs.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: TypeScript, Node.js, NestJS 11
|
||||
**Primary Dependencies**: NestJS, CASL, class-validator
|
||||
**Storage**: MariaDB (for audit logs `ai_audit_logs`)
|
||||
**Testing**: Jest (Unit & Integration tests)
|
||||
**Target Platform**: Backend API (Node.js)
|
||||
**Project Type**: Backend Module (NestJS)
|
||||
**Performance Goals**: Low latency dispatch (< 10ms for tool routing)
|
||||
**Constraints**: Must strictly follow ADR-019, ADR-007, ADR-025
|
||||
**Scale/Scope**: Impacts all AI features; easily extensible for new tools.
|
||||
|
||||
## Constitution Check
|
||||
|
||||
_GATE: Must pass before Phase 0 research. Re-check after Phase 1 design._
|
||||
|
||||
- ✅ Zero `any` usage in new tool layer logic.
|
||||
- ✅ ADR-019 strictly adhered to (no `id: number` exposed).
|
||||
- ✅ CASL enforcement integrated directly in tool handlers.
|
||||
- ✅ No raw entities leaked to LLM context.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/200-fullstacks/225-ai-tool-layer-architecture/
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── contracts/
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
backend/
|
||||
└── src/
|
||||
└── modules/
|
||||
└── ai/
|
||||
└── tool/
|
||||
├── ai-tool.module.ts
|
||||
├── ai-tool-registry.service.ts
|
||||
├── rfa-tool.service.ts
|
||||
├── drawing-tool.service.ts
|
||||
├── transmittal-tool.service.ts
|
||||
├── correspondence-tool.service.ts
|
||||
├── circulation-tool.service.ts
|
||||
├── document-tool.service.ts
|
||||
└── types/
|
||||
├── tool-call-result.type.ts
|
||||
├── rfa-tool-result.type.ts
|
||||
├── drawing-tool-result.type.ts
|
||||
└── ...
|
||||
```
|
||||
|
||||
**Structure Decision**: The implementation will be housed in a new NestJS module `AiToolModule` inside `backend/src/modules/ai/tool/`. This module will manage tool registry and service handlers, and it will be imported by `AiModule`.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
| -------------------------- | ------------------ | ------------------------------------ |
|
||||
| N/A | | |
|
||||
@@ -0,0 +1,50 @@
|
||||
# Quickstart: AI Tool Layer Architecture
|
||||
|
||||
## Testing the Tool Layer Manually
|
||||
|
||||
You can test the tool registry directly through the NestJS REPL or by hitting the `POST /ai/intent` endpoint once the gateway is connected.
|
||||
|
||||
### Example Request (Simulated)
|
||||
```json
|
||||
POST /ai/intent
|
||||
{
|
||||
"query": "Get the latest RFA for project A",
|
||||
"context": {
|
||||
"type": "project",
|
||||
"publicId": "019505a1-7c3e-7000-8000-abc123def456"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Expected Response
|
||||
If user is authorized:
|
||||
```json
|
||||
{
|
||||
"intent": "GET_RFA",
|
||||
"confidence": 0.95,
|
||||
"result": {
|
||||
"ok": true,
|
||||
"data": [
|
||||
{
|
||||
"publicId": "019505a1-8d2b-7000-8000-112233445566",
|
||||
"rfaNumber": "RFA-001",
|
||||
"statusCode": "PENDING",
|
||||
...
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If user is unauthorized:
|
||||
```json
|
||||
{
|
||||
"intent": "GET_RFA",
|
||||
"confidence": 0.95,
|
||||
"result": {
|
||||
"ok": false,
|
||||
"reason": "FORBIDDEN",
|
||||
"message": "ไม่มีสิทธิ์เข้าถึง RFA"
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,13 @@
|
||||
# Research Notes: AI Tool Layer Architecture
|
||||
|
||||
- **ADR-025 Analysis**: Focus on Server-Side Dispatch. Instead of giving LLM direct tool calling capabilities, we map a `ServerIntent` to a function call securely on our server. This ensures CASL enforcement prior to executing logic, rather than relying on the LLM runtime to provide constraints.
|
||||
- **Data Shape**: Tools will return `ToolCallResult<T>` which is defined as:
|
||||
```typescript
|
||||
type ToolCallReason = 'FORBIDDEN' | 'NOT_FOUND' | 'INVALID_PARAMS' | 'SERVICE_ERROR';
|
||||
type ToolCallResult<T> =
|
||||
| { ok: true; data: T }
|
||||
| { ok: false; reason: ToolCallReason; message: string };
|
||||
```
|
||||
- **Error Types**: Follows ADR-007 layered classification.
|
||||
- **Identifiers**: Adheres to ADR-019 (Hybrid Identifier). No internal integer `id` exposed. All references utilize `publicId`.
|
||||
- **Security Check**: Enforce `CaslAbilityGuard` behavior directly inside the Tool Service methods, utilizing `CaslAbilityFactory` instantiated with the `RequestUser`.
|
||||
@@ -0,0 +1,75 @@
|
||||
# Feature Specification: AI Tool Layer Architecture
|
||||
|
||||
**Feature Branch**: `225-ai-tool-layer-architecture`
|
||||
**Created**: 2026-05-19
|
||||
**Status**: Draft
|
||||
**Input**: User description: ADR-025-ai-tool-layer-architecture.md
|
||||
|
||||
## User Scenarios & Testing _(mandatory)_
|
||||
|
||||
### User Story 1 - AI Gateway Request for RFA (Priority: P1)
|
||||
|
||||
AI Gateway ที่ได้รับ Intent `GET_RFA` ต้องสามารถเรียกใช้ `RfaToolService.getRfa` เพื่อดึงข้อมูลมาทำ context ให้ LLM โดยต้องถูกจำกัดสิทธิ์ (CASL) และคืนค่าแค่ publicId + business codes
|
||||
|
||||
**Why this priority**: การดึงข้อมูล RFA เป็น use case หลักที่ใช้ทดสอบ AI Tool Layer และตรวจสอบ CASL authorization ได้ครอบคลุม
|
||||
|
||||
**Independent Test**: สามารถส่งคำขอ POST ไปยัง Gateway แล้วดูว่า tool คืนค่าข้อมูลที่ไม่มี INT `id` และอนุญาตให้เฉพาะ user ที่มีสิทธิ์ได้หรือไม่
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** User ที่มีสิทธิ์อ่าน RFA ในโครงการ A, **When** AI Gateway ส่ง Intent `GET_RFA` พร้อม `projectPublicId` โครงการ A, **Then** ระบบคืนค่า `{ ok: true, data: [...] }` ที่มี RFA publicId และไม่มี INT `id`
|
||||
2. **Given** User ที่ไม่มีสิทธิ์อ่าน RFA ในโครงการ B, **When** AI Gateway ส่ง Intent `GET_RFA` สำหรับโครงการ B, **Then** ระบบคืนค่า `{ ok: false, reason: 'FORBIDDEN' }`
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - AI Gateway Request for Drawing (Priority: P2)
|
||||
|
||||
AI Gateway ที่ได้รับ Intent `GET_DRAWING` ต้องสามารถเรียกใช้ `DrawingToolService.getDrawing` อย่างปลอดภัยเช่นเดียวกับ RFA
|
||||
|
||||
**Why this priority**: พิสูจน์ความยืดหยุ่นของ Tool Registry ว่ารองรับ tool ใหม่ได้ง่าย
|
||||
|
||||
**Independent Test**: จำลอง Intent `GET_DRAWING` ไปยัง Tool Registry
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** User ปกติที่เข้าถึง Drawing ได้, **When** เรียก Request สำหรับ Drawing, **Then** คืนค่า DrawingToolResult ที่มีเฉพาะ `publicId` และ metadata
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Graceful Degradation on Error (Priority: P2)
|
||||
|
||||
เมื่อ Tool ทำงานผิดพลาด (เช่น Database Error, หาข้อมูลไม่พบ) จะต้องคืนค่าอย่างเป็นระบบ เพื่อไม่ให้ Gateway พังและสามารถบอก LLM หรือ User ได้
|
||||
|
||||
**Why this priority**: จำเป็นสำหรับ Error Handling (ADR-007)
|
||||
|
||||
**Independent Test**: Mock error (เช่น SERVICE_ERROR หรือ NOT_FOUND) จาก tool function
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** Service เกิด exception, **When** เรียก tool function, **Then** ระบบต้องจับ Exception และคืนค่า `{ ok: false, reason: 'SERVICE_ERROR' }` แทนที่จะโยน exception กลับไปที่ HTTP layer โดยตรง
|
||||
|
||||
---
|
||||
|
||||
## Requirements _(mandatory)_
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: ระบบ MUST รองรับการลงทะเบียน Tool Functions ใน `AiToolRegistryService` (Static Map) ที่จับคู่ `ServerIntent` กับ Tool Handler
|
||||
- **FR-002**: ระบบ MUST เรียกใช้งาน Tool Handler พร้อมส่งผ่าน `RequestUser` เพื่อใช้ทำ CASL Enforcement ภายใน Tool
|
||||
- **FR-003**: Tool ทุกตัว MUST คืนค่าข้อมูลที่ตรงกับ Type `ToolCallResult<T>` ซึ่งประกอบด้วย `ok: true|false`, `data`, `reason`, `message`
|
||||
- **FR-004**: Data ที่คืนกลับมาจาก Tool (`*ToolResult` DTO) MUST ประกอบด้วย field แบบ `publicId` และรหัส Business Codes (เช่น `rfaNumber`, `statusCode`) และห้ามมี Integer Primary Key (`id`) หรือ Relation Entity ตามกฏ ADR-019
|
||||
- **FR-005**: ระบบ MUST บันทึกประวัติการเรียก Tool ใน `ai_audit_logs` พร้อมข้อมูล `intent`, `params`, ผลลัพธ์ (`ok`, `reason`), `latencyMs`, `projectPublicId`, และ `userPublicId`
|
||||
|
||||
### Key Entities
|
||||
|
||||
- **Tool Registry**: ศูนย์รวม Static Map สำหรับเรียก Tool Functions
|
||||
- **AiAuditLog**: ข้อมูลการทำ Log ทุกๆ Tool Execution เพื่อวัตถุประสงค์ด้าน Audit
|
||||
|
||||
## Success Criteria _(mandatory)_
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: 100% ของ Tool Response ไม่มี Field ที่เป็น Integer Primary Key (ADR-019 Compliance)
|
||||
- **SC-002**: Tool Executions ที่เกิดจาก User ไม่มีสิทธิ์ (CASL Fail) 100% ถูก Block และคืนค่า Reason `FORBIDDEN` อย่างถูกต้อง
|
||||
- **SC-003**: มี Audit Logs ครบ 100% ของทุก Tool Execution (ทั้งสำเร็จและล้มเหลว)
|
||||
- **SC-004**: AI Tool Layer ครอบคลุมการทำงานอย่างน้อย `GET_RFA`, `GET_DRAWING`, และ `GET_TRANSMITTAL`
|
||||
@@ -0,0 +1,55 @@
|
||||
# Implementation Tasks: AI Tool Layer Architecture
|
||||
|
||||
**Feature Branch**: `225-ai-tool-layer-architecture`
|
||||
**Created**: 2026-05-19
|
||||
**Updated**: 2026-05-19 (Implementation complete)
|
||||
|
||||
## Task Strategy
|
||||
|
||||
Implementation of the Server-Side Tool Layer. This will be integrated into the existing `AiModule` but isolated in a `AiToolModule` submodule. All tests must verify CASL restrictions and payload format mapping.
|
||||
|
||||
## Phase 1: Core Framework (Tool Registry & Base Types)
|
||||
|
||||
- [X] **1.1: Define Core Types**
|
||||
- **File**: `backend/src/modules/ai/tool/types/tool-call-result.type.ts`
|
||||
- **Action**: Implement `ToolCallReason` and `ToolCallResult<T>` as defined in the contract.
|
||||
- **Verification**: Type-checks pass.
|
||||
|
||||
- [X] **1.2: Implement Tool Registry Service**
|
||||
- **File**: `backend/src/modules/ai/tool/ai-tool-registry.service.ts`
|
||||
- **Action**: Create a service with a static map connecting `ServerIntent` to their corresponding handler functions.
|
||||
- **Verification**: Unit tests verify that calling `getHandler(intent)` returns the correct function or throws a clean error if not found.
|
||||
|
||||
- [X] **1.3: Set up AiToolModule**
|
||||
- **File**: `backend/src/modules/ai/tool/ai-tool.module.ts`
|
||||
- **Action**: Scaffold the module, export `AiToolRegistryService`, and import it into `AiModule`.
|
||||
- **Verification**: Application boots successfully.
|
||||
|
||||
## Phase 2: Implement Tool Handlers
|
||||
|
||||
- [X] **2.1: Implement RFA Tool Service**
|
||||
- **File**: `backend/src/modules/ai/tool/rfa-tool.service.ts`
|
||||
- **Action**: Implement `getRfa` using `RfaService`. Wrap in CASL check (`AbilityFactory`). Return mapped `RfaToolResult`.
|
||||
- **Verification**: Unit tests confirm unauthorized users receive `{ ok: false, reason: 'FORBIDDEN' }`, and authorized users receive `{ ok: true, data: [...] }` without `id`.
|
||||
|
||||
- [X] **2.2: Implement Drawing Tool Service**
|
||||
- **File**: `backend/src/modules/ai/tool/drawing-tool.service.ts`
|
||||
- **Action**: Implement `getDrawing` using `ShopDrawingService`. Wrap in CASL check. Return mapped `DrawingToolResult`.
|
||||
- **Verification**: Tests confirm `DrawingToolResult` complies with ADR-019.
|
||||
|
||||
- [X] **2.3: Implement Transmittal Tool Service**
|
||||
- **File**: `backend/src/modules/ai/tool/transmittal-tool.service.ts`
|
||||
- **Action**: Implement `getTransmittal` with CASL check.
|
||||
- **Verification**: Tests confirm CASL enforcement.
|
||||
|
||||
## Phase 3: Integration and Audit Logging
|
||||
|
||||
- [X] **3.1: Integrate Audit Logging**
|
||||
- **File**: `backend/src/modules/ai/tool/ai-tool-registry.service.ts`
|
||||
- **Action**: Add logic to write to `ai_audit_logs` (using AuditLog entity directly) for every tool execution.
|
||||
- **Verification**: Integration test shows DB row created after tool execution.
|
||||
|
||||
- [X] **3.2: Expose Endpoint / Update AI Gateway**
|
||||
- **File**: `backend/src/modules/ai/ai.controller.ts`
|
||||
- **Action**: Wire up the `AiToolRegistryService` dispatch within the `POST /ai/intent` handler.
|
||||
- **Verification**: E2E test making an intent request and getting a mapped response back.
|
||||
Reference in New Issue
Block a user