Spaces:
Sleeping
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:
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, usingbaseVersion), its current API does not support this. Therefore, the Vietjourney Agent Feature is solely responsible for obtaining timeline context, performing overlap validation, and managingbaseVersionfor proposals.
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
Useraccount. - 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/filterendpoint to resolveexternalPlaceIdand other details for places provided by the Hugging Face agent (if not fully specified).
- Interaction: This component has an associated
Useraccount 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:
{
"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}/eventsBackend Controller:
com.project.backend.modules.timeline.controller.TimelineEventControllerBackend Service:
com.project.backend.modules.timeline.service.TimelineEventService.createTimelineEvent()Required Request Body JSON (based on
CreateTimelineEventRequest):{ "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:
{ "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}/proposalsBackend Controller:
com.project.backend.modules.timeline.controller.TimelineProposalControllerBackend Service:
com.project.backend.modules.timeline.proposal.TimelineProposalService.submitProposal()Required Request Body JSON (based on
SubmitProposalRequest):{ "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_EVENTProposal:{ "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
datafield's schema depends on theactionand would mirror the respectiveTimelineEventDTOs for creation, update, or deletion.)
4. Agent Authentication & Authorization
The agent will authenticate using a standard JWT flow:
- Agent User Account: A dedicated
Useraccount (agent-user-01,ai-planner-bot, etc.) will be created in the system. This account should have theUSERrole and potentially a customAGENTrole for specific permissions. - Login: The agent will perform a
POST /api/v1/auth/loginusing its username and password to obtain a JWT. - Bearer Token: All subsequent API calls by the agent to timeline-related endpoints will include this JWT in the
Authorization: Bearer <token>header. - 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:
{
"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:
{
"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:
- Receive JSON Plan: Consume the structured JSON array of proposed timeline events (conforming to the schema in section 3.0).
- Authenticate: Obtain or refresh a JWT for API calls using the dedicated agent user account.
- Resolve Place Details: For each proposed event in the JSON plan:
- If
location_idis provided and is a valid UUID, use it directly asexternalPlaceId. - If
location_idisnull, missing, or a non-UUID placeholder/search term, use thelocation(and inferredcategoryfromactivity) to call thePOST /api/v1/places/filterendpoint to find theexternalPlaceId. 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).
- If
- Retrieve Timeline Context: Fetch the target timeline's current details (
GET /api/v1/timelines/{timelineId}) to obtain thebaseVersionrequired for submitting proposals and to validate event placement. - 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
CreateTimelineEventRequestpayload:startTime/endTime: Combine the overall plan'sstart_date(from the initial user request to the HF agent) with the event'stimestring (e.g., "08:00 - 10:00") to formLocalDateTimeobjects.category: Infer from theactivityfield (e.g., "Uống cafe" ->DRINKorFOOD, "Tham quan" ->ACTIVITY).orderIndex: Assign sequentially for events on the same day, ordered bystartTime.notes: Use theactivityand/orlocationfields.
- Direct Add: Construct the transformed
CreateTimelineEventRequestpayload and make aPOSTrequest toBACKEND_BASE_URL/api/v1/timelines/{timelineId}/events. - Submit Proposal: Construct a
SubmitProposalRequestpayload (settingchangeTypetoADD_EVENTanddatato the transformedCreateTimelineEventRequeststructure), and make aPOSTrequest toBACKEND_BASE_URL/api/v1/timelines/{timelineId}/proposals.
- Data Transformation: Convert the Hugging Face agent's event format into a
- Adhere to Schemas: Ensure all generated JSON payloads strictly conform to the
CreateTimelineEventRequestandSubmitProposalRequestschemas. - Include JWT: All requests must include the valid JWT in the
Authorization: Bearer <token>header.
- Determine Execution Strategy: Based on configuration or a flag, decide whether to directly add the event or submit it as a proposal.
- Process Responses & Report:
- Handle successful API responses (e.g., log successful event creation/proposal submission).
- Manage error responses (e.g.,
400 Bad Requestfor validation issues,403 Forbiddenfor permissions). Log errors clearly and potentially report back to an orchestrating system or user.
- 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.