careervivid 1.12.2 → 1.12.4

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 (122) hide show
  1. package/dist/agent/CareerVividProxyEngine.d.ts +73 -0
  2. package/dist/agent/CareerVividProxyEngine.d.ts.map +1 -0
  3. package/dist/agent/CareerVividProxyEngine.js +320 -0
  4. package/dist/agent/QueryEngine.d.ts +1 -0
  5. package/dist/agent/QueryEngine.d.ts.map +1 -1
  6. package/dist/agent/QueryEngine.js +130 -2
  7. package/dist/agent/providers/AnthropicProvider.js +2 -2
  8. package/dist/agent/providers/LLMProvider.d.ts +2 -0
  9. package/dist/agent/providers/LLMProvider.d.ts.map +1 -1
  10. package/dist/agent/providers/OpenAIProvider.js +2 -2
  11. package/dist/agent/tools/browser.d.ts +22 -0
  12. package/dist/agent/tools/browser.d.ts.map +1 -0
  13. package/dist/agent/tools/browser.js +666 -0
  14. package/dist/agent/tools/coding.d.ts.map +1 -1
  15. package/dist/agent/tools/coding.js +25 -0
  16. package/dist/agent/tools/jobs.d.ts +1 -0
  17. package/dist/agent/tools/jobs.d.ts.map +1 -1
  18. package/dist/agent/tools/jobs.js +211 -0
  19. package/dist/agent/tools/local-tracker.d.ts +29 -0
  20. package/dist/agent/tools/local-tracker.d.ts.map +1 -0
  21. package/dist/agent/tools/local-tracker.js +777 -0
  22. package/dist/api.d.ts +31 -0
  23. package/dist/api.d.ts.map +1 -1
  24. package/dist/api.js +7 -0
  25. package/dist/apply/adapters/ashby.d.ts +21 -0
  26. package/dist/apply/adapters/ashby.d.ts.map +1 -0
  27. package/dist/apply/adapters/ashby.js +209 -0
  28. package/dist/apply/adapters/generic.d.ts +24 -0
  29. package/dist/apply/adapters/generic.d.ts.map +1 -0
  30. package/dist/apply/adapters/generic.js +249 -0
  31. package/dist/apply/adapters/greenhouse.d.ts +31 -0
  32. package/dist/apply/adapters/greenhouse.d.ts.map +1 -0
  33. package/dist/apply/adapters/greenhouse.js +285 -0
  34. package/dist/apply/adapters/icims.d.ts +26 -0
  35. package/dist/apply/adapters/icims.d.ts.map +1 -0
  36. package/dist/apply/adapters/icims.js +191 -0
  37. package/dist/apply/adapters/lever.d.ts +16 -0
  38. package/dist/apply/adapters/lever.d.ts.map +1 -0
  39. package/dist/apply/adapters/lever.js +88 -0
  40. package/dist/apply/adapters/linkedin.d.ts +22 -0
  41. package/dist/apply/adapters/linkedin.d.ts.map +1 -0
  42. package/dist/apply/adapters/linkedin.js +135 -0
  43. package/dist/apply/browser.d.ts +56 -0
  44. package/dist/apply/browser.d.ts.map +1 -0
  45. package/dist/apply/browser.js +164 -0
  46. package/dist/apply/gemini-agent.d.ts +85 -0
  47. package/dist/apply/gemini-agent.d.ts.map +1 -0
  48. package/dist/apply/gemini-agent.js +319 -0
  49. package/dist/apply/index.d.ts +35 -0
  50. package/dist/apply/index.d.ts.map +1 -0
  51. package/dist/apply/index.js +52 -0
  52. package/dist/commands/agent/configurator.d.ts +22 -0
  53. package/dist/commands/agent/configurator.d.ts.map +1 -0
  54. package/dist/commands/agent/configurator.js +190 -0
  55. package/dist/commands/agent/engineResolver.d.ts +17 -0
  56. package/dist/commands/agent/engineResolver.d.ts.map +1 -0
  57. package/dist/commands/agent/engineResolver.js +87 -0
  58. package/dist/commands/agent/index.d.ts +3 -0
  59. package/dist/commands/agent/index.d.ts.map +1 -0
  60. package/dist/commands/agent/index.js +99 -0
  61. package/dist/commands/agent/repl.d.ts +16 -0
  62. package/dist/commands/agent/repl.d.ts.map +1 -0
  63. package/dist/commands/agent/repl.js +313 -0
  64. package/dist/commands/agent/toolRegistry.d.ts +7 -0
  65. package/dist/commands/agent/toolRegistry.d.ts.map +1 -0
  66. package/dist/commands/agent/toolRegistry.js +84 -0
  67. package/dist/commands/agent.d.ts.map +1 -1
  68. package/dist/commands/agent.js +201 -95
  69. package/dist/commands/apply.d.ts +15 -0
  70. package/dist/commands/apply.d.ts.map +1 -0
  71. package/dist/commands/apply.js +667 -0
  72. package/dist/commands/auth.d.ts.map +1 -1
  73. package/dist/commands/auth.js +3 -1
  74. package/dist/commands/eval.d.ts +17 -0
  75. package/dist/commands/eval.d.ts.map +1 -0
  76. package/dist/commands/eval.js +145 -0
  77. package/dist/commands/jobs.d.ts.map +1 -1
  78. package/dist/commands/jobs.js +3 -0
  79. package/dist/commands/logout.d.ts +3 -0
  80. package/dist/commands/logout.d.ts.map +1 -0
  81. package/dist/commands/logout.js +36 -0
  82. package/dist/commands/publish.d.ts +2 -0
  83. package/dist/commands/publish.d.ts.map +1 -1
  84. package/dist/commands/publish.js +3 -0
  85. package/dist/config.d.ts +11 -0
  86. package/dist/config.d.ts.map +1 -1
  87. package/dist/config.js +27 -0
  88. package/dist/eval/index.d.ts +17 -0
  89. package/dist/eval/index.d.ts.map +1 -0
  90. package/dist/eval/index.js +15 -0
  91. package/dist/eval/runner.d.ts +39 -0
  92. package/dist/eval/runner.d.ts.map +1 -0
  93. package/dist/eval/runner.js +349 -0
  94. package/dist/eval/scorer.d.ts +64 -0
  95. package/dist/eval/scorer.d.ts.map +1 -0
  96. package/dist/eval/scorer.js +245 -0
  97. package/dist/eval/storage/CsvDataLogger.d.ts +37 -0
  98. package/dist/eval/storage/CsvDataLogger.d.ts.map +1 -0
  99. package/dist/eval/storage/CsvDataLogger.js +162 -0
  100. package/dist/eval/storage/FirebaseDataLogger.d.ts +48 -0
  101. package/dist/eval/storage/FirebaseDataLogger.d.ts.map +1 -0
  102. package/dist/eval/storage/FirebaseDataLogger.js +91 -0
  103. package/dist/eval/storage/IDataLogger.d.ts +48 -0
  104. package/dist/eval/storage/IDataLogger.d.ts.map +1 -0
  105. package/dist/eval/storage/IDataLogger.js +18 -0
  106. package/dist/eval/test-cases/base-agent.d.ts +11 -0
  107. package/dist/eval/test-cases/base-agent.d.ts.map +1 -0
  108. package/dist/eval/test-cases/base-agent.js +140 -0
  109. package/dist/eval/test-cases/index.d.ts +19 -0
  110. package/dist/eval/test-cases/index.d.ts.map +1 -0
  111. package/dist/eval/test-cases/index.js +25 -0
  112. package/dist/eval/test-cases/jobs-agent.d.ts +15 -0
  113. package/dist/eval/test-cases/jobs-agent.d.ts.map +1 -0
  114. package/dist/eval/test-cases/jobs-agent.js +309 -0
  115. package/dist/eval/test-cases/resume-agent.d.ts +16 -0
  116. package/dist/eval/test-cases/resume-agent.d.ts.map +1 -0
  117. package/dist/eval/test-cases/resume-agent.js +137 -0
  118. package/dist/eval/types.d.ts +163 -0
  119. package/dist/eval/types.d.ts.map +1 -0
  120. package/dist/eval/types.js +18 -0
  121. package/dist/index.js +35 -1
  122. package/package.json +8 -7
@@ -0,0 +1,73 @@
1
+ /**
2
+ * CareerVividProxyEngine
3
+ *
4
+ * A drop-in replacement for QueryEngine that routes all Gemini API calls
5
+ * through the CareerVivid `agentProxy` Firebase function instead of calling
6
+ * Gemini directly. This allows users without a personal Gemini key to use
7
+ * the AI agent via their CareerVivid account credits.
8
+ *
9
+ * The proxy handles:
10
+ * - Authentication (via cv_live_... API key)
11
+ * - Credit deduction (atomically with each Gemini call)
12
+ * - Gemini API call (server-side, using the CareerVivid Gemini secret)
13
+ *
14
+ * The engine handles:
15
+ * - History management
16
+ * - Tool execution (locally, in the CLI)
17
+ * - Agentic loop (multi-turn tool calls)
18
+ * - Context compaction
19
+ */
20
+ import type { Content } from "@google/genai";
21
+ import { Tool } from "./Tool.js";
22
+ export interface ProxyEngineOptions {
23
+ cvApiKey: string;
24
+ model?: string;
25
+ systemInstruction?: string;
26
+ tools?: Tool[];
27
+ thinkingBudget?: number;
28
+ includeThoughts?: boolean;
29
+ maxHistoryLength?: number;
30
+ }
31
+ export interface ProxyIterationHook {
32
+ onStart?: () => void;
33
+ onResponse?: (creditInfo: {
34
+ creditsUsed: number;
35
+ creditsRemaining: number;
36
+ monthlyLimit: number;
37
+ }) => void | Promise<void>;
38
+ onToolCall?: (toolName: string, args: any) => Promise<boolean | void>;
39
+ onToolResult?: (toolName: string, result: any) => void;
40
+ onError?: (error: Error) => void;
41
+ onChunk?: (text: string) => void;
42
+ onThinking?: (thought: string) => void;
43
+ onCompacting?: () => void;
44
+ /** Fired when credit limit is reached — engine will stop the loop */
45
+ onCreditLimitReached?: (remaining: number) => void;
46
+ }
47
+ export declare class CareerVividProxyEngine {
48
+ private cvApiKey;
49
+ private model;
50
+ private systemInstruction;
51
+ private tools;
52
+ private toolMap;
53
+ private thinkingBudget;
54
+ private includeThoughts;
55
+ private maxHistoryLength;
56
+ private history;
57
+ private sessionCreditsUsed;
58
+ private lastKnownRemaining;
59
+ private monthlyLimit;
60
+ constructor(options: ProxyEngineOptions);
61
+ getHistory(): Content[];
62
+ setHistory(history: Content[]): void;
63
+ /** Credits used in this session */
64
+ get sessionUsed(): number;
65
+ /** Last known remaining credits */
66
+ get remaining(): number | null;
67
+ private callProxy;
68
+ private compactHistory;
69
+ private executeToolCalls;
70
+ runLoopStreaming(prompt: string, hooks?: ProxyIterationHook): Promise<string>;
71
+ runLoop(prompt: string, hooks?: ProxyIterationHook): Promise<string>;
72
+ }
73
+ //# sourceMappingURL=CareerVividProxyEngine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CareerVividProxyEngine.d.ts","sourceRoot":"","sources":["../../src/agent/CareerVividProxyEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAQ,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,IAAI,EAAsB,MAAM,WAAW,CAAC;AAcrD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,gBAAgB,EAAE,MAAM,CAAC;QACzB,YAAY,EAAE,MAAM,CAAC;KACtB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACtE,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACvD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B,qEAAqE;IACrE,oBAAoB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AAoCD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,OAAO,CAAiB;IAGhC,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,YAAY,CAAuB;gBAE/B,OAAO,EAAE,kBAAkB;IAWhC,UAAU,IAAI,OAAO,EAAE;IAIvB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE;IAIpC,mCAAmC;IACnC,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,mCAAmC;IACnC,IAAI,SAAS,IAAI,MAAM,GAAG,IAAI,CAE7B;YAMa,SAAS;YAqDT,cAAc;YAed,gBAAgB;IA6DjB,gBAAgB,CAC3B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,kBAAkB,GACzB,OAAO,CAAC,MAAM,CAAC;IAQL,OAAO,CAClB,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,kBAAkB,GACzB,OAAO,CAAC,MAAM,CAAC;CAwInB"}
@@ -0,0 +1,320 @@
1
+ /**
2
+ * CareerVividProxyEngine
3
+ *
4
+ * A drop-in replacement for QueryEngine that routes all Gemini API calls
5
+ * through the CareerVivid `agentProxy` Firebase function instead of calling
6
+ * Gemini directly. This allows users without a personal Gemini key to use
7
+ * the AI agent via their CareerVivid account credits.
8
+ *
9
+ * The proxy handles:
10
+ * - Authentication (via cv_live_... API key)
11
+ * - Credit deduction (atomically with each Gemini call)
12
+ * - Gemini API call (server-side, using the CareerVivid Gemini secret)
13
+ *
14
+ * The engine handles:
15
+ * - History management
16
+ * - Tool execution (locally, in the CLI)
17
+ * - Agentic loop (multi-turn tool calls)
18
+ * - Context compaction
19
+ */
20
+ import { convertToGenAITool } from "./Tool.js";
21
+ // ─────────────────────────────────────────────────────────────────────────────
22
+ // Constants
23
+ // ─────────────────────────────────────────────────────────────────────────────
24
+ const FIREBASE_REGION = "us-west1";
25
+ const FIREBASE_PROJECT_ID = "jastalk-firebase";
26
+ const PROXY_URL = `https://${FIREBASE_REGION}-${FIREBASE_PROJECT_ID}.cloudfunctions.net/agentProxy`;
27
+ // ─────────────────────────────────────────────────────────────────────────────
28
+ // Retry utility
29
+ // ─────────────────────────────────────────────────────────────────────────────
30
+ async function sleep(ms) {
31
+ return new Promise((resolve) => setTimeout(resolve, ms));
32
+ }
33
+ async function retryWithBackoff(fn, maxRetries = 3, baseDelayMs = 1000) {
34
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
35
+ try {
36
+ return await fn();
37
+ }
38
+ catch (e) {
39
+ const isRetryable = e?.status === 429 ||
40
+ e?.status === 503 ||
41
+ /rate.?limit|quota|too.?many.?requests|service.?unavailable/i.test(e?.message || "");
42
+ if (attempt === maxRetries || !isRetryable)
43
+ throw e;
44
+ await sleep(baseDelayMs * Math.pow(2, attempt));
45
+ }
46
+ }
47
+ throw new Error("retryWithBackoff: unreachable");
48
+ }
49
+ // ─────────────────────────────────────────────────────────────────────────────
50
+ // CareerVividProxyEngine
51
+ // ─────────────────────────────────────────────────────────────────────────────
52
+ export class CareerVividProxyEngine {
53
+ cvApiKey;
54
+ model;
55
+ systemInstruction;
56
+ tools;
57
+ toolMap;
58
+ thinkingBudget;
59
+ includeThoughts;
60
+ maxHistoryLength;
61
+ history = [];
62
+ // Running credit totals for the session
63
+ sessionCreditsUsed = 0;
64
+ lastKnownRemaining = null;
65
+ monthlyLimit = null;
66
+ constructor(options) {
67
+ this.cvApiKey = options.cvApiKey;
68
+ this.model = options.model ?? "gemini-2.5-flash";
69
+ this.systemInstruction = options.systemInstruction ?? "";
70
+ this.tools = options.tools ?? [];
71
+ this.toolMap = new Map(this.tools.map((t) => [t.name, t]));
72
+ this.thinkingBudget = options.thinkingBudget ?? 0;
73
+ this.includeThoughts = options.includeThoughts ?? false;
74
+ this.maxHistoryLength = options.maxHistoryLength ?? 40;
75
+ }
76
+ getHistory() {
77
+ return this.history;
78
+ }
79
+ setHistory(history) {
80
+ this.history = history;
81
+ }
82
+ /** Credits used in this session */
83
+ get sessionUsed() {
84
+ return this.sessionCreditsUsed;
85
+ }
86
+ /** Last known remaining credits */
87
+ get remaining() {
88
+ return this.lastKnownRemaining;
89
+ }
90
+ // ─────────────────────────────────────────────────────────────────────────
91
+ // Private helpers
92
+ // ─────────────────────────────────────────────────────────────────────────
93
+ async callProxy(contents) {
94
+ const genAITools = this.tools.map(convertToGenAITool);
95
+ const body = {
96
+ apiKey: this.cvApiKey,
97
+ model: this.model,
98
+ contents,
99
+ systemInstruction: this.systemInstruction || undefined,
100
+ };
101
+ if (genAITools.length > 0) {
102
+ // @google/generative-ai format: { functionDeclarations: [...] }
103
+ body.tools = [{ functionDeclarations: genAITools.flatMap((t) => t.functionDeclarations ?? [t]) }];
104
+ }
105
+ if (this.thinkingBudget > 0) {
106
+ body.thinkingBudget = this.thinkingBudget;
107
+ body.includeThoughts = this.includeThoughts;
108
+ }
109
+ const response = await fetch(PROXY_URL, {
110
+ method: "POST",
111
+ headers: { "Content-Type": "application/json" },
112
+ body: JSON.stringify(body),
113
+ });
114
+ if (response.status === 402) {
115
+ const data = await response.json();
116
+ return {
117
+ creditsUsed: 0,
118
+ creditsRemaining: data.creditsRemaining ?? 0,
119
+ monthlyLimit: data.monthlyLimit ?? 100,
120
+ reason: "limit_reached",
121
+ };
122
+ }
123
+ if (!response.ok) {
124
+ const data = await response.json().catch(() => ({}));
125
+ throw new Error(data.error || `Proxy error: HTTP ${response.status}`);
126
+ }
127
+ return response.json();
128
+ }
129
+ async compactHistory() {
130
+ // Simple compaction: keep the last 20 turns
131
+ if (this.history.length > this.maxHistoryLength) {
132
+ const summary = {
133
+ role: "user",
134
+ parts: [
135
+ {
136
+ text: `[Context compacted — ${this.history.length} prior turns summarized to save context space. Continue the conversation normally.]`,
137
+ },
138
+ ],
139
+ };
140
+ this.history = [summary, ...this.history.slice(-20)];
141
+ }
142
+ }
143
+ async executeToolCalls(functionCalls, hooks) {
144
+ const functionResponses = [];
145
+ for (const call of functionCalls) {
146
+ const toolName = call.name || "";
147
+ const args = call.args || {};
148
+ const tool = this.toolMap.get(toolName);
149
+ if (!tool) {
150
+ functionResponses.push({
151
+ functionResponse: {
152
+ name: toolName,
153
+ response: {
154
+ error: `Tool "${toolName}" not found. Available: ${[...this.toolMap.keys()].join(", ")}`,
155
+ },
156
+ },
157
+ });
158
+ continue;
159
+ }
160
+ if (hooks?.onToolCall) {
161
+ const allow = await hooks.onToolCall(toolName, args);
162
+ if (allow === false) {
163
+ functionResponses.push({
164
+ functionResponse: {
165
+ name: toolName,
166
+ response: { error: "User denied tool execution." },
167
+ },
168
+ });
169
+ continue;
170
+ }
171
+ }
172
+ try {
173
+ const result = await tool.execute(args);
174
+ if (hooks?.onToolResult)
175
+ hooks.onToolResult(toolName, result);
176
+ functionResponses.push({
177
+ functionResponse: { name: toolName, response: { result } },
178
+ });
179
+ }
180
+ catch (err) {
181
+ functionResponses.push({
182
+ functionResponse: {
183
+ name: toolName,
184
+ response: { error: String(err.message || err) },
185
+ },
186
+ });
187
+ }
188
+ }
189
+ return functionResponses;
190
+ }
191
+ // ─────────────────────────────────────────────────────────────────────────
192
+ // Public: runLoopStreaming (interface-compatible with QueryEngine)
193
+ // Note: The proxy does not stream — text is printed all at once after each
194
+ // proxy call. True streaming requires a different proxy endpoint.
195
+ // ─────────────────────────────────────────────────────────────────────────
196
+ async runLoopStreaming(prompt, hooks) {
197
+ return this.runLoop(prompt, hooks);
198
+ }
199
+ // ─────────────────────────────────────────────────────────────────────────
200
+ // Public: runLoop
201
+ // ─────────────────────────────────────────────────────────────────────────
202
+ async runLoop(prompt, hooks) {
203
+ this.history.push({ role: "user", parts: [{ text: prompt }] });
204
+ let maxIterations = 30;
205
+ let iterations = 0;
206
+ let finalAnswer = "";
207
+ while (iterations < maxIterations) {
208
+ iterations++;
209
+ if (hooks?.onStart)
210
+ hooks.onStart();
211
+ // Compact if needed
212
+ if (this.history.length > this.maxHistoryLength) {
213
+ if (hooks?.onCompacting)
214
+ hooks.onCompacting();
215
+ await this.compactHistory();
216
+ }
217
+ try {
218
+ const proxyResult = await retryWithBackoff(() => this.callProxy(this.history));
219
+ // Credit limit reached
220
+ if (proxyResult.reason === "limit_reached") {
221
+ this.lastKnownRemaining = proxyResult.creditsRemaining;
222
+ if (hooks?.onCreditLimitReached) {
223
+ hooks.onCreditLimitReached(proxyResult.creditsRemaining);
224
+ }
225
+ finalAnswer = "❌ Credit limit reached. Please upgrade or top up at careervivid.app/developer";
226
+ break;
227
+ }
228
+ // Update credit tracking
229
+ this.sessionCreditsUsed += proxyResult.creditsUsed ?? 0;
230
+ this.lastKnownRemaining = proxyResult.creditsRemaining;
231
+ this.monthlyLimit = proxyResult.monthlyLimit;
232
+ if (hooks?.onResponse) {
233
+ await hooks.onResponse({
234
+ creditsUsed: proxyResult.creditsUsed,
235
+ creditsRemaining: proxyResult.creditsRemaining,
236
+ monthlyLimit: proxyResult.monthlyLimit,
237
+ });
238
+ }
239
+ // Parse Gemini response
240
+ const candidate = proxyResult.candidates?.[0];
241
+ if (!candidate) {
242
+ finalAnswer = "No response from Gemini.";
243
+ break;
244
+ }
245
+ const parts = candidate.content?.parts ?? [];
246
+ // Add model response to history
247
+ this.history.push({
248
+ role: "model",
249
+ parts: parts.length > 0 ? parts : [{ text: "" }],
250
+ });
251
+ // Extract thinking text
252
+ if (this.includeThoughts && hooks?.onThinking) {
253
+ const thoughtParts = parts.filter((p) => p.thought);
254
+ for (const part of thoughtParts) {
255
+ if (part.text)
256
+ hooks.onThinking(part.text);
257
+ }
258
+ }
259
+ // Extract function calls
260
+ const functionCalls = parts
261
+ .filter((p) => p.functionCall)
262
+ .map((p) => ({
263
+ name: p.functionCall.name,
264
+ args: p.functionCall.args ?? {},
265
+ }));
266
+ if (functionCalls.length > 0) {
267
+ // Tool call turn — execute tools and loop
268
+ const functionResponses = await this.executeToolCalls(functionCalls, hooks);
269
+ this.history.push({ role: "user", parts: functionResponses });
270
+ continue;
271
+ }
272
+ // Text response — emit chunks and break
273
+ const textParts = parts
274
+ .filter((p) => p.text && !p.thought)
275
+ .map((p) => p.text);
276
+ const fullText = textParts.join("");
277
+ // [Harness Engineering] Prevent lazy conversational exits for Jobs Agent
278
+ if (this.systemInstruction && this.systemInstruction.includes("DO NOT ASK FOR PERMISSION")) {
279
+ const textOut = fullText;
280
+ const lowerText = textOut.toLowerCase();
281
+ const askingPermission = lowerText.includes("would you like me to") ||
282
+ lowerText.includes("how would you like to proceed") ||
283
+ lowerText.includes("should i go ahead") ||
284
+ lowerText.includes("shall i") ||
285
+ lowerText.includes("could you please provide") ||
286
+ lowerText.includes("i need your permission") ||
287
+ lowerText.includes("please provide") ||
288
+ lowerText.includes("could you provide");
289
+ if (askingPermission && iterations < maxIterations - 1) {
290
+ if (hooks?.onThinking)
291
+ hooks.onThinking("Harness intercepted permission seeking. Auto-correcting...");
292
+ this.history.push({
293
+ role: 'user',
294
+ parts: [{ text: "[Harness Instruction]: You halted execution to ask for permission or missing information. RE-READ YOUR HARNESS DIRECTIVES. You must autonomously execute the mutation (e.g., update_local_job or add_local_job) using defaults for missing fields. Do not wait for confirmation. Do it now." }]
295
+ });
296
+ continue;
297
+ }
298
+ }
299
+ // Emit as a "chunk" so the caller's onChunk handler can print it
300
+ if (hooks?.onChunk && fullText) {
301
+ hooks.onChunk(fullText);
302
+ }
303
+ finalAnswer = fullText;
304
+ break;
305
+ }
306
+ catch (e) {
307
+ if (hooks?.onError)
308
+ hooks.onError(e);
309
+ finalAnswer = `Generation Error: ${e.message}`;
310
+ break;
311
+ }
312
+ }
313
+ if (iterations >= maxIterations) {
314
+ finalAnswer =
315
+ finalAnswer ||
316
+ "Max iterations (30) exceeded without a final answer.";
317
+ }
318
+ return finalAnswer;
319
+ }
320
+ }
@@ -1,6 +1,7 @@
1
1
  import { GenerateContentResponse, Content } from '@google/genai';
2
2
  import { Tool } from './Tool.js';
3
3
  export declare const CODING_AGENT_SYSTEM_PROMPT: string;
4
+ export declare const JOBS_SYSTEM_PROMPT: string;
4
5
  export interface QueryEngineOptions {
5
6
  model?: string;
6
7
  systemInstruction?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"QueryEngine.d.ts","sourceRoot":"","sources":["../../src/agent/QueryEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,uBAAuB,EAAE,OAAO,EAAQ,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,IAAI,EAAsB,MAAM,WAAW,CAAC;AAMrD,eAAO,MAAM,0BAA0B,QA8B/B,CAAC;AAMT,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACtE,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACvD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,kDAAkD;IAClD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,wEAAwE;IACxE,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAyCD;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,gBAAgB,CAAS;gBAErB,OAAO,GAAE,kBAAuB;IAyBrC,UAAU,IAAI,OAAO,EAAE;IAIvB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE;IAIpC,8CAA8C;IACvC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE;IAW7B,OAAO,CAAC,mBAAmB;YAcb,YAAY;YAOZ,gBAAgB;IA6DjB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAgF5E;;;;OAIG;IACU,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;CA+FtF"}
1
+ {"version":3,"file":"QueryEngine.d.ts","sourceRoot":"","sources":["../../src/agent/QueryEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,uBAAuB,EAAE,OAAO,EAAQ,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,IAAI,EAAsB,MAAM,WAAW,CAAC;AAMrD,eAAO,MAAM,0BAA0B,QA8B/B,CAAC;AAKT,eAAO,MAAM,kBAAkB,QAgFI,CAAC;AAMpC,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,gEAAgE;IAChE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,0FAA0F;IAC1F,UAAU,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,uBAAuB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACtE,YAAY,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,IAAI,CAAC;IACvD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,kDAAkD;IAClD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,wEAAwE;IACxE,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gDAAgD;IAChD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAyCD;;;;GAIG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAAc;IACxB,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,iBAAiB,CAAS;IAClC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,gBAAgB,CAAS;gBAErB,OAAO,GAAE,kBAAuB;IAyBrC,UAAU,IAAI,OAAO,EAAE;IAIvB,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE;IAIpC,8CAA8C;IACvC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE;IAW7B,OAAO,CAAC,mBAAmB;YAcb,YAAY;YAOZ,gBAAgB;IA6DjB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAqG5E;;;;OAIG;IACU,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;CAoHtF"}
@@ -36,6 +36,90 @@ For every coding task, follow this loop:
36
36
  - Keep functions short and focused on a single responsibility.
37
37
  `.trim();
38
38
  // ---------------------------------------------------------------------------
39
+ // Elite Jobs System Prompt
40
+ // ---------------------------------------------------------------------------
41
+ export const JOBS_SYSTEM_PROMPT = `You are the CareerVivid elite jobs agent — a proactive career strategist.
42
+
43
+ ## CRITICAL: TOOL-FIRST POLICY (MANDATORY — NO EXCEPTIONS)
44
+ You MUST call a tool BEFORE writing any response text when the user's message concerns their job pipeline or search.
45
+ NEVER answer pipeline questions from memory or general knowledge. ALWAYS fetch fresh data from tools first.
46
+
47
+ ### Mandatory Tool Dispatch Table
48
+ | If the user asks about... | You MUST call... |
49
+ |---|---|
50
+ | pipeline, jobs list, tracker, companies | list_local_jobs |
51
+ | priority, what to work on, best ROI, what next | score_pipeline |
52
+ | how is my search, dashboard, stats, metrics, apply rate | get_pipeline_metrics |
53
+ | neglecting, stale, cold, going dark, need attention | flag_stale_jobs |
54
+ | adding a company, tracking a new job | add_local_job |
55
+ | updating status, marking applied, setting follow-up | update_local_job |
56
+ | resume, background, skills, experience | get_resume |
57
+ | job search, find jobs, search for roles | get_resume THEN search_jobs |
58
+
59
+ This table is NON-NEGOTIABLE. Do not skip tools. Do not describe what you "would" do. CALL THE TOOL.
60
+
61
+ ## Core Tools
62
+ - list_local_jobs → Show the pipeline (supports tier/status filters and sort_by)
63
+ - update_local_job → Update any field on a job entry (status, attention, excitement, notes, follow-up)
64
+ - add_local_job → Add a new company to the tracker (auto-generates ID + priority score)
65
+ - score_pipeline → 📊 Priority-ranked view using attention formula (use for "what next?" questions)
66
+ - get_pipeline_metrics → 📈 Full analytics dashboard (apply rate, avg scores, salary, stale count)
67
+ - flag_stale_jobs → ⚠️ Surface companies going cold with next-action recommendations
68
+ - get_resume → Load the user's CareerVivid resume to personalize advice
69
+ - search_jobs → Search for newly posted jobs scored against the user's resume
70
+ - list_jobs → Show online Kanban board (separate from local CSV)
71
+
72
+ ## Attention Matrix (v2 Schema)
73
+ Every company in the tracker has 8 attention/effort metrics:
74
+ - attention_score (1–10): How top-of-mind is this company right now?
75
+ - excitement (1–10): Pure enthusiasm for the role/company
76
+ - apply_effort (Low/Medium/High): How much work is this application?
77
+ - prep_time_hours: Estimated research hours needed
78
+ - company_stage: Seed / Series A-C / Public / Enterprise
79
+ - open_roles_count: How many roles are open
80
+ - interview_rounds: Known interview process length
81
+ - last_activity_date: Auto-stamped on every update (staleness detection)
82
+
83
+ Priority Score formula: 40% attention + 30% excitement + 20% fit + 10% recency
84
+
85
+ ## Behavioral Rules
86
+ 1. ALWAYS call a tool first before giving any information about the user's pipeline
87
+ 2. ALWAYS call score_pipeline for "what should I work on?", "highest priority?", "what next?"
88
+ 3. ALWAYS call get_pipeline_metrics for "how is my search?", "stats", "dashboard", "apply rate"
89
+ 4. ALWAYS call flag_stale_jobs for "what am I neglecting?", "stale", "cold", "need attention"
90
+ 5. When marking a job Applied, AUTOMATICALLY suggest setting a follow-up date 7 days out
91
+ 6. Surface quick-apply opportunities (Low effort + To Apply) whenever user has limited time
92
+ 7. NEVER fabricate job data — only reference data returned by tools
93
+
94
+ ## Harness Directives: Autonomous Execution & Anti-Rationalization
95
+ 1. DO NOT ASK FOR PERMISSION. If the user's context clearly implies an action, you MUST autonomously use 'update_local_job', 'add_local_job', or other mutative tools to advance their pipeline without waiting for approval.
96
+ 2. If the user asks you to add or modify a job but doesn't provide all possible details (e.g., date, role, url), DO NOT ask them for the missing details. Use defaults like 'TBD', today's date, or empty strings and execute the tool immediately.
97
+ 3. If you catch yourself explaining what you are going to do instead of calling the tool, STOP. Call the tool.
98
+ 4. Complete the workflow entirely in a single turn. Do not use conversational handoffs (e.g. "Would you like me to...", "Could you provide...", "I need your permission") unless performing a destructive action.
99
+ 5. "Ask for forgiveness, not permission." Execute the action automatically.
100
+
101
+ ## Response Style
102
+ - Format pipeline views as clean tables or bulleted lists with icons
103
+ - Always show [ID], company, role, status, and priority score when discussing specific jobs
104
+ - Be proactive: if you notice stale jobs or low apply velocity, mention it unprompted
105
+
106
+ ## Greeting Protocol
107
+ When the user sends a generic greeting (e.g., "hey", "hello", "hi", "start"), you MUST return exactly this standardized routing menu, word-for-word, and do not call any tools:
108
+
109
+ "Hello! How can I help you today? Are you looking to:
110
+
111
+ View your job pipeline?
112
+
113
+ Find new job opportunities?
114
+
115
+ Update a job's status?
116
+
117
+ Tailor your resume?
118
+
119
+ Get an overview of your job search progress?
120
+
121
+ Let me know what you need!"`.trim();
122
+ // ---------------------------------------------------------------------------
39
123
  // Retry utility
40
124
  // ---------------------------------------------------------------------------
41
125
  const RETRYABLE_STATUS_CODES = new Set([429, 500, 502, 503, 504]);
@@ -240,7 +324,29 @@ export class QueryEngine {
240
324
  : [{ text: response.text || '' }],
241
325
  });
242
326
  if (!hasToolCalls) {
243
- finalAnswer = response.text || '';
327
+ const textOut = response.text || '';
328
+ // [Harness Engineering] Prevent lazy conversational exits for Jobs Agent
329
+ if (this.systemInstruction.includes("DO NOT ASK FOR PERMISSION")) {
330
+ const lowerText = textOut.toLowerCase();
331
+ const askingPermission = lowerText.includes("would you like me to") ||
332
+ lowerText.includes("how would you like to proceed") ||
333
+ lowerText.includes("should i go ahead") ||
334
+ lowerText.includes("shall i") ||
335
+ lowerText.includes("could you please provide") ||
336
+ lowerText.includes("i need your permission") ||
337
+ lowerText.includes("please provide") ||
338
+ lowerText.includes("could you provide");
339
+ if (askingPermission && iterations < maxIterations - 1) {
340
+ if (hooks?.onThinking)
341
+ hooks.onThinking("Harness intercepted permission seeking. Auto-correcting...");
342
+ this.history.push({
343
+ role: 'user',
344
+ parts: [{ text: "[Harness Instruction]: You halted execution to ask for permission or missing information. RE-READ YOUR HARNESS DIRECTIVES. You must autonomously execute the mutation (e.g., update_local_job or add_local_job) using defaults for missing fields. Do not wait for confirmation. Do it now." }]
345
+ });
346
+ continue;
347
+ }
348
+ }
349
+ finalAnswer = textOut;
244
350
  break;
245
351
  }
246
352
  const functionResponses = await this.executeToolCalls(functionCalls, hooks);
@@ -331,7 +437,29 @@ export class QueryEngine {
331
437
  if (hooks?.onResponse)
332
438
  await hooks.onResponse(undefined);
333
439
  if (!hasToolCalls) {
334
- finalAnswer = accumulatedText;
440
+ const textOut = accumulatedText;
441
+ // [Harness Engineering] Prevent lazy conversational exits for Jobs Agent
442
+ if (this.systemInstruction.includes("DO NOT ASK FOR PERMISSION")) {
443
+ const lowerText = textOut.toLowerCase();
444
+ const askingPermission = lowerText.includes("would you like me to") ||
445
+ lowerText.includes("how would you like to proceed") ||
446
+ lowerText.includes("should i go ahead") ||
447
+ lowerText.includes("shall i") ||
448
+ lowerText.includes("could you please provide") ||
449
+ lowerText.includes("i need your permission") ||
450
+ lowerText.includes("please provide") ||
451
+ lowerText.includes("could you provide");
452
+ if (askingPermission && iterations < maxIterations - 1) {
453
+ if (hooks?.onThinking)
454
+ hooks.onThinking("Harness intercepted permission seeking. Auto-correcting...");
455
+ this.history.push({
456
+ role: 'user',
457
+ parts: [{ text: "[Harness Instruction]: You halted execution to ask for permission or missing information. RE-READ YOUR HARNESS DIRECTIVES. You must autonomously execute the mutation (e.g., update_local_job or add_local_job) using defaults for missing fields. Do not wait for confirmation. Do it now." }]
458
+ });
459
+ continue;
460
+ }
461
+ }
462
+ finalAnswer = textOut;
335
463
  break;
336
464
  }
337
465
  const functionResponses = await this.executeToolCalls(accumulatedFunctionCalls, hooks);
@@ -83,7 +83,7 @@ export class AnthropicProvider {
83
83
  const messages = this.toAnthropicMessages(history, userTurn);
84
84
  const anthropicTools = tools.length > 0 ? this.toAnthropicTools(tools) : undefined;
85
85
  const body = {
86
- model: "", // set by caller
86
+ model: request.model || "", // set by caller
87
87
  max_tokens: 8192,
88
88
  system: systemInstruction,
89
89
  messages,
@@ -136,7 +136,7 @@ export class AnthropicProvider {
136
136
  const messages = this.toAnthropicMessages(history, userTurn);
137
137
  const anthropicTools = tools.length > 0 ? this.toAnthropicTools(tools) : undefined;
138
138
  const body = {
139
- model: "",
139
+ model: request.model || "",
140
140
  max_tokens: 8192,
141
141
  system: systemInstruction,
142
142
  messages,
@@ -21,6 +21,8 @@ export interface LLMRequest {
21
21
  thinkingBudget?: number;
22
22
  /** Whether to include thinking text */
23
23
  includeThoughts?: boolean;
24
+ /** Optional model override for BYO providers */
25
+ model?: string;
24
26
  }
25
27
  export interface LLMResponse {
26
28
  /** Text response parts from the model */
@@ -1 +1 @@
1
- {"version":3,"file":"LLMProvider.d.ts","sourceRoot":"","sources":["../../../src/agent/providers/LLMProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,iEAAiE;IACjE,QAAQ,EAAE,OAAO,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,yBAAyB;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAClD,+EAA+E;IAC/E,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjB,kBAAkB;IAClB,UAAU,EAAE,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,OAAO,CAAC;CAC5D;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IACnD,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEpD;;;OAGG;IACH,cAAc,CACZ,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GACvC,OAAO,CAAC,WAAW,CAAC,CAAC;CACzB"}
1
+ {"version":3,"file":"LLMProvider.d.ts","sourceRoot":"","sources":["../../../src/agent/providers/LLMProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,WAAW,UAAU;IACzB,yEAAyE;IACzE,OAAO,EAAE,OAAO,EAAE,CAAC;IACnB,iEAAiE;IACjE,QAAQ,EAAE,OAAO,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,yBAAyB;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IAClD,+EAA+E;IAC/E,QAAQ,EAAE,IAAI,EAAE,CAAC;IACjB,kBAAkB;IAClB,UAAU,EAAE,MAAM,GAAG,YAAY,GAAG,YAAY,GAAG,OAAO,CAAC;CAC5D;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,GAAG,CAAA;KAAE,CAAC,CAAC;IACnD,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;IAClB,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEpD;;;OAGG;IACH,cAAc,CACZ,OAAO,EAAE,UAAU,EACnB,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,GACvC,OAAO,CAAC,WAAW,CAAC,CAAC;CACzB"}
@@ -97,7 +97,7 @@ export class OpenAIProvider {
97
97
  const messages = this.toOpenAIMessages(history, userTurn, systemInstruction);
98
98
  const openAITools = tools.length > 0 ? this.toOpenAITools(tools) : undefined;
99
99
  const body = {
100
- model: "", // caller sets via fetch; we don't store model here
100
+ model: request.model || "", // fallback to empty if missing
101
101
  messages,
102
102
  ...(openAITools ? { tools: openAITools, tool_choice: "auto" } : {}),
103
103
  };
@@ -147,7 +147,7 @@ export class OpenAIProvider {
147
147
  const messages = this.toOpenAIMessages(history, userTurn, systemInstruction);
148
148
  const openAITools = tools.length > 0 ? this.toOpenAITools(tools) : undefined;
149
149
  const body = {
150
- model: "",
150
+ model: request.model || "",
151
151
  messages,
152
152
  stream: true,
153
153
  ...(openAITools ? { tools: openAITools, tool_choice: "auto" } : {}),
@@ -0,0 +1,22 @@
1
+ /**
2
+ * browser.ts — Browser control tools for the CareerVivid Agent.
3
+ *
4
+ * These tools give the Gemini agent interactive browser control, enabling it
5
+ * to navigate pages, read interactive elements, fill forms, click buttons,
6
+ * and handle multi-page application workflows — just like Antigravity or
7
+ * Claude Desktop's Computer Use.
8
+ *
9
+ * Architecture:
10
+ * - Uses a DEDICATED automation Chromium profile (never conflicts with real Chrome)
11
+ * - Sessions persist via ~/.careervivid/browser-session/ between agent runs
12
+ * - Each tool is a standard Tool object that plugs into QueryEngine's tool loop
13
+ * - DOM is simplified to a numbered Accessibility Object Model (AOM) for the LLM
14
+ *
15
+ * Why NOT the real Chrome profile:
16
+ * Chrome locks its profile while running. Attempting launchPersistentContext
17
+ * on the real profile while Chrome is open causes a SIGTRAP crash.
18
+ * The dedicated profile avoids this entirely and is always available.
19
+ */
20
+ import { Tool } from "../Tool.js";
21
+ export declare const ALL_BROWSER_TOOLS: Tool[];
22
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/agent/tools/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAysBlC,eAAO,MAAM,iBAAiB,EAAE,IAAI,EAanC,CAAC"}