feat(location-agent): using createLocation instead of updateLocation to simplify
This commit is contained in:
@ -53,14 +53,6 @@ const contactPrompt = `
|
|||||||
* **listContacts**: Retrieves the existing contact list. **Must** be called first if potential contacts are found in the image, to enable duplicate checking.
|
* **listContacts**: Retrieves the existing contact list. **Must** be called first if potential contacts are found in the image, to enable duplicate checking.
|
||||||
* **createContact**: Adds a *new*, non-duplicate contact. Only call *after* listContacts confirms the person is new. name is mandatory.
|
* **createContact**: Adds a *new*, non-duplicate contact. Only call *after* listContacts confirms the person is new. name is mandatory.
|
||||||
* **stopAgent**: Signals that processing for the current image is complete (either action was taken, no action was needed, or all identified contacts already existed). Call this as the final step or when no other action is applicable based on the workflow.
|
* **stopAgent**: Signals that processing for the current image is complete (either action was taken, no action was needed, or all identified contacts already existed). Call this as the final step or when no other action is applicable based on the workflow.
|
||||||
|
|
||||||
**Key Instructions & Constraints:**
|
|
||||||
|
|
||||||
* **Strict Output Separation:** **Never mix text content and tool call structures in the same response content. Generate ONLY the tool call when using a tool.**
|
|
||||||
* **Tool Order:** listContacts (if contacts found) -> [createContact (if new contacts exist, potentially multiple calls)] -> stopAgent. OR stopAgent directly if no contacts found or all contacts exist.
|
|
||||||
* **Accuracy & Completeness:** Strive for accurate extraction and provide all available details when calling createContact.
|
|
||||||
* **No Duplicates:** The core purpose of the listContacts check is to prevent duplicate entries.
|
|
||||||
* **Use Provided Tools Only:** Only use listContacts, createContact, and stopAgent.
|
|
||||||
`
|
`
|
||||||
|
|
||||||
const contactTools = `
|
const contactTools = `
|
||||||
@ -85,10 +77,10 @@ const contactTools = `
|
|||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"contactId": {
|
"contactId": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The UUID of the contact. You should only provide this IF you believe the contact already exists, from listContacts."
|
"description": "The UUID of the contact. You should only provide this IF you believe the contact already exists, from listContacts."
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The full name of the person being added as a contact. This field is mandatory."
|
"description": "The full name of the person being added as a contact. This field is mandatory."
|
||||||
@ -133,9 +125,6 @@ type createContactsArguments struct {
|
|||||||
Address *string `json:"address"`
|
Address *string `json:"address"`
|
||||||
Email *string `json:"email"`
|
Email *string `json:"email"`
|
||||||
}
|
}
|
||||||
type linkContactArguments struct {
|
|
||||||
ContactID string `json:"contactId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewContactAgent(log *log.Logger, contactModel models.ContactModel) client.AgentClient {
|
func NewContactAgent(log *log.Logger, contactModel models.ContactModel) client.AgentClient {
|
||||||
agentClient := client.CreateAgentClient(client.CreateAgentClientOptions{
|
agentClient := client.CreateAgentClient(client.CreateAgentClientOptions{
|
||||||
@ -187,27 +176,5 @@ func NewContactAgent(log *log.Logger, contactModel models.ContactModel) client.A
|
|||||||
return contact, nil
|
return contact, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("linkContact", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
|
||||||
args := linkContactArguments{}
|
|
||||||
err := json.Unmarshal([]byte(_args), &args)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
contactUuid, err := uuid.Parse(args.ContactID)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = contactModel.SaveToImage(ctx, info.ImageId, contactUuid)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Saved", nil
|
|
||||||
})
|
|
||||||
|
|
||||||
return agentClient
|
return agentClient
|
||||||
}
|
}
|
||||||
|
@ -24,27 +24,11 @@ Core Logic:
|
|||||||
* Use listLocations to check if a location matching InputName or InputAddress already exists in the saved list.
|
* Use listLocations to check if a location matching InputName or InputAddress already exists in the saved list.
|
||||||
* **If *no match*** is found:
|
* **If *no match*** is found:
|
||||||
* Use createLocation, providing the extracted InputName (required) and any other details like InputAddress.
|
* Use createLocation, providing the extracted InputName (required) and any other details like InputAddress.
|
||||||
* *(Proceed to step 5)*
|
* If no location details could be extracted from the input, use stopAgent.
|
||||||
* **If a *match*** is found (meaning it's a potential duplicate/update candidate - let the matching saved location have ExistingLocationId):
|
|
||||||
* Use updateLocation. Provide the locationId = ExistingLocationId.
|
|
||||||
* Also provide any *new or potentially refined* details extracted from the current input (e.g., name = InputName, address = InputAddress). The updateLocation tool should handle updating the record with these details and/or linking the new input context (like the image) to this existing location.
|
|
||||||
* *(Proceed to step 5)*
|
|
||||||
* If no location details could be extracted from the input in Step 1.
|
|
||||||
* *(Proceed to step 5)*
|
|
||||||
|
|
||||||
**Summarize & Stop:** Always finish by writing a concise message explaining the outcome of the turn. Examples:
|
|
||||||
* "Okay, I've answered your query about [Location Name]." (after calling reply)
|
|
||||||
* "I couldn't find [Queried Location Name] in my saved list." (after failing to find a match for a query)
|
|
||||||
* "I've saved '[InputName]' as a new location." (after calling createLocation)
|
|
||||||
* "I found that '[InputName]' was already saved, so I've updated its information/context based on your latest input." (after calling updateLocation)
|
|
||||||
* "I couldn't identify a specific location from your input." (if Step 1 failed or no action was taken)
|
|
||||||
* After providing the summary message, call stopAgent to signal the end of processing for this turn.
|
|
||||||
|
|
||||||
Tool Usage:
|
Tool Usage:
|
||||||
|
|
||||||
* listLocations: Check saved locations. Used to find matches for user queries or to detect existing entries before creating/updating. Returns matching location(s) including their locationId.
|
* listLocations: Check saved locations. Used to find matches for user queries or to detect existing entries before creating/updating. Returns matching location(s) including their locationId.
|
||||||
* createLocation: Save a *new* location. Requires name, can include address, etc.
|
* createLocation: Save a *new* location. Requires name, can include address, etc. You may also use this to update the information in a location, by providing a locationId obtained from listLocations if you believe this location already exists.
|
||||||
* updateLocation: Update an *existing* location. Requires locationId. Can include name, address, etc., to update specific fields or simply to associate the new input context with the existing location.
|
|
||||||
* stopAgent: Signals the end of the agent's processing for the current turn. Call this *after* providing the summary message.
|
* stopAgent: Signals the end of the agent's processing for the current turn. Call this *after* providing the summary message.
|
||||||
`
|
`
|
||||||
|
|
||||||
@ -93,6 +77,10 @@ const locationTools = `
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The primary name of the location (e.g., 'Eiffel Tower', 'Mom's House', 'Acme Corp HQ'). This field is mandatory."
|
"description": "The primary name of the location (e.g., 'Eiffel Tower', 'Mom's House', 'Acme Corp HQ'). This field is mandatory."
|
||||||
},
|
},
|
||||||
|
"locationId": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The UUID of the location. You should only provide this IF you believe the contact already exists, from listLocation."
|
||||||
|
},
|
||||||
"address": {
|
"address": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The full street address of the location, if available (e.g., 'Champ de Mars, 5 Av. Anatole France, 75007 Paris, France'). Include if extracted."
|
"description": "The full street address of the location, if available (e.g., 'Champ de Mars, 5 Av. Anatole France, 75007 Paris, France'). Include if extracted."
|
||||||
@ -101,23 +89,6 @@ const locationTools = `
|
|||||||
"required": ["name"]
|
"required": ["name"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "function",
|
|
||||||
"function": {
|
|
||||||
"name": "updateLocation",
|
|
||||||
"description": "Updates an existing saved location identified by its locationId. Use when input matches a pre-existing location. Pass locationId and any new details (name, address) to update.",
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"locationId": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The UUID of the location you are trying to update"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": ["locationId"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
%s
|
%s
|
||||||
{
|
{
|
||||||
@ -144,8 +115,9 @@ func getLocationAgentTools(allowReply bool) string {
|
|||||||
|
|
||||||
type listLocationArguments struct{}
|
type listLocationArguments struct{}
|
||||||
type createLocationArguments struct {
|
type createLocationArguments struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Address *string `json:"address"`
|
LocationID *string `json:"locationId"`
|
||||||
|
Address *string `json:"address"`
|
||||||
}
|
}
|
||||||
type updateLocationArguments struct {
|
type updateLocationArguments struct {
|
||||||
LocationID string `json:"locationId"`
|
LocationID string `json:"locationId"`
|
||||||
@ -180,7 +152,18 @@ func NewLocationAgent(log *log.Logger, locationModel models.LocationModel) clien
|
|||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
|
locationId := uuid.Nil
|
||||||
|
if args.LocationID != nil {
|
||||||
|
locationUuid, err := uuid.Parse(*args.LocationID)
|
||||||
|
if err != nil {
|
||||||
|
return model.Locations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
locationId = locationUuid
|
||||||
|
}
|
||||||
|
|
||||||
location, err := locationModel.Save(ctx, info.UserId, model.Locations{
|
location, err := locationModel.Save(ctx, info.UserId, model.Locations{
|
||||||
|
ID: locationId,
|
||||||
Name: args.Name,
|
Name: args.Name,
|
||||||
Address: args.Address,
|
Address: args.Address,
|
||||||
})
|
})
|
||||||
@ -197,24 +180,6 @@ func NewLocationAgent(log *log.Logger, locationModel models.LocationModel) clien
|
|||||||
return location, nil
|
return location, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("updateLocation", func(info client.ToolHandlerInfo, _args string, call client.ToolCall) (any, error) {
|
|
||||||
args := updateLocationArguments{}
|
|
||||||
err := json.Unmarshal([]byte(_args), &args)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
locationId, err := uuid.Parse(args.LocationID)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
locationModel.SaveToImage(ctx, info.ImageId, locationId)
|
|
||||||
return "Saved", nil
|
|
||||||
})
|
|
||||||
|
|
||||||
agentClient.ToolHandler.AddTool("reply", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
agentClient.ToolHandler.AddTool("reply", func(info client.ToolHandlerInfo, args string, call client.ToolCall) (any, error) {
|
||||||
return "ok", nil
|
return "ok", nil
|
||||||
})
|
})
|
||||||
|
@ -30,7 +30,50 @@ func (m LocationModel) List(ctx context.Context, userId uuid.UUID) ([]model.Loca
|
|||||||
return locations, err
|
return locations, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m LocationModel) Get(ctx context.Context, locationId uuid.UUID) (model.Locations, error) {
|
||||||
|
getLocationStmt := Locations.
|
||||||
|
SELECT(Locations.AllColumns).
|
||||||
|
WHERE(Locations.ID.EQ(UUID(locationId)))
|
||||||
|
|
||||||
|
location := model.Locations{}
|
||||||
|
err := getLocationStmt.QueryContext(ctx, m.dbPool, &location)
|
||||||
|
|
||||||
|
return location, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m LocationModel) Update(ctx context.Context, location model.Locations) (model.Locations, error) {
|
||||||
|
existingLocation, err := m.Get(ctx, location.ID)
|
||||||
|
if err != nil {
|
||||||
|
return model.Locations{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
existingLocation.Name = location.Name
|
||||||
|
|
||||||
|
if location.Description != nil {
|
||||||
|
existingLocation.Description = location.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
if location.Address != nil {
|
||||||
|
existingLocation.Address = location.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLocationStmt := Locations.
|
||||||
|
UPDATE(Locations.MutableColumns).
|
||||||
|
MODEL(existingLocation).
|
||||||
|
WHERE(Locations.ID.EQ(UUID(location.ID))).
|
||||||
|
RETURNING(Locations.AllColumns)
|
||||||
|
|
||||||
|
updatedLocation := model.Locations{}
|
||||||
|
err = updateLocationStmt.QueryContext(ctx, m.dbPool, &updatedLocation)
|
||||||
|
|
||||||
|
return updatedLocation, err
|
||||||
|
}
|
||||||
|
|
||||||
func (m LocationModel) Save(ctx context.Context, userId uuid.UUID, location model.Locations) (model.Locations, error) {
|
func (m LocationModel) Save(ctx context.Context, userId uuid.UUID, location model.Locations) (model.Locations, error) {
|
||||||
|
if location.ID != uuid.Nil {
|
||||||
|
return m.Update(ctx, location)
|
||||||
|
}
|
||||||
|
|
||||||
insertLocationStmt := Locations.
|
insertLocationStmt := Locations.
|
||||||
INSERT(Locations.Name, Locations.Address, Locations.Description).
|
INSERT(Locations.Name, Locations.Address, Locations.Description).
|
||||||
VALUES(location.Name, location.Address, location.Description).
|
VALUES(location.Name, location.Address, location.Description).
|
||||||
|
Reference in New Issue
Block a user