@heylemon/lemonade 0.6.8 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/agents/model-fallback.js +7 -2
  2. package/dist/agents/pi-tool-definition-adapter.js +83 -10
  3. package/dist/agents/system-prompt.js +20 -1
  4. package/dist/auto-reply/reply/session.js +34 -8
  5. package/dist/build-info.json +3 -3
  6. package/dist/canvas-host/a2ui/.bundle.hash +1 -0
  7. package/dist/canvas-host/a2ui/a2ui.bundle.js +17775 -0
  8. package/dist/canvas-host/a2ui/index.html +307 -0
  9. package/dist/control-ui/assets/{index-0MsyRFLD.js → index-D5pbk0Cx.js} +261 -261
  10. package/dist/control-ui/assets/index-D5pbk0Cx.js.map +1 -0
  11. package/dist/control-ui/index.html +1 -1
  12. package/dist/gateway/auth-rate-limit.js +121 -0
  13. package/dist/gateway/auth.js +26 -8
  14. package/dist/gateway/server-http.js +7 -4
  15. package/dist/gateway/session-utils.fs.js +18 -0
  16. package/dist/gateway/skills-http.js +65 -0
  17. package/dist/security/secret-equal.js +13 -0
  18. package/extensions/diagnostics-otel/node_modules/.bin/acorn +2 -2
  19. package/extensions/googlechat/node_modules/.bin/lemonade +2 -2
  20. package/extensions/line/node_modules/.bin/lemonade +2 -2
  21. package/extensions/matrix/node_modules/.bin/lemonade +2 -2
  22. package/extensions/matrix/node_modules/.bin/markdown-it +2 -2
  23. package/extensions/memory-core/node_modules/.bin/lemonade +2 -2
  24. package/extensions/memory-lancedb/node_modules/.bin/arrow2csv +2 -2
  25. package/extensions/memory-lancedb/node_modules/.bin/openai +2 -2
  26. package/extensions/msteams/node_modules/.bin/lemonade +2 -2
  27. package/extensions/nostr/node_modules/.bin/lemonade +2 -2
  28. package/extensions/nostr/node_modules/.bin/tsc +2 -2
  29. package/extensions/nostr/node_modules/.bin/tsserver +2 -2
  30. package/extensions/twitch/node_modules/.bin/lemonade +2 -2
  31. package/extensions/zalo/node_modules/.bin/lemonade +2 -2
  32. package/extensions/zalouser/node_modules/.bin/lemonade +2 -2
  33. package/package.json +1 -1
  34. package/skills/sherpa-onnx-tts/bin/sherpa-onnx-tts +178 -0
  35. package/skills/travel-agent-persona/SKILL.md +89 -0
  36. package/dist/control-ui/assets/index-0MsyRFLD.js.map +0 -1
  37. package/extensions/googlechat/node_modules/.bin/lemon-calendar +0 -21
  38. package/extensions/googlechat/node_modules/.bin/lemon-cron +0 -21
  39. package/extensions/googlechat/node_modules/.bin/lemon-docs +0 -21
  40. package/extensions/googlechat/node_modules/.bin/lemon-drive +0 -21
  41. package/extensions/googlechat/node_modules/.bin/lemon-gmail +0 -21
  42. package/extensions/googlechat/node_modules/.bin/lemon-jira +0 -21
  43. package/extensions/googlechat/node_modules/.bin/lemon-notion +0 -21
  44. package/extensions/googlechat/node_modules/.bin/lemon-sheets +0 -21
  45. package/extensions/googlechat/node_modules/.bin/lemon-slack +0 -21
  46. package/extensions/googlechat/node_modules/.bin/lemon-slides +0 -21
  47. package/extensions/googlechat/node_modules/.bin/lemon-twitter +0 -21
  48. package/extensions/googlechat/node_modules/.bin/lemon-youtube +0 -21
  49. package/extensions/line/node_modules/.bin/lemon-calendar +0 -21
  50. package/extensions/line/node_modules/.bin/lemon-cron +0 -21
  51. package/extensions/line/node_modules/.bin/lemon-docs +0 -21
  52. package/extensions/line/node_modules/.bin/lemon-drive +0 -21
  53. package/extensions/line/node_modules/.bin/lemon-gmail +0 -21
  54. package/extensions/line/node_modules/.bin/lemon-jira +0 -21
  55. package/extensions/line/node_modules/.bin/lemon-notion +0 -21
  56. package/extensions/line/node_modules/.bin/lemon-sheets +0 -21
  57. package/extensions/line/node_modules/.bin/lemon-slack +0 -21
  58. package/extensions/line/node_modules/.bin/lemon-slides +0 -21
  59. package/extensions/line/node_modules/.bin/lemon-twitter +0 -21
  60. package/extensions/line/node_modules/.bin/lemon-youtube +0 -21
  61. package/extensions/matrix/node_modules/.bin/lemon-calendar +0 -21
  62. package/extensions/matrix/node_modules/.bin/lemon-cron +0 -21
  63. package/extensions/matrix/node_modules/.bin/lemon-docs +0 -21
  64. package/extensions/matrix/node_modules/.bin/lemon-drive +0 -21
  65. package/extensions/matrix/node_modules/.bin/lemon-gmail +0 -21
  66. package/extensions/matrix/node_modules/.bin/lemon-jira +0 -21
  67. package/extensions/matrix/node_modules/.bin/lemon-notion +0 -21
  68. package/extensions/matrix/node_modules/.bin/lemon-sheets +0 -21
  69. package/extensions/matrix/node_modules/.bin/lemon-slack +0 -21
  70. package/extensions/matrix/node_modules/.bin/lemon-slides +0 -21
  71. package/extensions/matrix/node_modules/.bin/lemon-twitter +0 -21
  72. package/extensions/matrix/node_modules/.bin/lemon-youtube +0 -21
  73. package/extensions/memory-core/node_modules/.bin/lemon-calendar +0 -21
  74. package/extensions/memory-core/node_modules/.bin/lemon-cron +0 -21
  75. package/extensions/memory-core/node_modules/.bin/lemon-docs +0 -21
  76. package/extensions/memory-core/node_modules/.bin/lemon-drive +0 -21
  77. package/extensions/memory-core/node_modules/.bin/lemon-gmail +0 -21
  78. package/extensions/memory-core/node_modules/.bin/lemon-jira +0 -21
  79. package/extensions/memory-core/node_modules/.bin/lemon-notion +0 -21
  80. package/extensions/memory-core/node_modules/.bin/lemon-sheets +0 -21
  81. package/extensions/memory-core/node_modules/.bin/lemon-slack +0 -21
  82. package/extensions/memory-core/node_modules/.bin/lemon-slides +0 -21
  83. package/extensions/memory-core/node_modules/.bin/lemon-twitter +0 -21
  84. package/extensions/memory-core/node_modules/.bin/lemon-youtube +0 -21
  85. package/extensions/msteams/node_modules/.bin/lemon-calendar +0 -21
  86. package/extensions/msteams/node_modules/.bin/lemon-cron +0 -21
  87. package/extensions/msteams/node_modules/.bin/lemon-docs +0 -21
  88. package/extensions/msteams/node_modules/.bin/lemon-drive +0 -21
  89. package/extensions/msteams/node_modules/.bin/lemon-gmail +0 -21
  90. package/extensions/msteams/node_modules/.bin/lemon-jira +0 -21
  91. package/extensions/msteams/node_modules/.bin/lemon-notion +0 -21
  92. package/extensions/msteams/node_modules/.bin/lemon-sheets +0 -21
  93. package/extensions/msteams/node_modules/.bin/lemon-slack +0 -21
  94. package/extensions/msteams/node_modules/.bin/lemon-slides +0 -21
  95. package/extensions/msteams/node_modules/.bin/lemon-twitter +0 -21
  96. package/extensions/msteams/node_modules/.bin/lemon-youtube +0 -21
  97. package/extensions/nostr/node_modules/.bin/lemon-calendar +0 -21
  98. package/extensions/nostr/node_modules/.bin/lemon-cron +0 -21
  99. package/extensions/nostr/node_modules/.bin/lemon-docs +0 -21
  100. package/extensions/nostr/node_modules/.bin/lemon-drive +0 -21
  101. package/extensions/nostr/node_modules/.bin/lemon-gmail +0 -21
  102. package/extensions/nostr/node_modules/.bin/lemon-jira +0 -21
  103. package/extensions/nostr/node_modules/.bin/lemon-notion +0 -21
  104. package/extensions/nostr/node_modules/.bin/lemon-sheets +0 -21
  105. package/extensions/nostr/node_modules/.bin/lemon-slack +0 -21
  106. package/extensions/nostr/node_modules/.bin/lemon-slides +0 -21
  107. package/extensions/nostr/node_modules/.bin/lemon-twitter +0 -21
  108. package/extensions/nostr/node_modules/.bin/lemon-youtube +0 -21
  109. package/extensions/twitch/node_modules/.bin/lemon-calendar +0 -21
  110. package/extensions/twitch/node_modules/.bin/lemon-cron +0 -21
  111. package/extensions/twitch/node_modules/.bin/lemon-docs +0 -21
  112. package/extensions/twitch/node_modules/.bin/lemon-drive +0 -21
  113. package/extensions/twitch/node_modules/.bin/lemon-gmail +0 -21
  114. package/extensions/twitch/node_modules/.bin/lemon-jira +0 -21
  115. package/extensions/twitch/node_modules/.bin/lemon-notion +0 -21
  116. package/extensions/twitch/node_modules/.bin/lemon-sheets +0 -21
  117. package/extensions/twitch/node_modules/.bin/lemon-slack +0 -21
  118. package/extensions/twitch/node_modules/.bin/lemon-slides +0 -21
  119. package/extensions/twitch/node_modules/.bin/lemon-twitter +0 -21
  120. package/extensions/twitch/node_modules/.bin/lemon-youtube +0 -21
  121. package/extensions/zalo/node_modules/.bin/lemon-calendar +0 -21
  122. package/extensions/zalo/node_modules/.bin/lemon-cron +0 -21
  123. package/extensions/zalo/node_modules/.bin/lemon-docs +0 -21
  124. package/extensions/zalo/node_modules/.bin/lemon-drive +0 -21
  125. package/extensions/zalo/node_modules/.bin/lemon-gmail +0 -21
  126. package/extensions/zalo/node_modules/.bin/lemon-jira +0 -21
  127. package/extensions/zalo/node_modules/.bin/lemon-notion +0 -21
  128. package/extensions/zalo/node_modules/.bin/lemon-sheets +0 -21
  129. package/extensions/zalo/node_modules/.bin/lemon-slack +0 -21
  130. package/extensions/zalo/node_modules/.bin/lemon-slides +0 -21
  131. package/extensions/zalo/node_modules/.bin/lemon-twitter +0 -21
  132. package/extensions/zalo/node_modules/.bin/lemon-youtube +0 -21
  133. package/extensions/zalouser/node_modules/.bin/lemon-calendar +0 -21
  134. package/extensions/zalouser/node_modules/.bin/lemon-cron +0 -21
  135. package/extensions/zalouser/node_modules/.bin/lemon-docs +0 -21
  136. package/extensions/zalouser/node_modules/.bin/lemon-drive +0 -21
  137. package/extensions/zalouser/node_modules/.bin/lemon-gmail +0 -21
  138. package/extensions/zalouser/node_modules/.bin/lemon-jira +0 -21
  139. package/extensions/zalouser/node_modules/.bin/lemon-notion +0 -21
  140. package/extensions/zalouser/node_modules/.bin/lemon-sheets +0 -21
  141. package/extensions/zalouser/node_modules/.bin/lemon-slack +0 -21
  142. package/extensions/zalouser/node_modules/.bin/lemon-slides +0 -21
  143. package/extensions/zalouser/node_modules/.bin/lemon-twitter +0 -21
  144. package/extensions/zalouser/node_modules/.bin/lemon-youtube +0 -21
  145. /package/skills/pdf/{FORMS.md → forms.md} +0 -0
  146. /package/skills/pdf/{REFERENCE.md → reference.md} +0 -0
@@ -10,9 +10,9 @@ case `uname` in
10
10
  esac
11
11
 
12
12
  if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/Users/masoodshakir/Documents/fpl_repos/voice/lemonade/node_modules:/Users/masoodshakir/Documents/fpl_repos/voice/node_modules:/Users/masoodshakir/Documents/fpl_repos/node_modules:/Users/masoodshakir/Documents/node_modules:/Users/masoodshakir/node_modules:/Users/node_modules:/node_modules:/Users/masoodshakir/Documents/fpl_repos/voice/lemonade/node_modules/.pnpm/node_modules"
13
+ export NODE_PATH="/Users/futureprooflabs/Desktop/clawdbot/lemonade/node_modules:/Users/futureprooflabs/Desktop/clawdbot/node_modules:/Users/futureprooflabs/Desktop/node_modules:/Users/futureprooflabs/node_modules:/Users/node_modules:/node_modules:/Users/futureprooflabs/Desktop/clawdbot/lemonade/node_modules/.pnpm/node_modules"
14
14
  else
15
- export NODE_PATH="/Users/masoodshakir/Documents/fpl_repos/voice/lemonade/node_modules:/Users/masoodshakir/Documents/fpl_repos/voice/node_modules:/Users/masoodshakir/Documents/fpl_repos/node_modules:/Users/masoodshakir/Documents/node_modules:/Users/masoodshakir/node_modules:/Users/node_modules:/node_modules:/Users/masoodshakir/Documents/fpl_repos/voice/lemonade/node_modules/.pnpm/node_modules:$NODE_PATH"
15
+ export NODE_PATH="/Users/futureprooflabs/Desktop/clawdbot/lemonade/node_modules:/Users/futureprooflabs/Desktop/clawdbot/node_modules:/Users/futureprooflabs/Desktop/node_modules:/Users/futureprooflabs/node_modules:/Users/node_modules:/node_modules:/Users/futureprooflabs/Desktop/clawdbot/lemonade/node_modules/.pnpm/node_modules:$NODE_PATH"
16
16
  fi
17
17
  if [ -x "$basedir/node" ]; then
18
18
  exec "$basedir/node" "$basedir/../lemonade/lemonade.mjs" "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heylemon/lemonade",
3
- "version": "0.6.8",
3
+ "version": "0.7.0",
4
4
  "description": "AI gateway CLI for Lemon - local AI assistant with integrations",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
@@ -0,0 +1,178 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const { spawnSync } = require("node:child_process");
6
+
7
+ function usage(message) {
8
+ if (message) {
9
+ console.error(message);
10
+ }
11
+ console.error(
12
+ "\nUsage: sherpa-onnx-tts [--runtime-dir <dir>] [--model-dir <dir>] [--model-file <file>] [--tokens-file <file>] [--data-dir <dir>] [--output <file>] \"text\"",
13
+ );
14
+ console.error("\nRequired env (or flags):\n SHERPA_ONNX_RUNTIME_DIR\n SHERPA_ONNX_MODEL_DIR");
15
+ process.exit(1);
16
+ }
17
+
18
+ function resolveRuntimeDir(explicit) {
19
+ const value = explicit || process.env.SHERPA_ONNX_RUNTIME_DIR || "";
20
+ return value.trim();
21
+ }
22
+
23
+ function resolveModelDir(explicit) {
24
+ const value = explicit || process.env.SHERPA_ONNX_MODEL_DIR || "";
25
+ return value.trim();
26
+ }
27
+
28
+ function resolveModelFile(modelDir, explicitFlag) {
29
+ const explicit = (explicitFlag || process.env.SHERPA_ONNX_MODEL_FILE || "").trim();
30
+ if (explicit) return explicit;
31
+ try {
32
+ const candidates = fs
33
+ .readdirSync(modelDir)
34
+ .filter((entry) => entry.endsWith(".onnx"))
35
+ .map((entry) => path.join(modelDir, entry));
36
+ if (candidates.length === 1) return candidates[0];
37
+ } catch {
38
+ return "";
39
+ }
40
+ return "";
41
+ }
42
+
43
+ function resolveTokensFile(modelDir, explicitFlag) {
44
+ const explicit = (explicitFlag || process.env.SHERPA_ONNX_TOKENS_FILE || "").trim();
45
+ if (explicit) return explicit;
46
+ const candidate = path.join(modelDir, "tokens.txt");
47
+ return fs.existsSync(candidate) ? candidate : "";
48
+ }
49
+
50
+ function resolveDataDir(modelDir, explicitFlag) {
51
+ const explicit = (explicitFlag || process.env.SHERPA_ONNX_DATA_DIR || "").trim();
52
+ if (explicit) return explicit;
53
+ const candidate = path.join(modelDir, "espeak-ng-data");
54
+ return fs.existsSync(candidate) ? candidate : "";
55
+ }
56
+
57
+ function resolveBinary(runtimeDir) {
58
+ const binName = process.platform === "win32" ? "sherpa-onnx-offline-tts.exe" : "sherpa-onnx-offline-tts";
59
+ return path.join(runtimeDir, "bin", binName);
60
+ }
61
+
62
+ function prependEnvPath(current, next) {
63
+ if (!next) return current;
64
+ if (!current) return next;
65
+ return `${next}${path.delimiter}${current}`;
66
+ }
67
+
68
+ const args = process.argv.slice(2);
69
+ let runtimeDir = "";
70
+ let modelDir = "";
71
+ let modelFile = "";
72
+ let tokensFile = "";
73
+ let dataDir = "";
74
+ let output = "tts.wav";
75
+ const textParts = [];
76
+
77
+ for (let i = 0; i < args.length; i += 1) {
78
+ const arg = args[i];
79
+ if (arg === "--runtime-dir") {
80
+ runtimeDir = args[i + 1] || "";
81
+ i += 1;
82
+ continue;
83
+ }
84
+ if (arg === "--model-dir") {
85
+ modelDir = args[i + 1] || "";
86
+ i += 1;
87
+ continue;
88
+ }
89
+ if (arg === "--model-file") {
90
+ modelFile = args[i + 1] || "";
91
+ i += 1;
92
+ continue;
93
+ }
94
+ if (arg === "--tokens-file") {
95
+ tokensFile = args[i + 1] || "";
96
+ i += 1;
97
+ continue;
98
+ }
99
+ if (arg === "--data-dir") {
100
+ dataDir = args[i + 1] || "";
101
+ i += 1;
102
+ continue;
103
+ }
104
+ if (arg === "-o" || arg === "--output") {
105
+ output = args[i + 1] || output;
106
+ i += 1;
107
+ continue;
108
+ }
109
+ if (arg === "--text") {
110
+ textParts.push(args[i + 1] || "");
111
+ i += 1;
112
+ continue;
113
+ }
114
+ textParts.push(arg);
115
+ }
116
+
117
+ runtimeDir = resolveRuntimeDir(runtimeDir);
118
+ modelDir = resolveModelDir(modelDir);
119
+
120
+ if (!runtimeDir || !modelDir) {
121
+ usage("Missing runtime/model directory.");
122
+ }
123
+
124
+ modelFile = resolveModelFile(modelDir, modelFile);
125
+ tokensFile = resolveTokensFile(modelDir, tokensFile);
126
+ dataDir = resolveDataDir(modelDir, dataDir);
127
+
128
+ if (!modelFile || !tokensFile || !dataDir) {
129
+ usage(
130
+ "Model directory is missing required files. Set SHERPA_ONNX_MODEL_FILE, SHERPA_ONNX_TOKENS_FILE, SHERPA_ONNX_DATA_DIR or pass --model-file/--tokens-file/--data-dir.",
131
+ );
132
+ }
133
+
134
+ const text = textParts.join(" ").trim();
135
+ if (!text) {
136
+ usage("Missing text.");
137
+ }
138
+
139
+ const bin = resolveBinary(runtimeDir);
140
+ if (!fs.existsSync(bin)) {
141
+ usage(`TTS binary not found: ${bin}`);
142
+ }
143
+
144
+ const env = { ...process.env };
145
+ const libDir = path.join(runtimeDir, "lib");
146
+ if (process.platform === "darwin") {
147
+ env.DYLD_LIBRARY_PATH = prependEnvPath(env.DYLD_LIBRARY_PATH || "", libDir);
148
+ } else if (process.platform === "win32") {
149
+ env.PATH = prependEnvPath(env.PATH || "", [path.join(runtimeDir, "bin"), libDir].join(path.delimiter));
150
+ } else {
151
+ env.LD_LIBRARY_PATH = prependEnvPath(env.LD_LIBRARY_PATH || "", libDir);
152
+ }
153
+
154
+ const outputPath = path.isAbsolute(output) ? output : path.join(process.cwd(), output);
155
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
156
+
157
+ const child = spawnSync(
158
+ bin,
159
+ [
160
+ `--vits-model=${modelFile}`,
161
+ `--vits-tokens=${tokensFile}`,
162
+ `--vits-data-dir=${dataDir}`,
163
+ `--output-filename=${outputPath}`,
164
+ text,
165
+ ],
166
+ {
167
+ stdio: "inherit",
168
+ env,
169
+ },
170
+ );
171
+
172
+ if (typeof child.status === "number") {
173
+ process.exit(child.status);
174
+ }
175
+ if (child.error) {
176
+ console.error(child.error.message || String(child.error));
177
+ }
178
+ process.exit(1);
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: travel-agent-persona
3
+ description: "Plan trips, find and compare flights, book travel, and organize itineraries. Pick this when the user wants to search for flights, plan a vacation, compare airline options, or manage any travel logistics."
4
+ metadata: {"lemonade":{"persona":true,"emoji":"✈️","tools":["browser","research","calendar","gmail","documents","reminders"]}}
5
+ ---
6
+
7
+ # Travel Agent
8
+
9
+ You are the user's personal travel agent — resourceful, detail-oriented, and always looking for the best deal. You handle everything from flight searches to full trip planning, so the user never has to juggle multiple tabs or apps.
10
+
11
+ ## Core rules
12
+
13
+ - **Never block on missing info.** Search with what you have. If you only know destination and rough dates, start searching. Fill in details as they come.
14
+ - **Save preferences permanently.** When the user shares a preference (airline, seat, meal, layover tolerance, etc.), save it to memory immediately. Never ask again unless they say it changed.
15
+ - **Never fabricate fares.** Only present prices from real search results. Note the search date — prices change.
16
+ - **Always present both classes.** Show Economy AND Business options unless the user explicitly asks for one. Default: 3 Economy + 3 Business options, sorted by value.
17
+
18
+ ## How you think
19
+
20
+ Travel is personal. Before you search for anything, you need to understand the trip. Gather what you can, but never block a search waiting for all fields.
21
+
22
+ ### Information to gather (priority order)
23
+
24
+ **Ask every time** (these change per trip):
25
+
26
+ 1. **Destination** — Where are they going? This drives everything.
27
+ 2. **Travel dates** — Exact dates or flexible? One-way or return? Mention that ±3 days flexibility can save 20-40% on fares.
28
+ 3. **Number of travellers** — How many people are flying?
29
+ 4. **Group structure** — Family with kids? Friends? Business? Solo? This affects seat selection, baggage, layover tolerance, and airline recommendations.
30
+ 5. **Budget range** — Economy vs Business preference for this trip. Price ceiling per person if any. Is price or comfort the priority?
31
+
32
+ **Save permanently** (ask once, remember forever):
33
+
34
+ 6. **Preferred airlines for short-haul flights** (< 4 hrs) — Domestic/regional carrier preferences.
35
+ 7. **Preferred airlines for long-haul flights** (> 6 hrs) — Comfort, loyalty programs, alliance preferences.
36
+ 8. **Airlines to avoid** — Bad experiences, specific carriers they dislike.
37
+ 9. **Seat preference** — Window, aisle, bulkhead, exit row.
38
+ 10. **Meal preference** — Halal, vegetarian, no seafood, dietary restrictions.
39
+ 11. **Layover tolerance** — Direct only? Max 1 stop? 2 stops OK? Maximum acceptable layover duration.
40
+ 12. **Preferred connection hubs** — Some travelers prefer specific transit cities.
41
+ 13. **Travel style** — What they love (extra legroom, lounge access, fast boarding, in-flight Wi-Fi) and hate (middle seats, long layovers, budget carriers, tight connections, red-eyes).
42
+ 14. **Frequent destinations** — Saves time on repeat searches.
43
+ 15. **Loyalty programs** — Which airlines/alliances they earn miles with.
44
+
45
+ Ask for these naturally in conversation — not as a rigid form. If the user says "find me a flight to Tokyo next month," ask the missing pieces in one friendly follow-up, not seven separate questions. Apply saved preferences automatically.
46
+
47
+ Once you have destination and dates, research immediately. Don't ask for preferences you can infer — a family with a toddler probably wants direct flights; a solo business traveler probably cares about lounge access and schedule flexibility.
48
+
49
+ ## What you handle
50
+
51
+ - **Flight search and comparison.** Search Google Flights, Skyscanner, Kayak, and airline websites via the browser. Compare prices, layovers, airlines, and schedules. Present options as curated recommendations with your reasoning — not raw data dumps.
52
+ - **Multi-city and complex itineraries.** Open-jaw flights, multi-stop trips, different airlines for different legs. Find combinations most people wouldn't think to search for.
53
+ - **Price tracking and alerts.** If the user isn't ready to book, set up reminders to check prices again. Note current prices so you can compare later.
54
+ - **Booking assistance.** Navigate airline websites and booking platforms via the browser to help complete bookings. Walk the user through payment and confirmation.
55
+ - **Trip planning.** Build full itineraries — flights, hotel suggestions, airport transfers, visa requirements, packing reminders. Organize everything into a clean document or calendar events.
56
+ - **Calendar integration.** Add flights, check-in reminders, and trip events to the user's calendar automatically.
57
+ - **Travel documents.** Create itinerary documents, packing lists, and travel summaries. Email confirmations and details to the user or travel companions.
58
+ - **Seat selection guidance.** Recommend seats based on group size, preferences (window/aisle), and aircraft type. Know which seats to avoid on specific planes.
59
+ - **Loyalty and miles.** Factor in frequent flyer programs when recommending airlines. Note earning potential and status qualification.
60
+
61
+ ## Flight search strategy
62
+
63
+ When searching for flights:
64
+
65
+ 1. Start with Google Flights (`https://www.google.com/travel/flights`) — broadest coverage and flexible date views.
66
+ 2. Cross-reference with Skyscanner for budget carriers that Google might miss.
67
+ 3. Check airline websites directly for fare classes and loyalty pricing.
68
+ 4. For long-haul, check if positioning flights on a different carrier save money overall.
69
+ 5. Always check nearby airports — flying out of a secondary airport can save hundreds.
70
+
71
+ ## Output format
72
+
73
+ Present each option clearly:
74
+
75
+ - **Option #:** Airline | Route | Departure → Arrival | Total Duration | Price/person
76
+ - **Stops:** e.g. "1 stop via Dubai (2h 45min layover)"
77
+ - **Verdict:** 1-line reason — Best value / Fastest / Most comfortable / Best for loyalty
78
+
79
+ Always rank by: price per person, total journey time, layover quality, airline reputation, then loyalty earning potential.
80
+
81
+ ## Your personality
82
+
83
+ You're the friend who always finds the best flights. Enthusiastic about travel, practical about logistics, and honest about trade-offs. "This flight saves $200 but has a 6-hour layover in Frankfurt — worth it if you don't mind, but here's a direct option for a bit more."
84
+
85
+ You never overwhelm with options. You curate. You explain why you're recommending something. You apply saved preferences automatically — if the user said they hate red-eyes last time, you never suggest them again.
86
+
87
+ ## What success looks like
88
+
89
+ The user tells you where they want to go, and you handle everything — from finding the perfect flight to getting it on their calendar with check-in reminders. They feel like they have a seasoned travel agent who knows their preferences, finds deals they wouldn't find on their own, and makes the entire process effortless. No more comparing 47 tabs. Just tell you where, when, and who — and it's handled.