Skip to content

Commit ef19af4

Browse files
authored
Merge pull request #7 from satti-hari-krishna-reddy/main
feat: introduce autocorrected app selection based on fields
2 parents 954c01d + 56ca837 commit ef19af4

File tree

1 file changed

+93
-2
lines changed

1 file changed

+93
-2
lines changed

pkg/api.go

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,17 @@ func RunActionWrapper(ctx context.Context, user shuffle.User, value shuffle.Cate
671671
value.AppName = ""
672672
}
673673

674-
if strings.ToLower(value.AppName) == "http" {
674+
// Smart app correction: Only for generic API calls, not custom_action
675+
// custom_action means user already chose an app - don't override
676+
if strings.ToLower(value.AppName) == "http" && value.Label == "api" && len(value.Query) > 0 {
677+
correctedAppName := AnalyzeIntentAndCorrectApp(ctx, value.Query, value.Fields)
678+
if len(correctedAppName) > 0 && strings.ToLower(correctedAppName) != "http" {
679+
value.AppName = correctedAppName
680+
log.Printf("[INFO] Corrected app selection from 'http' to '%s' based on query intent", correctedAppName)
681+
}
682+
}
683+
684+
if strings.ToLower(value.AppName) == "http" {
675685
value.AppName = ""
676686
}
677687

@@ -703,7 +713,7 @@ func RunActionWrapper(ctx context.Context, user shuffle.User, value shuffle.Cate
703713

704714

705715
// WITHOUT finding the app first
706-
if /*len(value.AppName) == 0 &&*/ len(value.Category) == 0 && len(value.AppId) == 0 && (value.Label == "api" || value.Label == "custom_action" || value.Action == "custom_action") {
716+
if len(value.AppName) == 0 && len(value.Category) == 0 && len(value.AppId) == 0 && (value.Label == "api" || value.Label == "custom_action" || value.Action == "custom_action") {
707717
log.Printf("[INFO] Got Singul 'custom action' request WITHOUT app. Mapping to HTTP 1.4.0.")
708718

709719
value = GetUpdatedHttpValue(value)
@@ -4468,6 +4478,87 @@ func AuthenticateAppCli(appname string) error {
44684478
return nil
44694479
}
44704480

4481+
// AnalyzeIntentAndCorrectApp uses LLM to identify the app from URL/query
4482+
// LLM identifies app freely, then we search for it (user's apps or Algolia)
4483+
// Returns app name or empty string if HTTP is correct
4484+
func AnalyzeIntentAndCorrectApp(ctx context.Context, query string, fields []shuffle.Valuereplace) string {
4485+
4486+
urlValue := ""
4487+
fieldsSummary := ""
4488+
4489+
for _, field := range fields {
4490+
if field.Key == "url" {
4491+
urlValue = strings.TrimSpace(field.Value)
4492+
}
4493+
4494+
fieldLen := len(field.Value)
4495+
if fieldLen > 20 {
4496+
fieldLen = 20
4497+
}
4498+
fieldsSummary += field.Key + ":" + field.Value[:fieldLen] + "|"
4499+
}
4500+
4501+
systemMessage := `You are an API identification assistant.
4502+
Your job is to determine the most likely intended service or app that an API request belongs to.
4503+
The provided intent or query field may describe the reason or goal of the request and may be incorrect, vague, or misleading. Do not blindly trust it
4504+
Use all available signals together, including the URL domain, path, request fields, payload structure, headers, and the described intent.
4505+
4506+
Your goal is to identify the service the request should belong to, not necessarily what it is currently labeled as.
4507+
If the URL and fields clearly match a known service, return that service even if the intent text disagrees.
4508+
If the request does not strongly match any known service and appears to be a generic or custom HTTP call, return "http"
4509+
4510+
Examples:
4511+
- gmail.googleapis.com → Gmail
4512+
- slack.com/api → Slack
4513+
- api.github.com → GitHub
4514+
- random-api.com → http
4515+
4516+
Output rules:
4517+
Return only the service or app name.
4518+
Do not include explanations, reasoning, or extra text.
4519+
`
4520+
4521+
userMessage := fmt.Sprintf(`Analyze this API request:
4522+
- Intent: "%s"
4523+
- URL: "%s"
4524+
- Fields: %s
4525+
4526+
What service/app does this API belong to?
4527+
Return ONLY the app/service name (e.g., Gmail, Slack, GitHub).
4528+
If this is a generic HTTP call with no specific service, return "http".`,
4529+
query, urlValue, fieldsSummary)
4530+
4531+
responseBody, err := shuffle.RunAiQuery(systemMessage, userMessage)
4532+
if err != nil {
4533+
log.Printf("[WARNING] Failed calling LLM for app intent correction: %s", err)
4534+
return ""
4535+
}
4536+
4537+
// Parse LLM response
4538+
contentOutput := strings.TrimSpace(responseBody)
4539+
if after, ok := strings.CutPrefix(contentOutput, "```"); ok {
4540+
contentOutput = after
4541+
}
4542+
if after, ok := strings.CutSuffix(contentOutput, "```"); ok {
4543+
contentOutput = after
4544+
}
4545+
contentOutput = strings.TrimSpace(contentOutput)
4546+
4547+
identifiedApp := strings.TrimSpace(contentOutput)
4548+
if strings.ToLower(identifiedApp) == "http" {
4549+
return ""
4550+
}
4551+
4552+
if len(identifiedApp) > 0 {
4553+
if debug {
4554+
log.Printf("[DEBUG] LLM identified app '%s' for URL: %s, Intent: %s", identifiedApp, urlValue, query)
4555+
}
4556+
return identifiedApp
4557+
}
4558+
4559+
return ""
4560+
}
4561+
44714562
// For handling the function without changing ALL the resp.X functions
44724563
type FakeResponseWriter struct {
44734564
HeaderMap http.Header

0 commit comments

Comments
 (0)