Spaces:
Sleeping
Sleeping
File size: 16,229 Bytes
de35c56 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | # Implementation Plan: Vietjourney Timeline Agent Feature
## 1. Introduction
This document outlines the implementation plan for a new "Agent Feature" within the Vietjourney platform. The goal is to enable an automated agent to interact with trip timelines as if it were a human member, specifically by adding and proposing timeline events. This will allow for programmatic generation or suggestion of itinerary items, enhancing collaborative planning workflows.
## 2. Agent Capabilities & Persona
This feature involves two distinct agent components:
1. **Hugging Face Agent (The Planner):**
* **Role:** Acts as the natural language interface and planning engine.
* **Capabilities:** Receives user natural language requests (e.g., "Plan a 3-day trip to Hanoi"). It then generates a structured JSON plan, which is a list of proposed timeline events with place details, categories, and estimated times.
* **Output:** **Strictly JSON format**, conforming to the schema defined in section 3.0. It does **not** directly interact with the Vietjourney backend.
* **Note on `timeline_context`:** While providing current timeline context to the Hugging Face Agent would enable more intelligent planning (e.g., avoiding overlaps, using `baseVersion`), its current API does not support this. Therefore, the Vietjourney Agent Feature is solely responsible for obtaining timeline context, performing overlap validation, and managing `baseVersion` for proposals.
2. **Vietjourney Agent Feature (The Executor):**
* **Role:** Acts as the backend integration layer, consuming the JSON plan from the Hugging Face agent and executing it against the Vietjourney APIs.
* **Capabilities:**
* **Consume JSON Plan:** Reads the structured JSON output from the Hugging Face agent.
* **Authenticate:** Interacts with the backend API using JWT authentication, impersonating a dedicated `User` account.
* **Create Timeline Events:** Directly adds new events to a timeline via `POST /api/v1/timelines/{timelineId}/events`.
* **Submit Timeline Proposals:** Proposes new events or changes to a timeline, requiring human approval, via `POST /api/v1/timelines/{timelineId}/proposals`.
* **Place Lookup:** Uses the `POST /api/v1/places/filter` endpoint to resolve `externalPlaceId` and other details for places provided by the Hugging Face agent (if not fully specified).
* **Interaction:** This component has an associated `User` account in the system and interacts with the backend API using JWT authentication, just like a regular user. It directly handles all API calls to Vietjourney backend.
### 3.0. Hugging Face Agent Output / Vietjourney Agent Feature Input (JSON Schema)
The Hugging Face Agent (`https://youmei295-planning-agent.hf.space`) is expected to generate a JSON response with a `timeline` array. The Vietjourney Agent Feature will consume this `timeline` array directly. Each object in the `timeline` array should conform to the following schema, matching the HF agent's output:
```json
{
"type": "array",
"items": {
"type": "object",
"properties": {
"time": { "type": "string", "description": "Time range of the activity (e.g., '08:00 - 10:00')" },
"activity": { "type": "string", "description": "Description of the activity (e.g., 'Uống cafe')" },
"location": { "type": "string", "description": "Human-readable name of the place/event (e.g., 'Quán Cafe Yên')" },
"location_id": { "type": "string", "nullable": true, "description": "Optional: ID of the place from the place catalog (e.g., 'uuid-from-supabase'). If not provided, the Vietjourney Agent Feature will perform a lookup using 'location' and 'activity' to infer category." },
"cost_estimate": { "type": "string", "nullable": true, "description": "Optional: Estimated cost (e.g., '50000')" }
},
"required": ["time", "activity", "location"]
}
}
```
---
## 3. Backend Integration Points
The agent will primarily interact with the existing Spring Boot backend API. The core interactions will leverage endpoints and Data Transfer Objects (DTOs) from the `timeline` module, and potentially the `place` module for looking up place details.
### 3.1. Creating Timeline Events Directly
To directly add a timeline event, the agent will need to call the existing `TimelineEventController` endpoint.
* **API Endpoint:** `POST /api/v1/timelines/{timelineId}/events`
* **Backend Controller:** `com.project.backend.modules.timeline.controller.TimelineEventController`
* **Backend Service:** `com.project.backend.modules.timeline.service.TimelineEventService.createTimelineEvent()`
* **Required Request Body JSON (based on `CreateTimelineEventRequest`):**
```json
{
"externalPlaceId": "string", // ID of the place from the place catalog
"category": "FOOD" | "DRINK" | "ACTIVITY", // Category of the place
"startTime": "yyyy-MM-ddTHH:mm:ss", // ISO 8601 datetime for event start
"endTime": "yyyy-MM-ddTHH:mm:ss", // ISO 8601 datetime for event end
"orderIndex": 0, // Order index for events on the same day (integer)
"notes": "string" // Optional notes about the event
}
```
**Example:**
```json
{
"externalPlaceId": "place-abc-123",
"category": "FOOD",
"startTime": "2026-07-20T12:00:00",
"endTime": "2026-07-20T14:00:00",
"orderIndex": 1,
"notes": "Lunch at a highly-rated local restaurant."
}
```
### 3.2. Submitting Timeline Proposals
To propose a timeline event (requiring approval), the agent will interact with the `TimelineProposalController`. This is more complex as it involves specifying an `action` and `data` payload within the proposal.
* **API Endpoint:** `POST /api/v1/timelines/{timelineId}/proposals`
* **Backend Controller:** `com.project.backend.modules.timeline.controller.TimelineProposalController`
* **Backend Service:** `com.project.backend.modules.timeline.proposal.TimelineProposalService.submitProposal()`
* **Required Request Body JSON (based on `SubmitProposalRequest`):**
```json
{
"baseVersion": 0, // Current version of the timeline (for optimistic locking)
"action": "ADD_EVENT" | "UPDATE_EVENT" | "DELETE_EVENT", // Type of change being proposed
"data": { // Payload specific to the action
// For ADD_EVENT, this would be similar to CreateTimelineEventRequest
// For UPDATE_EVENT, it would be an object with fields to update and the event ID
// For DELETE_EVENT, it would contain the event ID
}
}
```
**Example for `ADD_EVENT` Proposal:**
```json
{
"baseVersion": 5,
"action": "ADD_EVENT",
"data": {
"externalPlaceId": "place-xyz-456",
"category": "ACTIVITY",
"startTime": "2026-07-20T15:00:00",
"endTime": "2026-07-20T17:00:00",
"orderIndex": 2,
"notes": "A proposed visit to a historical site."
}
}
```
*(Note: The `data` field's schema depends on the `action` and would mirror the respective `TimelineEvent` DTOs for creation, update, or deletion.)*
## 4. Agent Authentication & Authorization
The agent will authenticate using a standard JWT flow:
1. **Agent User Account:** A dedicated `User` account (`agent-user-01`, `ai-planner-bot`, etc.) will be created in the system. This account should have the `USER` role and potentially a custom `AGENT` role for specific permissions.
2. **Login:** The agent will perform a `POST /api/v1/auth/login` using its username and password to obtain a JWT.
3. **Bearer Token:** All subsequent API calls by the agent to timeline-related endpoints will include this JWT in the `Authorization: Bearer <token>` header.
4. **Permissions:** The agent's associated roles and permissions will determine its ability to view, create, and propose timeline events (e.g., `hasAnyRole('USER', 'LEADER', 'ADMIN')` or more granular permissions on timeline events).
## 5. Agent's Required Output (JSON Schemas)
For the agent to effectively communicate with the backend API, it must be capable of generating JSON payloads that conform to the existing backend DTOs. This implies the agent's internal reasoning or tool-use capabilities must output structured JSON matching these schemas.
### 5.1. JSON Schema for Creating Direct Timeline Events
The agent's "tool output" for creating a direct event would need to match the `CreateTimelineEventRequest` schema:
```json
{
"type": "object",
"properties": {
"externalPlaceId": { "type": "string", "description": "ID of the place from the place catalog" },
"category": { "type": "string", "enum": ["FOOD", "DRINK", "ACTIVITY"], "description": "Category of the place" },
"startTime": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime for event start (e.g., 2026-07-20T12:00:00)" },
"endTime": { "type": "string", "format": "date-time", "description": "ISO 8601 datetime for event end (e.g., 2026-07-20T14:00:00)" },
"orderIndex": { "type": "integer", "description": "Order index for events on the same day, starting from 0" },
"notes": { "type": "string", "nullable": true, "description": "Optional notes about the event" }
},
"required": ["externalPlaceId", "category", "startTime", "endTime", "orderIndex"]
}
```
### 5.2. JSON Schema for Submitting Timeline Proposals
The agent's "tool output" for submitting a proposal would need to match the `SubmitProposalRequest` schema, with a dynamic `data` field:
```json
{
"type": "object",
"properties": {
"baseVersion": { "type": "integer", "description": "The current version of the timeline (for optimistic locking)" },
"action": { "type": "string", "enum": ["ADD_EVENT", "UPDATE_EVENT", "DELETE_EVENT"], "description": "The type of change being proposed" },
"data": {
"type": "object",
"description": "The payload for the proposed action, schema varies by 'action' type.",
"oneOf": [
{
"if": { "properties": { "action": { "const": "ADD_EVENT" } } },
"then": { "$ref": "#/definitions/CreateTimelineEventData" }
},
{
"if": { "properties": { "action": { "const": "UPDATE_EVENT" } } },
"then": { "$ref": "#/definitions/UpdateTimelineEventData" }
},
{
"if": { "properties": { "action": { "const": "DELETE_EVENT" } } },
"then": { "$ref": "#/definitions/DeleteTimelineEventData" }
}
]
}
},
"required": ["baseVersion", "action", "data"],
"definitions": {
"CreateTimelineEventData": {
"type": "object",
"properties": {
"externalPlaceId": { "type": "string" },
"category": { "type": "string", "enum": ["FOOD", "DRINK", "ACTIVITY"] },
"startTime": { "type": "string", "format": "date-time" },
"endTime": { "type": "string", "format": "date-time" },
"orderIndex": { "type": "integer" },
"notes": { "type": "string", "nullable": true }
},
"required": ["externalPlaceId", "category", "startTime", "endTime", "orderIndex"]
},
"UpdateTimelineEventData": {
"type": "object",
"properties": {
"id": { "type": "string" }, // ID of the event to update
"externalPlaceId": { "type": "string", "nullable": true },
"category": { "type": "string", "enum": ["FOOD", "DRINK", "ACTIVITY"], "nullable": true },
"startTime": { "type": "string", "format": "date-time", "nullable": true },
"endTime": { "type": "string", "format": "date-time", "nullable": true },
"orderIndex": { "type": "integer", "nullable": true },
"notes": { "type": "string", "nullable": true }
},
"required": ["id"]
},
"DeleteTimelineEventData": {
"type": "object",
"properties": {
"id": { "type": "string" } // ID of the event to delete
},
"required": ["id"]
}
}
}
```
## 6. High-Level Vietjourney Agent Feature Workflow
The Vietjourney Agent Feature, upon receiving a JSON plan from the Hugging Face Agent, will follow these steps to execute the plan:
1. **Receive JSON Plan:** Consume the structured JSON array of proposed timeline events (conforming to the schema in section 3.0).
2. **Authenticate:** Obtain or refresh a JWT for API calls using the dedicated agent user account.
3. **Resolve Place Details:** For each proposed event in the JSON plan:
* If `location_id` is provided and is a valid UUID, use it directly as `externalPlaceId`.
* If `location_id` is `null`, missing, or a non-UUID placeholder/search term, use the `location` (and inferred `category` from `activity`) to call the `POST /api/v1/places/filter` endpoint to find the `externalPlaceId`. Handle cases where a place cannot be found or multiple matches exist (e.g., log a warning, skip the event, or use the first reasonable result).
4. **Retrieve Timeline Context:** Fetch the target timeline's current details (`GET /api/v1/timelines/{timelineId}`) to obtain the `baseVersion` required for submitting proposals and to validate event placement.
5. **Process Each Event (Direct Add or Proposal):** For each resolved event:
* **Determine Execution Strategy:** Based on configuration or a flag, decide whether to directly add the event or submit it as a proposal.
* **Data Transformation:** Convert the Hugging Face agent's event format into a `CreateTimelineEventRequest` payload:
* **`startTime`/`endTime`:** Combine the overall plan's `start_date` (from the initial user request to the HF agent) with the event's `time` string (e.g., "08:00 - 10:00") to form `LocalDateTime` objects.
* **`category`:** Infer from the `activity` field (e.g., "Uống cafe" -> `DRINK` or `FOOD`, "Tham quan" -> `ACTIVITY`).
* **`orderIndex`:** Assign sequentially for events on the same day, ordered by `startTime`.
* **`notes`:** Use the `activity` and/or `location` fields.
* **Direct Add:** Construct the transformed `CreateTimelineEventRequest` payload and make a `POST` request to `BACKEND_BASE_URL/api/v1/timelines/{timelineId}/events`.
* **Submit Proposal:** Construct a `SubmitProposalRequest` payload (setting `changeType` to `ADD_EVENT` and `data` to the transformed `CreateTimelineEventRequest` structure), and make a `POST` request to `BACKEND_BASE_URL/api/v1/timelines/{timelineId}/proposals`.
* **Adhere to Schemas:** Ensure all generated JSON payloads strictly conform to the `CreateTimelineEventRequest` and `SubmitProposalRequest` schemas.
* **Include JWT:** All requests must include the valid JWT in the `Authorization: Bearer <token>` header.
6. **Process Responses & Report:**
* Handle successful API responses (e.g., log successful event creation/proposal submission).
* Manage error responses (e.g., `400 Bad Request` for validation issues, `403 Forbidden` for permissions). Log errors clearly and potentially report back to an orchestrating system or user.
7. **Generate Summary Report:** After processing all events in the plan, generate a summary of successful additions/proposals and any errors encountered.
## 7. Future Considerations/Enhancements
* **Agent Roles & Permissions:** Implement more granular roles for agents (e.g., a "suggestion-only" agent vs. a "direct-action" agent) to control their capabilities.
* **Conflict Resolution:** Implement logic for the agent to detect and potentially resolve conflicts (e.g., if a timeline event overlaps with an existing one when trying to add directly).
* **Natural Language to JSON Mapping:** Develop a robust mechanism within the agent to translate natural language requests into the structured JSON formats required by the API.
* **Feedback Loop:** Allow the agent to interpret responses from the backend (e.g., validation errors) and provide informative feedback to the user or retry with corrections.
* **Event Updates/Deletions:** Extend the agent's capabilities to update or delete existing timeline events through proposals or direct actions.
|